公众号:CppCoding
平衡二叉树
-
二叉查找树给我们带来了很多方便,但是由于其在有序序列插入时就会退化成单链表(时间复杂度退化成 O(n)),AVL-tree就克服了上述困难。AVL-tree是一个“加上了平衡条件的”二叉搜索树,平衡条件确保整棵树的深度为O(log n)。
-
AVL树是最先发明的自平衡二叉查找树。在AVL树中任何节点的两个子树的高度最大差别为一,所以它也被称为高度平衡树。查找、插入和删除在平均和最坏情况下都是 O(log n)。增加和删除可能需要通过一次或多次树旋转来重新平衡这个树。
-
节点的平衡因子是它的左子树的高度减去它的右子树的高度(有时相反)。带有平衡因子1、0或-1的节点被认为是平衡的。带有平衡因子-2或2的节点被认为是不平衡的,并需要重新平衡这个树。平衡因子可以直接存储在每个节点中,或从可能存储在节点中的子树高度计算出来。
AVL旋转
在理解AVL旋转之前,首先得知道以下几个概念:
- AVL 树节点的插入总是在叶子节点。
- AVL 树在插入节点之前总是满足平衡条件的。
- 插入新节点后有可能满足平衡条件也有可能不满足。
- 当不满足平衡条件后,我们就需要对新的树进行旋转。
单旋转
解释:
结点18的左子节点的深度是4,右子节点的深度是1,两个的相差为2,不满足平衡条件,即18结点是不平衡点,再其是LL情况,向右旋转,即可。
双旋转
如图,不平衡点仍是18,但是其情况变为LR,即要进行先左转,后右转
总结:
LL:不满足的点是左子节点的左子节点,要进行右转
RR:不满足的点是右子节点的右子节点,要进行左转
LR:不满足的情况是左子节点的右子节点,先进行左转,后进行右转
RL:不满足的情况是右子节点的左子节点,要先进行右转,再进行左转
AVL树的实现
结点类定义
#ifndef AVLNODE_H
#define AVLNODE_H
#include <iostream>
using namespace std;
template <class T> class AvlTree;// 声明AvlTree类
template <class T>
class AvlNode{
T data; //关键码
AvlNode* leftchild;
AvlNode* rightchild;
int balance; //平衡因子
public:
AvlNode():leftchild(NULL),rightchild(NULL),balance(0){}
AvlNode(const T& e,AvlNode<T> *lt=NULL,AvlNode<T> *rt=NULL):data(e),leftchild(lt),rightchild(rt),balance(0){}
int getBalance()const{
return balance;
}
AvlNode<T>* getLeftChild()const{
return leftchild;
}
AvlNode<T> * getRightChild()const{
return rightchild;
}
T getData() cosnt{
return data;
}
friend class AvlTree<T>;
};
#endif
AVL树类定义
template <class T>
class AvlTree{
AvlNode<T> *root;
bool Insert(AvlNode<T> *& rt,T x,bool &taller);
bool Remove(AvlNode<T> *& rt,T x,bool &sharter);
void RotateLeft(AvlNode<T> *&node); //左旋函数
void RotateRight(AvlNode<T> *&node); //右旋函数
void RightBalanceAfterInsert(AvlNode<T> * &sRoot,bool &taller);
void LeftBalanceAfterInsert(AvlNode<T> * &sRoot,bool &taller);
void RightBalanceAfterDelete(AvlNode<T> * &sRoot,bool &shorter);
void LeftBalanceAfterDelete(AvlNode<T> * &sRoot,bool &shorter);
public:
AvlTree():root(NULL){}
AvlNode<T> *getRoot() const{
return root;
}
bool Insert(T x){
bool taller=false;
return Insert(root,x,taller);
}
bool Remove(T x){
bool shorter=false;
return Remove(root,x,shorter);
}
//输出树形结构
void DisplayTree(AvlNode<T> *t,int player) const;
};
AVL树类中函数的具体实现
//左旋函数代码
template <typename T>
void AvlTree<T>::RotateLeft(AvlNode<T> *& node){
if(node == NULL) || (node->rightchild == NULL)) return ;
AvlNode<T> * tmpNode=new AvlNode<T> (node->data); //申请新的内存存储node数据
if(temNode == NULL) return;
tmpNode->leftchild=node->leftchild;//考虑的是node结点下的左子节点
node->leftchild=tmpNode;
tmpNode->rightchild=node->rightchild->leftchild;//考虑的是node结点右子节点的左子节点
AvlNode<T> *toDelete=node->rightchild;
node->data=toDelete->data;
node->rightchild=toDelete->rightchild;
delete toDelete;
}
//右旋函数代码
template<typename T>
void AvlTree<T>::RotateRight(AvlNode<T> *& node){
if((node==NULL)||(node->leftchild==NULL)) return;
AvlNode<T> *tmpNode=new AvlNode<T>(node->data);
tmpNode->rightchild=node->rightchild;
node->rightchild=tmpNode;
tmpNode->leftchild=node->leftchild->rightchild;
AvlNoed<T> *toDelete=node->leftchild;
node->data=toDelete->data;
node->rightchild=toDelete->rightchild;
delete toDelete;
}
//插入结点,rt的右高度增加,则调用函数进行平衡
template<typename T>
void AvlTree<T>::RightBalanceAfterInsert(AvlNode<T> *& sRoot,bool &taller){
if((sRoot==NULL)||(sRoot->rightchild==NULL)) return;
AvlNode<T> *rightsub=sRoot->rightchild,*leftsub;
switch(rightsub->balance){
case 1:
sRoot->balance=rightsub->balance=0;
RotateLeft(sRoot);
taller=false;
break;
case 0:
cout << "树已经平衡" << endl;
break;
case -1:
leftsub=rightsub->leftchild;
switch(leftsub->balance){
case 1:
sRoot->balance=-1;
rightsub->balance=0;
break;
case 0:
sRoot->balance=rightsub->balance=0;
break;
case -1:
sRoot->balance=0;
rightsub->balance=1;
break;
}
leftsub->balance=0;
RotateRight(rightsub);
RotateLeft(sRoot);
taller=false;
break;
}
}
//插入结点,rt的左高度增加,调用函数进行平衡
LeftBalanceAfterInsert函数与上面的函数类似,代码的更改只需要将上述的代码中left和right互换即可
//
template <typename T>
void AvlTree<T>::RightBalanceAfterDelete(AvlNode<T>*& sRoot,bool &shorter){
AvlNode<T>*rightsub=sRoot->rightchild,*leftsub;
switch(rightsub->balance){
case 1:
sRoot->balance=sRoot->balance=0;
RotateLeft(sRoot);
break;
case 0:
sRoot->balance=0;
rightsub->balance=-1;
RotateLeft(sRoot);
break;
case -1:
leftsub=rightsub->leftchild;
switch(leftsub->balance){
case -1:
sRoot->balance=0;
rightsub->balance=1;
break;
case 0:
sRoot->balance=rightsub->balance=0;
break;
case 1:
sRoot->balance=-1;
rightsub->balance=0;
break;
}
leftsub->balance=0;
RotateRight(rightsub);
RotateLeft(sRoot);
shorter=false;
break;
}
}
template<typename T>
bool AvlTree<T>::Insert(AvlNode<T> *& rt,T x,bool &taller){
bool success;
//递归函数的基本条件
if(rt==NULL){
rt=new AvlNode<T>(x);
success=rt!=NULL?true:false;
if(success) taller=true;
}
//如果x的值小于rt的关键码
else if(x<rt->data){
//insert的递归调用,从rt的左子树寻找合适的位置插入
success=Insert(rt->leftchild,x,taller);
if(taller){
switch(rt->balance){
case -1:
LeftBalanceAfterInsert(rt,taller);
break;
case 0:
rt->balance=-1;
break;
case 1:
rt->balance=0;
taller=false;
break;
}
}
}else if(x>rt->data){
success=Insert(rt->rightchild,x,taller);
if(taller){
switch(rt->balance){
case -1:
rt->balance=0;
taller=false;
break;
case 0:
rt->balance=1;
break;
case 1:
RightBalanceAfterInsert(rt,taller);
break;
}
}
}
return success;
}
//
template <typename T>
bool AvlTree<T>::Remove(AvlNode<T> *& rt,T x,bool &shorter){
bool success=false;
if(rt==NULL) return false;
//如果rt是要删除的结点
if(x==rt->data){
if(rt->leftchild!=NULL&&rt->rightchild!=NULL){
//寻找rt的中序遍历的前驱结点,用r表示
AvlNode<T> *r=rt->leftchild;
while(r->rightchild!=NULL){
r=r->rightchild;
}
//交换rt和r的值
T temp=rt->data;
rt->data=r->data;
r->data=temp;
//递归函数,从rt的左子树中删除关键码为x的结点
success=Remove(rt->leftchild,x,shorter);
if(shorter){
//如果删除后rt的左高度减少
switch(rt->balance){
case -1:
rt->balance=0;
break;
case 0:
rt->balance=1;
shorter=0;
break;
case 1:
RightBalanceAfterDelete(rt,shorter);
break;
}
}
}else{
//rt最多只有一个子女,这是递归的出口
AvlNode<T> *p=rt;
rt=rt->leftchild!=NULL?rt->leftchild:rt->rightchild;
delete p;
success=true;
shorter=true;
}
}else if(x<rt->data){
//递归调用,从rt的左子树中删除关键码为x的结点
success=Remove(rt->leftchild,x,shorter);
if(shorter){
//如果删除后rt的左高渡减少
switch(rt->balance){
case -1:
rt->balance=0;
break;
case 0:
rt->balance=1;
shorter=0;
break;
case 1:
RightBalanceAfterDelete(rt,shorter);
break;
}
}
}else if(x>rt->data){
//递归函数调用,从rt的右子树删除关键码为x的结点
success=Remove(rt->rightchild,x,shorter);
if(shorter){
//如果删除sRoot的右高度减少
switch(rt->balance){
case -1:
LeftBalanceAfterDelete(rt,shorter);
break;
case 0:
rt->balance=-1;
shorter=0;
break;
case 1:
rt->balance=0;
break;
}
}
}
return success;
}