AVL树原理以及插入代码讲解(插入操作画图~细节)

目录

原理

平衡因子

AVL树的插入insert

1. 新节点插入较高左子树的左侧---左左:右单旋

2.新节点插入较高右子树的右侧---右右:左单旋

新节点插入较高左子树的右侧---左右:先左单旋再右单旋

 新节点插入较高右子树的左侧---右左:先右单旋再左单旋​编辑


原理

AVL 树是一种平衡搜索二叉树,得名于其发明者的名字( Adelson-Velskii 以及 Landis)。(可见名字长的好处,命名都能多占一个字母出来)。在搜索树的前提下平衡搜索二叉树还定义如下:

  1. 左右子树的高度差小于等于 1。
  2. 其每一个子树均为平衡二叉树。

我们以SGI版本AVL树

先来查看树中每个结点内容。

template<class K,class V>
	struct AVLTreeNode
	{
		AVLTreeNode* _left;//左子树
		AVLTreeNode* _right;//右子树
		AVLTreeNode* _parent;//父节点
		pair<K, V> _kv;//数据存储内容
		int _bf;//平衡因子

		AVLTreeNode(pair<K, V>kv=pair<K, V>())//默认赋值构造
			:_kv(kv)
			, _left(nullptr)
			, _right(nullptr)
			, _parent(nullptr)
			,_bf(0)
		{}
	};

左子树与右子树指针我们不做过多介绍。

我们存储AVL树是一种存储key_value数据的树,所以我们使用pair库中类型存储数据。

让我们看看平衡因子是什么:

平衡因子

某个结点的右子树的高度减去左子树的高度得到的差值。

平衡因子在[-1,1]之间都是属于平衡的平衡搜索二叉树,每个结点都需要符合这个要求

在插入的过程中我们会破坏平衡,这个时候就需要对树结点进行转至操作。

AVL树的插入insert

和普通搜索二叉树一样,先要寻找插入的位置。

        bool Insert(const pair<K, V>& kv)
		{
			if (_root == nullptr)
			{
				_root = new Node(kv);
			}
			else
			{
				Node* parent = nullptr;//保存上级指针,我们链接都是cur走到空指针创建结点给cur
                                       //但是这个新的结点需要被链接到树中,我们不可以对
                                       //nullptr进行访问上级的数据,所以我们必须留一个parent            
                                       //用来链接新的结点。
				Node* cur = _root;
				while (cur)
				{
					parent = cur;
					if (cur->_kv.first > kv.first)
					{
						cur = cur->_left;//新数据小于当前数据,向cur的左边走
					}
					else if (cur->_kv.first < kv.first)
					{
						cur = cur->_right;//新数据大于当前数据,向cur的右边走
					}
					else
					{
						return false;//数据相同退出,并返回false
					}
				}
				cur = new Node(kv);//cur到了nullptr,创建新的结点。
                
                //新结点链接到树
				if (parent->_kv.first <cur->_kv.first)
				{
					parent->_right = cur;
				}
				else
				{
					parent->_left = cur;
				}
				cur->_parent = parent;//处理新结点的_parent

插入结点后我们需要修改平衡因子,确保插入数据后我们的树依旧是AVL树。

 更新平衡因子规则:

  1.  新增在右,parent->bf+ +;新增在左,parent->bf--;
  2. 更新后,parent->bf == 1 or -1,说明parent插入前的平衡因子是0,说明左右子树高度相等,插入后有一边高,parent高度变了,该节点插入稍稍改变平衡,需要继续往上更新平衡因子。
  3. 重新后,parent->bf == 0说parent插入前的平衡因子是1 or -1,说明左右子树一边高一边低,插入后两边一样高,插入填上了矮了那边,parent所在子树高度不变,不需要继续往上更新
  4. 更新后,parent->bf == 2 or -2,说明parent插入前的平衡因子是1 or -1,已经平衡临界值,插入变成2 or -2,打破平衡,parent所在子树需要旋转处理
  5. 更新后,parent->bf > 2 r< -2的值,不可能,如果存在,则说明插入前就不是AVL树,需要去检查之前操作的问题,不需要再去考虑现在代码的问题了。
while (parent)
{

	if (parent->_right == cur)//根结点(praent)的右子树(cur)插入了一个结点当前根结点平衡因子++
	{
		++parent->_bf;
	}
	else /*if()  可以不写这个*///根结点(praent)的左子树(cur)插入了一个结点当前根结点平衡因子--
	{
		--parent->_bf;
	}
	if (parent->_bf == 0)//修改更新平衡因子后,查看当前平衡因子,为0代表根补齐了该根的低子树
                         //parent所在子树高度不变,不需要继续往上更新
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

云的小站

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

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

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

打赏作者

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

抵扣说明:

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

余额充值