[AVL数四种旋转详细图解]

一.右单旋

新节点插入较高左子树的左侧—左左:右单旋
在这里插入图片描述

由于在较高左子树的左侧插入一个节点后,左边插入导致30的平衡因子更新为-1,而60平衡因子更新为-2,此时不平衡,引发旋转,右旋解决问题:看下图

在这里插入图片描述
将60进行一次右单旋后,30和60的平衡因子都更新为了0,此时AVL树重新平衡,更新结束。

代码实现:

void RotateR(Node* parent)
		{
			Node* subL = parent->_left;
			Node* subLR = subL->_right;
			parent->_left = subLR;
			if(subLR)
				subLR->_parent = parent;
			subL->_right = parent;
			Node* ppnode = parent->_parent;
			parent->_parent = subL;
			if (parent == _root)
			{
				_root = subL;
				subL->_parent = nullptr;
			}
			else
			{
				if (parent == ppnode->_left)
				{
					ppnode->_left = subL;
				}
				else
				{
					ppnode->_right = subL;
				}
				subL->_parent = ppnode;
			}
			parent->_bf = 0;
			subL->_bf = 0;
		}

二. 左单旋

新节点插入较高右子树的右侧—右右:左单旋
在这里插入图片描述

由于在较高右子树的右侧插入一个节点后,右边插入导致30的平衡因子更新为1,而60平衡因子更新为2,此时不平衡,引发旋转,左旋解决问题:看下图

在这里插入图片描述

将60进行一次左单旋后,30和60的平衡因子都更新为了0,此时AVL树重新平衡,更新结束。
代码实现:

void RotateL(Node* parent)
		{
			Node* subR = parent->_right;
			Node* subRL = subR->_left;
			parent->_right = subRL;
			if (subRL)
				subRL->_parent = parent;
			subR->_left = parent;
			Node* ppnode = parent->_parent;
			parent->_parent = subR;
			if (_root == parent)
			{
				_root = subR;
				subR->_parent = nullptr;
			}
			else
			{
				if (parent == ppnode->_left)
				{
					ppnode->_left = subR;
				}
				else
				{
					ppnode->_right = subR;
				}
				subR->_parent = ppnode;
			}
			parent->_bf = 0;
			subR->_bf = 0;
		}

三. 右左双旋

新节点插入较高右子树的左侧—右左:先右单旋再左单旋
此时进行右左双旋分为三种情况:
情况一:h==0
插入新结点后,60自己就是新增节点
在这里插入图片描述
此时先将60进行右旋
在这里插入图片描述
再将30进行左旋
在这里插入图片描述
情况二:h>0,在c插入(这里以h2为例)
同上理旋转:
在这里插入图片描述
先90进行右旋
在这里插入图片描述
最后30进行左旋
在这里插入图片描述
情况三:h>0,在b插入(这里以h
2为例)
在这里插入图片描述
先将90进行右旋
在这里插入图片描述
再将30进行左旋
在这里插入图片描述

右左双旋代码实现:

void RotateRL(Node* parent)
		{
			Node* subR = parent->_right;
			Node* subRL = parent->_left;
			int bf = subRL->_bf;
			RotateLR(subR);
			RotateL(parent);
			subRL->_bf = 0;
			if (bf == -1)
			{
				subR->_bf = 1;
				parent->_bf = 0;
			}
			else if (bf == 1)
			{
				subR->_bf = 0;
				parent->_bf = -1;
			}
			else if (bf == 0)
			{
				subR->_bf = 0;
				parent->_bf = 0;
			}
			else
			{
				assert(false);
			}
		}

四. 左右双旋

新节点插入较高左子树的右侧—左右:先左单旋再右单旋
此时进行左右双旋分为三种情况:
情况一:h==0
插入新结点后,60自己就是新增节点
在这里插入图片描述
30进行左旋
在这里插入图片描述
90进行右旋
在这里插入图片描述
情况二:h>0,在c插入(这里以h2为例)
在这里插入图片描述
30进行左旋
在这里插入图片描述
90进行右旋
在这里插入图片描述
情况三:h>0,在b插入(这里以h
2为例)
在这里插入图片描述
30进行左旋
在这里插入图片描述
90进行右旋
在这里插入图片描述
左右双旋代码实现:

void RotateLR(Node* parent)
		{
			Node* subL = parent->_left;
			Node* subLR = subL->_right;
			int bf = subLR->_bf;
			RotateL(subL);
			RotateR(parent);
			subLR->_bf = 0;
			if (bf == 0)
			{
				subL->_bf = 0;
				parent->_bf = 0;
			}
			else if (bf == 1)
			{
				subL->_bf = -1;
				parent->_bf = 0;
			}
			else if (bf == -1)
			{
				subL->_bf = 0;
				parent->_bf = 1;
			}
			else
			{
				assert(false);
			}
		}

**总结:1.对于单旋,旋转之后就平衡了,结束 2.对于双旋,旋转之后也平衡了,但此时要更新平衡因子,怎么更新取决于更新前代码中subL的平衡因子,
分三种情况,具体看代码实现。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

维生素C++

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

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

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

打赏作者

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

抵扣说明:

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

余额充值