平衡二叉樹(AVL樹)

轉載自:http://www.cnblogs.com/xiao-cheng/archive/2011/10/04/2198972.html

定義:一棵空二叉樹是AVL樹,如果T是非空二叉樹,TL和TR分別是其左子樹和右子樹,

則當且僅當TL和TR都爲AVL樹且|HL-HR|<=1時,T是AVL樹。

由定義知道一個AVL樹的任何節點的左右子樹的高度之差不超過1,這是AVL樹最基本的特徵。

AVL樹的高度:(固定節點數計算最大高度)

記N_h爲一棵高度爲h的AVL樹具有的最小節點數,則最壞情況是它的左右子樹的高度不等,

一個是N_(h-1)和N_(h-2),從而得到

N_h=N_(h-1)+N_(h-2)+1            N_0=0,N_1=1

這類似於Fibonacci數列:F_n=F_(n-1)+F_(n-2),(F_0=0,F_1=1)

而F_h=(1+sqrt(5))^h/sqrt(5)

從而高度h和節點數是對數關係,因此 h=O(log(N_h))

由此容易知道在不考慮恢復AVL樹的前提下,它的插入,刪除和查找的工作量不超過O(n)。

AVL樹節點的平衡因子

AVL樹節點的平衡因子定義爲其左子樹的高度減去右子樹的高度,我們可以在插入和刪除操作的時候更新平衡因子。

一棵AVL樹的各節點平衡因子爲1,-1, 0

樹的旋轉

在介紹插入和刪除操作之前首先介紹樹的旋轉操作

樹的旋轉操作是爲了改變樹的結構,使其達到平衡。旋轉總共分爲左旋和右旋兩類

左旋

如圖爲樹的以B爲軸左旋示意圖,從右到左是以A爲軸右旋,樹的旋轉操作要特別注意兒子節點是否爲空

頂層節點是否爲根節點。

AVL樹的插入操作

插入操作只會改變被插入節點到根節點路徑上的節點的平衡因子。

因爲在插入之前樹是AVL樹,因此各個節點的平衡因子是1,-1或0

一、如果路徑上節點平衡因子是0,則插入後不會打破這個節點的平衡性。

二、如果路徑上的節點的平衡因子是1或-1,則可能會打破平衡性,在這種情況下如果此節點的新的平衡

因子是0,則剛好將其補的更加平衡,平衡性未打破;否則平衡因子變成2或-2,則需要進行調整。

三、我們在對樹進行調整後恢復子樹相對於插入前的高度,不改變子子樹的平衡因子。

由以上三點:只需向根部查找從插入點開始第一個平衡因子不爲0的節點,令該節點爲A

更新步驟:

(1). 若A不存在,說明插入節點不影響平衡性,則自下而上更新平衡因子直到根部即可。

(2). 若bf(A)=1且插入節點在A地右子樹中,或者bf(A)=-1且插入節點在A的左子樹中,則自下而上更新

平衡因子直到A。(注:A的平衡因子變爲0)

(3). 若A的平衡性被打破,首先依然自下而上更新平衡因子,在按照下面進行分類:LL, LR, RR, RL

原bf(A)=1, 新的bf(A)=2, LL, LR,

原bf(A)=-1, 新的bf(A)=-2, RR, RL

如圖爲RR的情況,LL情況類似,旋轉後只需再次改變兩個節點的平衡因子

RR

如下圖爲RL的情況,LR類似,旋轉後需要再次改變三個節點的平衡因子

RL

至此,插入操作已經完成,可見最多多做兩次旋轉操作調整樹的結構使之平衡。

AVL樹的刪除操作:

刪除操作和插入操作一樣,也是先直接刪除二叉樹節點,然後在更新平衡因子,

調整AVL樹使之平衡。

這裏所指的刪除的節點是實際被刪除的節點,刪除操作不影響其子樹的平衡因子。

首先刪除節點,然後沿着該節點的父節點向根部更新平衡因子,考慮更新後的節點A

新的平衡因子,分爲下面三種情況:

(1)、如果bf(A)=0,則高度減少了1,從而繼續向上找非平衡點。

(2)、如果bf(A)=1或者-1,則之前必爲0,從而不影響平衡性,結束。

(3)、如果bf(A)=2(原來爲1)或者-2(原來爲-1),則A點非平衡。調整。

以bf(A)=-2爲例,稱A爲L不平衡

如果A的右節點的平衡因子是0,則進行一次左旋轉,如圖:

L0

由於子樹的高度和刪除前一樣,因此樹已經平衡。

如果A的右節點的平衡因子是-1,則稱爲L-1不平衡,也要進行一次做旋轉。

L-1

樹的高度減少1,這使得上面的祖先節點可能不平衡,一次還要沿着路徑在向上

尋找新的不平衡點,再次更新平衡因子,調整等。

如果A的右節點的平衡因子是1,則稱爲L1不平衡,要進行兩次旋轉。

L1

此時要根據BL的情況決定A和B的新的平衡因子。

由於樹的高度減少了1,因此還要沿着路徑繼續向上尋找新的不平衡點。

至此樹節點的刪除操作完成。

總結

歸納起來,AVL樹的查找操作等同於一般二叉樹,插入和刪除操作除了一般的二叉樹插入和刪除

還要更新樹的平衡因子,當平衡因子被打破時要通過旋轉恢復。而且在調整平衡時儘量影響局部範圍。


下面直接給出AVL樹的實現代碼,主要是基於前面的二叉查找樹的基類實現方法的代碼。

這裏是直接修改原來的代碼的,後面將會把它更新爲繼承的方式。

BinaryTreeNode.h 僅加入了一個balance平衡因子的數據成員和它的get,set方法

//此類爲AVL查找樹的樹節點類  
//定義的關鍵子,值,父節點和兒子節點 
#ifndef BINARY_TREE_NODE_H
#define BINARY_TREE_NODE_H
#include "objectclass.h"//通用類
class BinaryTreeNode
{
private:
    ObjectClass *theKey;//關鍵字
    ObjectClass *theValue;//值
    BinaryTreeNode *parent;//父親節點
    BinaryTreeNode *left;//左兒子
    BinaryTreeNode *right;//右兒子
 
    //定義左右子樹的寬度以便打印
    int leftWidth;
    int rightWidth;
 
    //定義當前節點應該輸出的位子,從左起點到右的寬度
    int leftOutPutLen;
 
    //定義平衡因子
    int balance;
public:
    BinaryTreeNode();
    BinaryTreeNode(ObjectClass *theKey,ObjectClass *theValue);
 
    ObjectClass *getKey();
    ObjectClass *getValue();
    BinaryTreeNode *getLeft();
    BinaryTreeNode *getRight();
    BinaryTreeNode *getParent();
    int getLeftWidth();
    int getRightWidth();
    int getLeftOutPutLen();
    int getBalance();
 
    void setKey(ObjectClass *theKey);
    void setValue(ObjectClass *theValue);   
    void setLeft(BinaryTreeNode *left);
    void setRight(BinaryTreeNode *Right);
    void setParent(BinaryTreeNode *parent);
    void setWidth(int,int);//設置子樹寬度
    void setLeftOutPutLen(int len);
    void setBalance(int balance);
};
#endif

BinaryTreeNode.cpp 文件

#include "BinaryTreeNode.h"
BinaryTreeNode::BinaryTreeNode()
{
    theKey = NULL;
    theValue = NULL;
    parent = NULL;
    left = NULL;
    right = NULL;
    leftWidth=0;
    rightWidth=0;
    leftOutPutLen=0;
    balance=0;
}
 
BinaryTreeNode::BinaryTreeNode(ObjectClass *theKey,ObjectClass *theValue)
{
    this->theKey = theKey;
    this->theValue = theValue;
    parent = NULL;
    left = NULL;
    right = NULL;
    leftWidth=0;
    rightWidth=0;
    leftOutPutLen=0;
    balance=0;
}
int BinaryTreeNode::getLeftWidth()
{
    return leftWidth;
}
 
int BinaryTreeNode::getRightWidth()
{
    return rightWidth;
}
 
ObjectClass *BinaryTreeNode::getKey()
{
    return theKey;
}
 
ObjectClass *BinaryTreeNode::getValue()
{
    return theValue;
}
 
BinaryTreeNode *BinaryTreeNode::getLeft()
{
    return left;
}
 
BinaryTreeNode *BinaryTreeNode::getRight()
{
    return right;
}
 
BinaryTreeNode *BinaryTreeNode::getParent()
{
    return parent;
}
int BinaryTreeNode::getBalance()
{
    return balance;
}
 
void BinaryTreeNode::setWidth(int leftWidth, int rightWidth)
{
    this->leftWidth=leftWidth;
    this->rightWidth=rightWidth;
}
 
void BinaryTreeNode::setValue(ObjectClass *theValue)
{
    this->theValue = theValue;
}
 
void BinaryTreeNode::setKey(ObjectClass *theKey)
{
    this->theKey = theKey;
}
 
void BinaryTreeNode::setLeft(BinaryTreeNode *left)
{
    this->left = left;
}
 
void BinaryTreeNode::setRight(BinaryTreeNode *right)
{
    this->right = right;
}
 
void BinaryTreeNode::setParent(BinaryTreeNode *parent)
{
    this->parent=parent;
}
int BinaryTreeNode::getLeftOutPutLen()
{
    return leftOutPutLen;
}
void BinaryTreeNode::setLeftOutPutLen(int len)
{
    this->leftOutPutLen = len;
}
void BinaryTreeNode::setBalance(int balance)
{
    this->balance = balance;
}

AVL.h 文件

//此類是AVL搜索樹類的定義部分
#include "BinaryTreeNode.h"
class BSTree
{
private:
//根節點
BinaryTreeNode *root;
 
public:
BSTree();
public:
BinaryTreeNode *get(ObjectClass *theKey);//搜索
BinaryTreeNode *getRoot();//返回根節點
 
BinaryTreeNode *remove(ObjectClass *theKey);//刪除
void insert(ObjectClass *theKey, ObjectClass *theValue);//插入
void ascend(BinaryTreeNode *);//遍歷
int calWidth(BinaryTreeNode *);//計算各節點的長度
void outPut();//輸出
BinaryTreeNode *tree_minimum(BinaryTreeNode *p);//最小節點
BinaryTreeNode *tree_maximum(BinaryTreeNode *p);//最大節點
BinaryTreeNode *tree_successor(BinaryTreeNode *p);//後繼節點
 
void leftRote(BinaryTreeNode *);
void rightRote(BinaryTreeNode *);
 
void deleteNode(BinaryTreeNode *);
};

AVL.cpp文件

//此文件是AVL搜索樹的實現部分
#include "AVL.h"
#include <iostream>
#include "queue.h"
using namespace std;
BSTree::BSTree()
{
    root = NULL;//根節點默認爲NULL
}
//查找關鍵字爲theKey的節點並返回指向節點的指針,找不到則返回空指針
BinaryTreeNode *BSTree::get(ObjectClass *theKey)
{
    BinaryTreeNode *p=root;
    while(p!=NULL)
    {
        //if(theKey < p->getKey())
        if(theKey->Compare(p->getKey()) == -1)
        p=p->getLeft();
        //if(theKey > p->getKey())
        else if(theKey->Compare(p->getKey()) == 1)
        p=p->getRight();
        else //如果找到了相同的關鍵字則成功返回
        return p;
    }
    return NULL;
}
//插入一個節點,如果節點關鍵字已經存在則覆蓋,否則插入到葉子節點處
void BSTree::insert(ObjectClass *theKey,ObjectClass *theValue)
{
    BinaryTreeNode *firstBalanceNode=NULL;
 
    int Path=1;//記錄firstBalanceNode開始往下的路徑,以1開始爲標記
    //00010010表示左左右左
 
    int k=0;//指示開始的位置,上例中k=4
 
    BinaryTreeNode *p=root; //search pointer
    BinaryTreeNode *parent=NULL;//parent of p;
    while(p!=NULL)
    {
        if(p->getBalance() != 0)
        {
           firstBalanceNode = p;
           Path=1;
           k=0;
        }
     
        parent=p;
        //if(theKey < p->getKey())
        if(theKey->Compare(p->getKey()) == -1)
        {
           k++;
           p=p->getLeft();
           Path=(Path<<1);//如果是向左走則Path後面加個0
        }
        //if(theKey > p->getKey())
        else if(theKey->Compare(p->getKey()) == 1)
        {
           k++;
           p=p->getRight();
           Path=(Path<<1);
           Path=Path+1;//如果是向右走,則Path後面加個1
        }
        else
        {
           p->setValue(theValue);
           //如果找到相同的關鍵字則覆蓋原有的
           return;
        }       
    }
    //等待插入的新節點
    BinaryTreeNode *newNode = new BinaryTreeNode(theKey,theValue);
    if(root == NULL)
       root = newNode;
    else
    {
        //當p爲空的時候parent最多隻有一個兒子節點
        //if(theKey < parent->getKey())
        if(theKey->Compare(parent->getKey()) == -1)
        {
           parent->setLeft(newNode);
           newNode->setParent(parent);
        }
        else
        {
           parent->setRight(newNode);
           newNode->setParent(parent);
        }
    }
 
    //第一種情況是沒有找到這種非平衡點
    if(firstBalanceNode == NULL)
    {
        if(newNode == root) return;
        //自下而上一次更新平衡因子,直到根節點
        while(newNode!=NULL)
        {
           if(newNode->getParent() == NULL) break;
 
           if(newNode == newNode->getParent()->getLeft())
              newNode->getParent()->setBalance(newNode->getParent()->getBalance()+1);
           else
              newNode->getParent()->setBalance(newNode->getParent()->getBalance()-1);
           newNode = newNode -> getParent();
        }
        return;
    }
    //第二種情況非平衡點剛好因爲新點的加入而變爲平衡點,這不會影響上面節點的因子,
    //與第一種情形可以合併寫,不過爲了看起來清晰就分開做
    else if((firstBalanceNode->getBalance() == -1 && ((Path>>(k-1))&1)==0) 
        || (firstBalanceNode->getBalance() == 1 && ((Path>>(k-1))&1)==1))
    {
        //自下而上更新平衡因子,直到原來的非平衡點
        while(newNode!=firstBalanceNode)
        {
           if(newNode->getParent() == NULL) break;
 
           if(newNode == newNode->getParent()->getLeft())
              newNode->getParent()->setBalance(newNode->getParent()->getBalance()+1);
           else
              newNode->getParent()->setBalance(newNode->getParent()->getBalance()-1);
           newNode = newNode -> getParent();
        }
        return;
    }
    //第三種情況,AVL樹被破壞掉了,要通過旋轉恢復
     else
    {
        //首先依然是改變平衡因子
        while(newNode!=firstBalanceNode)
        {
           if(newNode->getParent() == NULL) break;
 
           if(newNode == newNode->getParent()->getLeft())
              newNode->getParent()->setBalance(newNode->getParent()->getBalance()+1);
           else
              newNode->getParent()->setBalance(newNode->getParent()->getBalance()-1);
           newNode = newNode -> getParent();
        }
 
        if(((Path>>(k-1))&1)==0 && ((Path>>(k-2))&1)==0)//LL
        {       
            firstBalanceNode->setBalance(0);
            firstBalanceNode->getLeft()->setBalance(0);
            rightRote(firstBalanceNode->getLeft());//右旋轉
        }
        else if(((Path>>(k-1))&1)==1 && ((Path>>(k-2))&1)==1)//RR
        {
            firstBalanceNode->setBalance(0);
            firstBalanceNode->getRight()->setBalance(0);
            leftRote(firstBalanceNode->getRight());//左旋轉
        }
        else if(((Path>>(k-1))&1)==0 && ((Path>>(k-2))&1)==1)//LR
        {
            int bal=firstBalanceNode->getLeft()->getRight()->getBalance();
            firstBalanceNode->getLeft()->getRight()->setBalance(0);
            if(bal == 0)
            {
                firstBalanceNode->setBalance(0);
                firstBalanceNode->getLeft()->setBalance(0);
            }
            else if(bal == 1)
            {
                firstBalanceNode->setBalance(-1);
                firstBalanceNode->getLeft()->setBalance(0);
            }
            else
            {
                firstBalanceNode->setBalance(0);
                firstBalanceNode->getLeft()->setBalance(1);
            }
            leftRote(firstBalanceNode->getLeft()->getRight());
            rightRote(firstBalanceNode->getLeft());                                                  
        }
        else if(((Path>>(k-1))&1)==1 && ((Path>>(k-2))&1)==0)//RL
        {
            int bal=firstBalanceNode->getRight()->getLeft()->getBalance();
 
            firstBalanceNode->getRight()->getLeft()->setBalance(0);
 
            if(bal == 0)
            {
                firstBalanceNode->setBalance(0);
                firstBalanceNode->getRight()->setBalance(0);
            }
            else if(bal == 1)
            {
                firstBalanceNode->setBalance(0);
                firstBalanceNode->getRight()->setBalance(-1);
            }
            else
            {
                firstBalanceNode->setBalance(1);//1
                firstBalanceNode->getRight()->setBalance(0);
            }
            rightRote(firstBalanceNode->getRight()->getLeft());
            leftRote(firstBalanceNode->getRight());                                                 
        }
    }
    return;
}
//刪除節點,如果這個節點含有少於兩個兒子節點,則直接刪除它,然後將它的兒子節點鏈接到它原來所在的位置
//如果這個節點含有兩個兒子節點,則要先刪除它的後繼節點,然後將它的後繼節點的值換給它
BinaryTreeNode *BSTree::remove(ObjectClass *theKey)
{
    //先查找到要刪除的節點指針
    BinaryTreeNode *deletedNode=get(theKey);
    if(deletedNode==NULL) return NULL;
    //即將被刪除的節點,注意這個節點最多隻含有一個兒子節點
    BinaryTreeNode *todelete;
    //被刪除節點的兒子節點
    BinaryTreeNode *nextNode;
    if(deletedNode->getLeft()==NULL || deletedNode->getRight()==NULL)
        //當要刪除的節點只含有最多一個兒子節點時則即將被刪除節點就是要刪除的節點
        todelete = deletedNode;
    else
        todelete = tree_successor(deletedNode);//否則的話刪除它的後繼節點
    //////////////////////////////////////////////////////////////////////////////
    //這一步是爲了更新平衡因子調整樹的結構而設計的
    BinaryTreeNode *pend=todelete;
    while(pend!=NULL)
    {
        if(pend->getParent()==NULL)break;//根節點
        if(pend == pend->getParent()->getLeft())
            pend->getParent()->setBalance(pend->getParent()->getBalance()-1);
        else
            pend->getParent()->setBalance(pend->getParent()->getBalance()+1);
        pend=pend->getParent();
        if(pend->getBalance() != 0)break;
    }
    //////////////////////////////////////////////////////////////////////////////
 
    //獲取唯一的兒子節點,準備當前即將刪除節點的刪除工作
    if(todelete->getLeft()!=NULL)
        nextNode=todelete->getLeft();
    else
        nextNode=todelete->getRight();
    //開始刪除節點
    if(nextNode!=NULL)
        nextNode->setParent(todelete->getParent());
    if(todelete->getParent()==NULL)
        root=nextNode;
    else if(todelete->getParent()->getLeft()==todelete)
        todelete->getParent()->setLeft(nextNode);
    else
        todelete->getParent()->setRight(nextNode);
    //節點成功刪除,刪完後在考慮將原來節點的後續節點值的替換
    if(todelete!=deletedNode)
    {
        deletedNode->setKey(todelete->getKey());
        deletedNode->setValue(todelete->getValue());
    }
    //刪除節點
    delete todelete;
 
    //更新平衡因子
    deleteNode(pend);
 
    //返回不平衡點
    return pend;
}
 
//刪除節點函數的輔助函數,用於更新平衡因子,調整樹的結構,使之仍爲AVL樹
void BSTree::deleteNode(BinaryTreeNode *deletedNode)
{
    if(deletedNode==NULL)return;
    if(deletedNode->getBalance()==1 || deletedNode->getBalance()==-1 //如果非平衡點刪除之前的平衡因子是0,則無需調整
        || deletedNode->getBalance()==0)return;//如果非平衡點是根節點且平衡因子是0則無需調整
 
    if(deletedNode->getBalance()==2)//R
    {
        if(deletedNode->getLeft()->getBalance()==0)//R0
        {
            deletedNode->setBalance(1);
            deletedNode->getLeft()->setBalance(-1);
            rightRote(deletedNode->getLeft());
            return;// 經過R0旋轉後,AVL樹已經達到平衡所以直接返回即可
        }
        else if(deletedNode->getLeft()->getBalance()==1)//R-1
        {
            deletedNode->setBalance(0);
            deletedNode->getLeft()->setBalance(0);
            rightRote(deletedNode->getLeft());
        }
        else//R1
        {
            if(deletedNode->getLeft()->getRight()->getBalance()==0)
            {
                deletedNode->setBalance(0);
                deletedNode->getLeft()->setBalance(0);
            }
            else if(deletedNode->getLeft()->getRight()->getBalance()==1)
            {
                deletedNode->setBalance(-1);
                deletedNode->getLeft()->setBalance(0);
            }
            else
            {
                deletedNode->setBalance(0);
                deletedNode->getLeft()->setBalance(1);
            }
            deletedNode->getLeft()->getRight()->setBalance(0);
            leftRote(deletedNode->getLeft()->getRight());
            rightRote(deletedNode->getLeft());
 
        }
 
        }
    else if(deletedNode->getBalance()==-2)//L
    {
        if(deletedNode->getRight()->getBalance()==0)//L0
        {
            deletedNode->setBalance(-1);
            deletedNode->getRight()->setBalance(1);
            leftRote(deletedNode->getRight());
            return;
        }
        else if(deletedNode->getRight()->getBalance()==-1)//L-1
        {
            deletedNode->setBalance(0);
            deletedNode->getRight()->setBalance(0);
            leftRote(deletedNode->getRight());
        }
        else//L1
        {
            if(deletedNode->getRight()->getLeft()->getBalance()==0)
            {
                deletedNode->setBalance(0);
                deletedNode->getRight()->setBalance(0);
            }
            else if(deletedNode->getRight()->getLeft()->getBalance()==-1)
            {
                deletedNode->setBalance(1);
                deletedNode->getRight()->setBalance(0);
            }
            else
            {
                deletedNode->setBalance(0);
                deletedNode->getRight()->setBalance(-1);
            }
            deletedNode->getRight()->getLeft()->setBalance(0);
            rightRote(deletedNode->getRight()->getLeft());
            leftRote(deletedNode->getRight());
        }
    }
    //如果不是0旋轉則繼續向根部尋找非平衡點,
    deletedNode=deletedNode->getParent();//首先從當前的被調整後的子樹根節點開始出發
    while(deletedNode!=NULL)
    {
        if(deletedNode->getParent()==NULL)break;//根節點
        if(deletedNode == deletedNode->getParent()->getLeft())
            deletedNode->getParent()->setBalance(deletedNode->getParent()->getBalance()-1);
        else
            deletedNode->getParent()->setBalance(deletedNode->getParent()->getBalance()+1);
        deletedNode=deletedNode->getParent();
        if(deletedNode->getBalance() != 0)break;//找到非平衡點就退出,否則會一直找打根部
    }
    deleteNode(deletedNode);//繼續下一次更新
}
 
//計算左右的寬度,使用遞歸算法
int BSTree::calWidth(BinaryTreeNode *p)
{
    if(p!=NULL)
    {
        int leftWidth=0;//左寬度
        int rightWidth=0;//右寬度
        if(p->getLeft()!=NULL)
            leftWidth=calWidth(p->getLeft())+p->getKey()->getLength();
            //左寬度是左子樹的總寬度加上本節點的長度
        if(p->getRight()!=NULL)
            rightWidth=calWidth(p->getRight())+p->getKey()->getLength();
            //右寬度是右子樹的總寬度加上本節點的長度
        p->setWidth(leftWidth,rightWidth);//設置左右寬度
        //返回本節點爲根的子樹總寬度
        return leftWidth+rightWidth;
    }
    return 0;
}
 
//按照層次遍歷子樹並且打印出來
void BSTree::ascend(BinaryTreeNode *p)
{   
    if(p==NULL) return;
    calWidth(p);//計算左右子樹的寬度
 
    p->setLeftOutPutLen(p->getLeftWidth());//設置最頂層的左邊預留寬度
 
    //下面要用隊列實現樹的層次遍歷
    Queue<BinaryTreeNode *> Q;
    Q.EnQueue(p);
    int number=0;//存儲下一層的元素個數
    int numberLeave=1;//這一層還剩下多少元素
    BinaryTreeNode *dep;//保存當前從隊列彈出的節點指針
 
    int preLeftWidth=0;
    //存儲前一個節點的左寬度,以便後面一個節點的打印
    //如果當前節點在最開始,則前一節點左寬度爲0
 
    bool firstIn=true;
 
    while(!Q.isEmpty())//打印所有節點
    {
        dep=Q.DeQueue();
        numberLeave--;
        if(dep!=NULL)
        {
            if(dep->getLeft()!=NULL)
            {
                Q.EnQueue(dep->getLeft());//左節點加入隊列
                number++;//下層節點加一
            }
             
            if(dep->getRight()!=NULL)
            {
                Q.EnQueue(dep->getRight());//右節點加入隊列
                number++;//下層節點加一
            }
 
            int leftOutPutLen=dep->getLeftWidth();
            //如果是第一次進入就左邊預留寬度就是當前節點自己的寬度
             
            if(!firstIn)
            {
                if(dep==dep->getParent()->getLeft())
                    leftOutPutLen = dep->getParent()->getLeftOutPutLen()-dep->getRightWidth()-dep->getParent()->getKey()->getLength();
                //如果當前節點是左兒子,則它的左預留寬度是父節點的預留寬度減去當前節點右寬度
                else
                    leftOutPutLen = dep->getParent()->getLeftOutPutLen()+dep->getLeftWidth()+dep->getParent()->getKey()->getLength();
                //如果當前節點是右兒子,則它的左預留寬度是父節點的預留寬度加上當前節點的左寬度
                dep->setLeftOutPutLen(leftOutPutLen);//設置預留寬度
            }
 
            //根據當前節點左預留寬度和上一兄弟節點的結束寬度打印預留空格
            for(int i=0;i<leftOutPutLen-preLeftWidth;i++)
                cout<<" ";
            dep->getKey()->OutPut();//打印當前節點
            preLeftWidth=leftOutPutLen+dep->getKey()->getLength();
            //計算當前節點的結束寬度,以便下一兄弟節點的打印
 
            //如果當前節點在沒有兄弟節點了就換行
            if(numberLeave == 0)
            {
                cout<<endl;
                preLeftWidth=0;
                numberLeave = number;
                number = 0;
            }
        }
        firstIn=false;
    }
}
 
//輸出,這裏是默認從根節點輸出,如果直接調用ascend則可以輸出任何子樹
void BSTree::outPut()
{
    BinaryTreeNode *temp=root;
    ascend(temp);
}
 
BinaryTreeNode *BSTree::tree_minimum(BinaryTreeNode *p)
{
    if(p==NULL)
    return NULL;
    BinaryTreeNode *pp=p;
    while(pp->getLeft()!=NULL)
       pp=pp->getLeft();
    return pp;
}
 
BinaryTreeNode *BSTree::tree_maximum(BinaryTreeNode *p)
{
    if(p==NULL)
    return NULL;
    BinaryTreeNode *pp=p;
    while(pp->getRight()!=NULL)
       pp=pp->getRight();
    return pp;
}
 
//返回已知節點的後續節點
//如果這個節點有右子數,則返回右子樹的最小節點
//否則向父節點尋找,找到第一個向右轉的父節點爲止
BinaryTreeNode *BSTree::tree_successor(BinaryTreeNode *p)
{
    if(p==NULL) return NULL;
       BinaryTreeNode *pp=p;
    if(pp->getRight()!=NULL)
       return tree_minimum(pp->getRight());
    BinaryTreeNode *y=p->getParent();
    while(y!=NULL && pp==y->getRight())
    {
       pp=y;
       y=y->getParent();
    }
    return y;
}
 
BinaryTreeNode *BSTree::getRoot()
{
    return root;
}
//左旋轉,這裏需要特別注意根節點的變化
void BSTree::leftRote(BinaryTreeNode *p)
{
    BinaryTreeNode *parent=p->getParent();
    if(parent==root)
    {
        root=p;
        p->setParent(NULL);
    }
    else
    {
        p->setParent(parent->getParent());
        if(parent->getParent()->getLeft()==parent)
            parent->getParent()->setLeft(p);
        else
            parent->getParent()->setRight(p);
    }
    parent->setRight(p->getLeft());
    if(p->getLeft()!=NULL)
        p->getLeft()->setParent(parent);
    p->setLeft(parent);
    parent->setParent(p);
}
//右旋轉
void BSTree::rightRote(BinaryTreeNode *p)
{   
    BinaryTreeNode *parent=p->getParent();
    if(parent==root)
    {
    root=p;
    p->setParent(NULL);
    }
    else
    {
        p->setParent(parent->getParent());
        if(parent->getParent()->getLeft()==parent)
        parent->getParent()->setLeft(p);
        else
        parent->getParent()->setRight(p);
    }
    parent->setLeft(p->getRight());
    if(p->getRight()!=NULL)
        p->getRight()->setParent(parent);
    p->setRight(parent);
    parent->setParent(p);
}

下面用一個例子來測試AVL樹的平衡性

隨機的反覆插入和刪除樹中的節點,如代碼所示:

#include <iostream>
#include "AVL.h"
#include "IntClass.h"
#include <time.h>
#include <stdlib.h> 
#include "StringClass.h"
using namespace std;
int main()
{
BSTree bstree;
BSTree bstreeStr;
 
int max=50;
srand(unsigned(time(0)));
 
for(int j=0;j<50;j++)
{
    int number=rand()%7;
    for(int i=number;i>0;i--)
    {
        int a=rand()%max;
        bstree.insert(new IntClass(a),new StringClass("Tao",3));
    }
    for(int i=number;i>0;i--)
    {
        int a=rand()%max;
        bstree.remove(new IntClass(a));
    }
}
bstree.outPut();
cout<<"------------------------------------------------"<<endl;
bstreeStr.insert(new StringClass("Jim",3),new StringClass("Hello, I'm a student",20));
bstreeStr.insert(new StringClass("Lucy",4),new StringClass("Hello, I'm a teacher",20));
bstreeStr.insert(new StringClass("Brown",5),new StringClass("Hello, I'm a doctor",19));
bstreeStr.insert(new StringClass("Lily",4),new StringClass("Hello, I'm a actor",18));
bstreeStr.insert(new StringClass("Tao",3),new StringClass("Hello, I'm a student",20));
bstreeStr.insert(new StringClass("Peter",5),new StringClass("Hello, I'm a teacher",20));
bstreeStr.insert(new StringClass("John",4),new StringClass("Hello, I'm a doctor",19));
bstreeStr.insert(new StringClass("Tony",4),new StringClass("Hello, I'm a actor",18));
bstreeStr.insert(new StringClass("Linda",5),new StringClass("Hello, I'm a student",20));
bstreeStr.insert(new StringClass("Jurcy",5),new StringClass("Hello, I'm a teacher",20));
bstreeStr.insert(new StringClass("Chern",5),new StringClass("Hello, I'm a doctor",19));
bstreeStr.outPut();
cout<<"-------------------------------------------------"<<endl;
return 0;
}

結果如下圖,可見AVL樹的平衡性很好,幾乎達到完全二叉樹的效果

AVL


發佈了20 篇原創文章 · 獲贊 5 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章