AVL Tree
简介
在AVL树中,任一结点对应的两颗子树的最大高度差为1,因此它也被称为高度平衡树。查找、插入和删除在平均和最坏情况下的时间复杂度都是O(log n)。增加和删除元素的操作则可能需要借由一次或多次树旋转,以实现树的重新平衡。
在开始之前请明确树的高度的概念。
以下面这颗树为例,标明各个结点的高度
30(2)
/ \
/ \
17(1) 40(0)
/\
/ \
14(0) 20(0)
为了方便起见,空结点的高度设定为-1,例如上图右下的40结点,左右孩子都为空,高度看作-1,这样计算像40这样的结点高度时不用指定特殊情况:左右孩子高度最大值加一(-1+1=0)
属性
AVL树每个结点左右子树的高度差不超过1,如上图根结点30,左子树高度为1,右子树高度为0,相差1。
基本操作
旋转(Rotation)
如下图所示,从左到右为对X结点左旋(X结点移动到左侧),从右到左为对Y结点右旋(Y结点移动到右侧)
X Y
/ \ left_rotate(X) / \
/ \ ----------------> / \
A子树 Y <---------------- X C子树
/\ right_rotate(Y) /\
/ \ / \
B子树 C子树 A子树 B子树
此操作花费恒定的O(1)时间,而且变换后满足二叉搜索树的属性,你可以看到操作前后它的中序遍历都是A,X,B,Y,C
插入
- 插入到二叉搜索树
- 修复AVL属性
第一步就是很普通的把结点插入到二叉搜索树,重点在第二步如何保持AVL树的属性,请看下面的两种情况(括号内为结点高度):
如果X的右子树(Y树)右侧偏重(C子树高度大于B子树高度),进行左旋X操作
X(k) Y(k-1)
/ \ left_rotate(X) / \
/ \ ----------------> / \
A子树(k-3) Y(k-1) X(k-2) C子树(k-2)
/\ /\
/ \ / \
B子树(k-3) C子树(k-2) A子树(k-3) B子树(k-3)
否则,对Z进行右旋操作,再对X进行左旋操作
X right_totate(Z) Y
/ \ left_rotate(X) / \
/ \ ----------------> / \
A子树 Z X Z
/\ /\ /\
/ \ / \ / \
Y D子树 A B C D
/\ 子 子 子 子
/ \ 树 树 树 树
B子树 C子树
你可以使用它进行排序,逐个插入结点时间复杂度为O(nlogn)
,之后进行中序遍历时间复杂度为O(n)
,就可以得到递增的序列。
tags: #数据结构 #排序 #二叉搜索树 #AVL树