【C++】AVL树

目录

[AVL 树](#AVL 树)

[a. AVL树的实现](#a. AVL树的实现)

(一)树的构建

(二)树的插入


AVL 树

AVL 树又叫平衡二叉树,它也有搜索二叉树的性质,但是:当向二叉搜索树中插入新结点后,能保证每个结点的左右子树高度之差的绝对值不超过1(需要对树中的结点进行调整),即可降低树的高度

a. AVL树的实现

(一)树的构建

代码

	template<class K>
	struct node
	{
		node(const K& t)
		{
			s = t;
		}
		node* left = nullptr;
		node* right = nullptr;
		node* parent = nullptr;
		K s;
		int _bf = 0;
	};

// _bf 是平衡因子,记录左右子树之差,这里我们用 右子树高度 - 左子树高度

// parent 记录它们的父节点

(二)树的插入

实现原理和思路

插入前半部分和搜索二叉树一样,但是在插入时,时刻更新每个节点的平衡因子,和每个节点的父节点,如果向某个父节点插入右子树,则平衡因子++,插入左子树,平衡因子--(这里实现的平衡因子是 右子树高度 - 左子树高度)

插入一个节点后,影响的不只是父节点的平衡因子,还有可能是父节点的父节点的平衡因子

因此,平衡因子有三种可能:

  1. 如果父节点的平衡因子是 -1 或者 1

则父节点的原来的平衡因子是 0 (左右子树平衡),而现在平衡被破坏,则它的父节点的平衡因子也要更改**(所以我们需要向上更改父节点的平衡因子,直到父节点为空,或者平衡因子不属于这一种情况)**

  1. 如果父节点的平衡因子是 0

则现在的树已经平衡了,也不会影响它的父节点的平衡因子,不做任何处理,直接 break

  1. 如果父节点的平衡因子是 2 或者 - 2

则此时AVL树要保持左右子树一定高度(发生旋转)

代码大框架(里层实现没有完成)

template<class K>
class bin_node
{
public:
	typedef node<K>  Node;
	bool insert(K & t)
	{
		if (_root == nullptr)
		{
			_root = new Node(t);
			return true;
		}
		Node* _parent = _root;
		Node* cur = _root;
		while (cur)
		{
			if (cur->s > t)
			{
				_parent = cur;
				cur = cur->left;
			}
			else if (cur->s < t)
			{
				_parent = cur;
				cur = cur->right;
			}
			else
			{
				return false;
			}
		}
		cur = new Node(t);
		if (cur->s > _parent->s)
		{
			cur->parent = _parent;
			_parent->right = cur;
			_parent->_bf++;
		}
		else
		{
			cur->parent = _parent;
			_parent->left = cur;
			_parent->_bf--;
		}
		while (_parent)
		{
			if (_parent->_bf == 1 || _parent->_bf == -1)
			{
				cur = _parent;
				_parent = _parent->parent;
				if (_parent)
				{
					if (_parent->s > cur->s)
					{
						_parent->_bf--;
					}
					else
					{
						_parent->_bf++;
					}
				}
			}
			else if (_parent->_bf == 2 || _parent->_bf == -2)
			{
				 //旋转(代码实现在后面)
			}
			else if(_parent->_bf == 0)
			{
				break;
			}
			else
			{
				assert(false);
			}
		}
		
		return true;
	}

private:
	Node* _root = nullptr;
};

旋转原理

探讨什么时候发生旋转

  1. 第一种情况
  1. 第二种情况

针对第一种情况,举几个示例再细分一下:(向 c 插入节点)

综上:

左单旋:SubR的左子树链接root,root的右子树链接SubRL

我们容易发现,对于发生左单旋的树,root , SubR ,SubRL 的平衡因子都是 0

发生这个场景, root 的平衡因子是 2 ,SubR 的平衡因子是 1

针对第二种情况:(向 a 插入节点)

综上:

SubL的右子树链接root , root的左子树链接SubLR

我们容易发现,对于发生左单旋的树,root , SubL ,SubLR 的平衡因子都是 0

发生这个场景, root 的平衡因子是 -2 ,SubL 的平衡因子是 -1

回到第一种情况:(向 b 插入节点)

综上:

先右单旋,再左单旋

此情况发生在 root 的平衡因子为 2 ,SubR的平衡因子为 - 1

其它的情况照例分析即可(如 h = 1 是 ,插入是右子树)

回到第二种情况(向 b 插入节点)

同理可得: 先左单旋,再右单旋

此情况发生在 root 的平衡因子为 -2 ,SubR的平衡因子为 1

注意:

  1. 注意 根节点特殊情况 和 节点之间的相连(尤其是父节点的链接)
  2. 平衡因子的修改最好举例画图

完整代码

template<class K>
struct node
{
	node(const K& t)
	{
		s = t;
	}
	node* left = nullptr;
	node* right = nullptr;
	node* parent = nullptr;
	K s;
	int _bf = 0;
};
template<class K>
class bin_node
{
public:
	typedef node<K>  Node;
	bool insert(K & t)
	{
		if (_root == nullptr)
		{
			_root = new Node(t);
			return true;
		}
		Node* _parent = _root;
		Node* cur = _root;
		while (cur)
		{
			if (cur->s > t)
			{
				_parent = cur;
				cur = cur->left;
			}
			else if (cur->s < t)
			{
				_parent = cur;
				cur = cur->right;
			}
			else
			{
				return false;
			}
		}
		cur = new Node(t);
		if (cur->s > _parent->s)
		{
			cur->parent = _parent;
			_parent->right = cur;
			_parent->_bf++;
		}
		else
		{
			cur->parent = _parent;
			_parent->left = cur;
			_parent->_bf--;
		}
		while (_parent)
		{
			if (_parent->_bf == 1 || _parent->_bf == -1)
			{
				cur = _parent;
				_parent = _parent->parent;
				if (_parent)
				{
					if (_parent->s > cur->s)
					{
						_parent->_bf--;
					}
					else
					{
						_parent->_bf++;
					}
				}
			}
			else if (_parent->_bf == 2 || _parent->_bf == -2)//旋转
			{
				if (_parent->_bf == 2)
				{

					if (cur->_bf == 1)
					{
						RotateR(_parent);
						
						break;
					}
					else if (cur->_bf == -1)
					{
						RotateRL(_parent);
					}
					else
					{
						assert(false);
					}
				}
				else
				{
					if (cur->_bf == -1)
					{
						RotateR(_parent);
					}
					else if (cur->_bf == 1)
					{
						RotateLR(_parent);
					}
					else
					{
						assert(false);
					}
				}
				break;
			}
			else if(_parent->_bf == 0)
			{
				break;
			}
			else
			{
				assert(false);
			}
		}
		
		return true;
	}
	void InOder()
	{
		_InOder(_root);
	}
private:
	void _InOder(Node* root)
	{
		if (root == nullptr)
		{
			return;
		}
		_InOder(root->left);
		cout << root->s << " ";
		_InOder(root->right);
	}
	void RotateLR(Node* root)  //左右旋转
	{
		Node* SubL = root->left;
		Node* SubLR = SubL->right;
		int n = SubLR->_bf;
		RotateL(SubL);
		RotateR(root);
		if (n == -1)
		{
			SubL->_bf = 0;
			SubLR->_bf = 0;
			root->_bf = 1;
		}
		else if (n == 1)
		{
			SubLR->_bf = 0;
			SubL->_bf = -1;
			root->_bf = 0;
		}
		else if (n == 0)
		{
			SubLR->_bf = 0;
			SubL->_bf = 0;
			root->_bf = 0;
		}
		else
		{
			assert(false);
		}

	}
	void RotateRL(Node* root) //右左旋转
	{
		Node* SubR = root->right;
		Node* SubRL = SubR->left;
		int n = SubRL->_bf;
		RotateR(SubR);
		RotateL(root);
		if (n == -1)
		{
			SubR->_bf = 1;
			SubRL->_bf = 0;
			root->_bf = 0;
		}
		else if (n == 1)
		{
			SubRL->_bf = 0;
			SubR->_bf = 0;
			root->_bf = -1;
		}
		else if (n == 0)
		{
			SubRL->_bf = 0;
			SubR->_bf = 0;
			root->_bf = 0;
		}
		else
		{
			assert(false);
		}
	}
	void RotateL(Node* root)  //左单旋
	{
		Node* SubR = root->right;
		Node* SunRL = SubR->left;
		if (root == _root)
		{
			_root = SubR;
		}
		else
		{
			Node* parent = root->parent;
			if (parent->left == root)
			{
				parent->left = SubR;
			}
			else
			{
				parent->right = SubR;
			}
		}
		root->right = SunRL;
		SubR->left = root;
		SubR->parent = root->parent;
		root->parent = SubR;
		root->_bf = SubR->_bf = 0;
	}
	void RotateR(Node* root)  //右单旋
	{
		Node* SubL = root->left;
		Node* SubLR = SubL->right;
		if (root == _root)
		{
			_root = SubL;
		}
		else
		{
			Node* parent = root->parent;
			if (parent->left == root)
			{
				parent->left = SubL;
			}
			else
			{
				parent->right = SubL;
			}
		}
		root->left = SubLR;
		SubL->right = root;
		SubL->parent = root->parent;
		root->parent = SubL;
		root->_bf = SubL->_bf = 0;
	}
	Node* _root = nullptr;
};
相关推荐
娅娅梨34 分钟前
C++ 错题本--not found for architecture x86_64 问题
开发语言·c++
兵哥工控38 分钟前
MFC工控项目实例二十九主对话框调用子对话框设定参数值
c++·mfc
我爱工作&工作love我1 小时前
1435:【例题3】曲线 一本通 代替三分
c++·算法
娃娃丢没有坏心思1 小时前
C++20 概念与约束(2)—— 初识概念与约束
c语言·c++·现代c++
lexusv8ls600h1 小时前
探索 C++20:C++ 的新纪元
c++·c++20
lexusv8ls600h1 小时前
C++20 中最优雅的那个小特性 - Ranges
c++·c++20
白-胖-子1 小时前
【蓝桥等考C++真题】蓝桥杯等级考试C++组第13级L13真题原题(含答案)-统计数字
开发语言·c++·算法·蓝桥杯·等考·13级
好睡凯1 小时前
c++写一个死锁并且自己解锁
开发语言·c++·算法
依旧阳光的老码农2 小时前
标准C++ 字符串
开发语言·c++
白-胖-子3 小时前
【蓝桥等考C++真题】蓝桥杯等级考试C++组第13级L13真题原题(含答案)-成绩排序
c++·算法·蓝桥杯·真题·蓝桥等考