AVL树---升级版的二叉搜索树

AVL树:

是一棵高度平衡的搜索二叉树;
什么是搜索二叉树?
一棵二叉树中任意父节点都大于自己的左子树上的每一个子节点,小于自己右子树上的每一个节点的树是搜索二叉树。
搜索二叉树的 中序遍历(左中右)得到一个从小都大的有序序列,这些在二叉搜索树中都有讲解。
搜索二叉树最大的优点就是查找快,时间复杂度O(lgN)

那么既然有了二叉搜索树,为什么还要一个AVL树?
我们可以这样理解,AVL树是二叉搜索树的升级版,它弥补了二叉搜索树的不足,同时具备二叉搜索树的优点,我们具体来分析一下。
如果一棵二叉树呈现一边倒的情况,如图所示:
在这里插入图片描述
这个时候,我们就需要调整这棵树的结构,让它的时间复杂度依然保持在O(lgN),如图:
在这里插入图片描述
这就是AVL树的意义,接下来我们具体分析下它是如何调整的。

AVL树结构:(搜索树+平衡因子 )

AVL树的性质:
1)左子树和右子树的高度之差的绝对值不超过1;
2)树中的每个左子树和右子树都是AVL树;
3)每个节点都有一个平衡因子,任一节点的平衡因子是-1,0,1;(每个节点的平衡因子=右子树高度-左子树高度)
时间复杂度是:log以2为底N的对数

节点类型:
这里写图片描述

平衡因子发生改变的三种情况:(分别举一个例子来分析)
① 插入结点在右边:++_bf,这种呈现一种 “右-右型”

这里写图片描述
我们以10为中心,将9挪动下来,10放上去,有一种 “左旋” 的感觉。(左单旋)

② 插入结点在左边:- -_bf,这种呈现 右–左型“”

这里写图片描述
这里我们做了两步操作,先以10为中心,“向右旋转”,把11挪到下面去,把10挪动到上面去,然后再使用 “左旋转”,以10为中心,将9挪到下面来,10放上去,拆分步骤如下(右左双旋):
在这里插入图片描述

③ 插入结点任意一边:_bf不变

这里写图片描述

以上情况分析总结如下:
** 1) if 有父亲结点|_bf| == 2/-2就要发生旋转;
2) if 有父节点|_bf| == 1/-1高度改变,继续向上更新平衡因子,直到出现2/-2旋转,或者出现0停止;
3) if 有父节点|_bf| == 0时,停止更新平衡因子;**

旋转问题:
在删除插入等操作以后,AVL树会发生以下旋转方式来调整自己的高度:左单旋,右单旋,左右双旋,右左双旋;
左单旋:

这里写图片描述
右单旋同理;

左右双旋:
这里写图片描述

右左双旋:
在这里插入图片描述
** 如果是右左双旋,那么父节点的平衡因子就是2。
如果是左右双旋,那么父节点的平衡因子就是-2。**

左右双旋具体情况分析:
这里写图片描述
这里写图片描述
这里写图片描述

如果看完还是不理解,就记住下面两幅图吧,记住每个节点的位置:
综上所述,针对左右双旋做了一个总结:
在这里插入图片描述

针对右左双旋总结如下:
在这里插入图片描述
总结一下,当父亲平衡因子是-2时:
** 若curR == 0时,旋转后平衡因子parent = 0, cur = 0;
若curR == -1时,旋转后平衡因子parent = 1,cur = 0;
若curR == 1时,旋转后平衡因子parent == 0, cur = -1;**
右左双旋同理;

代码示例:


#include<string>
template <class K,class V>
struct AVLTreeNode
{
	K _key;
	V _value;
	AVLTreeNode<K,V>* _left;
	AVLTreeNode<K,V>* _right;
	AVLTreeNode<K,V>* _parent;
	int _bf;//平衡因子

	AVLTreeNode(const K& key,const V& value)
		:_key(key),_value(value),_left(NULL),_right(NULL),_parent(NULL),_bf(0)
	{}
};

template <class K,class V>
class AVLTree
{
	typedef AVLTreeNode<K,V> Node;
protected:
	Node* _root;
public:
	AVLTree()
		:_root(NULL)
	{}
	~AVLTree()
	{
		_Destroy(_root);
	}
	bool Insert(const K& key,const V& value)
	{
		return _Insert(key,value);
	}
	void Inorder()
	{
		cout<<"中序遍历AVL树:"<<endl;
		_InOrder(_root);
		cout<<endl;
	}


private:
	//结点插入与旋转有关
	bool _Insert(const K& key,const V& value)
	{
		if(NULL == _root)
		{
			_root = new Node(key,value);
			return true;
		}
		Node* cur = _root;
		Node* parent = cur;
		while(cur)
		{
			if(cur->_key == key)
			{
				return false;
			}
			else if(cur->_key < key)
			{
				parent = cur;
				cur = cur->_right;
			}
			else
			{
				parent = cur;
				cur = cur->_left;
			}
		}
		//开始插入结点
		cur = new Node(key,value);
		if(parent->_key > key)
		{
			parent->_left = cur;
		}
		else
		{
			parent->_right = cur;
		}
		cur->_parent = parent;
		//调节平衡因子
		while(parent)
		{
			if(parent->_left == cur)
			{
				--parent->_bf;
			}
			else
			{
				++parent->_bf;
			}
			if(parent->_bf == 0)
			{
				break;
			}
			else if(parent->_bf == 1 || parent->_bf == -1)
			{
				cur = parent;
				parent = parent->_parent;
			}
			else//parent==2/-2开始旋转
			{
				if(parent->_bf == 2)//右树高
				{
					if(cur->_bf == 1)
					{
						//左单旋
						RotateL(parent);
					}
					else
					{
						//cur->_bf == -1是右左双旋
						RotateRL(parent);
					}
				}
				else//parent->_bf == -2,左树高
				{
					if(cur->_bf == -1)
					{
						//右单旋
						RotateR(parent);
					}
					else
					{
						//cur->_bf == 1,这是左右双旋
						RotateLR(parent);
					}
				}
				break;
			}
		}
		return true;

	}
	//右单旋
	void RotateR(Node* parent)
	{
		Node* subL = parent->_left;
		Node* subLR = subL->_right;
		subL->_right = parent;
		parent->_left = subLR;
		if(subLR)
		{
			subLR->_parent = parent;
		}
		Node* pparent = parent->_parent;
		parent->_parent = subL;
		subL->_parent = pparent;
		if(pparent == NULL)//说明此时是根节点
		{
			_root = subL;
		}
		else
		{
			if(pparent->_left == parent)
			{
				pparent->_left = subL;
			}
			else
			{
				pparent->_right = subL;
			}
		}
		parent->_bf = subL->_bf = 0;
	}
	//左单旋
	void RotateL(Node* parent)
	{
		Node* subR = parent->_right;
		Node* subRL = subR->_left;
		subR->_left = parent;
		parent->_right = subRL;
		if(subRL)
		{
			subRL->_parent = parent;
		}
		Node* pparent = parent->_parent;
		parent->_parent = subR;
		subR->_parent = pparent;
		if(pparent == NULL)
		{
			_root = subR;
		}
		else
		{
			if(pparent->_left == parent)
			{
				pparent->_left = subR;
			}
			else
			{
				pparent->_right = subR;
			}
		}
		parent->_bf = subR->_bf = 0;
	}
	//右左双旋
	void RotateRL(Node* parent)
	{
		Node* subR = parent->_right;
		Node* subRL = subR->_left;
		int bf = subRL->_bf;
		RotateR(parent->_right);
		RotateL(parent);
		if(bf == 0)
		{
			subR->_bf = parent->_bf = 0;
		}
		else if(bf == -1)
		{
			parent->_bf = 0;
			subR->_bf = 1;
		}
		else
		{
			parent->_bf = -1;
			subR->_bf = 0;
		}
		subRL->_bf = 0;
	}
	//左右双旋
	void RotateLR(Node* parent)
	{
		Node* subL = parent->_left;
		Node* subLR = subL->_right;
		int bf = subLR->_bf;//提前存储好我们的curR的平衡因子
		RotateL(parent->_left);
		RotateR(parent);
		if(bf == 0)
		{
			subL->_bf = parent->_bf = 0;
		}
		else if(bf == -1)
		{
			subL->_bf = 0;
			parent->_bf = 1;
		}
		else
		{
			parent->_bf = 0;
			subL->_bf = -1;
		}
		subLR->_bf = 0;
	}
	void _InOrder(Node* root)
	{
		if(NULL == root)
		{
			return;
		}
		_InOrder(root->_left);
		cout<<root->_key<<","<<root->_value<<" ";
		_InOrder(root->_right);
	}
	void _Destroy(Node* root)
	{
		if(NULL == root)
		{
			return;
		}
		_Destroy(root->_left);
		_Destroy(root->_right);
		delete root;
	}
	

};

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值