为什么要AVL
在之前的介绍的二分搜索树中,我们发现它查找、添加、删除元素的复杂度为
O
(
l
o
g
n
)
O(logn)
O(logn)级别,但是在某些特殊情况下,比如在添加1,2,3,4,5,6时,你期望能够添加完成为左边的树,但是如果按顺序添加就会退化成链表,复杂度变为
O
(
n
)
O(n)
O(n)级别。此时这种二叉树就成为一种不平衡二叉树,而AVL树就是解决这种不平衡二叉树一种方法。
平衡二叉树从字面上理解就是这棵树要尽量的平衡。但是对于平衡有不同的定义,比如之前说的堆,它是一棵完全二叉树,空缺部分只能出现在右下角,这种平衡二叉树除了最后一层其它层必须是是满二叉树。而AVL中对于平衡二叉树的定义是对于每个节点,它的左右子树高度差不能超过1。
就像这棵树,虽然18节点只有一个叶子节点,但是所有节点的左右子树都是满足高度差不超过1的。此时如果继续往左边添加节点,就会发现不满足上述条件。
此时为了判断加入新节点后是否满足上述条件,需要记录每个节点的高度,并且计算左右子树的高度差。假设最底下一层高度为1,如果没有子树则子树高度为0。那么可以得到上述二叉树的高度差,可以发现存在高度差为2的节点,那此时就需要对二叉树进行相应的维护,使其满足平衡二叉树。
右旋转、左旋转
如果添加的节点处于左侧的左侧,也就是节点一直往左边添加。此时需要采用右旋转对二叉树进行维护。假设在添加元素
z
z
z时各子树如图所示,各子树与x,y,z的关系如图所示。在进行右旋转时,另
x
.
r
i
g
h
t
=
y
x.right=y
x.right=y,
y
.
l
e
f
t
=
T
3
y.left=T3
y.left=T3,经过旋转后仍然满足二叉搜索树的条件。
下面证明此二叉树满足平衡二叉树的条件。因为在加入z节点后才y才出现不平衡情况,那么x,z是平衡的。假设
m
a
x
H
e
i
g
h
t
(
T
1
,
T
2
)
=
h
maxHeight(T1,T2)=h
maxHeight(T1,T2)=h,那
h
e
i
g
h
t
(
z
)
=
h
+
1
height(z)=h+1
height(z)=h+1,因为x节点也是平衡的且
0
<
=
h
e
i
g
h
t
(
x
.
l
e
f
t
,
x
.
r
i
g
h
t
)
<
=
1
0<=height(x.left,x.right)<=1
0<=height(x.left,x.right)<=1,那么
h
e
i
g
h
t
(
T
3
)
=
h
+
1
或
h
height(T3)=h+1或h
height(T3)=h+1或h。因为节点y左右子树不平衡,所以节点y处的高度差为2,从而
h
e
i
g
h
t
(
T
4
)
=
h
height(T4)=h
height(T4)=h。那么经过右旋转后的高度如右图所示,因为高度差改变的只有y和x节点,所以只需要计算y和x的节点即可。
h
e
i
g
h
t
(
y
)
=
h
+
1
或
h
+
2
height(y)=h+1或h+2
height(y)=h+1或h+2,
h
e
i
g
h
t
(
z
)
=
h
+
1
height(z)=h+1
height(z)=h+1,所以x的高度差是不超过1的,满足AVL平衡二叉树的条件。(这段推理有点麻烦,大家用笔自己算下就可以了)。
理解了右旋转,那么左旋转也很好理解了。就是在添加元素时一直添加在右子树,通过左旋转就可以维护平衡。
感觉东西有点多,就先到这里,剩下的内容和编码实现在下一篇更新了。
AVL树的C++实现(1)
最新推荐文章于 2025-03-07 01:09:46 发布