AVL樹是帶有平衡條件的二叉查找樹,這個平衡條件必須要容易保持,而且必須保證樹的深度是O(logN)。其每個結點的左子樹和右子樹的高度最多差1。
在高度爲h的AVL樹中,最少結點數S(h)=S(h-1)+S(h-2)+1給出。
AVL樹插入操作隱含的困難:插入一個結點可能破壞AVL樹的特性。如果發生這種情況,則插入操作還包括恢復平衡性質。
在插入以後,只有那些從插入點到根結點的路徑上的結點的平衡可能被改變。要重新平衡的結點叫
(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++描述》第三版,僅供學習交流之用,轉發請註明原出處。