AVL树的C++实现

第一棵平衡二叉查找树又被称为AVL树,以它的发现者Adelson-Velskii和Landis命名的。

它广泛说明了平衡二叉查找树中使用的各种思想。就是具有附加平衡条件的二叉查找树。

任一平衡条件必须是易于维护,并确保树的深度是O(logN)。最简单的思想是要求左子树和

右子树具有同样的高度。但是这个要求太严格了,维持平衡的同时插入数据项太困难。

而AVL树在这方面找到了一个良好的折中点。

AVL树具有以下性质

1、它是一棵空树或它的左右两个子树的高度差的绝对值不超过1

2、左右两个子树都是一棵平衡二叉树

这里用C++实现了平衡二叉树的插入和删除操作,对于查询没有给出具体的实现,查询的实现应该不难,感兴趣的读者可以自行实现

内容都在代码里

#include<iostream>

using std::ostream;

class AVLTreeNode

{

private:

int value;

AVLTreeNode* lchild;

AVLTreeNode* rchild;

AVLTreeNode* parent;

friend class AVLTree;

friend ostream& operator<<(ostream& os,const AVLTree&);

public:

AVLTreeNode();

~AVLTreeNode();

};

class AVLTree

{

private:

AVLTreeNode* root;

public:

AVLTree();

~AVLTree();

void insert(int data);

void insert(int datas[],int num);

void remove(int);

void remove(int[],int);

AVLTreeNode* getRoot();

private:

void rightRotate(AVLTreeNode*);  //右旋

void leftRotate(AVLTreeNode*); //左旋

/*测试所用*/

bool check_tree(AVLTreeNode*);

int getHeight(AVLTreeNode*);

/*插入之后对树进行调整*/

void insertUpdate(AVLTreeNode*,int);

/*删除之后对树进行调整*/

void removeUpdate(AVLTreeNode*,int);

friend ostream& operator<<(ostream& os,const AVLTree&);

};

ostream& operator<<(ostream& os,const AVLTree&);

下面是.cpp文件内容部分。测试数据的显示量有点大,根据需要可进行调整。在插入数据和删除数组的方法中有测试打印语句部分,可根据需要进行修改

#include”averge_tree.h”
#include<vector>
using std::vector;
using std::endl;
using std::cout;
/*
AVLTreeNode类的函数实现
*/
AVLTreeNode::AVLTreeNode()
{
lchild=rchild=parent=NULL;
}
/*析构时采取级联的方式*/
AVLTreeNode::~AVLTreeNode()
{
delete lchild;
delete rchild;
}
/*AVLTree类的函数实现*/
AVLTree::AVLTree()
{
root=NULL;
}
AVLTree::~AVLTree()
{
delete root;
}
AVLTreeNode* AVLTree::getRoot()
{
return root;
}
void AVLTree::insert(int datas[], int num)
{
for(int i=0;i<num;i++)
{
/*cout<<“………………………………………………………………”<<endl;
cout<<“before insert “<<datas[i]<<endl;
cout<<*this<<endl;
insert(datas[i]);
cout<<“after insert “<<datas[i]<<endl;
cout<<*this<<endl;
if(check_tree(root))
{
cout<<“check passed “<<endl;
}
else
{
cout<<“check failed “<<endl;
break;
}*/
insert(datas[i]);
}
}
/*
插入后,可能对从这个插入节点向上到根的这条路径中的某个节点平衡造成影响
因此,需要找出这个节点,并且对这个节点进行调整
*/
void AVLTree::insert(int data)
{
if(!root) //空树
{
root=new AVLTreeNode;
root->parent=NULL;
root->lchild=root->rchild=NULL;
root->value=data;
}
else
{
AVLTreeNode* p=root;//用p指向要被插入的节点
AVLTreeNode* temp=data>p->value?p->rchild:p->lchild;
while(temp)
{
p=temp;
temp=data>p->value?p->rchild:p->lchild; //若值相同,是放在左边
}
AVLTreeNode* newNode=new AVLTreeNode;
newNode->rchild=newNode->lchild=NULL;
newNode->parent=p;
newNode->value=data;
if(data>p->value)
p->rchild=newNode;
else
p->lchild=newNode;
/*
向上查找到第一个需要调整的节点
*/
p=p->parent;
int v;
if(p)
v=abs(getHeight(p->lchild)-getHeight(p->rchild));
while(p&&v<=1)
{
p=p->parent;
if(p)
v=abs(getHeight(p->lchild)-getHeight(p->rchild));
}
//如果发现有节点受影响,那么需要对这个找到的第一个节点做调整
if(p)
{
insertUpdate(p,data);
}

}
}
/*
node代表从插入点向上找到的第一个不平衡点
共有四种情况及调整方案
1、在node的左孩子的左子树插入
对node的左孩子进行右旋转
2、在node的左孩子的右子树插入
对node的左孩子的右孩子进行左旋转,然后对node的左孩子进行右旋转
3、在node的右孩子的左子树插入
对node的右孩子的左孩子进行右旋转,然后对node的右孩子进行左旋转
4、在node的右孩子的右子树插入
对node的右孩子进行左旋转
*/
void AVLTree::insertUpdate(AVLTreeNode* node,int data)
{
if(data>node->value) //插入在了node的右子树中
{
AVLTreeNode* rNode=node->rchild;
if(data>rNode->value)  //右子树的右边
{
leftRotate(node->rchild);
}
else//右子树的左边
{
rightRotate(node->rchild->lchild);
leftRotate(node->rchild);
}
}
else //插入左子树中
{
AVLTreeNode* lNode=node->lchild;
if(data>lNode->value) //左孩子的右子树
{
leftRotate(node->lchild->rchild);
rightRotate(node->lchild);
}
else  //左孩子的左子树
{
rightRotate(node->lchild);
}
}
}
/*删除数组元素*/
void AVLTree::remove(int datas[],int num)
{
for(int i=0;i<num;i++)
{
cout<<“before remove “<<datas[i]<<endl;
cout<<*this<<endl;
remove(datas[i]);
cout<<“after remove “<<datas[i]<<endl;
cout<<*this<<endl;
if(check_tree(root))
{
cout<<“check passed “<<endl;
}
else
{
cout<<“check failed “<<endl;
break;
}
}
}
/*
用C表示data所在的节点
删除元素的时候,是选择一个元素来代替这个要被删除的元素
将这个被选择的元素成为N,用P表示N的父节点
删除元素N,然后从P开始向上寻找是否有平衡遭到破坏的点。如果有就进行调整
查找N的时候有两种方式,一种是寻找C左子树中值最大的那个节点
一种是寻找C右子树中值最小的那个节点
这里优先选择第一种,如果这个节点没有左子树,那么就选择第二种
*/
void AVLTree::remove(int data)
{
AVLTreeNode* node=root; //node表示data所在的那个节点
while(node&&node->value!=data)
node=data>node->value?node->rchild:node->lchild;
if(!node)  //要删除的值不在树中,不做处理
return;
AVLTreeNode* p=NULL;
if(node->lchild) //左子树存在,就找左子树中的最大值
{
p=node->lchild;
while(p->rchild)
p=p->rchild;
cout<<“p->value=”<<p->value<<endl;
node->value=p->value;
if(p==p->parent->lchild) //node的左孩子没有右子树
p->parent->lchild=p->lchild;
else
p->parent->rchild=p->lchild;
if(p->lchild)
p->lchild->parent=p->parent;
p->lchild=NULL;
AVLTreeNode* updateNode=p->parent;
delete p;
removeUpdate(updateNode,node->value);
}
else if(node->rchild) //左子树不存在,但右子树存在。选择右子树中的最小值
{
p=node->rchild;
while(p->lchild)
p=p->lchild;
cout<<“p->value=”<<p->value<<endl;
node->value=p->value;
if(p==p->parent->rchild) //node的右孩子没有左子树
p->parent->rchild=p->rchild;
else
p->parent->lchild=p->rchild;
if(p->rchild)
p->rchild->parent=p->parent;
AVLTreeNode* updateNode=p->parent;
delete p;
removeUpdate(updateNode,node->value);
}
else //左右子树都不存在
{
if(node->parent) //这个点有父节点
{
AVLTreeNode* updateNode=node->parent;
if(node==updateNode->lchild)
{
updateNode->lchild=NULL;
delete node;
}
else
{
updateNode->rchild=NULL;
delete node;
}
removeUpdate(updateNode,data);
}
else //这个节点是根节点,且又没有左右子树
{
root=NULL;
delete node;
}
}
}
/*
检查当前的节点是否符合平衡规则
若符合,就向上递归
若不符合,就调整,然后向上递归
若data小于node所指节点的值,那说明
*/
void AVLTree::removeUpdate(AVLTreeNode* node,int data)
{
if(!node)
return;
if(abs(getHeight(node->lchild)-getHeight(node->rchild))<=1)
removeUpdate(node->parent,data);
else
{
AVLTreeNode* parent=node->parent;
if(data>node->value) //真正删除的节点在node的右子树中,对node的左孩子进行右旋转
rightRotate(node->lchild);
else //真正删除的节点在node的左子树中,对node的右孩子进行左旋转
leftRotate(node->rchild);
removeUpdate(parent,data);
}
}
/*
检查树是否符合平衡二叉树的规定
检查方面如下
1、父子指向的指针是否正确
2、父子之间节点的值是否正确
3、高度是否正确
*/
bool AVLTree::check_tree(AVLTreeNode* node)
{
bool result=true;
if(!node)
return result;
if(node->lchild)
{
result=result&&(node->lchild->value<=node->value);
result=result&&(node->lchild->parent==node);
}
if(node->rchild)
{
result=result&&(node->rchild->value>=node->value);
result=result&&(node->rchild->parent==node);
}
int l_height=getHeight(node->lchild);
int r_height=getHeight(node->rchild);
result=result&&(abs(l_height-r_height)<=1);
result=result&&check_tree(node->lchild);
result=result&&check_tree(node->rchild);
return result;

}
int AVLTree::getHeight(AVLTreeNode* node)
{
int height=0;
if(node)
{
int l_height=getHeight(node->lchild);
int r_height=getHeight(node->rchild);
int child_height=l_height>r_height?l_height:r_height;
height=child_height+1;
}
return height;
}
/*
左旋
左旋之后的效果便是使node的父节点成为node左孩子节点。
p的左孩子节点成为node的父节点的孩子节点
(需要左旋的节点肯定有父节点,可能会有祖父节点)
*/
void AVLTree::leftRotate(AVLTreeNode* node)
{
AVLTreeNode* cur_left=node->lchild;
AVLTreeNode* parent=node->parent;
AVLTreeNode* grand=parent->parent;
/*代表其父节点在祖父节点的方向 1代表左,2代表右*/
if(grand)
{
int i=grand->lchild==parent?1:2;
/*对grand来说,改变的是左孩子或右孩子*/
if(i==1)
grand->lchild=node;
else
grand->rchild=node;
}
else
root=node;
/*对noe来说改变的是它的左孩子,和父节点*/
node->lchild=parent;
node->parent=grand;
/*对parent来说,改变的是父节点,右孩子*/
parent->parent=node;
parent->rchild=cur_left;
/*对cur_left来说,改变的是它的父节点*/
if(cur_left)
cur_left->parent=parent;
}
void AVLTree::rightRotate(AVLTreeNode* node)
{
AVLTreeNode* cur_right=node->rchild;
AVLTreeNode* parent=node->parent;
AVLTreeNode* grand=parent->parent;
/*若grand为NULL,则说明parent是root*/
if(grand)
{
/*代表其父节点在祖父节点的方向 1代表左,2代表右*/
int i=0;
i=grand->lchild==parent?1:2;
/*grand改变左子树或者右子树*/
if(i==1)
grand->lchild=node;
else
grand->rchild=node;
}
else
root=node;
/*node节点改变右子树和父节点*/
node->rchild=parent;
node->parent=grand;
/*parent节点改变父节点和左子树*/
parent->parent=node;
parent->lchild=cur_right;
/*cur_right改变父节点*/
if(cur_right)
cur_right->parent=parent;
}
/*输出函数
按照树的层次结构各个节点输出
*/
ostream& operator<<(ostream& os,const AVLTree& tree)
{
if(!tree.root)
return os;
vector<AVLTreeNode*> outQueue;
outQueue.push_back(tree.root);
int level=0;
while(outQueue.size()>0)
{
vector<AVLTreeNode*> tempQueue=outQueue;
outQueue.clear();
os<<” [ levle = “<<level<<” ] { “;
for(int i=0;i<tempQueue.size();i++)
{
AVLTreeNode* node=tempQueue[i];
AVLTreeNode* parent=node->parent;
cout<<” [ “<<node->value;
if(parent)
{
cout<<” parent=”<<parent->value;
if(node==parent->lchild)
cout<<” left”;
else
cout<<” right”;
}
else
cout<<” root”;
if(node->lchild)
outQueue.push_back(node->lchild);
if(node->rchild)
outQueue.push_back(node->rchild);
cout<<” ] “;
}
cout<<” } “<<endl;
level++;
tempQueue.clear();
}
return os;
}
int main()
{
int test[]={2,43,56,2,34,72,19,30,82,123,41,23,74,18,20,97,56,355,123,874,567,12,34,17,63};
AVLTree tree;
tree.insert(test,sizeof(test)/sizeof(int));
//cout<<tree<<endl;
tree.remove(test,sizeof(test)/sizeof(int));
}

运行结果显示的数据量比较大,这里选取其中的部分展示出来

《AVL树的C++实现》

《AVL树的C++实现》

《AVL树的C++实现》

《AVL树的C++实现》

    原文作者:AVL树
    原文地址: https://blog.csdn.net/yanlinwang/article/details/8146694
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞