二叉排序树的创建和基本操作---C++实现

我们已经在之前的文章里将了树和二叉树,今天讲的二叉排序树也是二叉树的一种,不过具有以下性质

1.左子树上所有结点的关键字均小于根结点的关键字;

2.右子树上所有结点的关键字均大于根结点的关键字。

3.左子树和右子树又各是一棵二叉排序树

简单来说就是根结点的左子树都是比根结点的元素值要小,根结点右边的元素都比根结点要大

代码实现如下:

二叉排序树的结点信息和初始化

cpp 复制代码
#include<iostream>
#include<stdlib.h>
#include<stdbool.h>
using namespace std;
//二叉排序树结点
typedef struct BSTNode
{
	int key;//数据域
	struct BSTNode* lchild, * rchild;//指针域
}*BSTree,BSTNode;//BSTree表示整棵树 BSTNode表示结点
//初始化
void InitTree(BSTree* T)
{
	(*T) = NULL;
}

二叉排序树的插入和构建二叉树

1.若原二叉树为空,则直接插入结点;

2.如果关键字k小于根结点值,则插入左子树

3.如果关键字k大于根结点值,则插入右子树

cpp 复制代码
//插入操作
int BST_Insert(BSTree* T, int k)
{
	//空树,直接插入结点
	if ((*T) == NULL)
	{
		(*T) = (BSTNode*)malloc(sizeof(BSTNode));
		if (*T == NULL)
			return -1;//插入失败
		(*T)->key = k;
		(*T)->lchild = NULL; //左孩子为空
		(*T)->rchild = NULL; //右孩子为空
		return 1;//插入成功
	}
	else if (k == (*T)->key)
		return -1; //如果插入相同的则直接返回
	else if (k > (*T)->key)
		return BST_Insert(&(*T)->rchild, k);//因为是要修改右子树,所以要取地址
	else
		return BST_Insert(&(*T)->lchild, k);
	return -1;
}
//构建二叉树
bool Creat_BSTree(BSTree* T, int arr[], int len)
{
	int i = 0;
	while (i < len)
	{
		BST_Insert(T, arr[i]);
		i++;
	}
	return true;
}

二叉排序树的查找(递归方式)

cpp 复制代码
//查找二叉树
BSTree BST_Search(BSTree T,int k)
{
	if (T == NULL)
		return NULL;//空树查找失败
	while (T != NULL && T->key != k)
	{
		if (k > T->key) //k大于根结点
			T = T->rchild;
		else
			T = T->lchild;
	}
	return T;
}

二叉排序树的删除

思想:

先搜索找到目标结点

1.如果被删除的结点z是叶子结点,则直接删除,不回破坏二叉排序树的性质

2.如果结点z只有一棵左子树或右子树,则让z的子树称为z父结点的子树,代替z的位置

3.如果结点z有左、右两棵子树,则令z的直接后继(或直接前驱)代替z,然后从二叉排序树中删去这个直接后继(或直接前驱),这样就转换成了第一后第二种情况

注意:

z的前驱:z的左子树中最右下的结点(该结点在左子树中一定最大)

z的后继:z的右子树中最左下的结点(该结点在右子树中一定最小)

cpp 复制代码
//删除二叉树
int Delete_BSTNode(BSTree* T, int k)
{
	if (*T == NULL)
		return -1;//空树无法删除

	BSTNode* p = BST_Search(*T, k);//查找当前元素
	BSTNode* parent = BST_SearchF((*T), k);//当前元素的父结点

	if (p == NULL)//没有该元素
		return -1;

	else if (p->lchild == NULL && p->rchild == NULL)//如果要删除叶子结点
	{
		if (parent == NULL)//如果只有一个结点
		{
			free(*T);
			*T = NULL;
		}
		else if (parent->lchild == p)//删除p
		{
			parent->lchild = NULL;
			free(p);
		}
		else
		{
			parent->rchild = NULL;
			free(p);
		}
		return 1;//删除成功
	}
	else if (p->lchild == NULL || p->rchild == NULL)//如果要删除单支结点(只有左孩子或者只有右孩子)
	{
		if (parent->lchild == p)//如果p为父结点的左孩子
		{
			if (p->lchild == NULL && p->rchild != NULL)//左孩子为空,右孩子不为空
			{
				parent->lchild = p->rchild;
				free(p);
				return 1;//删除成功
			}
			else if (p->lchild != NULL && p->rchild == NULL)//左孩子不为空,右孩子为空
			{
				parent->lchild = p->lchild;
				free(p);
				return 1;//删除成功
			}
		}
		if (parent->rchild == p)//如果p为父结点的右孩子
		{
			if (p->lchild == NULL && p->rchild != NULL)//左孩子为空,右孩子不为空
			{
				parent->rchild = p->rchild;
				free(p);
				return 1;//删除成功
			}
			else if (p->lchild != NULL && p->rchild == NULL)//左孩子不为空,右孩子为空
			{
				parent->rchild = p->lchild;
				free(p);
				return 1;//删除成功
			}
		}
	}
	else if (p->lchild != NULL && p->rchild != NULL)//如果要删除的结点有左右孩子
	{
		//查找要删除结点的直接后继(右孩子的第一个访问元素)
		BSTNode* q = p->rchild;
		while (q->lchild != NULL)
			q = q->lchild;
		p->key = q->key;

		//当前结点的直接后继的父结点
		BSTNode* currpar = BST_SearchF(*T, q->key);
		if (currpar->lchild == q)
		{
			if (q->rchild != NULL)
				currpar->lchild = q->rchild;
			else
				currpar->lchild = NULL;
			free(q);
		}
		else if (currpar->rchild == q)
		{
			if (q->rchild != NULL)
				currpar->rchild = q->rchild;
			else
				currpar->rchild = NULL;
			free(q);
		}
		return 1;//删除成功
	}
	return -1;//删除失败
}

main函数

cpp 复制代码
int main()
{
	//二叉树元素
	int arr[10] = { 60,58,98,45,65,24,37,49,86,82 };
	int len = sizeof(arr) / sizeof(arr[0]);//数组的长度
	//定义二叉树
	BSTree T;
	InitTree(&T);//初始化二叉树
	//构建二叉树
	Creat_BSTree(&T, arr,len);
	
	//查找二叉树结点(非递归算法)
	BSTNode * p = BST_Search(T,arr[9]);
	cout << "key = " << p->key << endl;//打印测试

	//删除二叉树结点
	Delete_BSTNode(&T, arr[9]);

	return 0;
}

查找效率分析:

1.若树高h,找到最下层的一个结点需要对比h次

2.最好情况:n个结点的二叉树最小高度为log2n + 1,平均查找长度为O(log2n)

3.最坏情况:每个结点只有一个分支,树高h=结点数n。则平均查找长度为O(n)

相关推荐
码匠许师傅8 小时前
【设计模式精讲】29.行为型模式总结与对比(Behavioral Patterns Summary)
c++·设计模式·uml
啦啦啦啦啦zzzz9 小时前
Logger的组装(c++20)
c++·算法·c++20
尾善爱看海10 小时前
前端算法与手写题集
前端·算法
繁星蓝雨10 小时前
C++的设计与演进大纲(如何从C语言一步步成长为C++)
c语言·开发语言·c++·c++历史·c++演进
程序员阿鹏10 小时前
为什么MySQL InnoDB选择B+树?
数据结构·数据库·b树·sql·mysql·算法·缓存
蒸蒸yyyyzwd11 小时前
机试学习笔记
c++·求职招聘
AI 思录11 小时前
Prompt 事故档案(八):日常表达被标为“待校准”,AI 的爹味语法从哪里来
大数据·人工智能·算法·prompt·用户体验·ai合规
月光船幽幽11 小时前
跨范式映射的稳定接口设计
人工智能·python·算法
handler0112 小时前
【Linux】线程与虚拟内存的底层世界
linux·运维·服务器·c++·线程·虚拟地址空间·共享内存
郝学胜-神的一滴12 小时前
C++11 工程级应用 09:告别无谓拷贝,解锁高性能移动语义
开发语言·数据结构·c++·vscode·软件工程·visual studio