二叉排序树 分析、梳理、代码总结

二叉排序树(binary sort tree)


二叉排序树的定义

    二叉排序树或是一棵空树,或是具有如下性质的非空二叉树:

      (1)若它的左子树非空,则其左子树所有结点的关键字值均小于其根结点的关键字值

      (2)若它的右子树非空,则其右子树所有结点的关键字值均大于其根结点的关键字值

      (3)它的左右子树也分别为一棵二叉排序树

二叉排序树的重要特征:对二叉排序树进行中序遍历可以得到一个关键字有序的序列

二叉排序树的存储:二叉链表

/*二叉排序树的二叉链表存储结构*/
typedef struct BTNode{
    Elemtype key;                       /*记录的关键字,忽略记录的其他数据项*/
    struct BTNode *lchild,*rchild;  
}BTNode,*BSTree;

二叉排序树的查找:

    二叉排序树不空的时候,将给定值key和结点的关键字比较,相等查找成功,小于查找左子树,大于查找右子树,返回空查找失败。

    查找过程实际上是从根结点到结点的路径,即该层的深度。

/*二叉排序树的查找*/
BTNode *SearchBST(BSTree T,int key)      /*T指向二叉排序树的根结点*/
{
    if(T==NULL)                     /*空树,查找失败*/
        return NULL;
    if(key==T->key)             /*查找成功*/
        return T;
    if(key<T->key)
        return SearchBST(T->lchild,key);        /*查找左子树*/
    if(key>T->key)
        return SearchBST(T->rchild,key);       /*查找右子树*/
}

二叉排序树的插入

    插入结点的条件:查找不成功

    基本思想:(1)若二叉排序树为空,则新结点作为二叉排序树的根结点

                     (2)若给定结点的关键字的值小于根结点的值,插入到左子树中

                     (3)若给定结点的关键字的值大于根结点的值,插入到右子树中

/*二叉排序树的插入*/
BSTree InsertBST_key(BSTree T,int key)
{/*在以T为根结点的二叉排序树上查找关键字为key的记录,若不存在将其插入*/
    BTNode *s=SearchBST(T,key);
    if(s!=NULL)
    {
        printf("\n关键字%d已存在!\n",s->key);
        return T;
    }
    s=(BTNode *)malloc(sizeof(BTNode));         /*生成一个结点空间*/
    if(s==NULL)
        printf("Error\n");
    s->key=key;
    s->lchild=s->rchild=NULL;
    T=InsertBST(T,s);               /*在二叉排序树上插入该结点*/
    return T;
}

/*在二叉排序树上插入一个结点*/
BSTree InsertBST(BSTree T,BTNode *s)
{  /*在以T为根的二叉树上插入一个指针s所指向的结点并返回根指针T*/
    if(T==NULL)         /*如果T是空树,则新插入的结点S作为新的树根*/
        T=s;
    else
    {
        if(s->key<T->key)
            T->lchild=InsertBST(T->lchild,s);       /*递归插到T的左子树中*/
        if(s->key>T->key)
            T->lchild=InsertBST(T->lchild,s);        /*递归插到T的右子树中*/
    }
    return T;
}


二叉排序树的创建

    二叉树的创建过程实际上就是一个查找插入的过程,每次插入的新结点都是二叉树上新的叶子结点,操作时不必像静态查找移动其他结点,只需改动新叶子结点的父结点的左或右指针,由空变为非空即可。二叉排序树既拥有类似折半查找的特性,又采用链表作为存储结构。

/*二叉排序树的创建*/
BSTree CreateBST()      /*由空树开始,输入关键字序列,建立一棵二叉排序树*/
{
    BSTree T=NULL,s=NULL;
    int key;
    printf("输入关键字序列,输入-1结束\n");
    while(1)
    {
        scanf("%d",&key);     
        if(key==-1)
            break;
        s=(BTNode *)malloc(sizeof(BTNode));         /*生成一个结点空间*/
        s->key=key;
        s->lchild=s->rchild=NULL;
        T=InsertBST(T,s);                   /*在二叉排序树中插入该结点*/
    }
    return T;
}

二叉排序树的删除

    假设待删除的结点为*p,f指向结点*p的双亲,s指向*p的左子树中关键字值最大的结点,q指向s的双亲

    删除分为3中情况:

      (1)*p为叶子结点,即其左右结点为空-----将其双亲结点f的lchild或rchild置空,删除结点

      (2)*p只有一棵非空子树(左子树或右子树)

           只有左子树-----用左子树的根结点取代要删除的结点

           只有右子树-----用右子树的根结点取代要删除的结点

      (3)*p左右子树均非空-----用*p左子树中关键字最大的结点*s替代*p,若*s有左孩子,将左孩子作为*s的双亲结点*q的右孩子  

                                             

    为了删除结点后重接子树,要修改查找算法

/*为了删除操作而修改的二叉排序树查找*/
BTNode *SearchBST_F(BSTree T,int key,BSTree *F)
{   /*T指向根结点,*F存储指向key的双亲的指针*/
    /*查找成功,返回指向key的记录指针,查找失败返回NULL*/
    if(T==NULL)
        return NULL;
    if(key==T->key)
        return T;
    *F=T;
    if(key<T->key)
        return SearchBST_F(T->lchild,key,F);
    if(key>T->key)
        return SearchBST_F(T->rchild,key,F);
}

/*在二叉排序树中查找并删除关键字为key的记录*/
BSTree SearchDeleteBST(BSTree T,int key)
{
        BTNode *f=NULL,*pNULL;
        p=SearchBST_F(T,key,&f);        /*查找key,p指向key,f指向双亲*/
        if(p!=NULL)
            T=DeleteBST(T,p,f);
        else
            printf("关键字为key的记录不存在!\n");
        return T;
}

二叉排序树的删除算法

/*二叉排序树的删除*/
BSTree DeleteBST(BSTree T,BTNode *p,BTNode *f)
{/*删除p指针指向的结点,f指向*p的双亲结点*/
 /*T是指向根结点的指针*/
    BTNode *par,*s;
    int kind;
    if(p->lchild==NULL&&p->rchild==NULL)            /*情况1,*p为叶子结点*/
        kind=1;                                                 
    else if(p->rchild==NULL)                /*情况2,*p只有左子树*/
        kind=2; 
    else if(p->lchild==NULL)                /*情况3,*p只有右子树*/
        kind=3;
    else                                                    /*情况4,*p左右子树非空*/
        kind=4;
    switch(kind)
    {
        case 1:    if(f==NULL)         /*p指向根结点,树中只有根结点*/
                                T=NULL;             /*删除结点*p,T变空树*/
                        else
                        {
                                if(f->lchild==p)       /* *p是*f的左孩子*/
                                    f->lchild=NULL;
                                else                           /* *p是*f的右孩子*/
                                    f->rchild==NULL;       
                        }
                        free(p);                       /*删除结点释放空间*/
                        break;
        case 2:    if(f==NULL)          /*f为NULL,*p为根结点,且只有左子树*/
                                T=p->lchild;
                        else
                        {
                            if(f->lchild==p)       /* *p是*f的左子树*/
                                f->lchild=p->lchild;
                            else                         /* *p是*f的右子树*/
                                f->rchild=p->lchild;
                        }
                        free(p);                       /*删除结点释放空间*/
                        break;
        case 3:     if(f==NULL)        /*f为NULL,*p为根结点,且只有左子树*/
                                T=p->rchild;
                           else
                           {
                               if(p==f->lchild)
                                    f->lchild=p->rchild;
                               else
                                    f->rchild=p->rchild;
                           }
                           free(p);
                           break;
        case 4:     par=p;
                          s=p->lchild;
                          while(s->rchild!=NULL)        /*找到p左子树的关键字最大(最右下)的结点*/
                          {
                              par=s;
                              s=s->rchild;
                          }
                          p->key=s->key;        /*s结点的值覆盖p结点的值*/
                          if(par==p)           /*处理特殊情况,*p的左孩子为*s*/
                                par->lchild=s->lchild;
                          else
                                par->rchild=s->lchild;      /*s的左子树连接到s的双亲结点作为双亲结点的右子树*/
                          free(s);           /*注意不是free(p),因为p的关键字被s的关键字覆盖,s已无用*/
    }
    return T;
}

完整代码如下:

#include <iostream>
#include<stdio.h>
#include<malloc.h>
using namespace std;
typedef int Elemtype;
/*二叉排序树的二叉链表存储结构*/
typedef struct BTNode{
    Elemtype key;                       /*记录的关键字,忽略记录的其他数据项*/
    struct BTNode *lchild,*rchild;
}BTNode,*BSTree;

/*二叉排序树的查找*/
BTNode *SearchBST(BSTree T,int key)      /*T指向二叉排序树的根结点*/
{
    if(T==NULL)                     /*空树,查找失败*/
        return NULL;
    if(key==T->key)             /*查找成功*/
        return T;
    if(key<T->key)
        return SearchBST(T->lchild,key);        /*查找左子树*/
    if(key>T->key)
        return SearchBST(T->rchild,key);       /*查找右子树*/
}

/*在二叉排序树上插入一个结点*/
BSTree InsertBST(BSTree T,BTNode *s)
{  /*在以T为根的二叉树上插入一个指针s所指向的结点并返回根指针T*/
    if(T==NULL)         /*如果T是空树,则新插入的结点S作为新的树根*/
        T=s;
    else
    {
        if(s->key<T->key)
            T->lchild=InsertBST(T->lchild,s);       /*递归插到T的左子树中*/
        if(s->key>T->key)
            T->lchild=InsertBST(T->lchild,s);        /*递归插到T的右子树中*/
    }
    return T;
}

/*二叉排序树的插入*/
BSTree InsertBST_key(BSTree T,int key)
{/*在以T为根结点的二叉排序树上查找关键字为key的记录,若不存在将其插入*/
    BTNode *s=SearchBST(T,key);
    if(s!=NULL)
    {
        printf("\n关键字%d已存在!\n",s->key);
        return T;
    }
    s=(BTNode *)malloc(sizeof(BTNode));         /*生成一个结点空间*/
    if(s==NULL)
        printf("Error\n");
    s->key=key;
    s->lchild=s->rchild=NULL;
    T=InsertBST(T,s);               /*在二叉排序树上插入该结点*/
    return T;
}

/*二叉排序树的创建*/
BSTree CreateBST()      /*由空树开始,输入关键字序列,建立一棵二叉排序树*/
{
    BSTree T=NULL,s=NULL;
    int key;
    printf("输入关键字序列,输入-1结束\n");
    while(1)
    {
        scanf("%d",&key);
        if(key==-1)
            break;
        s=(BTNode *)malloc(sizeof(BTNode));         /*生成一个结点空间*/
        s->key=key;
        s->lchild=s->rchild=NULL;
        T=InsertBST(T,s);                   /*在二叉排序树中插入该结点*/
    }
    return T;
}

/*为了删除操作而修改的二叉排序树查找*/
BTNode *SearchBST_F(BSTree T,int key,BSTree *F)
{   /*T指向根结点,*F存储指向key的双亲的指针*/
    /*查找成功,返回指向key的记录指针,查找失败返回NULL*/
    if(T==NULL)
        return NULL;
    if(key==T->key)
        return T;
    *F=T;
    if(key<T->key)
        return SearchBST_F(T->lchild,key,F);
    if(key>T->key)
        return SearchBST_F(T->rchild,key,F);
}

/*二叉排序树的删除*/
BSTree DeleteBST(BSTree T,BTNode *p,BTNode *f)
{/*删除p指针指向的结点,f指向*p的双亲结点*/
 /*T是指向根结点的指针*/
    BTNode *par,*s;
    int kind;
    if(p->lchild==NULL&&p->rchild==NULL)            /*情况1,*p为叶子结点*/
        kind=1;
    else if(p->rchild==NULL)                /*情况2,*p只有左子树*/
        kind=2;
    else if(p->lchild==NULL)                /*情况3,*p只有右子树*/
        kind=3;
    else                                                    /*情况4,*p左右子树非空*/
        kind=4;
    switch(kind)
    {
        case 1:    if(f==NULL)         /*p指向根结点,树中只有根结点*/
                                T=NULL;             /*删除结点*p,T变空树*/
                        else
                        {
                                if(f->lchild==p)       /* *p是*f的左孩子*/
                                    f->lchild=NULL;
                                else                           /* *p是*f的右孩子*/
                                    f->rchild==NULL;
                        }
                        free(p);                    /*删除结点释放空间*/
                        break;
        case 2:    if(f==NULL)          /*f为NULL,*p为根结点,且只有左子树*/
                                T=p->lchild;
                        else
                        {
                            if(f->lchild==p)       /* *p是*f的左子树*/
                                f->lchild=p->lchild;
                            else                         /* *p是*f的右子树*/
                                f->rchild=p->lchild;
                        }
                        free(p);                       /*删除结点释放空间*/
                        break;
        case 3:     if(f==NULL)        /*f为NULL,*p为根结点,且只有左子树*/
                                T=p->rchild;
                           else
                           {
                               if(p==f->lchild)
                                    f->lchild=p->rchild;
                               else
                                    f->rchild=p->rchild;
                           }
                           free(p);
                           break;
        case 4:     par=p;
                          s=p->lchild;
                          while(s->rchild!=NULL)        /*找到p左子树的关键字最大(最右下)的结点*/
                          {
                              par=s;
                              s=s->rchild;
                          }
                          p->key=s->key;        /*s结点的值覆盖p结点的值*/
                          if(par==p)           /*处理特殊情况,*p的左孩子为*s*/
                                par->lchild=s->lchild;
                          else
                                par->rchild=s->lchild;      /*s的左子树连接到s的双亲结点作为双亲结点的右子树*/
                          free(s);           /*注意不是free(p),因为p的关键字被s的关键字覆盖,s已无用*/
    }
    return T;
}

BSTree SearchDeleteBST(BSTree T,int key)
{
        BTNode *f=NULL,*p=NULL;
        p=SearchBST_F(T,key,&f);        /*查找key,p指向key,f指向双亲*/
        if(p!=NULL)
            T=DeleteBST(T,p,f);
        else
            printf("关键字为key的记录不存在!\n");
        return T;
}


int main()
{

    return 0;
}



   


  • 12
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
排序是一种特殊的二,它的左子上的所有节点的值都小于根节点的值,右子上的所有节点的值都大于根节点的值。因此,二排序可以用来实现快速的查找、插入和删除操作。下面是一个简单的C++二排序代码: ```c++ #include <iostream> using namespace std; struct TreeNode { int val; TreeNode* left; TreeNode* right; TreeNode(int x) : val(x), left(NULL), right(NULL) {} }; void insert(TreeNode*& root, int val) { if (root == NULL) { root = new TreeNode(val); return; } if (val < root->val) { insert(root->left, val); } else { insert(root->right, val); } } int main() { TreeNode* root = NULL; int n; cin >> n; for (int i = 0; i < n; i++) { int val; cin >> val; insert(root, val); } return 0; } ``` 在这个代码中,我们定义了一个结构体`TreeNode`表示二排序的节点,其中包含一个整数值`val`和两个指向左右子的指针`left`和`right`。我们还定义了一个`insert`函数用来向二排序中插入一个节点。在`insert`函数中,我们首先判断当前节点是否为空,如果为空,则直接创建一个新节点并将其作为根节点。否则,我们比较要插入的值和当前节点的值的大小关系,如果要插入的值小于当前节点的值,则递归地将其插入到左子中,否则递归地将其插入到右子中。最后,在`main`函数中,我们读入要插入的节点数和节点的值,并依次将其插入到二排序中。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值