数据结构——再赏“树“,关于搜索二叉树(BST树)和平衡二叉树(AVL树)那点事儿~(2)

简介: 数据结构——再赏“树“,关于搜索二叉树(BST树)和平衡二叉树(AVL树)那点事儿~(2)

二叉平衡树(AVL树)


什么是平衡二叉树


前戏~


树的高度


树的深度(Depth):树中所有结点中的最大层次是这棵树的深度或者高度


平衡因子


平衡因子(Balance Factor,简称BF): BF(T) = hL-hR,

其中hL和hR分别为T的左、右子树的高度


平衡二叉树


平衡二叉树(Balanced Binary Tree)(AVL树),平衡二叉树中不存在平衡因子大于 1 的节点,即|BF(T) |≤ 1。在一棵平衡二叉树中,节点的平衡因子只能取 0 、1 或者 -1 ,分别对应着左右子树等高,左子树比较高,右子树比较高。


注意:平衡二叉树也是一棵搜索树,所以搜索呀,删除呀等操作,对它一样是适用的,只是插入以后,可能会破坏平衡因子,所以待会要单独讲解平衡二叉树插入以后的调整问题,让树仍然保持是棵查找树

微信图片_20221017164503.jpg

平衡二叉树的性质


给定结点数为 n的AVL树的最大高度为O(log2n)


平衡二叉树的作用


可能有小伙伴读完什么树高、平衡因子,吧啦吧啦又来了一串定义、要求、性质,头已经大了微信图片_20221017164510.jpg

微信图片_20221017164626.jpg

平衡二叉树的调整(难点)


右单旋


形象化例子:将Mar 、 May 、 Nov依次插入

微信图片_20221017164727.jpg

不平衡的发现者是Mar,麻烦结点Nov 在发现者右子树的右边,因而叫 RR 插入,需要RR 旋转(右单旋)

右单旋原理图如下:微信图片_20221017164733.jpg

右单旋理解


小伙伴们看着原理图。现在可以把这棵树想象得很柔软,然后你握住了平衡因子处于中间地位的B结点,闭上双眼,使劲摇动它,在重力的作用下,发现者B结点变成了新的根。由搜索二叉树的性质告诉我们,在原来的树中,B结点是大于A结点的,于是现在新树中A结点成为了B结点的左子树,BL因为比B结点小但是又比A结点大,所以挂在了A的右子树上。


左单旋


形象化例子:将Aug 和 Apr插入到原本的平衡二叉树中

微信图片_20221017164738.jpg

不平衡的发现者是Mar,麻烦结点Apr在发现者左子树的左边,因而叫 LL 插入,需要LL 旋转(左单旋)

左单旋原理图如下:

微信图片_20221017164743.jpg

左单旋理解


咱们继续看着原理图。现在可以把这棵树想象得很柔软,然后你握住了平衡因子处于中间地位的B,闭上双眼,使劲摇动它,在重力的作用下,发现者B变成了新的根。二叉查找树的性质告诉我们,在原来的树中,B是小于A的,于是新树中,A变成了B的右子树,BL因为还是比B小,依旧挂在B的左子树,BR了,也是根据二叉查找树的性质,它只能到现在A的左子树挂着了。


左右双旋


形象化例子:将Jan插入到Mar的左子树上

微信图片_20221017164930.jpg

不平衡的发现者是May,麻烦结点Jan在左子树的右边,

因而叫 LR 插入,需要LR 旋转(左右单旋)

左右双旋原理图如下:微信图片_20221017164933.jpg

左右双旋理解


重点关注那三个结点,只要它们三平衡了,根据二叉搜索树的性质,其他点也可以相应调整平衡了。咱们继续看着原理图。现在子树C,对应上图的Mar。现在确实有一项插入进来了,无论它在插入到C的左子树还是C的右子树,它都来破坏平衡了。于是,我们可以将现在的树看作四棵子树由3个结点连接。为了重新平衡,我们可以看到不能让A再做根了,唯一的选择就是把平衡因子的大小是中间值C作为新的根结点,再结合二叉查找树的性质,迫使B做C的左儿子,A左C的右儿子,从而完全确定整棵树的最终位置。


右左双旋


形象化例子:将Fer插入到原本平衡的Dec的上面

微信图片_20221017164937.jpg

 

不平衡的发现者是Aug,麻烦结点Feb在右子树的左边,

因而叫 RL 插入,需要RL 旋转

右左双旋原理图:

微信图片_20221017164944.jpg


左右双旋理解


因为和上文的左右双旋类似,相信大家也理解啦。所以这里不在赘述啦~


总结


到这里为止,平衡二叉树为了调整插入而带来的不平衡的四种四种方式已经讲完啦~

数起来是四种,实际就是一种,有没有发现了。左单旋、右单旋要关注的核心结点是被破坏以后衡因子居中的结点微信图片_20221017164956.jpg

对于左右双旋和右左双旋也是类似的,我上文着重说,注意那三个结点,咱们要去处理它们三个中平衡因子居中的那个结点。其实也可以做这种想,小学集合站队的时候,中等高度的小盆友出来出来站好了,其他的位置就可以类推了,这里就是取平衡因子居中的点为标杆。

相关文章
|
1月前
|
存储 算法 Java
算法系列之数据结构-二叉树
树是一种重要的非线性数据结构,广泛应用于各种算法和应用中。本文介绍了树的基本概念、常见类型(如二叉树、满二叉树、完全二叉树、平衡二叉树、B树等)及其在Java中的实现。通过递归方法实现了二叉树的前序、中序、后序和层次遍历,并展示了具体的代码示例和运行结果。掌握树结构有助于提高编程能力,优化算法设计。
54 9
 算法系列之数据结构-二叉树
|
3月前
|
Java C++
【C++数据结构——树】二叉树的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现二叉树的基本运算。​ 相关知识 创建二叉树 销毁二叉树 查找结点 求二叉树的高度 输出二叉树 //二叉树节点结构体定义 structTreeNode{ intval; TreeNode*left; TreeNode*right; TreeNode(intx):val(x),left(NULL),right(NULL){} }; 创建二叉树 //创建二叉树函数(简单示例,手动构建) TreeNode*create
95 12
|
3月前
|
C++
【C++数据结构——树】二叉树的性质(头歌实践教学平台习题)【合集】
本文档介绍了如何根据二叉树的括号表示串创建二叉树,并计算其结点个数、叶子结点个数、某结点的层次和二叉树的宽度。主要内容包括: 1. **定义二叉树节点结构体**:定义了包含节点值、左子节点指针和右子节点指针的结构体。 2. **实现构建二叉树的函数**:通过解析括号表示串,递归地构建二叉树的各个节点及其子树。 3. **使用示例**:展示了如何调用 `buildTree` 函数构建二叉树并进行简单验证。 4. **计算二叉树属性**: - 计算二叉树节点个数。 - 计算二叉树叶子节点个数。 - 计算某节点的层次。 - 计算二叉树的宽度。 最后,提供了测试说明及通关代
98 10
|
3月前
|
存储 算法 测试技术
【C++数据结构——树】二叉树的遍历算法(头歌教学实验平台习题) 【合集】
本任务旨在实现二叉树的遍历,包括先序、中序、后序和层次遍历。首先介绍了二叉树的基本概念与结构定义,并通过C++代码示例展示了如何定义二叉树节点及构建二叉树。接着详细讲解了四种遍历方法的递归实现逻辑,以及层次遍历中队列的应用。最后提供了测试用例和预期输出,确保代码正确性。通过这些内容,帮助读者理解并掌握二叉树遍历的核心思想与实现技巧。
114 2
|
4月前
|
数据库
数据结构中二叉树,哈希表,顺序表,链表的比较补充
二叉搜索树,哈希表,顺序表,链表的特点的比较
数据结构中二叉树,哈希表,顺序表,链表的比较补充
|
5月前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
559 9
|
5月前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
144 58
|
3月前
|
存储 C语言 C++
【C++数据结构——栈与队列】顺序栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现顺序栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 1.初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储
223 77
|
2月前
|
算法 调度 C++
STL——栈和队列和优先队列
通过以上对栈、队列和优先队列的详细解释和示例,希望能帮助读者更好地理解和应用这些重要的数据结构。
36 11
|
2月前
|
DataX
☀☀☀☀☀☀☀有关栈和队列应用的oj题讲解☼☼☼☼☼☼☼
### 简介 本文介绍了三种数据结构的实现方法:用两个队列实现栈、用两个栈实现队列以及设计循环队列。具体思路如下: 1. **用两个队列实现栈**: - 插入元素时,选择非空队列进行插入。 - 移除栈顶元素时,将非空队列中的元素依次转移到另一个队列,直到只剩下一个元素,然后弹出该元素。 - 判空条件为两个队列均为空。 2. **用两个栈实现队列**: - 插入元素时,选择非空栈进行插入。 - 移除队首元素时,将非空栈中的元素依次转移到另一个栈,再将这些元素重新放回原栈以保持顺序。 - 判空条件为两个栈均为空。