AVL(平衡二叉树)
1.平衡二叉树的定义
平衡二叉树是一种二叉排序树(具体定义可以参考其他博客),其中每一个节点的左子树和右子树的高度差至多差1。我们将二叉树上的每个结点左子树与右子树之差称为平衡因子(balance factor)。
2.解决策略
Ⅰ.两种旋转
解决策略:左旋以及右旋
1. 左旋
以高度为2(此时为不平衡状态)的二叉树为例:
2.右旋
右旋图示同理
Ⅱ.四种调整
- R型:在结点的右子的右子树上插入新结点导致失衡
分析:假设A,B,C三棵子树的高度为h。此时a的右子树C的高度为h,若新插入的结点为a的右子b的右子树A(A的高度变为h+1)上,插入前,a的平衡因子为-1(左子树高度为h,右子树为h+1),插入后a点平衡因子为-2,a点失衡。
调整方法:
绕着a点单左旋即可解决问题,
旋转后,修改b的平衡因子为0,a的平衡因子也为0,b代替a成为新的根结点
实现过程(即单左旋的过程):
Ⅰ. 创建一个指针指向a的右子b
Ⅱ. 将a的右子修改为b的左子,即断开a与b的链接,将a与b的左子树链接。(不改变二叉排序树的性质,b的左子是介于小于b和大于a之间的,所以将b的左子链接到a的右子上满足二叉排序树的性质)
Ⅲ. 此时我们将b作为新的根节点,因为b的左子已经断开,所以将a作为b的左子即可
- L型:在结点的左子的左子树上插入新结点导致失衡
分析:假设A,B,C三棵子树的高度为h。此时a的右子树C的高度为h,若新插入的结点为a的左子b的左子树A(A的高度变为h+1)上,插入前,a的平衡因子为1(左子树高度为h+1,右子树为h),插入后a点平衡因子为2,a点失衡。
调整方法:
绕着a点单右旋即可解决问题
旋转后,修改b的平衡因子为0,a的平衡因子也为0,b代替a成为新的根结点
实现过程(即单右旋的过程):
Ⅰ. 创建一个指针指向a的左子b
Ⅱ. 将a的左子修改为b的右子,即断开a与b的链接,将a与b的右子树链接。(不改变二叉排序树的性质,b的右子是介于大于b和小于a之间的,所以将b的右子链接到a的左子上满足二叉排序树的性质)
Ⅲ. 此时我们将b作为新的根节点,因为b的右子已经断开,所以将a作为b的右子即可
- LR型:在结点的左子的右子树上插入新结点导致失衡
分析:假设A,D两棵子树的高度为h+1,B,C两棵子树的高度为h。
注意: 此时虽然图上画出B,C两棵子树,插入时选择B,C两棵子树的的一棵插入!所以插入时会有两种情况(其实是三种)。
此时我们发现无法通过旋转一次解决问题(可以自己动手尝试),需要进行双螺旋!究其原因,主要是a的平衡因子为2但是a左子b的平衡因子为-1,两者异号,无法通过单旋转改变
调整方法:
先通过左旋的方式旋转a的左子b,使其平衡因子与父结点a相同符号!
再通过右旋的方式旋转根节点a
旋转后:若新插入的结点在子树B上,修改b的平衡因子为0,a的平衡因子为-1;若插入在子树c上,修改b的平衡因子为1,a的平衡因子为0;若A,B,C,D全为空,a与b的平衡因子都为0
- RL型:在结点的右子的左子树上插入新结点导致失衡
分析:假设A,D两棵子树的高度为h+1,B,C两棵子树的高度为h。
注意: 此时虽然图上画出B,C两棵子树,插入时选择B,C两棵子树的的一棵插入!所以插入时会有两种情况。
调整方法:
先通过右旋的方式旋转a的右子b,使其平衡因子与父结点a相同符号!
再通过左旋的方式旋转根节点a
旋转后:若新插入的结点在子树B上,修改b的平衡因子为0,a的平衡因子为1;若插入在子树c上,修改b的平衡因子为-1,a的平衡因子为0;若A,B,C,D全为空,a与b的平衡因子都为0
3.代码
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
bool taller = 0;
//定义树是否增高
struct avl
{
int balance;
int key;
avl* leftnode = NULL, * rightnode = NULL;
avl(int value)
{
balance = 0;
key = value;
}
};
//平衡二叉树结构体的定义
typedef avl* avltree;
//右旋
void r_rotate(avltree& t)
{
avltree temp;
temp = t->leftnode;
t->leftnode = temp->rightnode;
temp->rightnode = t;
t = temp;
}
//左旋
void l_rotate(avltree& t)
{
avltree temp;
temp = t->rightnode;
t->rightnode = temp->leftnode;
temp->leftnode = t;
t = temp;
}
//R型调整
void r_adjust(avltree& t)
{
l_rotate(t);
//左旋
//调整平衡因子
t->balance = 0;
t->leftnode->balance = 0;
}
//L型调整
void l_adjust(avltree& t)
{
r_rotate(t);
//右旋
//调整平衡因子
t->balance = 0;
t->rightnode->balance = 0;
}
//LR型调整
void lr_adjust(avltree& t)
{
l_rotate(t->leftnode);
r_rotate(t);
//双旋转
//调整平衡因子
switch (t->balance)
{
case -1:
t->rightnode->balance = 0;
t->leftnode->balance = 1;
break;
case 0:
t->leftnode->balance = 0;
t->rightnode->balance = 0;
break;
case 1:
t->leftnode->balance = 0;
t->rightnode->balance = -1;
}
t->balance = 0;
}
//RL型调整
void rl_adjust(avltree& t)
{
r_rotate(t->rightnode);
l_rotate(t);
switch (t->balance)
{
case -1:
t->rightnode->balance = 0;
t->leftnode->balance = 1;
break;
case 0:
t->leftnode->balance = 0;
t->rightnode->balance = 0;
break;
case 1:
t->leftnode->balance = 0;
t->rightnode->balance = -1;
break;
}
t->balance = 0;
}
//左平衡,当插入到根节点的左子树上,进行平衡
void left_balance(avltree& t)
{
avltree l;
l = t->leftnode;
switch (l->balance)
{
case 1:
l_adjust(t);
break;
case -1:
lr_adjust(t);
break;
}
}
//右平衡,当插入到根节点的右子树上,进行平衡
void right_balance(avltree& t)
{
avltree r;
r = t->rightnode;
switch (r->balance)
{
case -1:
r_adjust(t);
break;
case 1:
rl_adjust(t);
break;
}
}
//插入函数
bool insert_tree(avltree& t, int akey)
{
if (t == NULL)
{
t = new avl(akey);
taller = 1;
return 1;
}//结点为空,则申请空间插入,树长高
else
{
if (akey == t->key) //如果已经存在,则不插入
return 0;
else if (akey < t->key) //小于根节点,插入到左子树
{
insert_tree(t->leftnode, akey); //递归的进行插入
if (taller) //如果树长高,进行调整
{
switch (t->balance)
{
case 1:
//插入到开始平衡因子已经为1的左子树上,需要进行左平衡
left_balance(t);
taller = 0;
break;
//插入到平衡因子为0的左子树上,只修改平衡因子,树长高
case 0:
t->balance = 1;
taller = 1;
break;
//插入到平衡因子为-1的左子树上,插入后树平衡
case -1:
t->balance = 0;
taller = 0;
}
}
}
else
{
insert_tree(t->rightnode, akey);
if (taller)
{
switch (t->balance)
{
case 1:
t->balance = 0;
taller = 0;
break;
case 0:
t->balance = -1;
taller = 1;
break;
case -1:
right_balance(t);
taller = 0;
break;
}
}
}
}
return 1;
}
//层序遍历的代码
void depth_order(avltree t)
{
queue <avltree> q;
q.push(t);
while (!q.empty())
{
avltree temp = q.front();
cout << temp->key << " ";
if(temp->leftnode!=NULL)
q.push(temp->leftnode);
if(temp->rightnode!=NULL)
q.push(temp->rightnode);
q.pop();
delete temp;
}
}
int main()
{
int n;
cin >> n;
vector<int> v(n);
avltree t=NULL;
for (int i = 0; i < n; i++)
{
cin >> v[i];
insert_tree(t,v[i]);
}
depth_order(t);
//层序遍历进行验证
}