AVL树详解

目录

概念

结构

插入 

旋转分类

左旋

右旋

左右双旋

右左双旋

 AVL树验证

AVL树删除

AVL树的性能 


概念

AVL树是一种二叉平衡搜索树,它解决了二叉搜索树退化单枝的问题。 

AVL树的左右子树都是AVL树。

左右子树高度之差(简称平衡因子)的绝对值不超过1。

结构

 AVL树采用三叉链结构,增加了平衡因子bf,通过平衡因子的更新我们对AVL树进行调整,使其保持平衡。

template<class K,class V>
struct AVLTNode
{
	AVLTNode<K, V>* _left;
	AVLTNode<K, V>* _right;
	AVLTNode<K, V>* _parent;
	pair<K, V> _kv;
	int bf;
	AVLTNode(const pair<K, V>& kv)
		:_left(nullptr)
		,_right(nullptr)
		,_parent(nullptr)
		,_kv(kv)
		,bf(0)
	{

	}
};
template<class K,class V>
class AVLTree
{
	typedef AVLTNode<K, V> Node;
private:
    Node* _root;
}

插入 

插入分为两步:

1.按二叉搜索树规则插入

2.调节平衡因子,在右子树插入,则bf++,在左子树插入,则bf-- 

  • 1.parent->bf==0 此时不需要调整
  • 2.parent->bf==-1或parent->bf==1,此时需要继续向上调整
  • 3.parent->bf==2或parent->bf==-2,此时要进行旋转 
bool Insert(const pair<K, V>& kv)
	{
		if (_root == nullptr)
		{
			_root = new Node(kv);
			return true;
		}
		Node* parent = nullptr;
		Node* cur = _root;
		//找空节点
		while (cur)
		{
			if (kv.first > cur->_kv.first)
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (kv.first < cur->_kv.first)
			{
				parent = cur;
				cur = cur->_left;
			}
			else
			{
				return false;
			}
		}
		//插入节点
		cur = new Node(kv);
		if (parent->_kv.first < kv.first)
		{
			parent->_right = cur;
			cur->_parent = parent;
		}
		else
		{
			parent->_left = 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 if (parent->bf == -2 || parent->bf == 2)
			{
				//开始旋转,旋转后退出
				//单纯左边高,右旋
				if (parent->bf == -2 && cur->bf == -1)
				{
					RoateR(parent);
				}
				//单纯右边高,左旋
				else if (parent->bf == 2 && cur->bf == 1)
				{
					RoateL(parent);
				}
				//左边高, 左右双旋
				else if (parent->bf == -2 && cur->bf == 1)
				{
					RoateRL(parent);
				}
				//右边高,右左双旋
				else if (parent->bf == 2 && cur->bf == -1)
				{
					RoateRL(parent);
				}
				break;
			}
			else
			{
				assert(false);
			}
		}
		return true;
	}

 

旋转分类

左旋

单纯右边高,此时进行左旋 

 

 

void RoateL(Node* parent)
	{
		//更改链接关系
		Node* parentparent = parent->_parent;
		Node* subR = parent->_right;
		Node* subRL = subR->_left;
		parent->_right = subRL;
		if (subRL)
		{
			subRL->_parent = parent;
		}
		subR->_left = parent;
		parent->_parent = subR;
		if (parentparent == nullptr)
		{
			_root = subR;
			subR->_parent = nullptr;
		}
		else
		{
			if (parentparent->_left == parent)
			{
				parentparent->_left = subR;
				subR->_parent = parentparent;
			}
			else
			{
				parentparent->_right = subR;
				subR->_parent = parentparent;
			}
		}
		//调节平衡因子
		parent->bf = 0;
		subR->bf = 0;
	}

 

右旋

单纯左边高,此时进行右旋 

 

void RoateR(Node* parent)
	{
		//更改链接关系
		Node* parentparent = parent->_parent;
		Node* subL = parent->_left;
		Node* subLR = subL->_right;
		parent->_left = subLR;
		if (subLR)
		{
			subLR->_parent = parent;
		}
		subL->_right = parent;
		parent->_parent = subL;
		if (parentparent == nullptr)
		{
			_root = subL;
			subL->_parent = nullptr;
		}
		else
		{
			if (parentparent->_left == parent)
			{
				parentparent->_left = subL;
				subL->_parent = parentparent;
			}
			else
			{
				parentparent->_right = subL;
				subL->_parent = parentparent;
			}
		}
		//调节平衡因子
		parent->bf = 0;
		subL->bf = 0;
	}

 

左右双旋

 

 

void RoateLR(Node* parent)
	{
		Node* subL = parent->_left;
		Node* subLR = subL->_right;
		int bf = subLR->bf;
		RoateL(subL);
		RoateR(parent);
		//调节平衡因子
		if (bf == 0)
		{
			parent->bf = 0;
			subL->bf = 0;
		}
		else if (bf == -1)
		{
			parent->bf = 1;
			subL->bf = 0;
			subLR->bf = 0;
		}
		else if(bf == 1)
		{
			parent->bf = 0;
			subL->bf = -1;
			subLR->bf = 0;
		}
		else
		{
			assert(false);
		}
	}

 

右左双旋

 

 

void RoateRL(Node* parent)
	{
		Node* subR = parent->_right;
		Node* subRL = subR->_left;
		int bf = subRL->bf;
		RoateR(subR);
		RoateL(parent);
		if (bf == 0)
		{
			parent->bf = 0;
			subR->bf = 0;
		}
		else if (bf == -1)
		{
			parent->bf = 0;
			subR->bf = 1;
			subRL->bf = 0;
		}
		else if(bf == 1)
		{
			parent->bf = -1;
			subR->bf = 0;
			subRL->bf = 0;
		}
		else
		{
			assert(false);
		}

	}

 AVL树验证

如果验证是否是AVL树?

1.先对当前节点求出左右子树高度差,与平衡因子比较是否相等,并确定高度差绝对值是否小于2 

2. 验证左子树是否平衡,验证右子树是否平衡

int Height(Node* root)
	{
		if (root == nullptr)
		{
			return 0;
		}
		int lefth = Height(root->_left);
		int righth = Height(root->_right);
		return lefth > righth ? lefth + 1 : righth + 1;
	}
	bool isBanlance()
	{
		return _isBanlance(_root);
	}
	bool _isBanlance(Node* root)
	{
		if (root == nullptr)
		{
			return true;
		}
		int left = Height(root->_left);
		int right = Height(root->_right);
		if ((right-left) != root->bf)
		{
			cout << root->_kv.first << "现在是:" << root->bf << endl;
			cout << root->_kv.first << "应该是:" << (right - left) << endl;
			return false;
		}

		return abs(left - right) < 2 && _isBanlance(root->_left)
			&& _isBanlance(root->_right);
	}

AVL树删除

 AVL树作为了解型数据结构,只需掌握插入即可,如有兴趣,可以查看算法导论里AVL树的删除。

AVL树的性能 

 查找效率为logn,但是如果对AVL树进行结构修改,它会旋转很多次,因此如果需要高效查找并且不改变数据个数,可以考虑AVL树。

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

嚞譶

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

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

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

打赏作者

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

抵扣说明:

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

余额充值