一、什么是平衡二叉树?
平衡二叉树: 又称为AVL树 ,它或者是一棵空树,或者是具备以下性质的二叉排序树:
- 每棵子树中的左子树和右子树的深度差(平衡因子)的绝对值不能超过1;
- 二叉树中每棵子树都要求是平衡二叉树;
一棵AVL树必须满足以下条件:
- 条件一:必须是二叉排序树
- 条件二:每个节点的左子树和右子树的高度差的绝对值至多为1。
也就是说,平衡二叉树的前提是它是一棵二叉排序树
平衡二叉树的查找、插入、删除操作在平均和最坏的情况下都是O(logn),这得益于它时刻维护着二叉树的平衡。
二、平衡二叉树的相关概念
平衡因子: 每个结点都有其各自的平衡因子,表示的就是该节点左子树深度减去右子树深度的值称为该结点的平衡因子BF,那么平衡二叉树上的所有节点的平衡因子只能是-1,0,1。只要一棵树中存在平衡因子不是这几个值,则这棵树就是不平衡的,就需要对这棵树进行调整。
如上图这棵平衡二叉树:
- 节点50的左子树高度为3,右子树高度为2,则BF=3-2=1;
- 节点45的左子树高度为2,右子树高度为1,则BF=2-1=1;
- 节点44的左子树高度为1,右子树高度为0,则BF=1-0=1;
- 节点43的左子树高度为0,右子树高度为0,则BF=0-0=0;
- 节点65的左子树高度为0,右子树高度为1,则BF=0-1=-1;
最小不平衡子树: 距离插入节点最近的,且平衡因子的绝对值大于1的节点为根的子树。
上图中,左边二叉树的节点45的平衡因子为1,当插入节点43后,节点45的平衡因子等于2。节点45是距离插入节点43最近的BF不在[-1,1]范围ie内的节点,因此以节点45为根的子树是最小不平衡子树。
三、AVL(平衡二叉树)的平衡调整
1、平衡二叉树的实现原理
平衡二叉树构建的基本思想是在构建二叉树排序树的过程中,每当插入一个结点时,先检查是否因插入而破坏了树的平衡性,若是,则找出最小不平衡子树。在保持二叉排序树的特性的前提下,调整最小不平衡子树中各个结点之间的链接关系,进行相应的旋转,使之成为新的平衡子树。
现在表{3, 2, 1, 4, 5, 6, 7, 10, 9, 8}构建二叉排序树时,构建的二叉排序树如下图左图所示,虽然完全符合二叉排序树的定义,但是对这种高度为8的二叉树进行查找时,效率是比较低的O(n)。因此更希望构建出如下图右图的高度为4的二叉排序树,这样可以提供高效的查找效率O(logn)。
2、调整的四种类型
整个实现过程是通过在一棵平衡二叉树中依次插入元素(按照二叉排序树的方式),若出现不平衡,则要根据新插入的节点与最低不平衡节点的位置关系进行相应的调整。分为LL型,RR型,LR型和RL型4种类型,各调整方法如下(下面用A表示最低不平衡结点):
(1)LL型调整:
由于在A的左孩子(L)的左子树(L)上插入新结点,使原来的平衡二叉树变得不平衡,此时A的平衡因子由1增至2,下面图1是LL型的最简单形式,此时整棵树就成了最小不平衡子树,需要进行调整。因为A结点BF为正(2),因此整棵树进行右旋(顺时针),此时结点2成为了根结点,3成为了2的右孩子,这样三个结点的BF值均为0。
LL型调整的一般形式为如下图所示,表示在A的左孩子B的左子树BL(不一定为空)中插入结点(图中阴影部分所示)而导致不平衡(h表示子树的深度)。这种情况下进行调整如下(右旋):
(1). 将A的左孩子B提升为新的根结点;
(2). 将原来的根结点A降为B的右孩子;
(3). 各子树按大小关系连接(BL和AR不变,BR调整为A的左子树)
代码实现
(2)、RR型调整
由于在A的右孩子(R)的右子树(R)上插入新结点,使原来平衡二叉树变得不平衡,此时A的平衡因子由-1变成了-2。这是RR型的最简单形式。结点A的平衡因子为负(-2),此时需要进行调整(左旋),结点B成为新的根结点,A、C结点分别作为左右孩子结点,此时三个结点的BF都为0。
RR型调整的一般形式为下图所示,表示在A的右孩子B的右子树BR(不一定为空)中插入新节点(图中阴影部分所示)而导致不平衡(h表示子树的深度)。这种情况下进行调整如下(左旋):
(1) 将A的右孩子B提升为新的结点;
(2) 将原来的根结点A降为B的左孩子
(3)各子树按照大小关系连接(AL和BR不变,BL调整为A的右子树)
代码实现:
(3)、LR型调整
由于在A的左孩子(L)的右子树(R)上插入新节点,使原先的平衡二叉树变得不平衡,此时A的平衡因子由1变成了2,B的平衡因子从0变成了-1。下图是LR型的最简单的形式。可以发现直接进行左旋或者右旋是不能实现平衡二叉树的,这是在最小不平衡子树中,A的BF=2,B的BF=-1,一正一负,是异号的,上面直接进行左旋或者右旋是因为最小不平衡子树的根结点和它的子结点符号都是相同的。因为B的BF=-1,所以先对B-C进行左旋,然后再对整体进行右旋。
LR型调整的一般形式如下图所示,表示在A的左孩子B的右子树(根结点为C,不一定为空)中插入结点(图中两个阴影部分之一)而导致不平衡(h表示子树的深度)。这种情况调整如下:
(1)将B的右孩子C提升为新的根结点;
(2) 将原来的根结点A降为C的右孩子
(3) 各子树按照大小关系连接(BL和AR不变,CL和CR分别调整为B的右子树和A的左子树)
代码实现:
(4)、RL型调整
由于在A的右孩子B(R)的左子树(L)上插入新节点,使原来的平衡二叉树失去了平衡,此时A的平衡因子由-1变成了-2.下图是RL型的最简单形式。显然,按照大小关系,结点C应作为新的根结点,其余两个结点分别作为左右孩子结点才能平衡。
RL型调整的一般形式如下图,表示在A的右孩子B的左子树(根结点为C,不一定为空)中插入结点(图中两个阴影部分之一)而导致不平衡(h表示子树的深度)。这种情况调整如下:
(1) 将B的左孩子C作为新的根结点;
(2)将原先的根结点A降为C的左孩子;
(3)各子树按照大小关系连接(AL和BR不变,CL和CR分别调整为A的右子树和B的左子树)
代码实现:
平衡二叉树实现的实例
选取一组数据分别为2,1,0,3,4,5,6,9,8,7的十个结点来构造平衡二叉树。
- 首先数据为2的结点作为根结点插入,接着插入1,仍是平衡的,再插入0后,结点2的平衡因子等于2,此时u出现了不平衡,因此需要进行调整,最低不平衡结点为2,属于LL型,调整过程如图所示:
- 接着插入结点3,是平衡的,再插入结点4时,出现了不平衡,结点1和结点2的平衡因子都为-2,结点2为最低不平衡结点,属于RR型,调整过程如图所示:
- 接着插入结点5,此时结点1的平衡因子为-2,导致不平衡,结点1为最低不平衡结点,属于RR型,调整如图所示:
- 接着插入6,此时结点4的平衡因子为-2,导致不平衡,最小不平衡结点为结点4,属于RR型,调整如下:
- 接着插入9,是平衡的,再插入8,此时结点3,5,6的平衡因子都是-2,导致不平衡,结点6为最低不平衡结点,属于RL型,调整如图所示:
-
插入7,此时结点3、5的平衡因子为-2,导致不平衡,最低不平衡结点为5,属于RL型,调整如图:
这里整理的内容是参照下面这位大神的博客 https://blog.csdn.net/isunbin/article/details/81707606,感谢这为博主, 遗憾的是本篇文章未能python代码实现,后续会继续完成。