平衡二叉树(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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值