平衡二叉树

1.平衡二叉树的定义

平衡二叉树是一种二叉排序树(具体定义可以参考其他博客),其中每一个节点的左子树和右子树的高度差至多差1。我们将二叉树上的每个结点左子树与右子树之差称为平衡因子(balance factor)。
平衡二叉树

2.解决策略

Ⅰ.两种旋转

解决策略:左旋以及右旋

1. 左旋

以高度为2(此时为不平衡状态)的二叉树为例:
在这里插入图片描述
2.右旋
右旋图示同理
在这里插入图片描述

Ⅱ.四种调整

  1. 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的左子即可

    在这里插入图片描述
  2. 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的右子即可

    在这里插入图片描述
  3. LR型:在结点的左子的右子树上插入新结点导致失衡
    分析:假设A,D两棵子树的高度为h+1B,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
    在这里插入图片描述
  4. RL型:在结点的右子的左子树上插入新结点导致失衡
    分析:假设A,D两棵子树的高度为h+1B,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);
	//层序遍历进行验证
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Agreenhan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值