数据结构 平衡二叉树 右旋转 学习笔记

  

所谓平衡二叉树是指树中任一结点的左、右子树高度大致相同。
平衡二叉树有很多种最著名的是由前苏联数学家Adelse—Velskil和Landis在1962年提出的,称为AVL树。平衡二叉树(AVL树)定义如下:
平衡二叉树或者是一棵空树,或者是具有以下性质的二叉排序树:
(1)它的左子树和右子树的高度之差绝对值不超过1;
(2)它的左子树和右子树都是平衡二叉树。

通过以上几种性质  我们低昂以一个这样的二叉树

可以看出  这不是一个平衡二叉树  

40这个节点的节点最大高度差为2

 那么我们会用到旋转的方法让他变成一个平衡二叉树

这里我们主要介绍右旋

 可以看出  我们的二叉树是这样一个结构   A为不平衡节点

一般的  我们将

不平衡节点的父亲 

不平衡节点

不平衡节点的左

不平衡节点的左的右

四个节点进行操作来完成右旋

对节点的孩子关系的操作

A->左=B->右(E)

B->右=A

x->左(或右)=B

对节点的父亲的操作

E->父亲=A

A->父亲=B

B->父亲=x

通过右旋转将左边的二叉树变成右边的平衡二叉树 

下面是右旋函数  传根的引用

void RightRotate(BinaryTree*& pBoot)
{
	if (pBoot == nullptr || pBoot->pLeft==nullptr)
	{
		return;
	}
	//标记不平衡节点  A
	BinaryTree* pMark = pBoot;
	//标记不平衡节点的左  B
	BinaryTree* pTemp = pBoot->pLeft;
	//x  pMark->pFather   E   pTemp->pRight

	//三个孩子
	//不平衡节点的左->不平衡节点的 左的右   A->左=E 
	pMark->pLeft = pTemp->pRight;
	//不平衡节点左的右->不平衡节点       B->右=A
	pTemp->pRight = pMark;
	//不平衡节点是不是根
	
	  //是  不平衡的节点变为根
	if (pMark->pFather == nullptr)
	{
		  pBoot=pTemp;
	}
	  //不是 判断不平衡节点是父亲的左还是右   (A是父亲的左还是右)
	else
	{
		//左:
		  //不平衡节点的父亲的左孩子->不平衡节点   X->左=B
		if (pMark->pFather->pLeft == pMark)
		{
			pMark->pFather->pLeft =pTemp;
		}
		 //右:
		   //不平衡节点的父亲的右孩子->不平衡节点   X->右=B
		else 
		{
			pMark->pFather->pRight = pTemp;
		}
	}
	    
	    


	//三个父亲
	//不平衡节点左的右的父亲->不平衡节点  E->父亲=A
	if (pMark->pLeft!=nullptr)
	{
		pMark->pLeft->pFather = pMark;
	}
	//不平衡节点的左(B)的父亲=不平衡节点(A)的父亲
	pTemp->pFather = pMark->pFather;
    //不平衡节点(A)的父亲=不平衡节点的左(B)
	pMark->pFather = pTemp;
	

}

在主函数中我们定义一个这样的二叉树

//根
	BinaryTree* pBoot = new BinaryTree;
	pBoot->pFather = nullptr;
	pBoot->id = 40;
	

	//左
	pBoot->pLeft = new BinaryTree;
	pBoot->pLeft->id = 20;
	pBoot->pLeft->pFather = pBoot;
	
	//左的左
	pBoot->pLeft->pLeft = new BinaryTree;
	pBoot->pLeft->pLeft->id = 10;
	pBoot->pLeft->pLeft->pFather = pBoot->pLeft;
	//左的左的左
	pBoot->pLeft->pLeft->pLeft = new BinaryTree;
	pBoot->pLeft->pLeft->pLeft->id = 7;
	pBoot->pLeft->pLeft->pLeft->pFather = pBoot->pLeft->pLeft;
	pBoot->pLeft->pLeft->pLeft->pLeft = NULL;
	pBoot->pLeft->pLeft->pLeft->pRight = NULL;
	//左的左的右
	pBoot->pLeft->pLeft->pRight = NULL;
	//左的右
	pBoot->pLeft->pRight = new BinaryTree;
	pBoot->pLeft->pRight->id = 30;
	pBoot->pLeft->pRight->pFather = pBoot->pLeft;
	pBoot->pLeft->pRight->pLeft = NULL;
	pBoot->pLeft->pRight->pRight = NULL;
	//右
	pBoot->pRight = new BinaryTree;
	pBoot->pRight->id = 50;
	pBoot->pRight->pFather = pBoot;
	pBoot->pRight->pLeft = NULL;
	pBoot->pRight->pRight = NULL;

然后对其根节点40进行右旋 使其变为平衡二叉树

RightRotate(pBoot);

完整代码如下

#include<iostream>
#include<stack>
using namespace std;
//二叉排序树中不允许出现相同的值的节点
struct BinaryTree
{
	int id;
	BinaryTree* pLeft;
	BinaryTree* pRight;
	BinaryTree* pFather;

};

void Inorder(BinaryTree *pBoot)
{
	if (pBoot == nullptr)
	{
		return;
	}
	Inorder(pBoot->pLeft);
	cout << pBoot->id << " ";
	Inorder(pBoot->pRight);
}

void RightRotate(BinaryTree*& pBoot)
{
	if (pBoot == nullptr || pBoot->pLeft==nullptr)
	{
		return;
	}
	//标记不平衡节点  A
	BinaryTree* pMark = pBoot;
	//标记不平衡节点的左  B
	BinaryTree* pTemp = pBoot->pLeft;
	//x  pMark->pFather   E   pTemp->pRight

	//三个孩子
	//不平衡节点的左->不平衡节点的 左的右   A->左=E 
	pMark->pLeft = pTemp->pRight;
	//不平衡节点左的右->不平衡节点       B->右=A
	pTemp->pRight = pMark;
	//不平衡节点是不是根
	
	  //是  不平衡的节点变为根
	if (pMark->pFather == nullptr)
	{
		  pBoot=pTemp;
	}
	  //不是 判断不平衡节点是父亲的左还是右   (A是父亲的左还是右)
	else
	{
		//左:
		  //不平衡节点的父亲的左孩子->不平衡节点   X->左=B
		if (pMark->pFather->pLeft == pMark)
		{
			pMark->pFather->pLeft =pTemp;
		}
		 //右:
		   //不平衡节点的父亲的右孩子->不平衡节点   X->右=B
		else 
		{
			pMark->pFather->pRight = pTemp;
		}
	}
	    
	    


	//三个父亲
	//不平衡节点左的右的父亲->不平衡节点  E->父亲=A
	if (pMark->pLeft!=nullptr)
	{
		pMark->pLeft->pFather = pMark;
	}
	
	pTemp->pFather = pMark->pFather;
	pMark->pFather = pTemp;
	

}

int main()
{
	//根
	BinaryTree* pBoot = new BinaryTree;
	pBoot->pFather = nullptr;
	pBoot->id = 40;
	

	//左
	pBoot->pLeft = new BinaryTree;
	pBoot->pLeft->id = 20;
	pBoot->pLeft->pFather = pBoot;
	
	//左的左
	pBoot->pLeft->pLeft = new BinaryTree;
	pBoot->pLeft->pLeft->id = 10;
	pBoot->pLeft->pLeft->pFather = pBoot->pLeft;
	//左的左的左
	pBoot->pLeft->pLeft->pLeft = new BinaryTree;
	pBoot->pLeft->pLeft->pLeft->id = 7;
	pBoot->pLeft->pLeft->pLeft->pFather = pBoot->pLeft->pLeft;
	pBoot->pLeft->pLeft->pLeft->pLeft = NULL;
	pBoot->pLeft->pLeft->pLeft->pRight = NULL;
	//左的左的右
	pBoot->pLeft->pLeft->pRight = NULL;
	//左的右
	pBoot->pLeft->pRight = new BinaryTree;
	pBoot->pLeft->pRight->id = 30;
	pBoot->pLeft->pRight->pFather = pBoot->pLeft;
	pBoot->pLeft->pRight->pLeft = NULL;
	pBoot->pLeft->pRight->pRight = NULL;
	//右
	pBoot->pRight = new BinaryTree;
	pBoot->pRight->id = 50;
	pBoot->pRight->pFather = pBoot;
	pBoot->pRight->pLeft = NULL;
	pBoot->pRight->pRight = NULL;





	Inorder(pBoot);
	RightRotate(pBoot);
	cout << endl;
	Inorder(pBoot);










	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值