一、AVL树简介
(1)AVL树又称为高度平衡的二叉搜索树,是1962年有俄罗斯的数学家G.M.Adel’son-Vel’skii和E.M.Landis提出来的。
它能保持二叉树的高度平衡,尽量降低二叉树的高度,减少树的平均搜索长度;
(2)AVL树是既满足二叉搜索树的性质,同时又满足平衡树的性质(左右子树的高度差不超过1)
(3)AVL树的性质:
1>左子树和右子树的高度之差的绝对值不超过1
2>树中的每个左子树和右子树都是AVL树
3>每个节点都有一个平衡因子(balance factor–bf),任一节点的平衡因子是-1,0,1。
(每个节点的平衡因子等于右子树的高度减去左子树的高度)
(4)AVL树的插入/删除/查找的时间复杂度:
一棵AVL树有N个节点,其高度可以保持在log2N,插入/删除/查找的时间复杂度也是O(log2N).
(ps:log2N是表示log以2为底N的对数)
二、AVL树的插入
在二叉搜索树中,插入一个元素,只需要找到该元素适合的位置,然后插入元素;但是AVL树是二叉树的升级;AVL树在插入一个元素时,不仅要找到元素的位置进行插入,而且还要在插入后,检查是否会影响树的高度;即会不会影响树的平衡性;如果不影响树的平衡性,则插入完毕;如果影响了树的平衡性则需要去调整结点,保持树的平衡性
下面一一分析:
(1)当插入一个结点之后,该节点的父节点的平衡因子bf变为0;说明该数此时依然是AVL树,不会对上层父节点产生影响,插入完毕,bf更新为0;
5 添加9 5
3 8 -------> 3 8
2 4 6 2 4 6 9
(2)【该情况是直接插入节点后出现的情况】当插入一个结点之后,该节点的的父节点的bf变为1或者-1;说明该父节点之前的bf为0;插入该节点之后,影响了父节点的的树的平衡性;则一定会对上层的父节点产生影响;
循环更新上层的父节点的bf,假入上层父节点的bf更新完之后,
只是-1或者1,那么一直循环向上更新,直到父节点为停止,插入完毕;
如果上层父节点bf变为2或者-2;则要进行旋转,从而调整树的高度的平衡,更新结点的bf;插入完毕【即就是下面的第三种情况】;
(3)【该情况一定是循环向上更新父节点出现的】如果插入一个结点之后,该节点的父节点的bf变为-2或者2,那么要进行旋转,调整树的高度;更新结点的bf;
(4)不可能出现插入节点之后,其父节点变为3或者-3,因为,在插入之前,该数是一颗正确的AVL树,每个结点的bf
只能是0,1,-1三种;
注:旋转是为了降低树的高度,使AVL树保持平衡;
旋转时必须遵循规则是,旋转之后,该数依然是平衡树和搜索树(即高度平衡的AVL树);
旋转是以最先bf变为2或者-2的结点为起点进行旋转;
旋转分为四大类
(1)右单旋:向右旋转,左边的高度大于右边的高度;father->bf=-2,subL->bf=-1;
//右旋------✔
void RotateR(Node* father)
{
Node* SubL=father->_left;
Node* SubLR=SubL->_right;
Node* PPNode=father->_father;
//1.链接subLR和father
father->_left=SubLR;
if (SubLR)
{
SubLR->_father=father;
}
//2.链接SubL和PPNode,分两种情况
//2.1 ppNode为空,直接将SubL变为_root,将SubL的father指向PPnode
if (PPNode==NULL)
{
_root=SubL;
SubL->_father=PPNode;
}
//2.PPnode不为空
else
{
if (PPNode->_left==father)
{
PPNode->_left=SubL;
}
else
{
PPNode->_right=SubL;
}
SubL->_father=PPNode;
}
//3.链接father和SubL
SubL->_right=father;
father->_father=SubL;
//4.更新旋转以后的父节点和SubL的bf,因为father的左子树变了,所以bf回变,SubL的右子树变了所以bf会变
father->_bf=0;
SubL->_bf=0;
}
(2)左单旋:向左旋转,右边的高度大于左边的高度;father->bf=2; subR=1;
//左旋------✔
void RotateL(Node* father)
{
Node* SubR=father->_right;
Node* SubRL=SubR->_left;
Node* PPNode=father->_father;
//1.链接SubRL和father
father->_right=SubRL;
if (SubRL)
{
SubRL->_father=father;
}
//2.链接PPNode和SubR,分两种情况
//2.1PPNode为空
if (PPNode==NULL)
{
_root=SubR;
SubR->_father=PPNode;
}
//2.2ppNode不为空
else
{
if (PPNode->_left==father)
{
PPNode->_left=SubR;
}
else
{
PPNode->_right=SubR;
}
SubR->_father=PPNode;
}
//3.链接father和SubR
SubR->_left=father;
father->_father=SubR;
//4.更新平衡 因子
father->_bf=0;
SubR->_bf=0;
}
(3)左右双旋:先左旋,后右旋;
//左右旋转------✔
void RotateLR(Node* father)
{
Node* SubL=father->_left;
Node* SubLR=SubL->_right;
int bf=SubLR->_bf;
//1.先以SubL左旋
RotateL(SubL);
//2.再以father右旋
RotateR(father);
//3.根据SubLR->_bf原始的bf更新旋转之后各个结点的bf
if (bf==1)
{
SubL->_bf=-1;
father->_bf=0;
}
else if (bf==-1)
{
father->_bf=1;
SubL->_bf=-1;
}
else
{
SubL->_bf=0;
father->_bf=0;
}
SubLR->_bf=0;
}
(4)右左双旋:先右旋,后左旋
//右左旋转------✔
void RotateRL(Node* father)
{
Node* SubR=father->_right;
Node* SubRL=SubR->_left;
int bf=SubRL->_bf;
//1.先以SubR右旋
RotateR(SubR);
//2.在以father左旋
RotateL(father);
//3.根据SubRL的原始bf更新旋转以后的各节点bf
if(bf==1)
{
father->_bf=-1;
SubR=0;
}
else if (bf==-1)
{
SubR->_bf=1;
father->_bf=0;
}
else
{
SubR->_bf=0;
father->_bf=0;
}
SubRL->_bf=0;
}
AVL树的插入代码:
bool Insert(const K& key,const V& value)//AVL树的插入
{
//1.AVL树为空,直接插入
if (_root==NULL)
{
_root=new Node(key,value);
return true;
}
//2.AVL树不为空
//2.1先找到要插入的位置
Node* cur=_root;//记录要插入节点的位置
Node* father=_root;//记录要插入节点的父节点
while (cur)
{
//key已经存在,不用插入,直接返回
if (cur->_key==key)
{
return false;
}
//key大于根结点
else if (cur->_key<key)
{
father=cur;
cur=cur->_right;
}
//key小于根结点
else
{
father=cur;
cur=cur->_left;
}
}
//2.2cur找到插入的正确的位置,开始插入
cur=new Node(key,value);
//2.2.1插入右边,father->bf加1
if (key>father->_key)
{
father->_right=cur;
cur->_father=father;
}
//2.2.2插入左边,bf减1
else
{
father->_left=cur;
cur->_father=father;
}
//2.3更新父节点平衡因子,并判断是否需要调整树高度,让AVL树保持平衡
while(father)
{
//2.3.1更新平衡因子
//1>插入左边 bf减1
if (father->_left==cur)
{
father->_bf-=1;
}
//2>插入右边 bf加1
if (father->_right==cur)
{
father->_bf+=1;
}
//2.3.2根据更新的平衡因子,判断是否需要调整树的高度
//1>插入一个结点之后,父节点的平衡因子更新为0;不影响树的高度,无需调整,插入完毕
if (father->_bf==0)
{
return true;
}
//2>(直接插入影响)父节点的平衡因子更新为1或者-1,影响树的高度,那么会对上层父节点的平衡因子产生影响;继续判断上层父节点的bf更新
else if (father->_bf==-1||father->_bf==1)
{
cur=father;
father=father->_father;
}
//3>(循环判断得到)当父节点的平衡因子更新为2或者-2,影响树的高度,这时AVL树的平衡被破坏,那么需要旋转调整降低树的高度
else if (father->_bf==-2||father->_bf==2)
{
//3.1>左旋
if(father->_bf==2&&cur->_bf==1)
{
RotateL(father);
return true;
}
//3.2>右旋
if(father->_bf==-2&&cur->_bf==-1)
{
RotateR(father);
return true;
}
//3.3>左右双旋
if (father->_bf==-2&&cur->_bf==1)
{
RotateLR(father);
return true;
}
//3.4>右左双旋
if (father->_bf==2&&cur->_bf==-1)
{
RotateRL(father);
return true;
}
}
//4>父节点的平衡因子出现其他情况都是错误的,说明插入之前,这颗树就不是AVL树;
else
{
cout<<"平衡因子异常"<<endl;
}
}
}
三、AVL树的删除
AVL树的删除比较复杂;具体过程是这样的:
首先先通过Key值找到相应的结点;
1.如果AVL树为空,不用找了,直接返回查找失败;
2.AVL树不为空,然后找到了相应的结点;那么有以下几个情况;
2.1如果要删除的结点是叶子节点,则直接删除,然后根据删除结点时父节点的左右那个子节点来更新父节点的bf;并将父节点相应的指针置为空;
2.2如果要删除的结点只有一个子树(或左或右),那么先判断这个子树是删除结点左还是右,然后在判断删除结点是父节点的左还是右,然后根据这些信息,将删除结点的左或者右子树挂到其父节点相应的指针上;然后删除要删除的结点;通过判断挂在父节点的左右那个子树来更新父节点的bf;
3.如果要删除的结点左右子树都有,那么首先,先要找到要删除结点的右子树上的最小结点,即就是右子树的最左结点;然后将要删除的节点和找到的右子树的最小结点交换值;最后将最小结点删除,删除最小结点的时候,又要判断最小结点是否是叶子节点,如果是叶子节点,则直接删除,然后根据最小结点时父节点的左右那个孩子,来更新父节点的bf;如果不是叶子节点,则说明最小结点右子树不为空,则将最小结点的右子树挂在父节点上,这时又要判断改最小结点是父节点的左右那个孩子,除了最小结点为要删除的右子树的根结点时,最小结点为父节点(此时的父节点就是要一开始要删除的结点)的右子树以外,其他情况最小结点都是父节点的左子树;从而来更新最小结点(此时就是通过交换之后要删除的结点)的父节点的bf;
4.最后通过判断父节点的bf从而来调整树的高度或者向上更新父节点bf判断是否需要调整树的高度;
删除的时候在调整树的高度时和插入时的判断不一样;
【插入时】,在判断是否调整树的高度的条件是:
当插入一个结点后father的bf变为0,那么这个树的高度没有改变,不用调整;
当插入一个结点后当father的bf变为-1或者1时,这个树的高度有可能增加,所以必须向上更新父节点的bf,在更新的时候,如果发现父节点的bf变为2或者-2,就要通过旋转调整树的高度;如果一直更新到整棵树的根结点都没有发现bf为2或者-2 的情况出现,那么就不用通过旋转调整树的高度;
【删除时】,在判断是否需要调整的条件是:
当删除一个结点后,该节点的父节点的bf变为0,这时树的整体高度可能改变了;那么就要向上更新父节点bf,当出现父节点的bf为2或者-2 时,就需要通过旋转调整树的高度;
当删除一个结点之后,该节点的父节点的bf变为1或者-1,这时这棵树的整体高度没有改变,不同向上判断父节点的bf,直接就删除完毕;
总体删除的思想时:找—>删—>更新父节点bf—–>通过父节点bf判断是否调整树的高度或者继续向上更新bf以后判断是否需要调整树的高度
AVL树的删除代码:
bool Remove(const K& key)//删除AVL树上某个结点值---树中的每个结点的key是唯一的
{
//1.如果树为空,删除失败
if (_root==NULL)
{
return false;
}
//2.如果树不为空
Node* cur=_root;
Node* father=NULL;//始终记录要删除结点的父节点
Node* del=NULL;//记录要删除的结点
//2.1循环寻找要删除的结点位置
while (cur)
{
//2.1.1key大于向右找
if (key>cur->_key)
{
father=cur;
cur=cur->_right;
}
//2.1.2key小于向左找
else if (key < cur->_key)
{
father=cur;
cur=cur->_left;
}
//2.1.3找到了
else
{
//1.要删除的结点是叶子节点
if (cur->_left==NULL&&cur->_right==NULL)
{
//1.1要删除的结点不是跟结点
//1.1.1要删除的结点时父节点的左孩子,则删除以后父节点的bf增加1
if (father&&father->_left==cur)
{
father->_left=NULL;
father->_bf++;
}
//1.1.2要删除的结点时父节点的右孩子,则删除以后父节点的bf减1
else if (father&&father->_right==cur)
{
father->_right=NULL;
father->_bf--;
}
//1.2要删除的结点是根结点father==NULL&&cur==_root
else
{
cur->_father=NULL;
}
del=cur;//del记录要删除的节点
}
//2.要删除的结点只有一个子树
else if (cur->_left==NULL||cur->_right==NULL)
{
//2.1要删除的结点只有左子树且不是根结点
if (father&&cur->_left)//father!=NULL&&cur->_left!=NULL&&cur->_right==NULL
{
//2.1.1要删除的结点时父节点的左子树
if (father->_left==cur)
{
father->_left=cur->_left;
father->_bf++;
}
//2.1.2要删除的结点是父节点的右子树
else //father->_right==cur
{
father->_right=cur->_left;
father->_bf--;
}
del=cur;//del记录要删除的节点
}
//2.2要删除的结点只有右子树且不是根结点
else if (father&&cur->_right)//father!=NULL&&cur->_left=NULL&&cur->_right!=NULL
{
//2.2.1要删除的结点是父节点的左孩子
if (father->_left==cur)
{
father->_left=cur->_right;
father->_bf++;
}
//2.2.2要删除的结点是父节点的右孩子
else//father->_right==cur
{
father->_right=cur->_right;
father->_bf--;
}
del=cur;//del记录要删除的节点
}
//2.3要删除的结点是根结点
else//father==NULL
{
//2.3.1要删除的结点是根结点,且根结点只有左子树
if(cur->_left)//father==NULL&&cur=_root&&cur->_left!=NULL&&cur->_right==NULL
{
_root=cur->_left;
_root->_bf=0;
}
//2.3.2要删除的结点是根结点且根结点只有右子树
else//father==NULL&&cur=_root&&cur->_left&&cur->_right!=NULL
{
_root=cur->_right;
_root->_bf=0;
}
del=cur;//del记录要删除的节点
}
}
//3.要删除的结点左右子树都有
else//cur->_left&&cur->_right
{
//3.1寻找要删除的结点的右子树的最小结点(即右子树的中序遍历的第一个结点)
Node* RightMin=cur->_right;//记录要删除节点的右子树的最小结点
father=cur;
while (RightMin->_left)
{
father=RightMin;
RightMin=RightMin->_left;
}
std::swap(cur->_key,RightMin->_key);
std::swap(cur->_value,RightMin->_value);
//3.1寻找的要删除的结点的右子树的最小结点不是右子树的根结点
if (father->_left=RightMin)
{
father->_left=RightMin->_right;
father->_bf++;
}
//3.2寻找的要删除的结点的右子树的最小结点是右子树的根结点
else//Father->_right=RightMin
{
father->_right=RightMin->_right;
father->_bf--;
}
del=RightMin;//del记录要删除的节点
}
//根据父节点的bf调整AVL使其保持平衡
while(father)
{
cur=del;
if (father->_left==cur)
{
father->_bf++;
}
if (father->_right==cur)
{
father->_bf--;
}
//【直接删除造成父节点bf变为0】如果删除某个结点之后,father的bf为0,说明以前father的bf为1或-1,那么当bf变为0,树的高度改变,可能会对上层造成影响
//高度改变
if (father->_bf==0)
{
cur=father;
father=father->_father;//向上更新
}
//如果删除某个结点以后father的结点bf变为1或者-1,树的高度没有改变,那么不会对上层树的平衡造成影响,删除完成
//高度没有改变
else if (father->_bf==-1||father->_bf==1)
{
break;
}
//【向上循环更新bf变为2或者-2】当更新以后father的bf变为2或者-2,则要进行旋转,调整树的高度,保持树的平衡
else if(father->_bf==2||father->_bf==-2)
{
//3.1>左旋
if(father->_bf==2&&cur->_bf==1)
{
RotateL(father);
return true;
}
//3.2>右旋
if(father->_bf==-2&&cur->_bf==-1)
{
RotateR(father);
return true;
}
//3.3>左右双旋
if (father->_bf==-2&&cur->_bf==1)
{
RotateLR(father);
return true;
}
//3.4>右左双旋
if (father->_bf==2&&cur->_bf==-1)
{
RotateRL(father);
return true;
}
}
//更新以后father的bf变为其他值,说明在更新之前该节点的bf就有问题
else
{
cout<<"平衡因子出错"<<endl;
}
}
delete del;
del=NULL;
return true;
}
}
//2.2没找到
return false;
}
四、完整代码:
测试用例AVL树的插入过程:
#include<iostream>
using namespace std;
template<class K,class V>
struct AVLTreeNode
{
AVLTreeNode<K,V>* _left;
AVLTreeNode<K,V>* _right;
AVLTreeNode<K,V>* _father;
K _key;
V _value;
int _bf;//平衡因子
AVLTreeNode(const K& key,const V& value)
:_left(NULL)
,_right(NULL)
,_father(NULL)
,_key(key)
,_value(value)
,_bf(0)//平衡因子取决于左右子树的高度差,一个新创结点没有左右子树,所以平衡一直是0
{}
};
template<class K,class V>
class AVLTree
{
typedef AVLTreeNode<K,V> Node;
public:
AVLTree()//构造函数
:_root(NULL)
{}
~AVLTree()//析构函数
{
_Destroy(_root);
}
void InOrder()//中序打印
{
_InOrder(_root);
}
int Depth()//求树的高度(或深度)
{
return _Depth(_root);
}
bool IsBalance()//判断是AVL树是否平衡(递归)---一般方法O(N^N)
{
return _IsBalance(_root);
}
//判断是AVL树是否平衡---优化方法
//如果我们每一次遍历,都会带回树的高度,这样就会少遍历一次,时间复杂度是0(N)
bool IsBalanceOP()
{
int hight=0;
return _IsBalanceOP(_root,hight);
}
Node* Find(const K& key);//与BST(二插搜索树的查找一样),参考上一讲二插搜索树的查找
bool Insert(const K& key,const V& value)//AVL树的插入
{
//1.AVL树为空,直接插入
if (_root==NULL)
{
_root=new Node(key,value);
return true;
}
//2.AVL树不为空
//2.1先找到要插入的位置
Node* cur=_root;//记录要插入节点的位置
Node* father=_root;//记录要插入节点的父节点
while (cur)
{
//key已经存在,不用插入,直接返回
if (cur->_key==key)
{
return false;
}
//key大于根结点
else if (cur->_key<key)
{
father=cur;
cur=cur->_right;
}
//key小于根结点
else
{
father=cur;
cur=cur->_left;
}
}
//2.2cur找到插入的正确的位置,开始插入
cur=new Node(key,value);
//2.2.1插入右边,father->bf加1
if (key>father->_key)
{
father->_right=cur;
cur->_father=father;
}
//2.2.2插入左边,bf减1
else
{
father->_left=cur;
cur->_father=father;
}
//2.3更新父节点平衡因子,并判断是否需要调整树高度,让AVL树保持平衡
while(father)
{
//2.3.1更新平衡因子
//1>插入左边 bf减1
if (father->_left==cur)
{
father->_bf-=1;
}
//2>插入右边 bf加1
if (father->_right==cur)
{
father->_bf+=1;
}
//2.3.2根据更新的平衡因子,判断是否需要调整树的高度
//1>插入一个结点之后,父节点的平衡因子更新为0;不影响树的高度,无需调整,插入完毕
if (father->_bf==0)
{
return true;
}
//2>(直接插入影响)父节点的平衡因子更新为1或者-1,影响树的高度,那么会对上层父节点的平衡因子产生影响;继续判断上层父节点的bf更新
else if (father->_bf==-1||father->_bf==1)
{
cur=father;
father=father->_father;
}
//3>(循环判断得到)当父节点的平衡因子更新为2或者-2,影响树的高度,这时AVL树的平衡被破坏,那么需要旋转调整降低树的高度
else if (father->_bf==-2||father->_bf==2)
{
//3.1>左旋
if(father->_bf==2&&cur->_bf==1)
{
RotateL(father);
return true;
}
//3.2>右旋
if(father->_bf==-2&&cur->_bf==-1)
{
RotateR(father);
return true;
}
//3.3>左右双旋
if (father->_bf==-2&&cur->_bf==1)
{
RotateLR(father);
return true;
}
//3.4>右左双旋
if (father->_bf==2&&cur->_bf==-1)
{
RotateRL(father);
return true;
}
}
//4>父节点的平衡因子出现其他情况都是错误的,说明插入之前,这颗树就不是AVL树;
else
{
cout<<"平衡因子异常"<<endl;
}
}
}
bool Remove(const K& key)//删除AVL树上某个结点值---树中的每个结点的key是唯一的
{
//1.如果树为空,删除失败
if (_root==NULL)
{
return false;
}
//2.如果树不为空
Node* cur=_root;
Node* father=NULL;//始终记录要删除结点的父节点
Node* del=NULL;//记录要删除的结点
//2.1循环寻找要删除的结点位置
while (cur)
{
//2.1.1key大于向右找
if (key>cur->_key)
{
father=cur;
cur=cur->_right;
}
//2.1.2key小于向左找
else if (key < cur->_key)
{
father=cur;
cur=cur->_left;
}
//2.1.3找到了
else
{
//1.要删除的结点是叶子节点
if (cur->_left==NULL&&cur->_right==NULL)
{
//1.1要删除的结点不是跟结点
//1.1.1要删除的结点时父节点的左孩子,则删除以后父节点的bf增加1
if (father&&father->_left==cur)
{
father->_left=NULL;
father->_bf++;
}
//1.1.2要删除的结点时父节点的右孩子,则删除以后父节点的bf减1
else if (father&&father->_right==cur)
{
father->_right=NULL;
father->_bf--;
}
//1.2要删除的结点是根结点father==NULL&&cur==_root
else
{
cur->_father=NULL;
}
del=cur;//del记录要删除的节点
}
//2.要删除的结点只有一个子树
else if (cur->_left==NULL||cur->_right==NULL)
{
//2.1要删除的结点只有左子树且不是根结点
if (father&&cur->_left)//father!=NULL&&cur->_left!=NULL&&cur->_right==NULL
{
//2.1.1要删除的结点时父节点的左子树
if (father->_left==cur)
{
father->_left=cur->_left;
father->_bf++;
}
//2.1.2要删除的结点是父节点的右子树
else //father->_right==cur
{
father->_right=cur->_left;
father->_bf--;
}
del=cur;//del记录要删除的节点
}
//2.2要删除的结点只有右子树且不是根结点
else if (father&&cur->_right)//father!=NULL&&cur->_left=NULL&&cur->_right!=NULL
{
//2.2.1要删除的结点是父节点的左孩子
if (father->_left==cur)
{
father->_left=cur->_right;
father->_bf++;
}
//2.2.2要删除的结点是父节点的右孩子
else//father->_right==cur
{
father->_right=cur->_right;
father->_bf--;
}
del=cur;//del记录要删除的节点
}
//2.3要删除的结点是根结点
else//father==NULL
{
//2.3.1要删除的结点是根结点,且根结点只有左子树
if(cur->_left)//father==NULL&&cur=_root&&cur->_left!=NULL&&cur->_right==NULL
{
_root=cur->_left;
_root->_bf=0;
}
//2.3.2要删除的结点是根结点且根结点只有右子树
else//father==NULL&&cur=_root&&cur->_left&&cur->_right!=NULL
{
_root=cur->_right;
_root->_bf=0;
}
del=cur;//del记录要删除的节点
}
}
//3.要删除的结点左右子树都有
else//cur->_left&&cur->_right
{
//3.1寻找要删除的结点的右子树的最小结点(即右子树的中序遍历的第一个结点)
Node* RightMin=cur->_right;//记录要删除节点的右子树的最小结点
father=cur;
while (RightMin->_left)
{
father=RightMin;
RightMin=RightMin->_left;
}
std::swap(cur->_key,RightMin->_key);
std::swap(cur->_value,RightMin->_value);
//3.1寻找的要删除的结点的右子树的最小结点不是右子树的根结点
if (father->_left=RightMin)
{
father->_left=RightMin->_right;
father->_bf++;
}
//3.2寻找的要删除的结点的右子树的最小结点是右子树的根结点
else//Father->_right=RightMin
{
father->_right=RightMin->_right;
father->_bf--;
}
del=RightMin;//del记录要删除的节点
}
//根据父节点的bf调整AVL使其保持平衡
while(father)
{
cur=del;
if (father->_left==cur)
{
father->_bf++;
}
if (father->_right==cur)
{
father->_bf--;
}
//【直接删除造成父节点bf变为0】如果删除某个结点之后,father的bf为0,说明以前father的bf为1或-1,那么当bf变为0,树的高度改变,可能会对上层造成影响
//高度改变
if (father->_bf==0)
{
cur=father;
father=father->_father;//向上更新
}
//如果删除某个结点以后father的结点bf变为1或者-1,树的高度没有改变,那么不会对上层树的平衡造成影响,删除完成
//高度没有改变
else if (father->_bf==-1||father->_bf==1)
{
break;
}
//【向上循环更新bf变为2或者-2】当更新以后father的bf变为2或者-2,则要进行旋转,调整树的高度,保持树的平衡
else if(father->_bf==2||father->_bf==-2)
{
//3.1>左旋
if(father->_bf==2&&cur->_bf==1)
{
RotateL(father);
return true;
}
//3.2>右旋
if(father->_bf==-2&&cur->_bf==-1)
{
RotateR(father);
return true;
}
//3.3>左右双旋
if (father->_bf==-2&&cur->_bf==1)
{
RotateLR(father);
return true;
}
//3.4>右左双旋
if (father->_bf==2&&cur->_bf==-1)
{
RotateRL(father);
return true;
}
}
//更新以后father的bf变为其他值,说明在更新之前该节点的bf就有问题
else
{
cout<<"平衡因子出错"<<endl;
}
}
delete del;
del=NULL;
return true;
}
}
//2.2没找到
return false;
}
protected:
//中序打印----✔
void _InOrder(Node* root)
{
if (root==NULL)
{
return ;
}
_InOrder(root->_left);
cout<<root->_key<<":"<<root->_value<<" ";
_InOrder(root->_right);
}
//求树的高度---✔
int _Depth(Node* root)
{
if (root==NULL)
{
return 0;
}
int LeftDepth= _Depth(root->_left);
int RightDepth= _Depth(root->_right);
return LeftDepth > RightDepth? LeftDepth+1:RightDepth+1;
}
//判断AVL是否平衡----✔
bool _IsBalance(Node* root)
{
//1.空树也是AVL树,也平衡
if (root==NULL)
{
return true;
}
//2.非空树
int LeftHight=_Depth(root->_left);//左树高度
int RightHight=_Depth(root->_right);//右树高度
//如果该节点的左树高度减右树高度不等于该节点的平衡因子,说明平衡因子出错
if (RightHight-LeftHight!=root->_bf)
{
cout<<"平衡因子出错"<<endl;
}
//AVL平衡树说的是每一颗子树的左右高度差的绝对值都大于1。所以没课子树都要递归判断;
return abs(RightHight-LeftHight)<2 && _IsBalance(root->_left) && _IsBalance(root->_right);
}
bool _IsBalanceOP(Node* root,int& hight)
{
if (root==NULL)
{
hight=0;
return true;
}
int LeftHight,RightHight;
if (_IsBalanceOP(root->_left,LeftHight)&&_IsBalanceOP(root->_right,RightHight))
{
hight=LeftHight>RightHight? LeftHight+1:RightHight+1;
return abs(RightHight-LeftHight)<2;
}
else
{
return false;
}
}
//销毁
void _Destroy(Node* root)
{
if (root==NULL)
{
return ;
}
_Destroy(root->_left);
_Destroy(root->_right);
delete root;
root=NULL;
}
//左旋------✔
void RotateL(Node* father)
{
Node* SubR=father->_right;
Node* SubRL=SubR->_left;
Node* PPNode=father->_father;
father->_right=SubRL;
if (SubRL)
{
SubRL->_father=father;
}
if (PPNode==NULL)
{
_root=SubR;
SubR->_father=PPNode;
}
else
{
if (PPNode->_left==father)
{
PPNode->_left=SubR;
}
else
{
PPNode->_right=SubR;
}
SubR->_father=PPNode;
}
SubR->_left=father;
father->_father=SubR;
father->_bf=0;
SubR->_bf=0;
}
//右旋------✔
void RotateR(Node* father)
{
Node* SubL=father->_left;
Node* SubLR=SubL->_right;
Node* PPNode=father->_father;
father->_left=SubLR;
if (SubLR)
{
SubLR->_father=father;
}
if (PPNode==NULL)
{
_root=SubL;
SubL->_father=PPNode;
}
else
{
if (PPNode->_left==father)
{
PPNode->_left=SubL;
}
else
{
PPNode->_right=SubL;
}
SubL->_father=PPNode;
}
SubL->_right=father;
father->_father=SubL;
father->_bf=0;
SubL->_bf=0;
}
//左右旋转------✔
void RotateLR(Node* father)
{
Node* SubL=father->_left;
Node* SubLR=SubL->_right;
int bf=SubLR->_bf;
//1.先以SubL左旋
RotateL(SubL);
//2.再以father右旋
RotateR(father);
//3.根据SubLR->_bf原始的bf更新旋转之后各个结点的bf
if (bf==1)
{
SubL->_bf=-1;
father->_bf=0;
}
else if (bf==-1)
{
father->_bf=1;
SubL->_bf=-1;
}
else
{
SubL->_bf=0;
father->_bf=0;
}
SubLR->_bf=0;
}
//右左旋转------✔
void RotateRL(Node* father)
{
Node* SubR=father->_right;
Node* SubRL=SubR->_left;
int bf=SubRL->_bf;
//1.先以SubR右旋
RotateR(SubR);
//2.在以father左旋
RotateL(father);
//3.根据SubRL的原始bf更新旋转以后的各节点bf
if(bf==1)
{
father->_bf=-1;
SubR=0;
}
else if (bf==-1)
{
SubR->_bf=1;
father->_bf=0;
}
else
{
SubR->_bf=0;
father->_bf=0;
}
SubRL->_bf=0;
}
private:
Node* _root;
};
int main()
{
AVLTree<int, int> tree1;
int array1[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
for (int i = 0; i < sizeof(array1) / sizeof(array1[0]); ++i)
{
tree1.Insert(array1[i],array1[i]);
}
tree1.InOrder();
cout<<endl;
cout <<"IsBalance?"<< tree1.IsBalance() << endl;
cout << "IsBalance?" << tree1.IsBalanceOP() << endl;
tree1.Remove(16);//删除的是叶子节点
tree1.Remove(3);//删除的是叶子节点
tree1.Remove(7);//删除的结点只有一个子树
tree1.Remove(11);//要删除的结点左右子树都有
tree1.InOrder();
tree1.Remove(9);
tree1.Remove(26);
tree1.Remove(18);
tree1.Remove(15);
cout<<endl;
tree1.InOrder();
cout<<endl;
cout << "IsBalance?" << tree1.IsBalance() << endl;
int array2[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
AVLTree<int, int> tree2;
for (size_t i = 0;i<sizeof(array2) / sizeof(array2[0]);++i)
{
tree2.Insert(array2[i],array2[i]);
}
tree2.InOrder();
cout<<endl;
cout << "IsBalance?" << tree2.IsBalance() << endl;
cout << "IsBalance?" << tree2.IsBalanceOP() << endl;
tree2.Remove(5);
tree2.InOrder();
}