7.2 二叉排序树
二叉排序树的定义、查找、插入、构造与删除(三种情况),以及查找效率分析。
定义
根据二叉排序树的定义,左子树结点值 < 根结点值 < 右子树结点值,因此对二叉排序树进行中序遍历,可以得到一个递增的有序序列。
查找
二叉排序树的查找是从根结点开始,沿某个分支逐层向下比较的过程。若二叉排序树非空,先将给定值与根结点的关键字比较,若相等,则查找成功;若不等,若小于根结点的关键字,则在根结点的左子树上查找,否则在根结点的右子树上查找。这显然是一个递归的过程,也很容易用非递归实现。
插入与构造
二叉排序树作为一种动态树表,其特点是树的结构通常不是一次生成的,而是在查找过程中,当树中不存在关键字值等于给定值的结点时再进行插入的。插入的结点一定是一个新添加的叶结点,且是查找失败时的查找路径上访问的最后一个结点的左孩子或右孩子。
从一棵空树出发,依次输入元素,将它们插入二叉排序树中的合适位置,即可构造一棵二叉排序树:
动画演示二叉排序树(BST)
比较路径新插入被删除替代者
C 代码
1int BST_Insert(BiTree &T, KeyType k) {2 if (T == NULL) { // 原树为空,新插入的结点为根3 T = (BiTree)malloc(sizeof(BSTNode));4 T->key = k; T->lchild = T->rchild = NULL;5 return 1;6 } else if (k == T->key) // 存在相同关键字,插入失败7 return 0;8 else if (k < T->key)9 return BST_Insert(T->lchild, k);10 else11 return BST_Insert(T->rchild, k);12}
1/23依次插入序列:45, 24, 53, 12, 37, 93, 50, 28
在上面的控件中把模式切换为「查找」或「删除」,可以分别观察查找路径和删除过程。
删除
在二叉排序树中删除一个结点时,不能把以该结点为根的子树上的结点都删除,必须先把被删除结点从存储二叉排序树的链表上摘下,将因删除而断开的二叉链表重新链接起来,同时确保二叉排序树的性质不会丢失。删除操作的实现过程按 3 种情况来处理:
- 若被删除结点 z 是叶结点,则直接删除,不会破坏二叉排序树的性质;
- 若结点 z 只有一棵左子树或右子树,则让 z 的子树成为 z 父结点的子树,替代 z 的位置;
- 若结点 z 有左、右两棵子树,则令 z 的直接后继(或直接前驱)替代 z,然后从二叉排序树中删去这个直接后继(或直接前驱),这样就转换成了第 1 或第 2 种情况。
查找效率分析
二叉排序树的查找效率,主要取决于树的高度。
- 若二叉排序树的左、右子树的高度之差的绝对值不超过 1(平衡二叉树),则这样的二叉排序树的平均查找长度为 ;
- 若二叉排序树是一个只有右(左)孩子的单支树(类似于有序的单链表),则其平均查找长度为 。最坏情况下,即构造二叉排序树的输入序列是有序的,则会形成一个倾斜的单支树,此时二叉排序树的性能显著变差。
ASL成功 = (1 + 2×2 + 3×4)/7 = 17/7
按有序序列插入:退化为单支树,ASL = (1+2+…+7)/7 = 4
即时练习
即时练习5 题
点击选项即可作答
- 1在含有 n 个结点的二叉排序树中查找某个关键字的结点时,最多进行( )次比较。
- 2在二叉排序树中进行查找的效率与( )有关。
- 3按 (31, 25, 72, 16, 51, 82) 的顺序构造二叉排序树,其中序遍历序列为( )。
- 4在一棵二叉排序树中删除一个有左、右两棵子树的结点 z,若用其中序后继 s 代替 z,则 s( )。
- 5对下列关键字序列,不可能构成某二叉排序树中一条查找路径的序列是( )。
学完了吗?
标记完成后,侧栏会显示进度。进度仅保存在本浏览器中。