文章目录
1.写在前面
转行计算机虽有一段时间了,但由于基础单薄,对于一些原理性的知识理解较慢,故开始学习数据结构和算法相关的知识,希望通过自己的努力可以渐渐拿掉“小白”的称呼。
本文是我第一次在各位前辈、同行面前班门弄斧,汇报近期学习到的平衡二叉树旋转相关的知识。自知理解尚浅,如有错误,还望及时指正。
另外,本文的灵感来源:https://www.bilibili.com/video/BV1e4411x7rZ?t=746
2.二叉排序树
2.1.定义
给定一个数组,依次将数组中的元素按照 左节点 < 根节点 < 右节点的规则放入一个树中。也可以被称为二叉查找树。
例如:{3, 1, 2, 5, 9, 7}
2.2.优缺点
优点很明显,对于上述例子,相比于链表的查找效率会有所提高。
对于缺点,这里再举一个例子:
{1, 2, 3, 4, 5, 6}
对于一个有序数组,产生的树的结构和链表是一样的。
可见解决一个随机的数组很方便,产生的树比较正常,但对于有序数组,会产生比较畸形的二叉排序树。
3.平衡二叉排序树
3.1.二叉树逐渐优化为平衡二叉树
仍然是上述例子,我们选取数组的中间位置的元素作为二叉树的根节点,也就是元素“3”,这样我们可以得到下面的树:
相比之前的链表型的树,查找到节点“6”从6次减少为了4次。当然这还不是查找效率最高的形态,我们还可以优化为如下结果:
这样,找到节点“6”只需要3次查找。
3.2.平衡因子
为了判断二叉树是否平衡,引入平衡因子的概念(一个变量)。
如果:
平衡因子 = | 左子树高度 - 右子树高度 | < 2
那么当前这个二叉树是平衡的。
3.3.旋转
3.3.1.不平衡子树的类型
1.LL
说明:
左child的左child的高度已经大于了右边,这时又加入了一个元素,导致树不平衡。
(这样说对于I的情况是不严谨的,因为左child的左child已经导致了树的不平衡,但为了文字的简洁,后续三种类型仍按照这样的说法描述)
2.RR
说明:
右child的右child的高度已经大于了左边,这时又加入了一个元素,导致树不平衡。
3.RL
说明:
右chile的左child的高度已经大于了左边,这时又加入了一个元素,导致树不平衡。
4.LR
说明:
左child的左child的高度已经大于了右边,这时又加入了一个元素,导致树不平衡。
3.3.2.旋转策略
1.判断不平衡子树的类型
2.鸠占鹊巢
3.丢锅
这里对每一种情况做单独分析:
3.3.2.1.LL
对于LL情况的,采用右旋的方式(顺时针旋转)
(I)
(II)
说明:
当原有的根节点(图中的m)右旋转到圈起来的位置时,会出现“鸠占鹊巢”的现象,让圈起来的节点先走开,m安置好后,再去按照二叉查找树的规则(左 < 根 < 右)插入到m的左子节点位置。
(III)
3.3.2.2.RR
对于RR情况的,采用左旋的方式(逆时针旋转)
3.3.2.3.RL
对于RL情况的,采用让根节点甩锅给子节点右旋,再自己左旋的方式。
(I)
说明:
根节点的子节点右旋后,转变为RR情况。
(II)
说明:
旋转时如果目标位置有节点,则采取“鸠占鹊巢”策略。
(III)
3.3.2.3.LR
对于LR情况的,采用让根节点甩锅给子节点左旋,再自己右旋的方式。整体情况与RL如出一辙。
3.3.3.例子
{12, 4, 1, 3, 7, 8, 10, 9, 2, 11, 6, 5}
第一步:依次插入12, 4, 1,产生LL型不平衡树,右旋变为平衡树:
第二步:插入3, 7, 8,产生RL型不平衡树,先右再左变为平衡树
第三步:插入10, 9,产生LL型不平衡树,右旋变为平衡树
第四步:插入2,产生RL型不平衡树,先右再左变为平衡树
第五步:插入11,产生RR型不平衡树,左旋变为平衡树
第六步:插入6,产生RL型不平衡树,先右再左变为平衡树
第七步:插入5,产生LL型不平衡树,右旋变为平衡树
本例.drawio文件下载地址:https://download.csdn.net/download/Cui_maoxin/18525745?spm=1001.2014.3001.5501