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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值