二叉搜索树的查找/插入/删除以及二叉树搜索树的建立等基本操作的详细介绍

二叉搜索树(BST,Binary Search Tree),也称二叉排序树或二叉查找树
本文详细介绍了二叉搜索树的查找,插入,删除以及二叉树搜索树的建立等基本操作:

二叉搜索树定义

二叉搜索树:一棵二叉树,可以为空;如果不为空,满足以下性质:

  1. 非空左子树的所有结点的值小于其根结点的值。
  2. 非空右子树的所有结点的值大于其根结点的值。
  3. 左、右子树都是二叉搜索树。

二叉搜索树的基本操作

1.二叉搜索树的查找

二叉搜索树的查找操作:Find

例如在二叉树搜索树中查找X:

  • 查找从根结点开始,如果树为空,返回NULL
  • 若搜索树非空,则根结点关键字和X进行比较,并进行不同处理:
  1. 若X小于根结点值,只需在左子树中继续搜索;
  2. 如果X大于根结点的值,在右子树中进行继续搜索;
  3. 若两者比较结果是相等,搜索完成,返回指向此结点的指针。
    在这里插入图片描述
    很明显查找操作容易用递归实现,并且是尾递归;但由于非递归函数的执行效率高,可将“尾递归”函数改为迭代函数


    代码如下:
//在二叉搜索树中查找值为data的点,并放回该结点的地址
template<typename T> BiTree<T>* find_bst(T data,BiTree<T> *bst) {
    
    
	
	while (bst) {
    
    
		if (bst->data == data)     //查找成功,返回结点的找到结点的地址
			return bst;
		else if (bst->data < data)//向右子树中移动,继续查找
			bst = bst->right;
		else if (bst->data > data)//向左子树中移动,继续查找
			bst = bst->left;
	}
	return NULL;  //查找失败,bst为空或者bst中没有data
}

2.二叉搜索树中查找最大和最小元素

由搜索二叉树的性质可知:

  • 最大元素一定是在树的最右分枝的端结点上 ,即没有右结点
  • 最小元素一定是在树的最左分枝的端结点上 ,即没有左结点

如下图所示:
在这里插入图片描述


下面用迭代形式实现查找最小元素:

//在二叉树搜索树中迭代查找值最小的结点,并返回地址
template<typename T>BiTree<T>* find_min(BiTree<T>* bst)
{
    
       
	 if(bst)
	while(bst->left != NULL)
		bst = bst->left;

	return bst;
}

下面用递归形式实现查找最大元素

//在二叉树搜索树中递归查找值最大的结点,并返回地址
template<typename T>BiTree<T>* find_max(BiTree<T>* bst)
{
    
    
	if (!bst)return NULL;//如果二叉树为空,直接返回NULl

    if (bst->right == NULL)//如果没有右儿子了,那么它就是最大的值
	 return bst;
    else
	return find_max(bst->right);//继续递归查找	
}

2.二叉搜索树的插入

二叉搜索树的插入是建立二叉搜索树的基本操作
按查找(find)类似的方法找到元素要插入的位置,然后插入即可。插入的示例如下:
在这里插入图片描述
由此:插入一定是插入在二叉搜索树的底部的。

递归算法如下:

  • 如果bst 为空,则找到x的位置了,插入元素x,生成并返回该节点
  • 如果bst不为空
    1. 如果x < 当前节点的值,则递归插入左子树
    2. 如果x > 当前节点的值,则递归插入右子树

代码如下:

//在二叉树搜索树bst中插入一个元素data
template<typename T>BiTree<T>* insert_bst(T data, BiTree<T>* &bst) {
    
    
	if (!bst) {
    
    //若原树为空,生成并返回一个结点的二叉搜索树
		
		bst = new BiTree<T>;
		bst->data = data;
		bst->right = bst->left = NULL;
	}
	else     //开始找要插入元素的位置
	{
    
    
		if (data < bst->data) //递归插入左子树
			bst->left = insert_bst(data, bst->left);
		
		if (data > bst->data)//递归插入右子树
			bst->right = insert_bst(data, bst->right);
	}

	  return bst;
}

bst一定要传引用啊!我又在这调试了很久!┭┮﹏┭┮

4.二叉树的删除

二叉树中删除一个结点,首先进行查找,查找失败则无法删除:
查找成功,又需分三种情况去删除目标结点:

  1. 要删除的是叶结点(即无左右孩子):
    直接删除,并再修改其父结点指针—置为NULL如下图所示:

  2. 要删除的结点只有一个孩子结点:
    将其父结点的指针指向要删除结点的孩子结点:
    如下图,删除33,将41的左孩子指针指向35即可
    在这里插入图片描述

  3. 要删除的结点有左、右两棵子树:
    用另一结点替代被删除结点:
    右子树的最小元素(即待删结点的直接后继) 或者 左子树的最大元素(即待删结点的直接前驱)
    例如:

  • 方法一:用右子树的最小元素替代
    在这里插入图片描述
  • 方法二:用左子树的最大元素替代
    在这里插入图片描述
    具体的细节实现请看下面代码中的注释
    注:下面的代码采用的是右子树最大元素替代的方法,且是用迭代的形式
//在二叉搜索树bst中删除值为data的节点
template<typename T>BiTree<T>* delete_bst(T data, BiTree<T>* &bst) {
    
    
	BiTree<T>  * target,* pre_target,  * target_next,* pre_target_next,*temp;
	//target是要删除的目标节点,pre_target是待删结点target的双亲节点
	//target_next待删结点target的直接后继(target右子树的的最大元素)也就是我们要找的target的替代品
	//pre_target_next是结点target_next的双亲节点
	//temp临时指针
	pre_target = NULL;//这个细节用来出力要删结点就是bst的根节点的情况
	target = bst;
	/*查找到target*/
	while (target != NULL && target->data != data)
	{
    
    
		pre_target = target;         //pre_target始终指向target的双亲
		if (target->data < data)
			target = target->right;
		else if (target->data > data)
			target = target->left;
	}
	if (target == NULL)//查找失败
	{
    
    
		cout << "查找失败";
		return bst;
	}

	if (target->left && target->right)//如果目标节点的左右子树都不为空
	{
    
    
		pre_target_next = target;
		target_next = target;
		while (target_next->left != NULL)//给target_next定位
		{
    
    
			pre_target_next = target_next;   //pre_target_next始终指向target_next的双亲
			target_next = target->left;
		}
		target->data = target_next->data;

		//targetd_next已经补上去了,所以将其右子树接到其父亲节点上
		temp = target_next->right;	
		//这也要分两种情况
		if(pre_target_next == target)
			pre_target_next->right = temp;
		else
			pre_target_next->left = temp;

		delete temp;
		return bst;
	}
	else {
    
    //第二种情况,待删结点是单支结点
		  //(第一种情况即待删结点是叶节点也包含在这里)
		if (target->left != NULL)
			temp = target->left;
		else
			temp = target->right;
		if (pre_target == NULL)//如果要删除的节点就是根节点
		{
    
    
			delete temp;//直接释放掉待删结点的空间就可以了
		}
		else if(pre_target->right == target)//待删结点是其双亲节点的右孩子
		{
    
    
			pre_target->right = temp;  //则把待删结点的孩子接上去就行
		}
		else if(pre_target->left == target)
		{
    
    
			pre_target->left = temp;
		}
		delete target;
		return bst;
	}
}

二叉树基本操作的应用

1.二叉树的建立

基本思路:利用二叉树的插入不断插入
算法就和二叉树的建立类似

代码如下:

//创建一颗二叉树搜索树
template<typename T>BiTree<T>* create_bst() {
    
    
	T data;
	BiTree<T>* bst = NULL;

	cin >> data;
	while (data != flag)
	{
    
    
		
		insert_bst(data, bst);
		
		cin >> data;
	}
	return bst;
}

程序最终测试结果

在这里插入图片描述
完整的可调试代码请点击此链接:
二叉搜索树的查找/插入/删除以及二叉树搜索树的建立等基本操作实现的完整代码(可自行调试)

猜你喜欢

转载自blog.csdn.net/qq_45768060/article/details/106180123