文章目录
- 7.3.1 二叉排序树
- 1. 二叉排序树的定义
- 2. 二叉排序树的查找
- 3. 二叉排序树的插入
- 4. 二叉排序树的生成
- 5. 二叉排序树的删除
- 7.3.2 平衡二叉树
- 1. 平衡二叉树的定义
- 2. 平衡二叉树的平衡调整方法
- 3. 构造平衡二叉排序树

7.3.1 二叉排序树
二叉排序树(Binary Sort Tree)又称为二叉搜索树、二叉查找树。
1. 二叉排序树的定义
二叉排序树或是空树,或是满足如下性质的二叉树:
- 若其左子树非空,则左子树上所有结点的值均小于根节点的值;
- 若其右子树非空,则右子树上所有结点的值均大于等于根节点的值;
- 其左右子树本身又各是一棵二叉排序树。
举个例子

图1:
- 左子树上所有结点的值都小于根结点的 45。
- 右子树上所有结点的值都大于等于根结点的 45。
- 左右子树显然又是一棵二叉排序树。
图2:
- 再看这个每个结点的元素都是字符串的二叉排序树
- 右子树非空,按照首字母排序,右子树上的所有结点的元素都大于等于根节点。
中序遍历二叉排序树,结果有什么规律?

二叉排序树的性质:
2. 二叉排序树的查找
二叉排序树所有的左子树的值都小于根结点的值,右子树的值都大于根结点的值。
举个例子
- 若查找的关键字等于根节点,查找成功。
- 否则:
- 若小于根结点,查其左子树;
- 若大于根节点,查其右子树。
- 在左右子树上的操作类似。

找 105
- 先从根结点开始比较,发现要找的值 105 小于 根节点的值,说明要找的值如果存在,则一定在左子树。
- 再和左子树的根结点比较,105 大于 99,则说明要到右子树去找了。
- 依次类推,105 小于 110,去左子树,哦豁终于找到你了。
找 103
二叉排序树算法
算法步骤
- 若二叉排序树为空,则查找失败,返回空指针。
- 若二叉排序树非空,将给定值 key 与根节点的关键字 T->data.key 进行比较:
二叉排序树的存储结构

![在这里插入图片描述]()
算法描述
//在根结点指针 T 所指二叉排序树中递归查找某关键字等于 key 的数据元素
//若查找成功,则返回指向该数据元素结点的指针,否则返回空指针BSTree SearchBST(BSTree T,KeyType key)
{if((!T)||key == T->data.key)//树为空或根节点的值等于要查找的值{return T;//查找结束}else if(key < T.data.key){return SearchBST(T->lchild,key);//在左子树中继续查找}else{return SearchBST(T->rchild,key);//在右子树中继续查找}
}
二叉排序树算法分析

二叉排序树的平均查找长度:


如何提高形态不均衡的二叉排序树的查找效率?
做 平衡化(平衡二叉树)处理,尽量让二叉树的形状均衡!
3. 二叉排序树的插入
举个栗子

- 如果我们要插入的元素小于根结点,则往左子树上插。
- 同样的,到了左子树之后,如果要插入的值比当前的根节点 12 大,则往右子树插。
- 到了 12 的右子树 37 之后,发现 37 小于 40,往右子树插,又发现 37 的右子树为空,此时就在 37 的右孩子处安家了。
![在这里插入图片描述]()

算法步骤
- 若二叉排序树为空,则待插入结点 *S 作为根节点插入到空树中。
- 若二叉排序树非空,则将 key 与根结点的关键字 T->data.key 进行比较:
算法描述
//当二叉排序树 T 中不存在关键则等于 e.key 的数据元素时,则插入该元素void InsertBST(BSTree &T,ElmeType e)
{if(!T)//找到插入位置,递归结束{S = new BSTNode;//生成新结点 *SS->data = e;//将新结点 *S 的数据域置为 eS->lchild = S->rchild = NULL;//新结点*S作为叶子结点T= S;//将新结点 *S 连接到已找到的插入位置}else if(e.key < T-> data.key){InsertBST(T->lchild,e);//将*S插入左子树}else{InsertBST(T->rchild,e);//将*S插入右子树}
}
4. 二叉排序树的生成
二叉排序树的创建是从空的二叉排序树开始的,每输入一个结点,经过查找操作,将新结点插入到当前二叉排序树的合适位置。
举个例子
算法步骤
- 将二叉排序树 T 初始化为空树。
- 读入一个关键字为 key 的结点。
- 如果读入的关键字 key 不是输入结束标志,则循环执行以下操作:
算法描述
//依次读入一个关键字为 key 的结点,将此结点插入二叉排序树 T 中void CreatBST(BSTree &T)
{T = NULL;//将二叉树T初始化为空树cin >> e;//while(e.key != ENDFLAG)//ENDFLAG为自定义常量,作为输入结束标识{InsertBST(T,e);//将此结点插入二叉排序树 T 中cin >> e;}
}
算法分析
构造二叉排序树的特点
- 一个无序序列可以通过构造二叉排序树而变成一个有序序列。
- 插入的结点均为叶子结点,故无需移动其他结点。相当于在有序序列上插入记录而无需移动其他记录。
- 如果关键字的输入顺序不同,建立的二叉排序树的形态是不一样的(查找效率也会不同)。

5. 二叉排序树的删除
算法步骤
下面分 3 中情况进行讨论
- 被删除的结点是叶子结点:直接删除该结点。

- 被删除的结点只有左子树或者只有右子树,用其左子树或者右子树替换它(结点替换)。

- 被删除的结点即有左子树,又有右子树。

- 方法1:以其中序前趋值替换之(值替换),然后再删除该结点的前趋结点。前趋是左子树中最大的结点。

- 方法2:也可以用中序遍历的后继来替换它,然后在删除该结点的后继结点。后继是右子树中最小的结点。
- 总结:左边用最大,右边用最小

7.3.2 平衡二叉树

如何提高形态不均衡的二叉排序树的查找效率?
1. 平衡二叉树的定义
平衡二叉树(Balanced Binary Tree)
举个例子


- 对于一棵有 n 个结点的 AVL 树,其高度保持在 O(log₂n) 的数量级,ASL(平均查找长度) 也保持在 O(log₂n) 量级。
2. 平衡二叉树的平衡调整方法
- 当我们在一个平衡二叉排序树上插入一个结点时,有可能导致失衡,即出现平衡因子绝对值大于1的结点,如:2、-2。

- 如果在一棵 AVL 树中插入一个新结点后造成失衡,则必须重新调整树的结构,使之恢复平衡。
最小失衡子树

- 有时候添加一个结点之后,造成的失衡结点不止一个时,选择最小的失衡子树。
- 找离着插入结点最近且平衡因子绝对值超过 1 的祖先结点,以该节点为根的子树称为最小失衡子树。
- 找最小失衡子树其实是因为只要调整了这个子树,一般可以使上面的那些失衡结点也平衡,因为导致失衡的根本原因是插入结点
平衡调整的四种类型:

把需要调整的四种失衡形态表示成这样,分别研究一下怎样将失衡情况扭转回来。
- LL型:插入在结点左子树的左子树上而造成该结点失衡,这种失衡类型称为 LL型(左左型)。
- LR型:插入在结点左子树的右子树上而造成该结点失衡,这种失衡类型称为 LR型(左右型)。
- RL型:插入在结点右子树的左子树上而造成该结点失衡,这种失衡类型称为 RL型(右左型)。
- RR型:插入在结点右子树的右子树上而造成该结点失衡,这种失衡类型称为 RR型(右右型)。
调整原则
- 降低高度。
2.保持二叉排序树性质:比根小的放左子树,比根大的放右子树 。

LL型调整
新结点的插入位置在失衡结点的左子树的左子树上。

- 取这三个结点的中间值 B 作为根结点升上去。
- 然后根据二叉排序树的性质:将比根小的结点放左子树,比根大的结点放右子树。

举个例子

- 将这三个结点的中间值 4 作为根结点升上去。
- 然后根据二叉排序树的性质,比根小的 2 放左子树,比根大的 5 放右子树。
RR型调整
新插入的结点在失衡结点的右子树的右子树上。

- 根据二叉排序树的性质找出这三个结点的中间值 B 作为根节点。
- 根据二叉排序树的性质,A 为左孩子,β 作为右孩子。
- 其余结点一律根据性质自己找地方猫着。

举个例子
以失衡结点为起点,找出右子树的根结点,以及右子树的右子树的根结点

- 找到中间值 6,然后将中间值升上去作为根结点。
- 其余结点按照二叉排序树的性质排序。

LR型调整
新插入的结点在失衡结点的左子树的右子树上。

- 找出这三个结点的中间值 C 作为根节点升上去。
- 根据二叉排序树的性质:让 B 为左孩子,A 为右孩子。
- 其余节点按照二叉排序树的性质自己找位置待着。

举个例子

- 将中间值 7 作为根节点,呲溜一下提上去。
- 根据二叉排序树性质:3 为左孩子,16 为右孩子。
RL型调整
新插入的结点在失衡结点的右子树的左子树上。

- 根据二叉排序树性质或中序遍历找出 A C B 的排序,将中间值 C 置为根接单,A 为左孩子,B 为右孩子。
举个例子

- 新插入的结点在失衡结点的右子树的左子树上,由此判断是RL型。
- 分别找出失衡结点 7、根节点的右孩子 11、根节点的右孩子的左孩子 9,由此得出失衡的树。
- 按照中序遍历的方式排得出序列为:7 9 11.
- 将中间值 9 作为根节点,7 作为左孩子,11 作为右孩子。
- 其余结点按照二叉树性质找地方挂着。

3. 构造平衡二叉排序树
输入关键字序列(16,3,7,11,9,26,18,14,15),给出构造一棵 AVL (平衡二叉排序树)的步骤。(要根据二叉排序树的性质插入结点)
- 先输入第一个值 16,然后计算它的平衡因子。平衡因子为 0 可以继续插入输入后续结点。
- 输入第二个结点 3,到根节点的左孩子,计算这两个结点的平衡因子,没有失衡,无需调整继续构造。

- 输入第三个结点 7,比 16 小,比 3 大,放到 3 的右子树上,此时结点 16 失衡,调整二叉排序树:

- 输入第四个结点 11,继续计算平衡因子。

- 输入第五个结点 9,计算平衡因子,此时结点 16 失衡。

- 插入第六个结点 26,此时结点 7 失衡。

- 输入第七个结点 18 到 26 的左孩子处,检查平衡因子,此时结点 16 失衡了。

- 插入第八个结点 14 至结点 16 的左孩子处。

- 插入第九个结点 15 至结点 14 的右子树上,此时结点 16、18、11 均失衡。
AVL 树构造完成
