二叉搜索树(结点添加、后继搜索、前驱搜索、结点删除)

结点的添加:

一开始没有看书没有查,自己写了一个,花了好久才调试成功:

 1 bool BST::Add_Node(TreeNode* temp) {
 2     if (!root) {
 3         root = temp;
 4         return true;
 5     }
 6     TreeNode* current = root;
 7     while (current) {
 8         if (temp->getData() >= current->getData()) {
 9             if (current->getRightChild())
10                 current = current->getRightChild();
11             else
12                 break;
13         }
14         else if (temp->getData() < current->getData()) {
15             if (current->getLeftChild())
16                 current = current->getLeftChild();
17             else
18                 break;
19         }
20         else return false;
21     }
22     temp->setParent(current);
23     if (temp->getData() < current->getData())
24         current->setLeftChild(temp);
25     else
26         current->setRightChild(temp);
27     return true;
28 }

 

结点数据:

 

 构造成功后数据结构应该如图所示:

 

 这里对于有重复键值的结点的加入是这样的:(见8-12行)允许重复值的加入,如碰到相同值的结点,则将当前指针指向这个结点的右孩子。

其实这里对二叉搜索树的定义参考的是《算法导论》,其中是允许重复值的:

 

 如果想排除重复值,略微修改代码即可,很容易,不再叙述。

以上算法通过先序遍历验证,成功:

 

 再看《算法导论》中对于结点添加算法的描述:

 

 

 后继搜索:

看《算法导论》:

 

 

 假设y是x的后继(即中序排序:······x,y·········),如果x没有右子树,则y是x的最低的祖先,且y的左孩子也是x的祖先。

(这里,一个结点的“祖先”也包括结点本身)

所以换成人话就是:

假设y是x的后继,如果x没有右子树,则y是x的最低的祖先,且y的左孩子是x的祖先或x本身。

 

 因此,想找到y,只需要从x开始向上走,直到找到一个是其父结点的左孩子的结点。

 

二叉搜索树中,找任一结点的后继是什么思路呢?

如果右孩子非空,那非常好理解,直接找右子树上的最小值就是它的后继。

至于右孩子非空,那么其后继一定在他头顶上;倒过来想,当这个结点被添加进树的时候,由于比后继小,一定加在了其后继的左子树的某个位置上。

这样就很好理解上面粗体字的结论了,如果把结点x后继的左子树独立出来看,x要么是这棵树(我们叫它T'好了)的根结点,要么是非根的某个结点。(x∈T')

这么看来,上面代码就很好理解了:假设p是结点x的后继;先从结点本身这一层开始找起,p不断往上爬,t跟着它爬,每次一层,只要t还是p的右孩子,就说明p还不是后继,就继续往上爬。相当于我们从x开始找其所在的子树T'的根节点

或者还有一种更简单的理解:从结点x开始向上(包括x,因为x可能是T'的根结点)寻找一对父子结点p-t,父子结点对p-t满足:p键值>t键值;则找到的第一对父子结点p-t中的父节点p即为x的后继结点。

 

 把上面的二叉搜索树用中序遍历跑一下,对比着看,帮助理解。

重复键值嫌麻烦没有改,不影响理解。

前驱搜索:

本身逻辑其实一模一样,把后继搜索反过来就行了

结点删除:

直接看算法导论:

 

 

分成了三类:

1、如果要删除的结点没有孩子:直接将他的父结点对应的指针(左或右)指空,并删除他。

2、如果要删除的结点有1个孩子:直接将他的父结点对应的指针(左或右)指向他唯一的那个孩子,并删除他。

3、如果要删除的结点有2个孩子: 把他用他的后继结点代替。

以下是算法代码(由于使用的数据结构和出于简便的考虑,没有真正删除结点数据,只是删除了其关联信息)

 

 

 

 

测试删除50:

 

成功。

这里算法有个bug,如果删除根节点会出错,因为其父结点为null,访问null的左右孩子其实是不存在的,会抛出访问异常。

posted @ 2019-11-28 22:48  略略略——  阅读(367)  评论(0编辑  收藏  举报