269-AVL树(左,右双旋转)

AVL树(左,右双旋转)

在这里插入图片描述
我们依次插入数据结点56,90,67。最后形成了“折线”,所以我们要进行双旋转

在这里插入图片描述
我们依次插入数据结点78,34,45。最后形成了“折线”,所以我们要进行双旋转

我们要求的中序遍历是从小到大,旋转之后使得每个节点的平衡因子尽可能向0靠拢。

我们要借助左单旋转函数和右单旋转函数的能力来进行
在这里插入图片描述
我们把34和45,以45为基准,进行左单旋转,34放下来,45放上去,再以45位基准,把78进行右单旋转。
在这里插入图片描述

我们来看下面这个问题

在这里插入图片描述
(a)是平衡二叉树,我们可能在D或者F或者G插入数据,如果我们在D插入数据,D的高度由h变成h+1,我们回溯到B的时候,B的平衡因子由0变为-1,我们回溯到A,A的平衡因子由-1变成-2,我们的这3个结点在斜线上,进行右单旋转就OK了。
也有可能我们在F或者G插入数据,无论插入到F还是G底下,E的树高h,如果插入到的是G底下,E的高度变成h+1,回溯到B,B的平衡因子变为1,回溯到A,A的平衡因子变为-2。形成折线。我们以E为基准对B进行左旋,然后把A进行右旋。

我们再来看下面这张图

在这里插入图片描述
首先通过E节点进行转轴,对B进行左单旋转操作,变成c图。我们以E为基准点,对A进行右单旋转。最终的图形是d图。

如何知道进行1次右单旋转或者1次左单旋转或者1次左单旋转后再进行1次右单旋转?
在这里插入图片描述
如何判断这3个节点在一条直线上。如果是左平衡,节点的平衡因子从上到下依次为-2,-1,就在一条斜线上。(进行单旋转)

如果是下图,节点的平衡因子从上到下依次是-2,1,就是在一条折线上。(进行双旋转)
在这里插入图片描述

左单旋转的代码

void RotateLeft(AVLTree& root, AVLNode* ptr)
{
	AVLNode* newroot = ptr->rightchild;
	newroot->parent = ptr->parent;// 1
	ptr->rightchild = newroot->leftchild;
	if (newroot->leftchild != nullptr)
	{
		newroot->leftchild->parent = ptr;// 2
	}
	newroot->leftchild = ptr;
	if (ptr->parent == nullptr)
	{
		root = newroot;
	}
	else
	{
		if (ptr->parent->leftchild == ptr)
		{
			ptr->parent->leftchild = newroot;
		}
		else
		{
			ptr->parent->rightchild = newroot;
		}
	}
	ptr->parent = newroot;	 // 3
}

右单旋转的代码

void RotateRight(AVLTree& root, AVLNode* ptr) 
{
	AVLNode* newroot = ptr->leftchild;
	newroot->parent = ptr->parent;//1
	ptr->leftchild = newroot->rightchild;
	if (newroot->rightchild != nullptr)
	{
		newroot->rightchild->parent = ptr;
	}
	newroot->rightchild = ptr;
	if (ptr->parent == nullptr)
	{
		root = newroot;
	}
	else
	{
		if (ptr->parent->leftchild == ptr)
		{
			ptr->parent->leftchild = newroot;
		}
		else
		{
			ptr->parent->rightchild = newroot;
		}
	}
	ptr->parent = newroot;
}

左平衡的程序代码

如果形成的是下图这种结构。
在这里插入图片描述
在A节点发生了不平衡,ptr指向A节点,在哪个节点发生了不平衡,就把哪个节点的指针给给ptr,我们定义2个指针。一个指向其左孩子,一个指向空。
case ==-1的情况
对B进行右单旋转
在这里插入图片描述
case==1的情况
情况:是跑到E这个地方插入了。
不管在F还是G插入,总会导致E的树高增高。导致B的平衡因子变成1,A的平衡因子变为-2。形成折线。我们要进行双旋转。
在这里插入图片描述
在这里插入图片描述
我们要进行先左后右的双旋转。
在这里插入图片描述
在这里插入图片描述
如果我们是在G插入节点,A的左子树要指向G,B的右子树要指向F,E的左边要指向B,E的右边要指向A,并且E作为根节点。E的平衡因子是1,A的配合因子是0,B的平衡因子是-1。
如果是嵌套的case的值是-1,则是在F节点插入节点。

E的平衡因子是0的可能性:
在这里插入图片描述

void LeftBalance(AVLTree& tree, AVLNode* ptr)//左平衡,对不平衡的AVL树进行左平衡 
{
	AVLNode* leftsub = ptr->leftchild, * rightsub = nullptr;
	switch (leftsub->balance)
	{
	case 0: cout << "Left balance \n"; break;
	case -1://如果是等于-1,是右单旋转 
		ptr->balance = 0;
		leftsub->balance = 0;
		RotateRight(tree, ptr);
		break;
	case 1://进行双旋转 
		rightsub = leftsub->rightchild;
		switch (rightsub->balance)
		{
		case 1:
			ptr->balance = 0;
			leftsub->balance = -1;
			break;
		case 0:	     
			ptr->balance = 0;
			leftsub->balance = 0;
			break;
		case -1:    
			ptr->balance = 1;
			leftsub->balance = 0;
			break;
		}
		rightsub->balance = 0;
		RotateLeft(tree,leftsub);
		RotateRight(tree,ptr);
		break;
	}
}

右平衡的程序代码

在这里插入图片描述
首先进行左单旋转
在这里插入图片描述
在这里插入图片描述

void RightBalance(AVLTree& tree, AVLNode* ptr)//右平衡 
{
	AVLNode* rightsub = ptr->rightchild, * leftsub = nullptr;
	switch (rightsub->balance)
	{
	case 0: cout << "right balance \n"; break;
	case 1://左单旋转 
		ptr->balance = 0;
		rightsub->balance = 0;
		RotateLeft(tree, ptr);
		break;
	case -1://双旋转 
		leftsub = rightsub->leftchild;
		switch (leftsub->balance)
		{
		case 1:
			ptr->balance = -1;
			rightsub->balance = 0;
			break;
		case 0: 
			ptr->balance = 0;
			rightsub->balance = 0;
			break;
		case -1: 
			ptr->balance = 0;
			rightsub->balance = 1;
			break;
		}
		leftsub->balance = 0;
		RotateRight(tree, rightsub);
		RotateLeft(tree, ptr);
		break;
	}
}

插入数据

bool Insert(AVLTree& tree, KeyType kx)//插入 
{

	Adjust_AVL(tree, p);
	return true;
}

进行调整
在这里插入图片描述
在E插入一个数据130
在这里插入图片描述
如果我们插入一个67,然后插入34,然后插入100。
在这里插入图片描述
则不需要调整。
如果我们再插入23,45

在这里插入图片描述

高度不变,不需要回溯。
如果我们再插入120。90。也不需要回溯在这里插入图片描述

在这里插入图片描述
我们再插入130和140。需要进行旋转,旋转后,不需要回溯
在这里插入图片描述
调整后,不会使得平衡因子超过2。
一旦调用平衡函数,高度不会发生变化。

void Adjust_AVL(AVLTree& tree, AVLNode* ptr)//调整AVL树 
{
	AVLNode* pa = ptr->parent;//指向双亲 
	bool high = true;//高度初始化为真
	while (high && pa != nullptr)//还没到根节点 
	{
		if (pa->rightchild == ptr)//ptr插入到右子树 
		{
			switch (pa->balance)//看平衡因子 
			{
			case 0: pa->balance = 1; break;//右边插入,变为1 
			case -1:
			//右边低 左边高,给右边插入 
				pa->balance = 0;
				high = false;//高度不变,不需要回溯
				break;
			case 1:
			//右边高 ,左边低,给右边插入,调用右平衡 
				RightBalance(tree,pa);
				high = false;//高度不变,不需要回溯				
				break;
			}
		}
		else //在双亲的左边 
		{
			switch (pa->balance)
			{
			case 0: pa->balance = -1; break;//在左边插入,变为-1 
			case 1: //右边高左边低,在左边插入 
				pa->balance = 0; 
				high = false;//高度不变,不需要回溯
				break;
			case -1:
		    //右边低左边高,在左边插入 
				LeftBalance(tree, pa);//调动左平衡 
				high = false;//高度不变,不需要回溯
				break;
		    }
		}
		ptr = pa;
		pa = ptr->parent;//回溯 
	}
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

林林林ZEYU

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

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

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

打赏作者

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

抵扣说明:

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

余额充值