AVL树,最老的一种平衡查找树

来源:互联网 发布:淘宝主营类目在哪里看 编辑:程序博客网 时间:2024/06/04 20:02

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++描述》第三版,仅供学习交流之用,转发请注明原出处。

原创粉丝点击