Tekson

禧之狼

博客园 首页 联系 订阅 管理

 

8. AVL

AVL树得名于其发明者G.M.Adelson-VelskyE.M.LandisAVL树是一个各结点具有平衡高度的扩展的二叉搜索树。在AVL树中,任一结点的两个子树的高度差最多为1AVL树的高度不会超过 ,因此当需要快速访问元素时,AVL树是一种极具威力的存储方式。

【结论】AVL树既有二叉搜索树的搜索效率又可以避免二叉搜索树的最坏情况(退化树)出现。

AVL树的表示与二叉搜索树类似,其操作基本相同,但插入和删除方法除外,因为它们必须不断监控结点的左右子树的相对高度,这也正是AVL树的优势所在。

下面是AVL树的结点的一种,其中,balanceFcator(平衡因子)的值必须是-101三者之一。

left

data

balanceFactor

right

struct AVLTreeNode

{

     int data;

     AVLTreeNode *left, *right;

     int balanceFactor;

};

当然,也可以通过对TreeNode的继承来实现。

另一种AVL树的结点为:

left

data

height

right

其实现方法如下:

#include <stdafx.h>

#include <iostream>

using namespace std;

//AVL树可以从BST树继承,但是为了方便于应试,这里单独进行实现,以增加独立性。

struct AVLTreeNode

{

    int data;

    AVLTreeNode *left;

    AVLTreeNode *right;

int height; //height是结点的高度,叶子结点的高度为0,其父结点的高度为1,以此类推……

//【注】不要将这里的高度(height)与深度的概念相混淆。

     const int getHeight()const;

     AVLTreeNode(const int _data=0, AVLTreeNode *_left=NULL, AVLTreeNode *_right=NULL, int _height=0)

         :data(_data), left(_left), right(_right), height(_height){}

};

//定义该成员函数的目的是为了防止调用NULLheight成员时出现的未定义错误而导致程序崩溃

const int AVLTreeNode::getHeight()const

{

     if(NULL == this)

        return -1;//空结点的高度为-1

    return this->height;

}

class AVLTree

{

public:

     AVLTreeNode *root;

private:

     //_clearAVLTree_printAVLTree_findAVLNodecopyAVLTree的实现与BST树的几乎完全相同

     void _clearAVLTree(AVLTreeNode *node);//clearTree和析构函数中会被用到

     void _printAVLTree(AVLTreeNode *node, int level);//只能用在printTree函数中

     void _insertAVLNode(AVLTreeNode *&node, AVLTreeNode *newNode);

     //void _deleteAVLNode(AVLTreeNode *&node, int item);//AVL树的删除结点函数太难,从略。

     AVLTreeNode *copyAVLTree(AVLTreeNode *node);

     AVLTreeNode *_findAVLNode(AVLTreeNode *node, const int item)const;//只能用在findNode

     void singleRotateLeft(AVLTreeNode *&p);

     void singleRotateRight(AVLTreeNode *&p);

     void doubleRotateLeft(AVLTreeNode *&p);

     void doubleRotateRight(AVLTreeNode *&p);

public:

     AVLTree():root(NULL){};

     //复制构造函数、赋值操作符、析构函数、复制树、打印树、清除树、查找结点的实现与BST树的相应实现几乎完全相同,

     //仅仅由于AVL树的结点的数据比BST树多了个height成员变量才导致有所区别。

     AVLTree(const AVLTree *rhs);

     AVLTree & operator=(const AVLTree *rhs);

     ~AVLTree(){clearAVLTree();}

     void printAVLTree();

     void clearAVLTree();

     AVLTreeNode *findAVLNode(const int item)const;

     void insertAVLNode(const int item);

     //void deleteAVLNode(const int item);//AVL树的删除结点函数太难,从略。

};

void AVLTree::_clearAVLTree(AVLTreeNode *node)

{

     if(NULL == node)

         return;

     _clearAVLTree(node->left);

     _clearAVLTree(node->right);

     delete node;

}

void AVLTree::clearAVLTree()

{

     _clearAVLTree(root);

     root = NULL;

}

void AVLTree::_printAVLTree(AVLTreeNode *node, int level)

{

     if(NULL == node)

         return;

     _printAVLTree(node->right, level+1);

     for(int i=0; i<level; ++i)

         cout << " ";

     cout << node->data << endl;

     _printAVLTree(node->left, level+1);

}

void AVLTree::printAVLTree()

{

     _printAVLTree(root, 0);

}

AVLTreeNode *AVLTree::copyAVLTree(AVLTreeNode *node)

{

     if(NULL == node)

         return NULL;

     AVLTreeNode *newNode = new AVLTreeNode(node->data, copyAVLTree(node->left), copyAVLTree(node->right), node->height);

     return newNode;

}

AVLTree::AVLTree(const AVLTree *rhs)

{

     root = copyAVLTree(rhs->root);

}

AVLTree & AVLTree::operator=(const AVLTree *rhs)

{

     if(this == rhs)

         return *this;

     clearAVLTree();

     copyAVLTree(root);

     return *this;

}

AVLTreeNode *AVLTree::_findAVLNode(AVLTreeNode *node, const int item)const

{

     if(NULL == node)

     {

         cerr << "Can't find it\n";

         exit(1);

     }

     if(item == node->data)

         return node;

     else if(item < node->data)

         return _findAVLNode(node->left, item);

     else

         return _findAVLNode(node->right, item);

}

AVLTreeNode *AVLTree::findAVLNode(const int item)const

{

     return _findAVLNode(root, item);

}

/********************************************************************

singleRotateRight的图示:

          node                                   lcNode

           /                                     /     \

      lcNode                      ==>    newAVLNode    node

      /     \                                           /

newAVLNode  lcNode->right                            lcNode->right

【思想】newAVLNodelcNodenode在一条线上,并在左子树,故采用单右旋以调整高度使之达到平衡。实际中,如果AVL树在node点不平衡的话,lcNode->right肯定为NULL

*********************************************************************/

void AVLTree::singleRotateRight(AVLTreeNode *&node)

{

     //N:node, LC(left child):lcNode

    AVLTreeNode *lcNode = node->left;

    node->left = lcNode->right;

    lcNode->right = node;

     // 结点的位置变了, 要更新结点的高度值。而lcNode->right得高度没有变化,故不必更新

     //顺序:从低到高依次更新。这里,从nodelcNode依次更新。

     node->height = max(node->left->getHeight(), node->right->getHeight())+1;

    lcNode->height = max(lcNode->left->getHeight(), lcNode->right->getHeight())+1;

     node = lcNode;

}

/********************************************************************

singleRotateLeft的图示:

node                                    rcNode

         \                                      /  \

         rcNode           ==>               node   newAVLNode

        /     \                               \

rcNode->left  newAVLNode                 rcNode->left

【思想】newAVLNodercNodenode在一条线上,并在右子树,故采用单左旋以调整高度使之达到平衡。实际中,如果AVL树在node点不平衡的话,rcNode->left肯定为NULL

*********************************************************************/

void AVLTree::singleRotateLeft(AVLTreeNode *&node)

{

     //RC(right child):rcNode

    AVLTreeNode *rcNode = node->right;

    node->right = rcNode->left;

    rcNode->left = node;

     // 结点的位置变了, 要更新结点的高度值。而rcNode->left得高度没有变化,故不必更新

     //顺序:从低到高依次更新。这里,从nodercNode依次更新。

    node->height = max(node->left->getHeight(), node->right->getHeight())+1;

    rcNode->height = max(rcNode->left->getHeight(), rcNode->right->getHeight())+1;

     node = rcNode;

}

/***************************************************************************************************************

doubleRotateRight的图示:

           node                                          node                                 newAVLNode

            /                                             /                                   /        \

         lcNode        singleRotateLeft(node->left): newAVLNode  singleRotateRight(node)  lcNode        node

         /    \                      =>                 /    \                 =>         /  \            /

lcNode->left  newAVLNode                           lcNode  newAVLNode->right   lcNode->left newAVLNode newAVLNode

              /     \                              /    \                                    ->left     ->right

 newAVLNode->left   newAVLNode->right    lcNode->left newAVLNode->left

【思想】newAVLNodelcNodenode在不在一条线上,但同在左子树上,故采用双右旋以调整高度使之达到平衡,即先对lcNode进行单左旋,然后再对node进行单右旋。实际中,如果AVL树在node点不平衡的话,lcNode->leftnewAVLNode->leftnewAVLNode->right肯定为NULL

****************************************************************************************************************/

void AVLTree::doubleRotateRight(AVLTreeNode *&node)

{

    //先对左结点单左旋,然后再对该结点单右旋

    singleRotateLeft(node->left);

    singleRotateRight(node);

}

/***************************************************************************************************************

doubleRotateLeft的图示:

            node                                node                                 newAVLNode

              \          singleRotateRight       \         singleRotateLeft         /         \

            rcNode        (node->right):      newAVLNode        (node):           node         rcNode

            /    \              =>             /    \            =>                \           /     \

newAVLNode  lcNode->right           newAVLNode rcNode                      newAVLNode newAVLNode lcNode

       /     \                          ->left    /    \                        ->left    ->right   ->right

newAVLNode   newAVLNode                  newAVLNode lcNode->right

->left       ->right                    ->right

【思想】newAVLNodercNodenode不在一条线上,但同在右子树,故采用双左旋以调整高度使之达到平衡,即先对rcNode进行单右旋,然后再对node进行单左旋。实际中,如果AVL树在node点不平衡的话,lcNode->rightnewAVLNode->leftnewAVLNode->right肯定为NULL

****************************************************************************************************************/

void AVLTree::doubleRotateLeft(AVLTreeNode *&node)

{

    //先对右结点单右旋,然后再对该结点单左旋

    singleRotateRight(node->right);

    singleRotateLeft(node);

}

void AVLTree::_insertAVLNode(AVLTreeNode *&node, AVLTreeNode *newNode)

{

     if(NULL == node)

     {

         node = newNode;

         return;

     }

     if(newNode->data < node->data)//插入到左子树中

     {

         _insertAVLNode(node->left, newNode);

         //以下为AVL树区别于BST树的地方

         if(node->left->getHeight()-node->right->getHeight() == 2)//插入后检查是否要进行平衡更新。

         {

              if(newNode->data < node->left->data)

                   singleRotateRight(node);//插入到node的左孩子LC的左子树中, 做单右旋

              else

                   doubleRotateRight(node);//插入到node的左孩子LC的右子树中, 做双右旋

         }//左子树插入时要右旋,只有这样才能重新平衡AVL

     }

     else //插入到右子树中

    {

        _insertAVLNode(node->right, newNode);

         //以下为AVL树区别于BST树的地方

        if(node->right->getHeight()-node->left->getHeight() == 2)//AVL树不平衡

        {

            if (newNode->data >= node->left->data)           

                   singleRotateLeft(node);//插入到右子树右边, 做单左旋

              else

                   doubleRotateLeft(node);//插入到右子树左边, 做双左旋

         }//右子树插入时要左旋,只有这样才能重新平衡AVL

    }

     node->height = max(node->left->getHeight(), node->right->getHeight())+1;

     //从被插入结点一定是叶子结点。每次递归都要计算当前结点的高度,一直到根结点root为止,因为每次插入都会影响到参加旋

     //转的结点(包括newAVLNode)及其上面的结点。

}

void AVLTree::insertAVLNode(const int item)

{

     AVLTreeNode *newNode = new AVLTreeNode(item);

     _insertAVLNode(root, newNode);

}

int main()

{

     int a[10] = {9,8,7,6,5,4,3,2,1,0};

     AVLTree avlTree;

     //二叉搜索树的构建。事实上,二叉搜索树可以实现了数组的排序(只需通过LNR遍历将各结点的数据分别赋回给原数组便可以

     //达到排序的效果)

     for(int i=0; i!=10; ++i)

         avlTree.insertAVLNode(a[i]);

     avlTree.printAVLTree();

}

posted on 2009-10-08 17:10  珍宝老王  阅读(388)  评论(0编辑  收藏  举报