【知识讲解】 AVL树从基本成员的介绍到核心接口的实现(插入、判断、删除等等)


目录

前言

[Part1. AVL树相关成员介绍](#Part1. AVL树相关成员介绍)

[Part1.1. AVL树节点相关](#Part1.1. AVL树节点相关)

[Part1.2. AVL树本体](#Part1.2. AVL树本体)

[Part2. 四大旋转操作](#Part2. 四大旋转操作)

[Part2.1. 左单旋](#Part2.1. 左单旋)

[Part2.2. 右单旋](#Part2.2. 右单旋)

[Part2.3. 左右双旋](#Part2.3. 左右双旋)

[Part2.4. 右左双旋](#Part2.4. 右左双旋)

[Part3. 平衡因子作用解析](#Part3. 平衡因子作用解析)

[Part3.1. 平衡因子与旋转](#Part3.1. 平衡因子与旋转)

[Part3.2. 平衡因子与向上调整(插入)](#Part3.2. 平衡因子与向上调整(插入))

[Part4. 插入操作](#Part4. 插入操作)

[Part5. 判断操作](#Part5. 判断操作)

[Part6. Find接口](#Part6. Find接口)

[Part7. 删除操作](#Part7. 删除操作)

[Part7.1. 平衡因子与向上调整(删除)](#Part7.1. 平衡因子与向上调整(删除))

[Part7.2. 删除的旋转操作](#Part7.2. 删除的旋转操作)

[Part7.3. 删除的实现](#Part7.3. 删除的实现)

[Part8. 反思与总结](#Part8. 反思与总结)

[Part9. 代码分享](#Part9. 代码分享)

[Part9.1. AVL实现](#Part9.1. AVL实现)

[Part9.2. 测试](#Part9.2. 测试)

[Part10. 结语](#Part10. 结语)


前言

前置知识:【知识讲解】 二叉搜索树的相关知识与实现-CSDN博客


AVL树作为经典的数据结构之一,他的有些接口会稍显复杂,接下来跟随小编的视角来剖析一下它的全部吧。


let's go!!!!!!!!!


Part1. AVL树相关成员介绍

我们先来看构成AVL树的成员是哪些,这方便我们去介绍后续的内容,我们来看:


Part1.1. AVL树节点相关

我们先来看代码:


cpp 复制代码
template<class k,class v>
struct AVLTreeNode
{
	std::pair<k, v> _kv;
	AVLTreeNode<k, v>* _left;
	AVLTreeNode<k, v>* _right;
	AVLTreeNode<k, v>* _parent;
	int _bf;

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

我们来对各个成员详细介绍一下:

<1> _kv:存储数据的地方(key、value)。

<2> _left、_right:当前节点的左右节点。

<3> _parent:当前节点的父亲节点。

<4> _bf:平衡因子,用于衡量当前节点左右子树的情况(_bf=当前节点的右子树高度减去其左子树高度)(插入操作时,插到左子树_bf--,反之++)(后续调整旋转的核心)


Part1.2. AVL树本体

这个就比较简洁了,我们来看代码:


cpp 复制代码
typedef AVLTreeNode<k, v> Node;
Node* _root = nullptr;

通过一个_root来统一管理整棵树。


Part2. 四大旋转操作

虽然这个按道理来说应该放到后面来讲,但是把这个单拿出来详细讲解会对后面的的插入删除有很大的帮助,毕竟这个就是整个AVL树的核心。

四大旋转操作分为左单旋、右单旋、左右双旋、右左双旋,我们来分别看看吧:

Part2.1. 左单旋


代码实现:

cpp 复制代码
void RotateL(Node* parent)
{
	Node* subR = parent->_right;
	Node* subRL = subR->_left;
	subR->_left = parent;
	parent->_right = subRL;
	if (subRL != nullptr)//当h==0的情况
	{
		subRL->_parent = parent;
	}
	subR->_parent = parent->_parent;//记得还要更新_parent
	if (parent == _root)
	{
		_root = subR;
	}
	else
	{
		if (parent->_parent->_left == parent)
		{
			parent->_parent->_left = subR;
		}
		else
		{
			parent->_parent->_right = subR;
		}
	}
	parent->_parent = subR;
	parent->_bf = 0;//更新平衡因子(根据图片上来看)
	subR->_bf = 0;
}

Part2.2. 右单旋


代码实现:

cpp 复制代码
void RotateR(Node* parent)//逻辑同上
{
	Node* subL = parent->_left;
	Node* subLR = subL->_right;
	parent->_left = subLR;
	subL->_right = parent;
	if (subLR != nullptr)
	{
		subLR->_parent = parent;
	}
	subL->_parent = parent->_parent;
	if (parent == _root)
	{
		_root = subL;
	}
	else
	{
		if (parent->_parent->_left == parent)
		{
			parent->_parent->_left = subL;
		}
		else
		{
			parent->_parent->_right = subL;
		}
	}
	parent->_parent = subL;
	subL->_bf = 0;
	parent->_bf = 0;
}

Part2.3. 左右双旋


cpp 复制代码
void RotateLR(Node* parent)
{
	Node* subL = parent->_left;
	int bf = subL->_right->_bf;
	RotateL(subL);
	RotateR(parent);
	if (bf == 1)//更新平衡因子 //由于上面左旋右旋他对于平衡因子都会置为0 估值要修改不是0的就可以
	{
		subL->_bf = -1;
	}
	else if (bf == -1)
	{
		parent->_bf = 1;
	}
	else if (bf == 0)
	{
		;
	}
	else
	{
		assert(false);
	}
}

为什么这里要先采取一个左旋再来右旋呢?首先,这个场景下,是由于左边太'重'才导致的不平衡,因此我们要把左边的节点掰到右边去,这样才可以达到平衡,但是这个场景又不像上面的右单旋,直接右单旋是解决不了问题的。我们可以对比一下两者有什么区别,两者的区别就在于,右单旋在B这个子树中,他的重量是全部都在左边,左右单旋这个场景他是重在右边,因此我们要先用左单旋把重量先移到左边,让这个场景变成适用右单旋的场景,再用右单旋解决问题。
这里的平衡因子的更新也是充满细节,我们来看:



也就是说新增节点具体在左子树,右子树,或者自身作为叶子结点的时候,平衡因子的更新是有区别的,我们可以直接依靠看c结点的_bf来判断是加到哪了,从而来更新上面的平衡因子。


Part2.4. 右左双旋


cpp 复制代码
void RotateRL(Node* parent)//逻辑同上
{
	Node* subR = parent->_right;
	int bf = subR->_left->_bf;
	RotateR(subR);
	RotateL(parent);
	if (bf == 1)
	{
		parent->_bf = -1;
	}
	else if (bf == -1)
	{
		subR->_bf = 1;
	}
	else if (bf == 0)
	{
		;
	}
	else
	{
		assert(false);
	}
}

Part3. 平衡因子作用解析

上面我们这么大费周章的修改平衡因子是为了什么?他的这个作用又是什么?实际上我们可以只通过两个结点的_bf就可以知道我们用哪种旋转了,为什么?我们来看:



Part3.1. 平衡因子与旋转

旋转什么时候发生?当这个节点不平衡的时候,我们具体要对应与哪种旋转呢?我们来看:


<1> 当A处的_bf为2时候,说明右边节点高度高,则我们在最后一定要右旋,但是在那之前具体要左旋来调整还是不要就要具体来看了,具体到哪看?自然是到右边去看(因为是右子树比较重),看什么?看C处的_bf值,如果为1,说明新加的节点是在C的右边,也就是纯粹的右边重,也就是只需要一个整体的右旋就可以解决。反之,要是为-1,说明新加的是在左边,就要先局部左旋将整体调整为右旋的模型,在整体右旋解决。

<2> A处为-2逻辑同上。
也就是说,我们在遇到不平衡的节点时,我们根据++他是2还是-2,具体在到出问题的那边子树,在看那边的_bf值判断调用哪种旋转调整++。


Part3.2. 平衡因子与向上调整(插入)

当我们A处的_bf不为2、-2时候怎么办?什么时候我们要继续向上更新?这里更新的依据是什么?旋转后怎么办,还要继续向上调整吗?针对这些问题我们来看:



首先,我们是否向上调整关键在于我们一系列操作是否改变了树的高度,我们来看上面的图,我们修改的这个树也是上面的结点的子树,当我们调整的这个树高度改变,那么在上面看来就是它的一颗左子树与其右子树之间的高度差改变,也就是我们要继续向上调整了。

那平衡因子是怎么昭示高度改变呢?我们来看:

<1> 调整后_bf为0,说明原本其为1/-1,即就是原本它的子树有一个高,现在相当于加到那个比较矮的子树上了,相当于平衡了,高度不变,不用向上调整。

<2> 调整后_bf为1/-1,说明原本为0(不可能是2/-2,不符合AVL树,说明之前出问题了),0就说明之前是平衡的,现在1/-1,一边子树高了,高度改变,要向上调整。
为什么在插入操作流程旋转不用继续上向上调整了,我们来看:



我们可以数一数,调整前高度为h+2,调整后也是,对于上面四个都是,自然不用继续调整。
前置知识差不多了,我们来看插入和删除吧:


Part4. 插入操作

我们来直接看代码:


cpp 复制代码
bool insert(const std::pair<k, v>& kv)
{
	if (_root == nullptr)
	{
		_root = new Node(kv);
		return true;
	}
	Node* cur = _root;
	Node* parent = nullptr;
	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);
	if (parent->_kv.first > kv.first)
	{
		parent->_left = cur;
	}
	else
	{
		parent->_right = cur;
	}
	cur->_parent = parent;
//前面这些都是二叉平衡树的插入流程 不熟悉的可以看我前面博客
	while (parent)//当parent为nullptr自动退出
	{
		if (cur == parent->_left)//根据新加入的节点更新
		{
			parent->_bf--;
		}
		else
		{
			parent->_bf++;
		}
		if (parent->_bf == 0)//为0不用向上更新 退出
		{
			break;
		}
		else if (parent->_bf == 1 || parent->_bf == -1)//1/-1继续向上更新
		{
			cur = parent;
			parent = parent->_parent;
		}
		else if(parent->_bf == 2 || parent->_bf == -2)//根据_bf来决定用什么旋转
		{
			if (parent->_bf == -2 && cur->_bf == -1)
			{
				RotateR(parent);
			}
			else if (parent->_bf == 2 && cur->_bf == 1)
			{
				RotateL(parent);
			}
			else if (parent->_bf == -2 && cur->_bf == 1)
			{
				RotateLR(parent);
			}
			else if (parent->_bf == 2 && cur->_bf == -1)
			{
				RotateRL(parent);
			}
			else
			{
				assert(false);
			}
			break;
		}
		else
		{
			assert(false);
		}
	}
	return true;
}

插入操作就是综合前面的知识来,还结合了之前二叉搜索树的插入操作,接下来,我们来看看其他的接口吧。


Part5. 判断操作

我们来看代码:


cpp 复制代码
void IsAVLTree()const
{
	if (_IsAVLTree(_root) == -1)
	{
		cout << "NO" << endl;
	}
	else
	{
		cout << "YES" << endl;
	}
}

int _IsAVLTree(Node* root)const//利用后序遍历 从叶子节点往上判断 时间复杂度为O(N)
{
	if (root == nullptr)
	{
		return 0;
	}
	int left = _IsAVLTree(root->_left);
	int right = _IsAVLTree(root->_right);
	if (left == -1 || right == -1)
	{
		return -1;
	}
	if (abs(left - right) > 1 || root->_bf != right - left)//检查左右高度差以及_bf是否满足条件
	{
		return -1;
	}
	if (left > right)
	{
		right = left;
	}
	return right + 1;
}

Part6. Find接口

我们来看代码:


cpp 复制代码
Node* Find(const k& key)//与二叉搜索树一致
{
	Node* cur = _root;
	while (cur != nullptr)
	{
		if (cur->_kv.second > key)
		{
			cur = cur->_left;
		}
		else if (cur->_kv.second < key)
		{
			cur = cur->_right;
		}
		else
		{
			return cur;
		}
	}
	return nullptr;
}

Part7. 删除操作

删除的逻辑大致上与上面插入相似,不过在一些地方还是有所区别,我们来看看吧:


Part7.1. 平衡因子与向上调整(删除)

删除不与插入相似,对于相同的平衡因子数值,两者的操作会不一样,来看看吧:


<1> 当_bf为0时,说明之前的_bf数值为1或者-1,也就是说之前会有一棵子树的高度高于另一棵,现在删去了多的那一个,导致高度改变,需要向上调整。

<2> 当_bf为1/-1时,说明之前为0,现在是在两个高度相同的子树中的一个删去了,不影响树的整体高度,故直接停止向上调整。

<3> 当_bf为2/-2时,旋转调整,这个与插入有很大区别,来具体看看吧。


Part7.2. 删除的旋转操作


当A处的_bf为2,C处为1时,我们来看旋转的过程:



由于高度改变了,所以在旋转后还要向上调整,对于插入的四个情况是这样的,但是这里与上面的模型不同,b、c的_bf还可以为0,我们来看看当其为0的时候是什么情况:



所以在这种情况下,不用向上调整了,但要注意调整A、B的_bf。


Part7.3. 删除的实现

我们来看代码:


cpp 复制代码
void erase(const k& key)
{
	Node* cur = Find(key);//找到节点
	if (cur == nullptr)
		return;
	Node* parent = cur->_parent;
	int curn = 0;//用这个来标记上次处理是在左子还是右子
	if (cur->_left == nullptr&&cur->_right!=nullptr)//这些与二叉搜索树相似
	{
		if (cur == _root)
		{
			_root = cur->_right;
			_root->_parent = nullptr;
			delete cur;
			return;
		}
		if (parent->_left == cur)
		{
			parent->_left = cur->_right;
			cur->_right->_parent = parent;
			curn = -1;
		}
		else
		{
			parent->_right = cur->_right;
			cur->_right->_parent = parent;
			curn = 1;
		}
		delete cur;
	}
	else if (cur->_left != nullptr && cur->_right == nullptr)
	{
		if (cur == _root)
		{
			_root = cur->_left;
			_root->_parent = nullptr;
			delete cur;
			return;
		}
		if (parent->_left == cur)
		{
			parent->_left = cur->_left;
			cur->_left->_parent = parent;
			curn = -1;
		}
		else
		{
			parent->_right = cur->_left;
			cur->_left->_parent = parent;
			curn = 1;
		}
		delete cur;
	}
	else if (cur->_left == nullptr && cur->_right == nullptr)
	{
		if (cur == _root)
		{
			_root = nullptr;
			delete cur;
			return;
		}
		if (parent->_left == cur)
		{
			parent->_left = nullptr;
			curn = -1;
		}
		else
		{
			parent->_right = nullptr;
			curn = 1;
		}
		delete cur;
	}
	else
	{
		Node* replace = cur->_right;
		while (replace->_left != nullptr)
		{
			replace = replace->_left;
		}
		parent = replace->_parent;
		cur->_kv = replace->_kv;
		if (parent->_left == replace)
		{
			parent->_left = replace->_right;
			if(replace->_right!=nullptr)
			replace->_right->_parent = parent;
			curn = -1;
		}
		else
		{
			parent->_right = replace->_right;
			if (replace->_right != nullptr)
			replace->_right->_parent = parent;
			curn = 1;
		}
		delete replace;
	}
	
	cur = parent->_left;
	if (curn == 1)
	{
		cur = parent->_right;
	}

	while (parent)
	{
		if (curn==-1)//更新_bf
		{
			parent->_bf++;
		}
		else
		{
			parent->_bf--;
		}
		if (parent->_bf == 1 || parent->_bf == -1)//为1/-1时候退出向上调整
		{
			break;
		}
		else if (parent->_bf == 0)//为0的时候更新_bf
		{
			cur = parent;
			parent = parent->_parent;
			if (parent == nullptr)
			{
				break;
			}
			curn = 1;
			if (cur == parent->_left)
			{
				curn = -1;
			}
		}

		else if (parent->_bf == -2)//依靠_bf来旋转
		{
			cur = parent->_left;
			if (cur->_bf == -1)
			{
				RotateR(parent);
				parent = cur->_parent;
			}
			else if(cur->_bf == 1)
			{
				RotateLR(parent);
				parent = parent->_parent->_parent;
				cur = cur->_parent;
			}
			else//为0的时候
			{
				RotateR(parent);
				parent->_bf = -1;
				cur->_bf = 1;
				return;
			}
			if (parent == nullptr)
			{
				break;
			}
			curn = 1;
			if (cur == parent->_left)
			{
				curn = -1;
			}

		}
		else if (parent->_bf == 2)
		{
			cur = parent->_right;
			if (cur->_bf == 1)
			{
				RotateL(parent);
				parent = cur->_parent;
			}
			else if (cur->_bf == -1)
			{
				RotateRL(parent);
				parent = parent->_parent->_parent;
				cur = cur->_parent;
			}
			else
			{
				RotateL(parent);
				parent->_bf = 1;
				cur->_bf = -1;
				return;
			}
			if (parent == nullptr)
			{
				break;
			}
			curn = 1;
			if (cur == parent->_left)
			{
				curn = -1;
			}

		}
	}
}

Part8. 反思与总结

通过上面的一系列过程,其实可以认识到一个结论,那就是整个调整的过程就是依靠平衡因子来实现的,建立模型是为了具象化平衡因子带来的影响,以及在调整后高度是否改变从而来影响是否继续向上调整。所以++平衡因子是全局的关键。++


Part9. 代码分享

Part9.1. AVL实现

cpp 复制代码
#pragma once
#include<iostream>
#include<assert.h>
#include<algorithm>
#include<cstdlib>
#include<vector>
using namespace std;
template<class k,class v>
struct AVLTreeNode
{
	std::pair<k, v> _kv;
	AVLTreeNode<k, v>* _left;
	AVLTreeNode<k, v>* _right;
	AVLTreeNode<k, v>* _parent;
	int _bf;

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

template<class k,class v>
class AVLTree
{
	typedef AVLTreeNode<k, v> Node;

public:
	AVLTree() = default;

	bool insert(const std::pair<k, v>& kv)
	{
		if (_root == nullptr)
		{
			_root = new Node(kv);
			return true;
		}
		Node* cur = _root;
		Node* parent = nullptr;
		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);
		if (parent->_kv.first > kv.first)
		{
			parent->_left = cur;
		}
		else
		{
			parent->_right = cur;
		}
		cur->_parent = parent;
		while (parent)
		{
			if (cur == parent->_left)
			{
				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)
				{
					RotateR(parent);
				}
				else if (parent->_bf == 2 && cur->_bf == 1)
				{
					RotateL(parent);
				}
				else if (parent->_bf == -2 && cur->_bf == 1)
				{
					RotateLR(parent);
				}
				else if (parent->_bf == 2 && cur->_bf == -1)
				{
					RotateRL(parent);
				}
				else
				{
					assert(false);
				}
				break;
			}
			else
			{
				assert(false);
			}
		}
		return true;
	}

	void erase(const k& key)
	{
		Node* cur = Find(key);
		if (cur == nullptr)
			return;
		Node* parent = cur->_parent;
		int curn = 0;
		if (cur->_left == nullptr&&cur->_right!=nullptr)
		{
			if (cur == _root)
			{
				_root = cur->_right;
				_root->_parent = nullptr;
				delete cur;
				return;
			}
			if (parent->_left == cur)
			{
				parent->_left = cur->_right;
				cur->_right->_parent = parent;
				curn = -1;
			}
			else
			{
				parent->_right = cur->_right;
				cur->_right->_parent = parent;
				curn = 1;
			}
			delete cur;
		}
		else if (cur->_left != nullptr && cur->_right == nullptr)
		{
			if (cur == _root)
			{
				_root = cur->_left;
				_root->_parent = nullptr;
				delete cur;
				return;
			}
			if (parent->_left == cur)
			{
				parent->_left = cur->_left;
				cur->_left->_parent = parent;
				curn = -1;
			}
			else
			{
				parent->_right = cur->_left;
				cur->_left->_parent = parent;
				curn = 1;
			}
			delete cur;
		}
		else if (cur->_left == nullptr && cur->_right == nullptr)
		{
			if (cur == _root)
			{
				_root = nullptr;
				delete cur;
				return;
			}
			if (parent->_left == cur)
			{
				parent->_left = nullptr;
				curn = -1;
			}
			else
			{
				parent->_right = nullptr;
				curn = 1;
			}
			delete cur;
		}
		else
		{
			Node* replace = cur->_right;
			while (replace->_left != nullptr)
			{
				replace = replace->_left;
			}
			parent = replace->_parent;
			cur->_kv = replace->_kv;
			if (parent->_left == replace)
			{
				parent->_left = replace->_right;
				if(replace->_right!=nullptr)
				replace->_right->_parent = parent;
				curn = -1;
			}
			else
			{
				parent->_right = replace->_right;
				if (replace->_right != nullptr)
				replace->_right->_parent = parent;
				curn = 1;
			}
			delete replace;
		}
		
		cur = parent->_left;
		if (curn == 1)
		{
			cur = parent->_right;
		}
		while (parent)
		{
			if (curn==-1)
			{
				parent->_bf++;
			}
			else
			{
				parent->_bf--;
			}
			if (parent->_bf == 1 || parent->_bf == -1)
			{
				break;
			}
			else if (parent->_bf == 0)
			{
				cur = parent;
				parent = parent->_parent;
				if (parent == nullptr)
				{
					break;
				}
				curn = 1;
				if (cur == parent->_left)
				{
					curn = -1;
				}
			}

			else if (parent->_bf == -2)
			{
				cur = parent->_left;
				if (cur->_bf == -1)
				{
					RotateR(parent);
					parent = cur->_parent;
				}
				else if(cur->_bf == 1)
				{
					RotateLR(parent);
					parent = parent->_parent->_parent;
					cur = cur->_parent;
				}
				else
				{
					RotateR(parent);
					parent->_bf = -1;
					cur->_bf = 1;
					return;
				}
				if (parent == nullptr)
				{
					break;
				}
				curn = 1;
				if (cur == parent->_left)
				{
					curn = -1;
				}

			}
			else if (parent->_bf == 2)
			{
				cur = parent->_right;
				if (cur->_bf == 1)
				{
					RotateL(parent);
					parent = cur->_parent;
				}
				else if (cur->_bf == -1)
				{
					RotateRL(parent);
					parent = parent->_parent->_parent;
					cur = cur->_parent;
				}
				else
				{
					RotateL(parent);
					parent->_bf = 1;
					cur->_bf = -1;
					return;
				}
				if (parent == nullptr)
				{
					break;
				}
				curn = 1;
				if (cur == parent->_left)
				{
					curn = -1;
				}

			}
		}
	}

	void InOrder()const
	{
		_InOredr(_root);
		cout << endl;
	}

	void IsAVLTree()const
	{
		if (_IsAVLTree(_root) == -1)
		{
			cout << "NO" << endl;
		}
		else
		{
			cout << "YES" << endl;
		}
	}

	size_t Height()const
	{
		return _Height(_root);
	}

	size_t Size()const
	{
		return _Size(_root);
	}

	Node* Find(const k& key)
	{
		Node* cur = _root;
		while (cur != nullptr)
		{
			if (cur->_kv.second > key)
			{
				cur = cur->_left;
			}
			else if (cur->_kv.second < key)
			{
				cur = cur->_right;
			}
			else
			{
				return cur;
			}
		}
		return nullptr;
	}

private:
	void RotateR(Node* parent)
	{
		Node* subL = parent->_left;
		Node* subLR = subL->_right;
		parent->_left = subLR;
		subL->_right = parent;
		if (subLR != nullptr)
		{
			subLR->_parent = parent;
		}
		subL->_parent = parent->_parent;
		if (parent == _root)
		{
			_root = subL;
		}
		else
		{
			if (parent->_parent->_left == parent)
			{
				parent->_parent->_left = subL;
			}
			else
			{
				parent->_parent->_right = subL;
			}
		}
		parent->_parent = subL;
		subL->_bf = 0;
		parent->_bf = 0;
	}

	void RotateL(Node* parent)
	{
		Node* subR = parent->_right;
		Node* subRL = subR->_left;
		subR->_left = parent;
		parent->_right = subRL;
		if (subRL != nullptr)
		{
			subRL->_parent = parent;
		}
		subR->_parent = parent->_parent;
		if (parent == _root)
		{
			_root = subR;
		}
		else
		{
			if (parent->_parent->_left == parent)
			{
				parent->_parent->_left = subR;
			}
			else
			{
				parent->_parent->_right = subR;
			}
		}
		parent->_parent = subR;
		parent->_bf = 0;
		subR->_bf = 0;
	}

	void RotateLR(Node* parent)
	{
		Node* subL = parent->_left;
		int bf = subL->_right->_bf;
		RotateL(subL);
		RotateR(parent);
		if (bf == 1)
		{
			subL->_bf = -1;
		}
		else if (bf == -1)
		{
			parent->_bf = 1;
		}
		else if (bf == 0)
		{
			;
		}
		else
		{
			assert(false);
		}
	}

	void RotateRL(Node* parent)
	{
		Node* subR = parent->_right;
		int bf = subR->_left->_bf;
		RotateR(subR);
		RotateL(parent);
		if (bf == 1)
		{
			parent->_bf = -1;
		}
		else if (bf == -1)
		{
			subR->_bf = 1;
		}
		else if (bf == 0)
		{
			;
		}
		else
		{
			assert(false);
		}
	}

	void _InOredr(Node* root)const
	{
		if (root == nullptr)
			return;
		_InOredr(root->_left);
		cout << root->_kv.second << ":"<<root->_kv.second<<endl;
		_InOredr(root->_right);
	}

	int _IsAVLTree(Node* root)const
	{
		if (root == nullptr)
		{
			return 0;
		}
		int left = _IsAVLTree(root->_left);
		int right = _IsAVLTree(root->_right);
		if (left == -1 || right == -1)
		{
			return -1;
		}
		if (abs(left - right) > 1 || root->_bf != right - left)
		{
			return -1;
		}
		if (left > right)
		{
			right = left;
		}
		return right + 1;
	}

	int _Height(Node* root)const
	{
		if (root == nullptr)
			return 0;
		int leftH = _Height(root->_left);
		int rightH = _Height(root->_right);
		if (leftH > rightH)
		{
			rightH = leftH;
		}
		return rightH + 1;
	}

	int _Size(Node* root)const
	{
		if (root == nullptr)
			return 0;
		int leftSize = _Size(root->_left);
		int rightSize = _Size(root->_right);
		return leftSize + rightSize+1;
	}

	Node* _root = nullptr;
};

Part9.2. 测试

cpp 复制代码
#include"头.h"

void test()
{
	const int N = 1000;
	vector<int> arr;
	arr.reserve(N);
	srand(time(0));
	for (int i = 0; i < N; i++)
	{
		arr.push_back(rand()+i);
	}
	
	//int arr[] = { 54,0,55,16,5,4,29,38,22,14 };
	AVLTree<int, int> aaa;
	for (auto e : arr)
	{
		aaa.insert({e,e});
	}
	for (auto e : arr)
	{
		aaa.erase(e);
		aaa.InOrder();
		aaa.IsAVLTree();
		cout << "--------------------------------------------------------------" << endl;
	}
}
int main()
{
	test();
}

Part10. 结语

这篇文章我们认识到了AVL树的实现,接下来,小编也会带来更复杂的红黑树的讲解,敬请期待~
最后,祝大家可以:春风得意马蹄疾,一日看尽长安花!

最后的最后,要是觉得本文还可以的话,可以点点赞,关注小编一波,谢谢大家!~

相关推荐
可靠的仙人掌2 小时前
SAC(Soft Actor-Critic)算法底座
开发语言·算法·php
海石3 小时前
单调栈复健,顺便,牺牲一下吧,空间复杂度!一切献给AC
算法·leetcode
海石3 小时前
JS击败94%,Hard题想不到动态规划,那就用数组和栈试试
算法·leetcode
码少女4 小时前
数据结构——希尔排序
数据结构·排序算法
星子yu5 小时前
【学习】怎么学好数据结构
数据结构·学习
alphaTao6 小时前
LeetCode 每日一题 2026/7/6-2026/7/12
算法·leetcode
想吃火锅10056 小时前
【leetcode】56.合并区间js
算法·leetcode·职场和发展
imuliuliang6 小时前
可合并堆在多任务调度中的优势与实现技巧7
算法
学究天人6 小时前
数学公理体系大全:Comprehensive Collection of Mathematical Axiom Systems(卷6)
网络·算法·数学建模·动态规划·几何学·图论·拓扑学