AVL树是一种高度平衡树,对于每一个节点,其左子树的高度与右子树的高度相差之多为1。
AVL树是比红黑树更加平衡的树(红黑树中左右子树高度之比小于2)。
AVL树除了平衡性较好外,与普通的二叉查找树没什么大的区别。所以AVL树的代码实现可以基于前面的二叉树实现代码算法导论第十二章——二叉查找树的C++代码实现来实现。实现AVL树的关键在于维持树的平衡性。所以每插入一个节点或删除都有可能要对树进行翻转,以满足平衡性。翻转使用的方法是红黑树中提到的左旋和右旋。根据出现的不同情况对树进行旋转。
虽然思路很清晰,但是实现起来比较麻烦。需要如下步骤:
1、在进行插入节点或删除节点之后,首先要找到树中最大高度节点和最小高度节点:Lnode,Snode
2、然后找到Lnode和Snode的最近共同祖先。
3、根据最近共同祖先和两个节点的位置我们可以分为四种情况进行旋转处理。
情况一:Lnode在ans的右孩子的左侧,则右孩子(12)右旋,ans(6)左旋。
情况2:Lnode在ans右孩子的右侧则ans左旋。
情况三:,Lnode为ans左孩子左侧,ans左孩子(6)右旋,祖先右旋
纠错:节点4应该有一个右孩子
情况四:ans右旋
纠错:12节点应该有一个左孩子。
具体实现代码如下:
BinTreeNode.h
#include<iostream>
using namespace std;
class BinTree;
class BinTreeNode
{
private:
friend BinTree;
int key;
//添加节点高度记录
int height;
BinTreeNode* left;
BinTreeNode* right;
BinTreeNode* parent;
public:
BinTreeNode():key(-1),height(0),left(NULL),right(NULL),parent(NULL){}
BinTreeNode(BinTreeNode* node):key(node->key),height(node->height),left(node->left),right(node->right),parent(node->parent)
{}
BinTreeNode(int num):left(NULL),right(NULL),key(num){}
~BinTreeNode()
{}
int Getkey()
{
return key;
}
BinTreeNode* GetLeft()
{
return this->left;
}
BinTreeNode* Getright()
{
return this->right;
}
void Inorder()
{
if(this!=NULL)
{
this->left->Inorder();
cout<<this->key<<" ";
this->right->Inorder();
}
}
void Preorder()
{
if(this!=NULL)
{
cout<<this->key<<" ";
this->left->Preorder();
this->right->Preorder();
}
}
void Postorder()
{
if(this!=NULL)
{
this->left->Postorder();
this->right->Postorder();
cout<<this->key<<" ";
}
}
void MakeEmpty()
{
if(this!=NULL)
{
this->left->MakeEmpty();
this->right->MakeEmpty();
delete this;
}
}
int GetHeight()
{
int L,R;
if(this==NULL)
{
return 0;
}
L=this->left->GetHeight();
R=this->right->GetHeight();
return 1+(L>R? L:R);
}
};
BinTree.h
#include"BinTreeNode.h"
#include<string>
#include<bitset>
#include<queue>
class BinTree
{
private:
BinTreeNode* root;
//记录具有最大高度的节点
BinTreeNode* Lnode;
//记录具有最小高度的节点
BinTreeNode* Snode;
public:
BinTree():root(NULL),Lnode(NULL),Snode(NULL){}
// BinTree(BinTreeNode* node):root(node){}
~BinTree()
{
MakeEmpty();
Lnode=NULL;
Snode=NULL;
}
void MakeEmpty()
{
BinTreeNode *p=root;
p->MakeEmpty();
}
int Getkey(BinTreeNode* node)
{
return node->Getkey();
}
BinTreeNode* Getroot()
{
return root;
}
int GetHeight(BinTreeNode*node)
{
return node->height;
}
void Inorder()
{
return root->Inorder();
}
void Preorder()
{
return root->Preorder();
}
void Posetorder()
{
return root->Postorder();
}
//调整树的高度,使树的各个分支高度之差小于2.
void AdjustHeight()
{
//如果两个节点高度之差小于2则不需要调整
if(Lnode->height-Snode->height<2)
{
return ;
}
int num;
BinTreeNode*ans=FindNearestAnc(Lnode,Snode,num);
//如果Lnode和Snode在最近共同祖先ans的同一侧即num==0则说明该树根节点只有左孩子或只有右孩子
//
if(num==0)
{
//如果只有左孩子,则以左孩子为节点右旋
if(ans->left!=NULL)
{
RightRotate(ans);
}
else
LeftRotate(ans);
//在经过旋转之后,各个节点的高度可能打乱,需要进行调整
InitNodeHeight(root,1);
return;
}
//Lnode在祖先的右侧
else if(num==2)
{
//如果Lnode在祖先右孩子的左侧
if(SearchFromNode(Lnode->key,ans->right->left)!=NULL)
{
//右孩子右旋
RightRotate(ans->right);
//祖先左旋
LeftRotate(ans);
}
//如果Lnode在祖先右孩子的右侧
else
{
//祖先左旋
LeftRotate(ans);
}
//在经过旋转之后,各个节点的高度可能打乱,需要进行调整
InitNodeHeight(root,1);
return;
}
//Lnode在祖先的左侧
else
{
//如果Lnode在祖先左孩子的zuo侧
if(SearchFromNode(Lnode->key,ans->left->left)!=NULL)
{
//祖先左旋
RightRotate(ans);
}
//如果node1在祖先左孩子的you侧
else
{
//左孩子左旋
LeftRotate(ans->left);
//祖先右旋
RightRotate(ans);
}
//在经过旋转之后,各个节点的高度可能打乱,需要进行调整
InitNodeHeight(root,1);
return;
}
}
//非递归版本
void Insert(int num)
{
BinTreeNode* node=new BinTreeNode(num);
BinTreeNode* p=root,*q;
if(root==NULL)
{
root=node;
root->parent=NULL;
root->height=1;
//最大高度节点和最小高度节点都是root
Lnode=Snode=root;
return ;
}
while(p)
{
if(p->key==num)
{
cout<<num<<" has exist!"<<endl;
return ;
}
else if(p->key>num)
{
q=p;
p=p->left;
}
else
{
q=p;
p=p->right;
}
}
if(q->key>num)
{
q->left=node;
node->parent=q;
node->height=q->height+1;
}
else
{
q->right=node;
node->parent=q;
node->height=q->height+1;
}
//最大高度节点的查找
/* if(Lnode->height<node->height)
{
Lnode=node;
}*/
//最小高度节点查找
//找最大高度节点和最小高度节点
FindMinHeightNode();
FindMaxHeightNode(root);
//调整shu的高度
AdjustHeight();
}
//递归版本,以下两个函数共同构成了递归插入功能
void ReInsert(BinTreeNode* node,BinTreeNode* start)
{
BinTreeNode* p=start;
if(p->key==node->key)
{
cout<<"the "<<node->key<<"has exist!"<<endl;
return ;
}
else if(p->key>node->key)
{
if(p->left==NULL)
{
p->left=node;
node->parent=p;
return ;
}
ReInsert(node,p->left);
}
else
{
if(p->right==NULL)
{
p->right=node;
node->parent=p;
return ;
}
ReInsert(node,p->right);
}
}
void RecInsert(int num)
{
BinTreeNode* node=new BinTreeNode(num);
if(root==NULL)
{
root=node;
root->parent=NULL;
return ;
}
ReInsert(node,root);
}
//调整以node为根节点的树的各个节点的高度
void InitNodeHeight(BinTreeNode*node,int num)
{
BinTreeNode*p=node;
if(p!=NULL)
{
p->height=num;
InitNodeHeight(p->left,num+1);
InitNodeHeight(p->right,num+1);
}
}
//寻找最近共同祖先,利用两个队列,将node1的直系祖先放入qu1,将node2的直系祖先放入qu2
//然后从两个队首寻找相同的最小节点,该节点就是node1和node2的最近共同祖先
//num为0时代表两个节点不是按照最近共同祖先一左一右分布,num为1时代表node1在左边,node2在右边
//num为2时代表node1在右边,node2在左边,该num在进行树的高度调整的时候用到。
BinTreeNode*FindNearestAnc(BinTreeNode*node1,BinTreeNode*node2,int &num)
{
if(node1==node2)
{
num=0;
return node1;
}
queue<BinTreeNode*>qu1;
queue<BinTreeNode*>qu2;
BinTreeNode*p=root,*nod=root;
//两个while循环将node1和node2的直系祖先及其本节点分别放到qu1和qu2
while(p)
{
qu1.push(p);
if(p->key==node1->key)
{
break;
}
else if(p->key>node1->key)
{
p=p->left;
}
else
{
p=p->right;
}
}
p=root;
while(p)
{
qu2.push(p);
if(p->key==node2->key)
{
break;
}
else if(p->key>node2->key)
{
p=p->left;
}
else
{
p=p->right;
}
}
//寻找qu1和qu2中相同的最小的节点
while(!qu1.empty()&&(!qu2.empty()))
{
if(qu1.front()->key==qu2.front()->key)
{
nod=qu1.front();
qu1.pop();
qu2.pop();
}
else
{
break;
}
}
if(nod==node1||nod==node2)
{
num=0;
}
else
{
if(SearchFromNode(node1->key,nod->left)==NULL)
{
num=2;
}
else
num=1;
}
return nod;
}
//从树的根节点开始搜索
BinTreeNode* Search(int num)
{
BinTreeNode* p=root;
while(p)
{
if(p->key==num)
{
return p;
}
else if(p->key>num)
{
p=p->left;
}
else
{
p=p->right;
}
}
cout<<"there is no "<<num<<" in this tree!"<<endl;
return NULL;
}
//从树的node节点开始搜索
BinTreeNode* SearchFromNode(int num,BinTreeNode*node)
{
BinTreeNode* p=node;
while(p)
{
if(p->key==num)
{
return p;
}
else if(p->key>num)
{
p=p->left;
}
else
{
p=p->right;
}
}
return NULL;
}
//获取以node节点为根节点的树的最小元素,并返回该最小值
int Minnum(BinTreeNode*node)
{
BinTreeNode*p=node;
while(p->left!=NULL)
{
p=p->left;
}
return p->key;
}
//获取以node节点为根节点的树的最da元素,并返回该最da值
int Maxnum(BinTreeNode*node)
{
BinTreeNode*p=node;
while(p->right!=NULL)
{
p=p->right;
}
return p->key;
}
//获取以node节点为根节点的树的最小元素,并返回该节点
BinTreeNode* MinNum(BinTreeNode*node)
{
BinTreeNode*p=node;
while(p->left!=NULL)
{
p=p->left;
}
return p;
}
//获取以node节点为根节点的树的最大元素
BinTreeNode* MaxNum(BinTreeNode*node)
{
BinTreeNode*p=node;
while(p->right!=NULL)
{
p=p->right;
}
return p;
}
//获取Node节点的父母节点,如果是根节点返回NULL
BinTreeNode* GetParent(BinTreeNode*node)
{
return node->parent;
/*
if(node==root)
{
return NULL;
}
BinTreeNode*p=root,*q=p;
while(p)
{
if(p->key==node->key)
{
return q;
}
else if(p->key>node->key)
{
q=p;
p=p->left;
}
else
{
q=p;
p=p->right;
}
}
*/
}
//中序遍历的后续
BinTreeNode*InorderSuccessor(BinTreeNode*node)
{
if(node->right!=NULL)
{
return MinNum(node->right);
}
else
{
BinTreeNode*p=GetParent(node);
while(p&&node==p->right)
{
node=p;
p=GetParent(node);
}
return p;
}
}
//中序遍历的前趋
BinTreeNode*InordePredecessor(BinTreeNode*node)
{
if(node->left!=NULL)
{
return MaxNum(node->left);
}
else
{
BinTreeNode*p=GetParent(node);
while(p&&node==p->left)
{
node=p;
p=GetParent(node);
}
return p;
}
}
bool Delete(int num)
{
BinTreeNode*p,*q,*t;
//寻找key值为num的节点p
p=Search(num);
if(p==NULL)
{
return 0;
}
//如果p节点没有孩子节点,则直接去掉
if(p->left==NULL&&p->right==NULL)
{
q=GetParent(p);
if(p==root)
{
delete p;
return 1;
}
if(p==q->left)
{
q->left=NULL;
}
else
{
q->right=NULL;
}
//找最大高度节点和最小高度节点
delete p;
FindMinHeightNode();
FindMaxHeightNode(root);
//调整shu的高度
AdjustHeight();
return 1;
}
//如果只有右节点,则将右节点作为p的父母的孩子
else if(p->left==NULL)
{
q=GetParent(p);
if(p==root)
{
root=p->right;
p->right->parent=NULL;
InitNodeHeight(p->right,1);
delete p;
//找最大高度节点和最小高度节点
FindMinHeightNode();
FindMaxHeightNode(root);
//调整shu的高度
AdjustHeight();
return 1;
}
if(p==q->left)
{
q->left=p->right;
p->right->parent=q;
}
else
{
q->right=p->right;
p->right->parent=q;
}
//在删除某一节点前将该节点的孩子节点进行高度值的调整
InitNodeHeight(p->right,q->height+1);
delete p;
//找最大高度节点和最小高度节点
FindMinHeightNode();
FindMaxHeightNode(root);
//调整shu的高度
AdjustHeight();
return 1;
}
//如果只有左节点,则将左节点作为p的父母的孩子
else if(p->right==NULL)
{
q=GetParent(p);
if(p==root)
{
root=p->left;
p->left->parent=NULL;
InitNodeHeight(p->left,1);
delete p;
//找最大高度节点和最小高度节点
FindMinHeightNode();
FindMaxHeightNode(root);
//调整shu的高度
AdjustHeight();
return 1;
}
if(p==q->left)
{
q->left=p->left;
p->left->parent=q;
}
else
{
q->right=p->left;
p->left->parent=q;
}
//在删除某一节点前将该节点的孩子节点进行高度的调整
InitNodeHeight(p->left,q->height+1);
delete p;
//找最大高度节点和最小高度节点
FindMinHeightNode();
FindMaxHeightNode(root);
//调整shu的高度
AdjustHeight();
return 1;
}
//如果左右节点都具有,则找到p的后继,用p的后继来取代p
else
{
//找到p的后继,
q=InorderSuccessor(p);
//获取q的父母
t=GetParent(q);
//q的父母左孩子指向q的右孩子,这样q就删除了。
//因为q为p的后继所以最多有一个右孩子,而且q肯定为父母的左孩子,如果为父母的右孩子
//那么q就不可能成为p的后继
t->left=q->right;
if(q->right!=NULL)
q->right->parent=t;
//获取p的父母,使p的父母指向q,且q的左右孩子分别为p的左右孩子
t=GetParent(p);
if(p==root)
{
root=q;
q->parent=NULL;
}
else
{
if(t->left==p)
{
t->left=q;
q->parent=t;
}
else
{
t->right=q;
q->parent=t;
}
}
q->left=p->left;
p->left->parent=q;
q->right=p->right;
p->right->parent=q;
//在删除某一节点前将该节点的孩子节点进行高度的调整
InitNodeHeight(root,1);
delete p;
//找最大高度节点和最小高度节点
FindMinHeightNode();
FindMaxHeightNode(root);
//调整shu的高度
AdjustHeight();
return 1;
}
}
//左旋节点node
bool LeftRotate(BinTreeNode* node)
{
BinTreeNode*y;
if(node->right==NULL)
{
cout<<"can't left rotate!"<<endl;
return 0;
}
y=node->right;
node->right=y->left;
if(y->left!=NULL)
{
y->left->parent=node;
}
y->parent=node->parent;
if(node->parent==NULL)
{
root=y;
}
else if(node->parent->left==node)
{
node->parent->left=y;
}
else
{
node->parent->right=y;
}
y->left=node;
node->parent=y;
return 1;
}
//右旋节点
bool RightRotate(BinTreeNode* node)
{
if(node->left==NULL)
{
cout<<"can't rightrotate!"<<endl;
return 0;
}
BinTreeNode* x;
x=node->left;
node->left=x->right;
if(x->right!=NULL)
{
x->right->parent=node;
}
x->parent=node->parent;
if(node->parent==NULL)
{
root=x;
}
else if(node->parent->left==node)
{
node->parent->left=x;
}
else
{
node->parent->right=x;
}
node->parent=x;
x->right=node;
return 1;
}
//寻找叶子节点中具有最大高度节点和最小高度节点,最大高度节点可以在插入中简单的完成
void FindMinHeightNode()
{
if(root->left==NULL||root->right==NULL)
{
Snode=root;
return ;
}
//进行中序遍历查找
FindMinHeightNodeInNonRoot(root);
}
void FindMinHeightNodeInNonRoot(BinTreeNode* node)
{
if(node!=NULL)
{
FindMinHeightNodeInNonRoot(node->left);
if(node->left==NULL&&node->right==NULL)
{
if(Snode->left!=NULL||Snode->right!=NULL)
{
Snode=node;
}
else if(Snode->height>node->height)
{
Snode=node;
}
}
FindMinHeightNodeInNonRoot(node->right);
}
}
void FindMaxHeightNode(BinTreeNode* node)
{
if(node!=NULL)
{
FindMaxHeightNode(node->left);
if(node->left==NULL&&node->right==NULL)
{
if(Lnode->height<node->height)
Lnode=node;
}
FindMaxHeightNode(node->right);
}
}
};
test.cpp
#include"BinTree.h"
int main()
{
int a[12]={15,5,3,12,10,13,6,7,16,20,18,23};
int b[10]={15,14,13,10,9,8,7,6,5,4};
int i,num;
BinTree tree;
BinTree Avl;
for(i=0;i<12;i++)
{
tree.Insert(a[i]);
}
// Avl.Inorder();
tree.Inorder();
cout<<endl;
tree.Delete(16);
tree.Inorder();
cout<<endl;
tree.Delete(15);
tree.Inorder();
cout<<endl;
tree.Preorder();
cout<<endl;
tree.Posetorder();
cout<<endl;
cout<<"the heigth of the tree is :"<<tree.GetHeight(tree.Getroot())<<endl;
tree.Insert(13);
tree.Insert(100);
tree.Inorder();
cout<<endl;
tree.Search(45);
cout<<"the node "<<3<<" height is : "<<tree.GetHeight(tree.Search(3))<<endl;
if(tree.Delete(5))
{
cout<<"delete "<<5<<" successful!"<<endl;
}
cout<<"the node "<<3<<" height is : "<<tree.GetHeight(tree.Search(3))<<endl;
tree.Inorder();
cout<<endl;
cout<<"the min num of the tree is :"<<tree.Minnum(tree.Getroot())<<endl;
cout<<"the max num of the tree is :"<<tree.Maxnum(tree.Getroot())<<endl;
cout<<"the successor of element 7 is :"<<tree.InorderSuccessor(tree.Search(7))->Getkey()<<endl;
cout<<"the Predecessor of element 7 is :"<<tree.InordePredecessor(tree.Search(7))->Getkey()<<endl;
cout<<"the successor of element 13 is :"<<tree.InorderSuccessor(tree.Search(13))->Getkey()<<endl;
cout<<"the commen ans of "<<3<<" and "<<6<<" is: "<<tree.FindNearestAnc(tree.Search(3),tree.Search(6),num)->Getkey()<<endl;
cout<<num<<endl;
cout<<"the commen ans of "<<7<<" and "<<13<<" is: "<<tree.FindNearestAnc(tree.Search(7),tree.Search(13),num)->Getkey()<<endl;
cout<<num<<endl;
return 0;
}