数据结构学习笔记:二叉排序树

本文介绍了二叉排序树的概念,特点以及其查找、插入和删除操作的详细过程。二叉排序树是一种特殊的二叉树,左子树上的节点值小于根节点,右子树上的节点值大于根节点。在插入和删除操作中,都基于查找操作进行,插入时找到合适位置插入新节点,删除时需要考虑被删除节点是否有子节点及其类型。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

何为二叉排序树

     二叉排序树(Binary Sort Tree),又称二叉搜索树。它是一棵具有以下性质的二叉树:

  • 若根结点的左子树非空,则其左子树上所有结点的值都小于它。
  • 若根结点的右子树非空,则其右子树上所有结点的值都大于它。
  • 根结点的左,右子树也分别都为二叉排序树。

    例如:

二叉排序树的操作

二叉排序树的查找

        二叉排序树的结点结构定义与普通二叉树相同。

struct BSTNode {
      Data data ;
      struct BSTNode  *Lchild ;
      struct BSTNode  *Rchild ;
} ;
       当我们需要在二叉排序树中查找一个关键值时,我们可以利用二叉排序树的性质,从根结点开始,每次用关键值与当前结点比较,若关键值小于当前结点,则进入当前结点的左孩子结点,若大于则进入其右孩子结点。直到关键字匹配成功。 具体代码如下:

/*Now指向当前遍历的结点,key为关键值*/
/*若查找成功,Result指向目标结点,parent指向目标结点的双亲结点,否则parent指向最后一次遍历的结点*/
status SerchBST(struct BSTNode *Now, Data key, struct BSTNode *Result, struct BSTNode *Parent)
{
      Parent = NULL ;
      Result = NULL ;
      /*若查找不成功*/
      if(Now == NULL) {
             return FALSE ;
      }
      else if(key == Now -> data) {
             Result = Now ;
             return TRUE ;
      }
      else if(key < Now -> data) {
             Parent = Now ;
             return  SearchBST(Now -> Lchild, key, Result, parent) ;
      }
      else {
             Parent = Now ;
             return SearchBST(Now -> Rchild, key, Result, parent) ;
      }
}
        此函数为递归运行的函数,每次先检查当前结点是否为空,若为空说明未查找到关键字匹配的结点,返回FALSE。若不为空,则比较当前结点与关键字的大小,若关键字与当前结点匹配成功,则返回TRUE。若当前结点小于关键字,则进入当前结点的左孩子结点,否则进入当前结点的右孩子结点。
        例如,寻找关键字75的过程如下:



二叉排序树的插入

        二叉排序树的插入操作,可以看作是在查找操作的基础上多加了一个步骤而已。

        例如,想要在查找操作的例图中插入80这个数据,则首先执行以80为关键字的查找操作,当查找到75这个结点时,由于80 > 75, 而当前结点75的右孩子域为空,则将要插入的80结点赋到75结点的右孩子域。过程如下图:

        具体实现代码如下:

status InsertBST(struct BSTNode *Now, struct BSTNode *key)
{
       /*若当前结点为空,则直接插入关键字结点*/
       if(Now == NULL) {
             Now = key ;
             return TRUE ;
       }
       /*若有结点值与关键字相同,则返回FALSE,不重复插入*/
       if(Now -> data == key -> data) {
             return FALSE ;
      }
      else if(key -> data < Now -> data) {
             /*若关键字小于当前结点,且当前结点的左孩子结点为空,则插入关键字并返回TRUE*/
             if(Now -> Lchild == NULL) {
                     Now -> Lchild = key ;
                     return TURE ;
             }
             else {
                     return InsertBST(Now -> Lchild, key) ;
             }
      }
      else {
             /*若关键字大于当前结点,且当前结点的右孩子结点为空,则插入关键字并返回TRUE,*/
             if(Now -> Rchild == NULL) {
                     Now -> Rchild = key ;
                     return TURE ;
             }
             else {
                     return InsertBST(Now -> Rchild, key) ;
             }
     }
 }
        多次调用二叉排序树的插入函数,可以根据不同的关键字序列来创建一个二叉排序树。

二叉排序树的删除

        二叉排序树的删除操作也是基于查找操作的,被删除结点可能有三种情况:

  • 被删除结点是叶子结点。
  • 被删除结点只有左子树或只有右子树。
  • 被删除结点左右子树都存在。

        现在分析三种情况的结点。

  • 如果被删除结点是叶子结点,则直接将其删除,并将其双亲结点相应孩子域置空。
  • 如果被删除结点只有左子树或只有有子树,则将其删除后,还需要把它的左子树或右子树移动到被删除位置。
  • 如果被删除结点左右子树都存在,则将其删除后,还需对其左右子树做一些调整。有两种方案:1.取其左子树“最右边的结点”,即是左子树值最大的结点。2.取其右子树“最左边的结点”,即是右子树值最小的结点。

       例如要删除图中的根结点57,则需要在其左右子树中找到一个结点来替代它的位置,以实现对其整体结构变动最小,而这个替代它的结点需要满足二叉排序树的性质,所以就必须找到最接近根结点的结点,也就是其左子树中最大的结点44,或其右子树中最小的结点60。删除替代后就变成:


       具体实现代码如下:

Status DeleteBST(BSTNode *Root, Data key)
{
        BSTNode *temp = NULL, *temp_parent = NULL ;
        BSTNode *Result = NULL ;
        BSTNode *Parent = NULL ;
        if(SerchBST(Root, key -> data, Result, Parent) != TRUE) {
                 retrun FALSE ;
        }
        /*要删除的结点左子树为空*/
        if(Result -> Lchild == NULL) {
                 /*删除结点为根结点*/
                 if(Parent == NULL) {
                         Root = NULL ;
                         free(Result) ;
                         return TRUE ;
                 }
                 else {
                        if(Parent -> Lchild == Result) {
                                Parent -> Lchild = Result -> Rchild ;
                        }
                        else if(Parent -> Rchild == Result) {
                               Parent -> Rchild = Result -> Rchild ;
                        }
                        free(Result) ;
                        return TRUE ;
                 }
        }
        /*要删除的结点右子树为空*/
        if(Result -> Rchild == NULL) {
                 /*删除结点为根结点*/
                 if(Parent == NULL) {
                         Root = NULL ;
                         free(Result) ;
                         return TRUE ;
                 }
                 else {
                        if(Parent -> Lchild == Result) {
                                Parent -> Lchild = Result -> Lchild ;
                        }
                        else if(Parent -> Rchild == Result) {
                               Parent -> Rchild = Result -> Lchild ;
                        }
                        free(Result) ;
                        return TRUE ;
                 }
        }
        /*要删除结点左右子树都存在,采取右子树最小结点方案*/
        else {
                 /*进入要删除的结点的右子树*/
                 temp = Parent -> Rchild ;
                 temp_parent = Parent ;
                 /*循环查找右子树中最小的结点和最小结点的双亲结点*/
                 while(temp -> Lchild != NULL) {
                           temp_parent = temp ;
                           temp = temp -> Lchild ;
                 }
                 /*如果替换结点有右子树,则采用单侧子树结点的处理方式*/
                 if(temp -> Rchild != NULL) {
                          temp_parent -> Lchild = temp -> Rchild ;
                 }
                 /*如果删除结点是根结点*/
                 if(Parent == NULL) {
                          temp -> Lchild = Root -> Lchild ;
                          temp -> Rchild = Root -> Rchild ;
                          Root = temp ;
                          free(Result) ;
                          return TRUE ;
                 }
                 else {
                          temp -> Lchild = Result -> Lchild ;
                          temp -> Rchild = Result -> Rchild ;
                          if(Parent -> Lchild == Result) {
                                Parent -> Lchild = temp ;
                          }
                          else if(Parent -> Rchild == Result) {
                                Parent -> Rchild = temp ;
                          }
                          free(Result) ;
                          return TRUE ;
               }
        }
}                    

 
   

 
 


总结

          二叉排序树就像栈至于线性表一样,也是在普通的二叉树基础上,对其操作方式等加以限制,从而达到快速从二叉树中搜索关键数据的目的。在二叉排序树创建的过程中,序列的不同顺序会导致最后生成的树有差别。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值