AVL树平衡调整与应用解析

一、 AVL树的概念。
  • AVL树是高度平衡化的二叉搜索树,首先AVL树包括二叉搜索树的一切性质,且满足保证每个结点的左右子树高度之
    差的绝对值不超过1(需要对树中的结点进行调整)。也就是降低树的高度。
  1. 它的左右子树都是AVL树。
  2. 左右子树高度之差(简称平衡因子)的绝对值不超过1(-1/0/1)。
  3. 如果一棵二叉搜索树是高度平衡的,它就是AVL树。如果它有n个结点,其高度可保持在log2N ,搜索时
    间复杂度O( log2N)。
    AVL树的调整
二、AVL树的操作。
(一)AVL树的插入:
  • AVL树的插入一般分为两步
  1. 按照二叉搜索树的方式插入新节点。
  2. 调整节点的平衡因子。(调整平衡因子就是将各个节点的平衡因子绝对值调至小于等于1)
(二)AVL树的删除:
  • AVL树的删除:可按照二叉搜索树的方式将节点删除,然后再更新平衡因子,只不错与删除不同的时,删除节点后的平衡因子更新,最差情况下一直要调整到根节点的位置。
(三)AVL树的平衡调整:
  1. 第一种情况:向右旋转。(向左直线)
    向右旋转
    实现代码:
    void RotateR(AVLNode<Type> *&ptr)
	{
		AVLNode<Type> *subR = ptr;
		ptr = subR->leftChild;
		subR->leftChild = ptr->rightChild;
		ptr->rightChild = subR;
		ptr->bf = subR->bf = 0;
	}
  1. 第二种情况:向左旋转。(向右直线)
    左旋转
    实现代码:
    void RotateL(AVLNode<Type> *&ptr)
	{
		AVLNode<Type> *subL = ptr;
		ptr = subL->rightChild;
		subL->rightChild = ptr->leftChild;
		ptr->leftChild = subL;
		ptr->bf = subL->bf = 0;
	}
  1. 第三种情况:先左后右旋转。(向左拐)
    先左后右旋转
    实现代码:
    void RotateLR(AVLNode<Type> *&ptr)
	{
		AVLNode<Type> *subL = ptr->leftChild;
		AVLNode<Type> *subR = ptr;
		ptr = subL->rightChild;

		subL->rightChild = ptr->leftChild;
		ptr->leftChild = subL;
		//subL->bf;
		if (ptr->bf <= 0)
			subL->bf = 0;
		else
			subL->bf = -1;

		subR->leftChild = ptr->rightChild;
		ptr->rightChild = subR;
		//subR->bf;
		if (ptr->bf >= 0)
			subR->bf = 0;
		else
			subR->bf = 1;

		ptr->bf = 0;
	}
  1. 第四种情况:先右后左旋转。(向右拐)
    先右后左旋转
    实现代码:
	void RotateRL(AVLNode<Type> *&ptr)
	{
		AVLNode<Type> *subL = ptr;
		AVLNode<Type> *subR = ptr->rightChild;
		ptr = subR->leftChild;

		subR->leftChild = ptr->rightChild;
		ptr->rightChild = subR;
		//subR->bf
		if (ptr->bf >= 0)
			subR->bf = 0;
		else
			subR->bf = 1;

		subL->rightChild = ptr->leftChild;
		ptr->leftChild = subL;
		//subL->bf
		if (ptr->bf <= 0)
			subL->bf = 0;
		else
			subL->bf = -1;

		ptr->bf = 0;
	}
三、AVL树的模拟实现。
  1. AVL树的节点定义:
template<typename Type>
class AVLTree;

template<typename Type>
class AVLNode
{
	friend class AVLTree<Type>;
public:
	AVLNode(Type d = Type(), AVLNode<Type>*left = nullptr, AVLNode<Type>*right = nullptr)
		: data(d), leftChild(left), rightChild(right), bf(0)
	{}
	~AVLNode()
	{}
private:
	Type data;//值
	AVLNode<Type> *leftChild;//左孩子
	AVLNode<Type> *rightChild;//右孩子
	int bf; //平衡因子
};

  1. AVL树的定义:
template<typename Type>
class AVLTree
{
public:
	AVLTree() : root(nullptr)
	{}
public:
	bool Insert(const Type &x);  //插入接口
	bool Remove(const Type &key);//删除接口
protected:
	bool Insert(AVLNode<Type> *&t, const Type &x); //
	bool Remove(AVLNode<Type> *&t, const Type &key); //
protected:
	void RotateR(AVLNode<Type> *&ptr)//右旋转
	{
		AVLNode<Type> *subR = ptr;
		ptr = subR->leftChild;
		subR->leftChild = ptr->rightChild;
		ptr->rightChild = subR;
		ptr->bf = subR->bf = 0;
	}
	void RotateL(AVLNode<Type> *&ptr)//左旋转
	{
		AVLNode<Type> *subL = ptr;
		ptr = subL->rightChild;
		subL->rightChild = ptr->leftChild;
		ptr->leftChild = subL;
		ptr->bf = subL->bf = 0;
	}
	void RotateRL(AVLNode<Type> *&ptr)//先右后左旋转
	{
		AVLNode<Type> *subL = ptr;
		AVLNode<Type> *subR = ptr->rightChild;
		ptr = subR->leftChild;

		subR->leftChild = ptr->rightChild;
		ptr->rightChild = subR;
		//subR->bf
		if (ptr->bf >= 0)
			subR->bf = 0;
		else
			subR->bf = 1;

		subL->rightChild = ptr->leftChild;
		ptr->leftChild = subL;
		//subL->bf
		if (ptr->bf <= 0)
			subL->bf = 0;
		else
			subL->bf = -1;

		ptr->bf = 0;
	}
	void RotateLR(AVLNode<Type> *&ptr)//先左后右旋转
	{
		AVLNode<Type> *subL = ptr->leftChild;
		AVLNode<Type> *subR = ptr;
		ptr = subL->rightChild;

		subL->rightChild = ptr->leftChild;
		ptr->leftChild = subL;
		//subL->bf;
		if (ptr->bf <= 0)
			subL->bf = 0;
		else
			subL->bf = -1;

		subR->leftChild = ptr->rightChild;
		ptr->rightChild = subR;
		//subR->bf;
		if (ptr->bf >= 0)
			subR->bf = 0;
		else
			subR->bf = 1;

		ptr->bf = 0;
	}
private:
	AVLNode<Type> *root;
};

  1. 插入接口实现:
template<typename Type>
bool AVLTree<Type>::Insert(const Type &x)
{
	return Insert(root, x);
}
template<typename Type>
bool AVLTree<Type>::Insert(AVLNode<Type> *&t, const Type &x)
{
	stack<AVLNode<Type> *> st;
	//1 插入数据
	AVLNode<Type> *p = t;
	AVLNode<Type> *pr = nullptr;
	while (p != nullptr)
	{
		if (x == p->data)
			return false;

		pr = p;
		st.push(pr);

		if (x < p->data)
			p = p->leftChild;
		else
			p = p->rightChild;
	}
	p = new AVLNode<Type>(x);

	if (pr == nullptr)
	{
		t = p;
		return true;
	}

	//链接节点
	if (x < pr->data)
		pr->leftChild = p;
	else
		pr->rightChild = p;


	//2 平衡调整
	while (!st.empty())
	{
		pr = st.top();
		st.pop();

		if (pr->leftChild == p)
			pr->bf--;
		else
			pr->bf++;

		if (pr->bf == 0)  //在矮子树上插入节点
			break;
		if (pr->bf == 1 || pr->bf == -1) //增加了子树的高度
			p = pr;
		else   // |bf| == 2 需要平衡调整
		{
			if (pr->bf > 0)
			{
				if (p->bf > 0)    //    \ 
				{
					//cout<<"RotateL"<<endl;
					RotateL(pr);
				}
				else             //      >
				{
					//cout<<"RotateRL"<<endl;
					RotateRL(pr);
				}
			}
			else
			{
				if (p->bf < 0)    //      /
				{
					//cout<<"RotateR"<<endl;
					RotateR(pr);
				}
				else             //     <
				{
					//cout<<"RotateLR"<<endl;
					RotateLR(pr);
				}
			}
			break;
		}
	}
	if (st.empty())
	{
		t = pr;
	}
	else
	{
		AVLNode<Type> *q = st.top();
		if (pr->data < q->data)
			q->leftChild = pr;
		else
			q->rightChild = pr;
	}
	return true;
}
  1. 删除接口实现:
template<class Type>
bool AVLTree<Type>::Remove(AVLNode<Type> *&t, const Type &key)
{
	AVLNode<Type> *pr = nullptr;
	AVLNode<Type> *p = t, *q;
	stack<AVLNode<Type>*> st;
	while(p != nullptr)
	{
		if(key == p->data)
			break;

		pr = p;
		st.push(pr);
		
		if(key < p->data)
			p = p->leftChild;
		else
			p = p->rightChild;
	}
	if(p == nullptr)
		return false;

	if(p->leftChild!=nullptr && p->rightChild!=nullptr)
	{
		pr = p;
		st.push(pr);

		q = p->rightChild;
		while(q->leftChild != nullptr)
		{
			pr = q;
			st.push(pr);
			q = q->leftChild;
		}
		p->data = q->data;
		p = q;
	}

	if(p->leftChild != nullptr)
		q = p->leftChild;
	else
		q = p->rightChild;

	//p被删除节点,q删除节点子女节点
	if(pr == nullptr)
		t = q;
	else
	{
		if(p == pr->leftChild)
			pr->leftChild = q;
		else
			pr->rightChild = q;

		//调整平衡
		while(!st.empty())
		{
			pr = st.top();
			st.pop();

			if(p->data < pr->data)
				pr->bf++;
			else
				pr->bf--;

			if(pr->bf==1 || pr->bf==-1)
				break;

			if(pr->bf != 0)
			{
				//让q指向较高子树
				if(pr->bf < 0)
					q = pr->leftChild;
				else
					q = pr->rightChild;

				if(q->bf == 0)
				{
					if(pr->bf < 0)
					{
						RotateR(pr);
						pr->bf = 1;
						pr->rightChild->bf = -1;
					}
					else
					{
						RotateL(pr);
						pr->bf = -1;
						pr->leftChild->bf = 1;
					}

					if(!st.empty())
					{
						AVLNode<Type> *ppr = st.top();
						if (ppr->data < pr->data)
							ppr->rightChild = pr;
						else
							ppr->leftChild = pr;
					}
					else
						t = pr;
					
					break;
				}

				if(pr->bf < 0)
				{
					if(q->bf < 0)
					{
						RotateR(pr);
					}
					else
					{
						RotateLR(pr);
					}
				}
				else
				{
					if(q->bf > 0)
					{
						RotateL(pr);
					}
					else
					{
						RotateRL(pr);
					}
				}

				if (!st.empty())
				{
					AVLNode<Type> *ppr = st.top();
					if (ppr->data < pr->data)
						ppr->rightChild = pr;
					else
						ppr->leftChild = pr;
				}
				else
					t = pr;
			}

			q = pr;

		}//end while
	}
	delete p;
	return true;
}
四、AVL树的应用。
  • AVL树是一棵绝对平衡的二叉搜索树,其要求每个节点的左右子树高度差的绝对值都不超过1,这样可以保证查询时高效的时间复杂度。
    但是如果要对AVL树做一些结构修改的操作,性能非常低下,比如:
  1. 插入时要维护其绝对平衡,旋转的次数比较多,更差的是在删除时,有可能一直要让旋转持续到根的位置。
  2. 如果需要一种查询高效且有序的数据结构,而且数据的个数为静态的(即不会改变),可以考虑AVL树,但一个结构经常修改,就不太适合。
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值