【C++学习】AVL树四种旋转

本文详细介绍了AVL树在插入新节点导致不平衡时,通过右单旋转、左单旋转、左右单旋和右左单旋来保持平衡的过程,包括代码实现和平衡因子的更新策略。
摘要由CSDN通过智能技术生成

前言:

前个屁言好好复习(ノ`Д)ノ(ノ`Д)ノ

一、AVL树的右单旋转

 

上图在插入前,AVL树是平衡的,新节点插入到30的左子树(注意:此处不是左孩子)中,30左子树增加了一层,导致以60为根的二叉树不平衡,要让60平衡,只能将60左子树的高度减少一层,右子树增加一层,即将左子树往上提,这样60转下来,因为60比30大,只能将其放在30的右子树,而如果30有右子树,右子树根的值一定大于30,小于60,只能将其放在60的左子树,旋转完成后,更新节点的平衡因子即可。在旋转过程中,有以下几种情况需要考虑:

  1. 30节点的右孩子可能存在,也可能不存在
  2. 60可能是根节点,也可能是子树
  3. 如果是根节点,旋转完成后,要更新根节点
  4. 如果是子树,可能是某个节点的左子树,也可能是右子树

 1.1代码实现

void RotateR(Node* parent)
	{
		Node* cur = parent->_left;
		Node* curRight = cur->_right;

		parent->_left = curRight;
		cur->_right = parent;
		Node* ppNode = parent->_parent;
		if (curRight)//右孩子可能存在,也可能不存在,所以需要判断,需要在parent改变前判断
		{
			curRight->_parent = parent;
		}

		parent->_parent = cur;

		if (parent == _root)//parent可能是根节点,也可能不是根节点
		{
			_root = cur;
			cur->_parent = nullptr;
		}
		else
		{
			if (ppNode->_left == parent)
			{
				ppNode->_left = cur;
			}
			else
			{
				ppNode->_right = cur;
			}
			cur->_parent = ppNode;
		}
		cur->_bf = parent->_bf = 0;//将平衡因子调整
	}

二、AVL树的左单旋转

  • 新节点插入较高右子树的右侧—右右:左单旋

这里进行参考右单旋转就可理解

注:如果是左单旋转parent的平衡因子应该是2,cur的平衡因子应该是1
如果是右单旋转parent的平衡因子应该是-2,cur的平衡因子应该是-1。

三、AVL树的左右单旋 

新节点插入较高左子树的右侧—左右:先左单旋再右单旋

即:先对30进行左单旋,然后再对90进行右单旋,旋转完成后再考虑平衡因子的更新。 

注:平衡因子的更新分为三种情况

1.当h是为0的时候,进行左右双旋,那么它的平衡因子都是为0的。

2.当h>0的时候,进行左右双旋,那么它的平衡因子修改分为两种情况

(1)当插入节点在b的位置,如图所示,30节点的平衡因子修改为0,60节点的平衡因子修改为090节点的平衡因子修改为1

(2)当擦汗如节点在c的位置,将上图的紫色方框放到c的位置,那么60和90节点的平衡因子为0,30节点的平衡因子为-1.这个平衡因子的修改是根据目录AVL树的定义的方式修改的。

3.1代码实现 :

void RotateLR(Node* parent)
	{
		Node* cur = parent->_left;
		Node* curRight = cur->_right;
		int bf = curRight->_bf;

		//复用左单旋转和右单旋转
		RotateL(cur);
		RotateR(parent);

		if (bf == 0)
		{
			parent->_bf = 0;
			cur->_bf = 0;
			curRight->_bf = 0;
		}
		else if (bf == -1)//curRight的左树插入新节点
		{
			parent->_bf = 1;
			cur->_bf = 0;
			curRight->_bf = 0;
		}
		else if (bf == 1)//curRight的右树插入新节点
		{
			cur->_bf = -1;
			parent->_bf = 0;
			curRight->_bf = 0;
		}
		else//不可能出现此情况,如果出现就是出错
		{
			assert(false);
		}
	}

四、AVL树的右左单旋

  • 新节点插入较高右子树的左侧—右左:先右单旋再左单旋

4.1代码实现

void RotateRL(Node* parent)
	{
		Node* cur = parent->_right;
		Node* curleft = cur->_left;
		int bf = curleft->_bf;
		//复用右单旋转和左单旋转
		RotateR(cur);
		RotateL(parent);

		if (bf == 0)
		{
			parent->_bf = 0;
			cur->_bf = 0;
			curleft->_bf = 0;
		}
		else if (bf == 1)//curLeft的右树插入新节点
		{
			parent->_bf = -1;
			cur->_bf = 0;
			curleft->_bf = 0;
		}
		else if(bf == -1)//curLeft的左树插入新节点
		{
			cur->_bf = 1;
			parent->_bf = 0;
			curleft->_bf = 0;
		}
		else
		{
			assert(false);
		}
	}

 后记:

慢慢肝咯,好好学习天天向上

  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值