C++——AVL树

目录

1.AVL树概念

2.AVL树性质

3. 实现

3.1 AVLTreeNode

3.2 Insert

3.3 Inorder

3.4 Height

3.5 IsBalance


1.AVL树概念

AVL树:平衡搜索二叉树

二叉搜索树的数据如果接近有序,就会变为单支树,查找效率降低。AVL树应用一种方法——当左右子树高度差超过1,降低树的高度。使二叉搜索树能够一直保持平衡状态。

2.AVL树性质

  • 左右子树都是AVL树
  • 左右子树高度之差的绝对值不超过1(0/1/-1)

如果AVL树有N个节点。高度=logN,搜索的时间复杂度为O(logN)。

3. 实现

3.1 AVLTreeNode

为了使左右子树高度差不超过1,可以采用很多方法。

在这里通过引入平衡因子来标志左右子树高度差,当平衡因子超过-1或1的时候,降低树的高度。

template<class K, class V>
struct AVLTreeNode
{
	pair<K, V> _kv;
	AVLTreeNode<K, V>* _left;
	AVLTreeNode<K, V>* _right;
	AVLTreeNode<K, V>* _parent;

	int _bf;  // balance factor平衡因子

	AVLTreeNode(const pair<K, V>& kv)
		:_kv(kv)
		, _left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _bf(0)
	{}
};

3.2 Insert

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

成果插入之后,需要更新平衡因子。如果插入到父的左,平衡因子--,如果插入到父的右平衡因子++。然后判断是否需要调整祖先的平衡因子或调整高度。

1.parent->_bf == 0

插入之后,parent左右高度相同了,说明parent树原先就有一个孩子,新增节点刚好是另一个孩子。parent树的高度没变,不需要再往上。


2.parent->_bf == -1 || parent->_bf == 1

父节点的平衡因子原来是0,插入之后++--才会变成1或-1。父这棵树的高度增加了1,祖先的平衡因子也要变,需要往上继续调整。具体往上多少层不能确定,最坏的情况是一直调整到_root。


3.parent->_bf == 2 || parent->_bf == -2

说明parnet之前是1/-1,新增节点后让这颗子树又让这棵树的高度加1。

调整方法为——旋转。

1.让这颗子树树的左右子树高度差不超过1

2.旋转后仍是搜索树

3.更新该子树的平衡因子

4.让这颗子树的高度和之前保持一致,不影响上一层,结束调整平衡因子

1.右边高,新增节点是右孩子(subR)的子树,左单旋

abc是高度为h的子树,紫色是新增节点,高度为1,插入后使子树高度增加1。

左单旋的操作:

1.把subRL放到parent的右,parent放到subR的左。
2.注意链接parent的父(旋转后该子树的根变了)。
3.更新平衡因子。只改变了parent和subR的左右子树,只把这俩的平衡因子改成0。

  • h=0

  • h=1

  • h=2

2. 左边高,新增节点是左孩子的子树,右单旋

3.左边高,新增在左孩子的右子树,左右双旋

新增节点如果使d或e的高度增加1,就会向上调节平衡因子,导致parent变成-2。

1)h为0

2)h不为0

  • 新增在d之下

  • 新增在e之下

单旋中直接控制平衡因子为0的方法已经不适用了,这里新增在d下和e下,平衡因子不同。

可以通过subLR在插入后的平衡因子,推断出在d下还是e下。

4.右边高,新增在右孩子的左子树,右左双旋

1)h为0

2)h不为0

  • 新增在d之下

  • 新增在e只下

template<class K, class V>
class AVLTree
{
	typedef AVLTreeNode<K, V> Node;
public:
	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 (cur->_kv.first > kv.first)
			{
				parent = cur;
				cur = cur->_left;
			}
			else if (cur->_kv.first < kv.first)
			{
				parent = cur;
				cur = cur->_right;
			}
			else
			{
				return false;
			}
		}

		cur = new Node(kv);
		//cur为空时,应该插入新节点。new了之后并不表示和树链接上了,cur只是父节点左或右子树地址的拷贝,修改它(把new出的新节点给cur)对父节点没有一点影响。还需要记录父节点。不清楚cur到底是左还是右,再判断一次。
		if (parent->_kv.first > kv.first)
		{
			parent->_left = cur;
			cur->_parent = parent;
		}
		else
		{
			parent->_right = cur;
			cur->_parent = parent;
		}

		//成功插入之后要更新平衡因子
		while (parent)
		{
			if (cur == parent->_left)
			{
				parent->_bf--;
			}
			else
			{
				parent->_bf++;
			}

			//判断需不需要再向上去调整parent的parent
			if (parent->_bf == 0)//插入之后,parent左右高度相同了,说明parent树原先就有一个孩子,新增节点刚好是另一个孩子。parent树的高度没变,不需要再往上。
			{
				break;
			}
			else if (parent->_bf == -1 || parent->_bf == 1)//父节点的平衡因子原来是0,插入之后++--才会变成1或-1。父这棵树的高度增加了1,祖先的平衡因子也要变,需要往上继续调整。
			{
				cur = parent;
				parent = parent->_parent;
			}
			else if (parent->_bf == 2 || parent->_bf == -2)
			{
				//旋转
				if (parent->_bf == 2 && cur->_bf == 1)//右子树高,左单旋
				{
					RotateL(parent);
				}
				else if(parent->_bf == -2 && cur->_bf == -1)//左子树高,右单旋
				{
					RotateR(parent);
				}
				else if (parent->_bf == 2 || cur->_bf == -1)//双旋,先右后左
				{
					RotateRL(parent);
				}
				else if (parent->_bf == -2 || cur->_bf == 1)//双旋,先左后右
				{
					RotateLR(parent);
				}
				else
				{
					assert(false);
				}

				break;//旋转结束后,高度保持不变,对父没有影响,不需要再往上去调整
			}
			else
			{
				assert(false);
			}
		}

		return true;
	}




	//任务1.把subRL放到parent的右,parent放到subR的左。
	//2.注意链接_parent。注意链接parent的父(旋转后该子树的根变了)
	//3.更新平衡因子。只改变了parent和subR的左右子树,只把这俩的平衡因子改成0。

	void RotateL(Node* parent)
	{
		Node* subR = parent->_right;
		Node* subRL = subR->_left;

		parent->_right = subRL;
		if (subRL)//当h为0的时候,subRL为空
		{
			subRL->_parent = parent;
		}

		Node* ppNode = parent->_parent;

		subR->_left = parent;
		parent->_parent = subR;

		if (ppNode == nullptr)
		{
			_root = subR;
			_root->_parent = nullptr;
		}
		else
		{
			if (ppNode->_left == parent)
			{
				ppNode->_left = subR;
			}
			else
			{
				ppNode->_right = subR;
			}
			subR->_parent = ppNode;
		}

		parent->_bf = subR->_bf = 0;
	}

	void RotateR(Node* parent)//左边高
	{
		Node* subL = parent->_left;
		Node* subLR = subL->_right;
		parent->_left = subLR;
		if (subLR)
		{
			subLR->_parent = parent;
		}

		//parent去subL的右
		Node* ppNode = parent->_parent;
		parent->_parent = subL;
		subL->_right = parent;

		//ppNode和subL
		if (ppNode)
		{
			if (ppNode->_left == parent)
			{
				ppNode->_left = subL;
			}
			else
			{
				ppNode->_right = subL;
			}
			subL->_parent = ppNode;

		}
		else
		{
			_root = subL;
			_root->_parent = nullptr;
		}

		parent->_bf = subL->_bf = 0;

	}

	void RotateLR(Node* parent)
	{
		Node* subL = parent->_left;
		Node* subLR = subL->_right;
		int bf = subLR->_bf;

		RotateL(subL);
		RotateR(parent);

		if (bf == -1)
		{
			subLR->_bf = 0;
			subL->_bf = 0;
			parent->_bf = 1;
		}
		else if (bf == 1)
		{
			subLR->_bf = 0;
			subL->_bf = -1;
			parent->_bf = 0;

		}
		else if (bf == 0)//subLR自己就是新增
		{
			parent->_bf = 0;
			subL->_bf = 0;
			subLR->_bf=0;
		}
		else
		{
			assert (false);
		}
	}

	void RotateRL(Node* parent)
	{
		Node* subR = parent->_right;
		Node* subRL = subR->_left;
		int bf = subRL->_bf;

		RotateR(subR);
		RotateL(parent);

		if (bf == 1)
		{
			subRL->_bf = 0;
			parent->_bf = -1;
			subR->_bf = 0;
		}
		else if (bf == -1)
		{
			subRL->_bf = 0;
			parent->_bf = 0;
			subR->_bf = 1;

		}
		else if (bf == 0)
		{
			subRL->_bf = 0;
			subR->_bf = 0;
			parent->_bf = 0;
		}
		else
		{
			assert(false);
		}

	}

private:
	Node* _root=nullptr;

};

3.3 Inorder

void Inorder()
	{
		_Inorder(_root);
	}

	void _Inorder(Node* root)
	{
		if (root == nullptr)
		{
			return;
		}

		_Inorder(root->_left);
		cout << root->_kv.first << ":" << root->_kv.second << endl;
		_Inorder(root->_right);
	}


	

3.4 Height

int Height(Node* root)
	{
		if (root == nullptr)
		{
			return 0;
		}

		int lh = Height(root->_left);
		int rh = Height(root->_right);

		return lh > rh ? lh + 1 : rh + 1;
	}

3.5 IsBalance

bool IsBalance()
	{
		return _IsBalance(_root);
	}

bool _IsBalance(Node* root)
	{
		if (root == nullptr)
		{
			return true;
		}

		int leftHeight = Height(root->_left);
		int rightHeight = Height(root->_right);

		if (rightHeight - leftHeight != root->_bf)
		{
			cout << root->_kv.first << "平衡因子异常" << endl;
			return false;
		}

		return abs(rightHeight - leftHeight) < 2 
			&& _IsBalance(root->_left) 
			&& _IsBalance(root->_right);
	}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值