二叉搜索树(C/C++)

描述:

二叉搜索树又称二叉查找树或二叉排序树,其特点是:树中所有的结点,若存在左子树,其左子树结点的值一定小于其值;若存在右子树,其右子树结点的值一定大于其值;且树中所有结点的值都是唯一的(或者说关键字是唯一的),不允许存在重复的结点值(或关键字)。

//定义结点
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;//赋值
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值