AVL树基本概念
一棵AVL(
Adelson-
Velskii and
Landis)树满足下面三个条件:
- 是一棵二叉搜索树(Binary Search Tree);
- 对于树中的每一个结点,其左、右子树的高度差的绝对值小于等于1;
- 空树的高度定义为-1。
如图1,左边的是一棵AVL树,而右边的则不是(17是不平衡的,其左子树的高度为1,而右子树的高度为-1),但它们都是二叉搜索树。
图1 AVL树和二叉搜索树
AVL树在基本的二叉搜索树上加以限制条件来控制树的平衡,施加的条件可以多样化,比如可以要求每个结点的的左右子树高度差的绝对值为0,但这太严格了,实际上只有满二叉树能达到这个要求;若再把限制条件放松一点点,即允许高度差的绝对值不超过1,那么就成了AVL树;如果再把限制条件放松,还可以定义出其它类型的平衡树。
AVL树的插入操作
插入操作同普通的二叉搜索树的插入操作时一样的,可以参考数据结构教材,这儿不详述。对于AVL树,插入一个新结点后,可能导致上述条件2被破坏。导致这种情况发生的情形有4种,下面只分析其中两种,另外两种情况是对称的。我们假设首先被打破平衡状态的结点为α。
情形1——插入到α的左孩子的左子树中
如图2左边所示,此时可以将α进行右旋转,得到右边的结果,旋转后的根节点变成了β,整棵树维持平衡。
图2 左-左插入及平衡恢复
情形2——插入到α的左孩子的右子树中
如图3左边所示,
注意:此时的B和C高度不可能同时为h-1。对于这种情形,需要进行两次旋转,先对β进行左旋转,然后对α进行右旋转,整棵树维持平衡。
图3 左-右插入及平衡恢复
情形3——插入到α的右孩子的右子树中
这与情形1是对称的。
情形4——插入到α的右孩子的左子树中
这与情形2是对称的。
插入操作C语言伪代码
设函数avl_insert()接受参数为一个AvlTree类型的变量以及要插入的键值key,函数返回插入key后的新的AVL树,则伪代码如下:
AvlTree avl_insert(AvlTree t, int key)
{
if (NULL == t) {
/* alloc new node here and assign it to t */
} else if (t->key > key) {
t->left = avl_insert(t->left, key);
if (t is unbalanced) {
if (key < t->left->key)
t = single_rotate_r(t); /* Left-Left */
else
t = double_rotate_lr(t); /* Left-Right */
}
} else if (t->key < key) {
t->right = avl_insert(t->right, key);
if (t is unbalanced) {
if (key > t->right->key)
t = single_rotate_l(t); /* Right-Right */
else
t = double_rotate_rl(t); /* Right-Left */
}
} else
; /* duplicate key, do nothing */
/* adjust t's height */
t->height = max(height(t->left), height(t->right)) + 1;
return t;
}
AVL树的删除操作
删除结点后,我们设第一个被打破平衡状态的结点为α