AVL树[非常详细有用]
来源:互联网 发布:银行卡被网络盗刷 编辑:程序博客网 时间:2024/05/22 04:32
定义:一棵空二叉树是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情况类似,旋转后只需再次改变两个节点的平衡因子
如下图为RL的情况,LR类似,旋转后需要再次改变三个节点的平衡因子
至此,插入操作已经完成,可见最多多做两次旋转操作调整树的结构使之平衡。
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,则进行一次左旋转,如图:
由于子树的高度和删除前一样,因此树已经平衡。
如果A的右节点的平衡因子是-1,则称为L-1不平衡,也要进行一次做旋转。
树的高度减少1,这使得上面的祖先节点可能不平衡,一次还要沿着路径在向上
寻找新的不平衡点,再次更新平衡因子,调整等。
如果A的右节点的平衡因子是1,则称为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树[非常详细有用]
- 非常详细的虚拟语气讲解,四六级绝对有用
- IOS非常详细和有用的动画讲解
- AVL的详细讲解
- 非常有用的方法
- 非常有用的链接
- 非常有用的实用程序
- 非常有用的网站
- Eclipse 非常有用命令
- 非常有用的社区
- 非常有用的站点
- 非常有用的效果
- 非常有用的文档
- 非常有用专业网站
- AVL树的旋转操作 图解 最详细
- AVL树的旋转操作 图解 最详细
- AVL树的旋转操作 图解 最详细
- AVL树的旋转操作 图解 最详细
- 快速矩阵幂
- java第十三天_集合,List集合
- windows下信号量的使用
- 黑马程序员_I/O流(递归、配置文件、流的合并拆分)
- 蓝桥杯(填火柴)
- AVL树[非常详细有用]
- KL25的启动顺序
- page request session application 作用域
- 新手必知20点VC技巧【转】
- JS部分
- 智联招聘简历刷新器
- python中必须使用global声明全局变量的情况
- 51Job简历刷新器
- 判断一个单链表是否有环