二叉搜索树的查找、最值查找、插入和删除

对于一棵二叉搜索树,如果不为空,它应该满足以下三个特点:

1、树上的任一结点,该结点的值都大于它的非空左子树的值。

2、树上的任一结点,该结点的值都小于它的非空右子树的值。

3、任一结点的左右子树都是二叉搜索树。

对于二叉搜索树的查找,思路方法是:

1、从根结点开始查找,如果树为空,就返回NULL

2、如果树不空,就让数据X和根结点的数据Data作比较。

3、如果X的值大于根结点的Data,就往右子树中进行搜索;如果X的值小于根结点的Data,就往左子树中进行搜索。

4、如果X的值等于Data,就表示查找完成,返回该结点。

根据这个思路,我们很容易就能用递归的方式实现二叉搜索树的查找:

《二叉搜索树的查找、最值查找、插入和删除》

49行首先判断树空不空,空就返回NULL。如果不空,第52行开始就判断数据XBT>Data,如果X更大,就往右子树去递归查找;如果XData小,就往左子树去递归查找;最后第68行的else也就是X不比Data大也不比Data小,也就是XData相等了,也就是找到了,就retuen这个结点。

以上使用的是递归的方式实现,除了递归方式外,当然可以用循环的方式实现,而且循环的方式比递归执行效率更高。《二叉搜索树的查找、最值查找、插入和删除》

循环查找的方式这样理解,同样一开始判断树空不空,这里用的是while判断,只要树不空就执行while里面的语句,如果树空,就直接执行第72行的return NULL。那么当树不空时,我们就开始做判断,如果X大于Data,就让BT=BT>Right,也就是往右边查找;如果X小于Data,就让BT=BT>Left,让左边查找;当X等于Data了,也就是第6869行,找到了,就return这个结点。这里循环查找方式用的是while循环。

接下来到二叉搜索树的最值查找。如何查找最大值和最小值,根据二叉搜索树的特点,最大值一定是在树的最右边的结点上,而最小值就一定是在最左边的结点上,那么思路很清晰了,既可以用递归实现也可以循环实现。

递归实现方法:

《二叉搜索树的查找、最值查找、插入和删除》

《二叉搜索树的查找、最值查找、插入和删除》

对于递归查找最大最小元素,都是一开始先判断结点是否为空,如果为空就返回NULL,否则就一直往左(或者往右)递归,直到找到最左(或最右的结点为止),判断最左或最右结点的方法就是递归到结点为NULL,就证明找到最左或最右的叶结点了。

循环实现方法:

《二叉搜索树的查找、最值查找、插入和删除》

《二叉搜索树的查找、最值查找、插入和删除》

循环函数也是,一开始判断结点空不空,不空就通过while循环,对于查找最小值,只要BT>Left不为NULL,就让BT=BT>Left,直到BT>Left为空了,就证明找到了最左的叶结点,就退出了while循环,最后return出去。最大值方法一样,循环右子树直到找到最右结点,再return出去就可以了。

说完查找后,接下来到插入。对于二叉搜索树的插入,插入结点后应该仍然要保持树是二叉搜索树,也就是说插入的结点应该仍要保持该结点的左子树比它小,右子树比它大,可以采用的方法是改造一下递归查找函数Find的方法。

《二叉搜索树的查找、最值查找、插入和删除》

程序第4447行有两个作用,第一个是当树为空的时候,也就是往一棵空树里做插入操作,就申请一个结点空间,把X赋给BT>Data,然后BT->Left=BT->Right=NULL,接着return这个结点。第二个作用就是用作树不为空时插入结点,用一个例子来说明:

《二叉搜索树的查找、最值查找、插入和删除》

例如这样一棵二叉搜索树,我们要把25插入到树中,首先进入树的根结点,25大于13,就往右子树走,25小于35,就往左子树走,接着2522大了,再往右子树走,这时发现结点22的右子树为空了,也就是要做插入操作了。这时程序就会进入第49行做一次递归,第49行中的BT这时是22这个结点,此时22这个结点的Right是等于NULL的,所以这行里的Insert函数里就会执行第44行申请一个结点,把X赋给DataBT->Right=BT->Left=NULL,然后return出来,return出来后就把这个新插入的结点赋给了BT->Right,也就是22这个结点的right这时就连接上新插入的结点了,程序的过程就是这样。

最后到删除操作,删除操作分三种情况:

第一种情况,要删除的结点是叶结点,也就是没有左右子树。这样的情况只要把该结点的父结点指向NULL即可。

第二种情况,要删除的结点有一个子树(左子树或右子树),这时删除该结点的方法就是让该结点的父结点指向该结点的子树即可。

第三种情况,要删除的结点有左右两个子树,这个时候我们要采取的方法就是:从左子树里找一个最大值来代替,或者从右子树里找一个最小值来代替。拿这个例子来说明一下:

《二叉搜索树的查找、最值查找、插入和删除》

假如我们要删除35这个结点,它有左右两个子树,这时我们可以选择第一,从右子树中找最小值,35的右子树只有41,可以把41的值拷贝去替换掉35,然后删除41这个节点。,这棵树仍是二叉搜索树,满足相应的关系。第二,从左子树中找最大值,35的左子树中最大值是28,就把28拷贝替换掉35的位置,然后删除28这个结点,此时25顺应就接到了22的右子树的位置上,可以发现替换后树仍然是一棵二叉搜索树。这样做的好处是,把第三种情况要删除的结点有两个子树变成要删除的结点只有一个子树。为什么是这样?因为我们可以想一下,左子树中的最大值,肯定是在左子树的最右边,而这个结点肯定不会有两个结点,要么没有要么就只有一个结点。右子树中的最小值同样是这样。

那么程序要怎么写:《二叉搜索树的查找、最值查找、插入和删除》

同样一开始判断树空不空,如果空就输出一条语句提示,接着判断XData谁大谁小,因为先要找到那个要删除的结点,所以X小的话就从左边递归删除,X大的话就从右边递归删除,当X等于Data了,也就是找到要删除的那个结点了(第47行),然后就做判断,判断要删除的这个结点有多少个子树,如果有两个子树,这里举例用在右子树中找最小值的方法,就调用FindMin函数找到右子树中的最小值结点,把它赋给TP,然后把TP->Data也就是右子树中找到的最小值拷贝给要删除的点BT->Data,接着删除掉原本要删除的结点BT的右子树中的最小值的结点。这样就完成了替换了。那么还有情况就是要删除的结点只有一个子树或者没有子树,前面方法说了就是把要删除的结点的父结点指向该结点的左子树或右子树即可(第52-59行)。在左子树中找最大值方法一样,稍作修改即可。

 

    原文作者:二叉查找树
    原文地址: https://blog.csdn.net/justinzengTM/article/details/80310860
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞