一、二叉搜索树的概念
二叉搜索树又称为二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:
1.若它的左子树不为空,则左子树上所有结点的值都小于根结点的值。
2.若它的右子树不为空,则右子树上所有结点的值都大于根结点的值。
3.它的左右子树也分别是二叉搜索树。
下面就是一颗二叉搜索树
二、二叉搜索树的算法实现
1、创建二叉搜索树
创建二叉搜索树的方法就是将每一个结点依次插入二叉搜索树。主要思想是为目标节点找出合适的叶节点位置,然后将该节点作为叶节点插入。
在左边这个树里插入4,从根节点开始,4小于5,因此继续搜索左子树。4大于2,而且2没有右孩子,因此4作为2的右孩子插入到树中。
2、删除二叉搜索树的一个结点
这里的删除操作是用一个合适的子节点来替换要删除的目标节点,使整体操作变化最小。如果目标节点值大于当前节点,则指向右子树去寻找目标节点;如果目标节点值小于当前节点,则指向左子树去寻找目标节点。如果找到了目标节点,我们分为三种情况:
1:目标节点没有子节点,可以直接删除目标节点。如下图所示:
2:目标节点有右结点,右子树最左边的结点进行替代(也就是右子树里面最小的结点),该结点位于右子树中较低的位置。然后可以从后继结点的位置递归向下操作以删除后继结点。如下图所示:
3:目标节点只有左节点,可以使用它的左子树最右边的节点进行替代(也就是左子树里面的最大节点),然后再递归的向下删除节点。如下图所示:
#include<iostream>
#include<queue>
using namespace::std;
typedef struct Node
{
int data;
Node* lchild, * rchild;
}Btree;
//插入一个结点
Btree* InsertNode(Btree* T, int k)
{
if (T == nullptr)
{
T = new Btree;
T->data = k;
T->lchild = NULL;
T->rchild = NULL;
return T;
}
if (k > T->data)
{
T->rchild=InsertNode(T->rchild, k);
}
else
{
T->lchild=InsertNode(T->lchild, k);
}
return T;
}
Btree* CreatTree(Btree* T, int a[],int len)
{
for (int i = 0; i < len; i++)
{
T=InsertNode(T, a[i]); //将数据插入二叉搜索树中
}
return T;
}
//先序遍历
void PreOrder(Btree* t)
{
if (t)
{
cout << t->data<<" "; //输出结点数据
PreOrder(t->lchild);//访问左孩子
PreOrder(t->rchild);//访问右孩子
}
}
Btree* DeleteNode(Btree* T, int key)
{
Btree* Node = T;
Btree* parent=new Btree;
int flag=-1;
//找到要删除的结点
while (Node) {
if (Node->data == key)
{
break;
}
else if (key > Node->data) //如果要寻找的值大于结点的值,则向右子树遍历
{
parent = Node; //保存父节点
flag = 1; //表明删除的结点是父节点右孩子
Node = Node->rchild;
}
else
{
parent = Node; //保存父节点
flag = 0; //表明删除的结点是父结点左孩子
Node = Node->lchild; //如果要寻找的值小于结点的值,则向左子树遍历
}
}
//要删除的结点无孩子结点,直接删除
if (Node->lchild == NULL && Node->rchild == NULL)
{
if (flag == -1) //如果只有T一个结点,直接删除,返回一个空指针
{
return NULL;
}
else if (flag == 0)//删除左孩子
{
parent->lchild = NULL;
}
else if (flag == 1)//删除右孩子
{
parent->rchild = NULL;
}
}
//要删除的结点有右孩子
else if (Node->rchild != NULL)
{
Btree* MostLchild = Node->rchild;
int temp=MostLchild->data;
//找到右孩子中的最左边的结点,也就是右孩子中最小的结点
while (MostLchild->lchild)
{
MostLchild = MostLchild->lchild;
temp = MostLchild->data; //保存这个结点的值
}
//先删除再交换,如果先交换那么二叉树里面就有两个相同的结点了
DeleteNode(T, MostLchild->data); //删除右孩子的最小的结点,这一步就是相当于将要删除的结点与右孩子的最小结点互换了,然后将右孩子的最小结点删除
Node->data = temp; //将右子树中最小的结点的值覆盖掉要删除的结点的值
}
//要删除的结点没有右孩子,只有左孩子
else
{
Btree* MostRchild = Node->lchild;
int temp;
//找到左孩子中的最右边的结点,也就是左孩子中最大的结点
while (MostRchild->rchild)
{
MostRchild = MostRchild->rchild;
temp = MostRchild->data; //保存这个结点的值
}
DeleteNode(T, MostRchild->data);
Node->data = temp; //将左子树中最大的结点的值覆盖掉要删除的结点的值
}
return T;
}
int main()
{
int a[10] = { 5,3,7,1,4,6,8,0,2,9 };
Btree* T=NULL;
Btree* BT=CreatTree(T, a,10); //创建二叉搜索树
cout << "先序遍历:";
PreOrder(BT); //先序遍历二叉树
cout << endl;
BT=DeleteNode(BT,8); //删除值为8的结点
cout << "删除后:";
PreOrder(BT); //先序遍历二叉树
}
运行结果: