AVL树是带有平衡条件的二叉查找树,这个平衡条件必须要容易保持,而且必须保证树的深度是O(logN)。其每个结点的左子树和右子树的高度最多差1。
在高度为h的AVL树中,最少结点数S(h)=S(h-1)+S(h-2)+1给出。
AVL树插入操作隐含的困难:插入一个结点可能破坏AVL树的特性。如果发生这种情况,则插入操作还包括恢复平衡性质。
在插入以后,只有那些从插入点到根结点的路径上的结点的平衡可能被改变。要重新平衡的结点叫
α
。高度不平衡时,
α
点的两棵子树的高度差2。这种不平衡有4种可能情况:
(1)对
α
的左儿子的左子树进行一次插入。
(2)对
α
的左儿子的右子树进行一次插入。
(3)对
α
的右儿子的左子树进行一次插入。
(4)对
α
的右儿子的右子树进行一次插入。
(1)和(4)、(2)和(3)分别关于
α
镜像对称。
当插入发生在(1)或(4)中,即“外边”,通过对树进行一次单旋转而完成调整。
当插入发生在(2)或(3)中,即“内部”,通过对树进行双旋转来处理。
单旋转示例
从空的AVL树开始插入3、2、1,然后依序插入4到7:
双旋转示例
在上面例子的基础上以倒序插入10-16,接着插入8,然后在插入9:
插入16不破坏平衡,插入15,一次双旋转:
插入14,一次双旋转:
插入13,右右,一次单旋转
插入12,一次单旋转
插入11,一次单旋转;插入10,也要一次单旋转;插入8,不破坏平衡
插入9,左右,一次双旋转
AVL树的结点声明
struct AvlNode
{
Comparable element;
AvlNode *left;
AvlNode *right;
int height;
AvlNode( const Comparable & theElement, AvlNode *lt,
AvlNode *rt, int h = 0 )
: element( theElement ), left( lt ), right( rt ), height( h ) { }
};
计算AVL结点高度的函数
/**
* Return the height of node t or -1 if NULL.
*/
int height( AvlNode *t ) const
{
return t == NULL ? -1 : t->height;
向AVL树的插入操作
/**
* Internal method to insert into a subtree.
* x is the item to insert.
* t is the node that roots the subtree.
* Set the new root of the subtree.
*/
void insert( const Comparable & x, AvlNode * & t )
{
if( t == NULL )
t = new AvlNode( x, NULL, NULL );
else if( x < t->element )
{
insert( x, t->left ); //这一步最终都要执行开头的if,插入一个结点,但未平衡
if( height( t->left ) - height( t->right ) == 2 )
if( x < t->left->element ) //x在左儿子的左子树中
rotateWithLeftChild( t );
else
doubleWithLeftChild( t ); //x在左儿子的右子树中
}
else if( t->element < x )
{
insert( x, t->right );
if( height( t->right ) - height( t->left ) == 2 )
if( t->right->element < x ) //x在右儿子的左子树中
rotateWithRightChild( t );
else
doubleWithRightChild( t ); //x在右儿子的右子树中
}
else
; // Duplicate; do nothing
t->height = max( height( t->left ), height( t->right ) ) + 1; //在每一次递归返回的时候,计算该处结点的高度height。
}
执行单旋转的例程
/**
* Rotate binary tree node with left child.
* For AVL trees, this is a single rotation for case 1.
* Update heights, then set new root.
*/
void rotateWithLeftChild( AvlNode * & k2 )
{
AvlNode *k1 = k2->left;
k2->left = k1->right;
k1->right = k2;
k2->height = max( height( k2->left ), height( k2->right ) ) + 1;
k1->height = max( height( k1->left ), k2->height ) + 1;
k2 = k1; //k2一直是指向root结点的指针
}
执行双旋转的例程
/**
* Double rotate binary tree node: first left child
* with its right child; then node k3 with new left child.
* For AVL trees, this is a double rotation for case 2.
* Update heights, then set new root.
*/
void doubleWithLeftChild( AvlNode * & k3 )
{
rotateWithRightChild( k3->left );
rotateWithLeftChild( k3 );
}
参考Mark Allen Weiss《数据结构与算法分析c++描述》第三版,仅供学习交流之用,转发请注明原出处。