AVL树插入时对于旋转子树的理解

AVL树的概念

当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之 差的绝对值不超过1(需要对树中的结点进行调整),即可降低树的高度,从而减少平均搜索长度。
一棵AVL树或者是空树,或者是具有以下性质的二叉搜索树:
它的左右子树都是AVL树
左右子树高度之差(简称平衡因子)的绝对值不超过1(-1/0/1)

平衡因子=右子树子树高度-左子树的高度

AVL树的简单代码实现
#pragma once
#include <utility>
using namespace std;
template <class k,class v>
struct  AVLTreeNode 
{
	AVLTreeNode<k, v>*_left;
	AVLTreeNode<k, v>*_right;
	AVLTreeNode<k, v>*_parent;//帮助找到父亲节点
	
	int _p;//平衡因子
	pair<k,v> _kv;
};

左旋

1.插入的新节点在较高右子树的右侧

 

 

void RoatetL(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 (ppNode->_left == parent)
		{
			ppNode->_left = subR;
		}
		else
		{
			ppNode->_right = subR;
		}
		subR->_parent = ppNode;
	}
	//更新平衡因子
	subR->_p = 0;
    parent->_p = 0;
}

右旋

void RoatetR(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 (_root == parent)
	{
		_root = subL;
		subL->_parent = nullptr;
	}
	else
	{
		if (ppNode->_left==parent)
		{
			ppNode->_left = subL;
		}
		else
		{
			ppNode->_right = subL;
		}
		subL->_parent = ppNode;
	}
	subL->_p = parent->_p = 0;

}

左右双旋

先进行左旋在再进行右旋

 

 

 

void RoatetLR(Node * parent)
{
	Node * subL = parent->_left;
	Node *subLR = subL->_right;
	int _p = subLR->_p;
	RoatetR(subL);
	RoatetL(parent);

	if (_p == 1)
	{
		parent->_p = -1;
		subL->_p = 0;
		subLR->_p = 0;
	}
	if (_p == -1)
	{
		parent->_p = 1;
		subL->_p = 0;
		subLR->_p = 0;
	}
	if (_p == 0)
	{
		parent->_p = 0;
		subL->_p = 0;
		subLR->_p = 0;
	}
}

右左双旋

void RoatetRL(Node * parent)
{
	Node * subR = parent->_right;
	Node * subRL = subR->_left;
	int _p = subRL->_p;
	RoatetR(subR);
	RoatetL(parent);
	if (_p==-1)
	{
		parent->_p = 0;
		subR->_p = 1;
		subRL->_p = 0;
	}
	else if (_p==1)
	{
		parent->_p = -1;
		subR->_p = 0;
		subRL->_p = 0;
	}
	else if (_p==0)
	{
		parent->_p = 0;
		subR->_p = 0;
		subRL->_p = 0;
	}

}

根据平衡因子来选择如何旋转

while (parent)
	{
		if (cur == parent->_right)
		{
			parent->_p++;
		}
		else
		{
			parent->_p--;
		}
		if (parent->_p == 0)
		{
			break;
		}
		else if (parent->_p==1 || parent->_p==-1)
		{
			cur = parent;
			parent = parent->_parent;
		} 
		//else if (parent->_p == 2 || parent->_p == -2)
		//平衡因子出现问题,parent所在子树不平衡,需要旋转子树。
		else
		{
			if (parent->_bf == 2)
			{
				if (cur->_bf == 1)  //  '\'   左单旋 
				{
					_RotateL(parent);
				}
				else  //-1   '>' 右左双旋
				{
					_RotateRL(parent);
				}
			}
			else  //-2
			{
				if (cur->_bf == -1)  // '/' 右单旋
				{
					_RotateR(parent);
				}
				else   // '<' 左右双旋
				{
					_RotateLR(parent);
				}
			}
			break;
		}
	}
	return true;
}

总结

AVL树是一棵绝对平衡的二叉搜索树,其要求每个节点的左右子树高度差的绝对值都不超过1,这样可以保证查询时高效的时间复杂度,即log2(N)。但是如果要对AVL树做一些结构修改的操作,性能非常低下,比如:插入时要维护其绝对平衡,旋转的次数比较多,更差的是在删除时,有可能一直要让旋转持续到根的位置。因此:如果需要一种查询高效且有序的数据结构,而且数据的个数为静态的(即不会改变),可以考虑AVL树,但一个结构经常修改,就不太适合。(当插入节点次数较多时可以使用红黑树)

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值