描述:
二叉搜索树又称二叉查找树或二叉排序树,其特点是:树中所有的结点,若存在左子树,其左子树结点的值一定小于其值;若存在右子树,其右子树结点的值一定大于其值;且树中所有结点的值都是唯一的(或者说关键字是唯一的),不允许存在重复的结点值(或关键字)。
//定义结点
typedef struct BSTree
{
int data=0;
BSTree *ltree=nullptr,*rtree=nullptr,*parent=nullptr;//三个指针,分别指向左右子树及父结点
}BSTree;
搜索:
由于二叉排序树的特点,查找元素很简单,效率也较高,只要不断与当前的结点对比大小,不断向下搜索即可,直到找到目标结点并返回其地址;若达到最底层依然没有找到目标,则返回空指针。
//搜索结点
BSTree* search_bstree(BSTree *&T,int val)
{
if(T==nullptr) return nullptr;
BSTree *p=T;
while(p!=nullptr)
{
if(val<p->data)
p=p->ltree;
else if(val>p->data)
p=p->rtree;
else
return p;
}
return nullptr;
}
插入:
由于树中的值不允许重复,在插入结点之前,要先搜索“准备插入的结点值”是否已存在。
接下来的操作与搜索操作相似,不断与当前结点对比大小,不断向下搜索,直到找到目标位置,再插入新结点。
//插入结点
void insert_bstree(BSTree *&T,int val)
{
if(T==nullptr)//空树
{
T=new BSTree;
T->data=val;
return;
}
if(!search_bstree(T,val))//若树中不存在值为val的元素才执行插入操作
{
BSTree *t=new BSTree;
t->data=val;
BSTree *p=T;
bool flag=false;//表示新结点是否已插入到树中
while(!flag)
{
if(t->data<p->data)
{
if(p->ltree!=nullptr)
p=p->ltree;
else
{
p->ltree=t;
t->parent=p;
flag=true;
}
}
else
{
if(p->rtree!=nullptr)
p=p->rtree;
else
{
p->rtree=t;
t->parent=p;
flag=true;
}
}
}
}
}
创建:
不断调用插入函数,直到数组中的值全部插入到树中为止。
//创建树
void creat_bstree(BSTree *&T,const vector<int> &v)
{
T=nullptr;
int n=v.size();
for(int i=0;i<n;++i)
{
insert_bstree(T,v[i]);
}
}
删除:
要删除树中的某个结点,会有以下3种情况:
1、要删除的是叶子结点,直接删除即可;
2、要删除的结点只有左子树或右子树,那么就让其父结点指向其子树,然后再删除该结点;
3、要删除的结点既有左子树又有右子树,此时要先找到其左子树中值最大的结点或其右子树中值最小的结点替代之(值覆盖),然后再删除其子树中的那个结点(对该结点也调用删除函数)。
//删除结点
void delete_bstree(BSTree *&T,int val)
{
BSTree *p=search_bstree(T,val);
if(p!=nullptr)
{
if(p->ltree==nullptr && p->rtree==nullptr) //叶子结点
{
if(p!=T) //如果不是根结点,需要修改其父结点的指向
{
BSTree *t=p->parent;
if(t->ltree==p)
t->ltree=nullptr;
else
t->rtree=nullptr;
}
delete p;
}
else if(p->ltree!=nullptr && p->rtree==nullptr) //左子树存在,右子树为空
{
if(p!=T) //如果不是根结点
{
//改变其父结点的指向
BSTree *t=p->parent;
if(t->ltree==p)
{
t->ltree=p->ltree;
}
else
{
t->rtree=p->ltree;
}
}
else
{
T=T->ltree;
}
delete p;
}
else if(p->ltree==nullptr && p->rtree!=nullptr) //左子树为空,右子树存在
{
if(p!=T) //如果不是根结点
{
//改变其父结点的指向
BSTree *t=p->parent;
if(t->ltree==p)
{
t->ltree=p->rtree;
}
else
{
t->rtree=p->rtree;
}
}
else
{
T=T->rtree;
}
delete p;
}
else //左右子树皆存在
{
//寻找结点p的左子树中值最大的结点
//在排序二叉树中,右子树的值大于父结点的值,所以一直向右搜索即可
BSTree *t=p->ltree;
while(t->rtree!=nullptr)
{
t=t->rtree;
}
int val=t->data;//保存结点t的值
delete_bstree(T,t->data);//删除结点t
p->data=val;//赋值
}
}
}