AVL樹,最老的一種平衡查找樹

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++描述》第三版,僅供學習交流之用,轉發請註明原出處。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章