C++ AVL树(更新中)

前言

二叉搜索树是具有特殊存储结构的树,任意根节点的左子树的所有节点值都比根节点的值小,右子树的所有节点值都比根节点大。
C++ AVL树(更新中)_第1张图片
这种特殊的存储结构使得查找的效率大大提升,为logN。但是还有缺陷。
因为二叉搜索树的构建是一个节点一个节点的插入,每次插入会找到合适的位置,但如果插入的节点的大小是顺序插入的,就会出现歪脖子树
C++ AVL树(更新中)_第2张图片
这样的查找效率还是N,就失去了特性。
而AVL树,平衡二叉搜索树就是在二叉搜索树的基础上,解决了歪脖子树这一特例的树。
接下来,我们就来学习AVL树

C++ AVL树(更新中)_第3张图片

文章目录

  • 前言
  • 一. AVL树
  • 二. AVL树节点的插入
    • 1. 节点的定义
    • 2. 节点的插入
    • 3. 平衡因子更新
    • 4. 左单旋/右单旋
    • 5. 左右双旋
    • 6. 完整代码
  • 四. 完整代码
  • 结束语

一. AVL树

AVL树就是平衡二叉搜索树。为了解决歪脖子的二叉搜索树,我们规定二叉搜索树的每个节点的左右子树高度差的绝对值不超过1。
C++ AVL树(更新中)_第4张图片
节点上的红色数字就是每个节点的高度
而左右子树的高度差就是拿左子树的高度-右子树的高度,或者右子树的高度-左子树的高度。
本篇博客规定,高度差是右子树-左子树。所以15节点的高度差是-1,6节点的高度差是0,7节点的高度差是1。AVL树存储的也是KV值
所有节点的高度差的绝对值都不大于1,那这棵树就是平衡的。

二. AVL树节点的插入

1. 节点的定义

AVL树的实现方式有很多种,本篇博客仅介绍一种。
节点的插入跟二叉搜索树的插入一致,但是当插入节点后,有节点的高度差不符合规定,那么我们需要对这棵树进行调整,所以首先我们可以有一个成员变量,存储当前节点的高度差,我们把它叫作平衡因子
高度的其中一种调整如下图
C++ AVL树(更新中)_第5张图片
节点上黑色的数字是平衡因子,也就是高度差。
可以看到,在插入节点10后,7节点的高度差变成了2,不符合规定,需要调整,我们把这种调整称为旋转
所以新节点的插入会引起祖先节点的平衡因子的改变,所以我们需要回溯,为此我们使用三叉链的树结构。
即节点的定义中,有左孩子指针,右孩子指针,还有双亲指针

节点的定义如下:

//三叉链
template<class K,class V>
struct AVLTreeNode
{
	AVLTreeNode<K,V>*_left;//左指针
	AVLTreeNode<K,V>*_right;//右指针
	AVLTreeNode<K, V>*_parent;//双亲指针
	pair<K, V>_kv;//KV值
	int _bf;//平衡因子
	
	//构造
	AVLTreeNode(const pair<K,V>&kv)
		:_left(nullptr)
		,_right(nullptr)
		,_parent(nullptr)
		,_kv(kv)
		_bf(0)
	{

	}
};

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

这就是AVL树的基本结构。


AVL树,节点的插入同二叉搜索树。但是AVL树要保持平衡,所以在插入后还要根据情况调整节点。
所以AVL节点的插入可以分为3步
1.节点插入
2.平衡因子更新
3.旋转

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 (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;

		return true;
	}

3. 平衡因子更新

我们规定平衡因子是右子树的高度-左子树的高度
所以,如果插入节点是父亲节点的右节点,那么父亲节点的平衡因子就+1
是父亲节点的左节点,那么父亲节点的平衡因子就-1
而插入一个新节点,受影响的只有其祖先
C++ AVL树(更新中)_第6张图片
如果插入4,那么影响的只有左图圈出的部分;如果插入13,那么影响的只有右图圈出的部分。
改变插入节点的父亲节点后,还要不要继续向上调整,有以下三种情况:

  1. 改变后,父节点的平衡因子变成1/-1,代表父节点的平衡因子原先是0
    因为原先父节点的平衡因子是0,变成1/-1后,说明高度变了,那么父节点所在子树也变了,所以需要继续向上更新
  2. 改变后,父节点的平衡因子变成2/-2
    虽然高度也变了,但是已经不平衡了。不需要继续向上更新,而是直接进行旋转,调整高度
  3. 改变后,节点的平衡因子变成0
    说明当前子树变得更平衡了不需要往上更新

插入节点之后更新平衡因子

//更新平衡因子
		while (parent)
		{
			//左减右加
			if (cur == parent->_left)
			{
				--parent->_bf;
			}
			else
			{
				++parent->_bf;
			}

			//判断是否需要继续向上更新
			if (parent->_bf == 1 || parent->_bf == -1)
			{
				//需要继续向上更新
				cur = parent;
				parent = parent->_parent;
			}
			else if (parent->_bf == 2 || parent->_bf == -2)
			{
				//不需要继续更新,需要旋转

				//旋转:1.让AVL树变得更平衡  2.降高度

				break;
			}
			else if (parent->_bf == 0)
			{
				//更平衡了,不需要继续向上更新
				return true;
			}
			else
			{
				//出现别的情况,说明当先AVL树出问题了,直接报错
				assert(false);
			}
		}

4. 左单旋/右单旋

节点的插入和平衡因子的更新都完成后,当parent的平衡因子变成2/-2时,我们还需要根据情况进行不同的旋转

首先是单旋
我们先使用抽象图进行分析
C++ AVL树(更新中)_第7张图片
我们举例h=0/1/2三种情况


C++ AVL树(更新中)_第8张图片
在b位置插入也会改变高度,但不是左单旋,这里先不作讨论


C++ AVL树(更新中)_第9张图片
在b位置插入不是左单旋,此处先不作讨论


C++ AVL树(更新中)_第10张图片
h==2的时候,c的位置一定是x形的
证明如下
C++ AVL树(更新中)_第11张图片
假设c是y形的,那么插入节点有这三种情况
第一种情况变得更平衡了,不需要单旋
第二种情况在子树就已经出现-2,子树就不是AVL树了,更新不到30,不符合
第三种情况同第二种
所以单旋中,c的位置一定是x形,而a/b是任意一种,所以h为2时,树的结构有9种,插入位置有4种,共36种可能,但是都可以利用左单旋解决


接下来,我们就来讲解左单旋的操作步骤
我们以h==1作例子
C++ AVL树(更新中)_第12张图片

首先,b是比30大,比60小的节点
将b变成30的右孩子
再让30变成60的左孩子
最后再更新平衡因子
左单旋就结束了
我们用代码实现一下


我们将需要改变的节点定义一下
C++ AVL树(更新中)_第13张图片

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

		//1. 将subRL变成parent的右节点
		parent->_right = subRL;
		if (subRL)
			subRL->_parent = parent;

		
		//记录当前子树的父节点
		Node*ppnode = parent->_parent;

		//2. 将parent变成subR的左节点
		subR->_left = parent;
		parent->_parent = subR;

		//3. 链接ppnode
		if (ppnode == nullptr)
		{
			//如果是ppnode是空,代表parent是根节点

			//更新根
			_root = subR;
			_root->_parent = nullptr;
		}
		else
		{
			if (ppnode->_left == parent)
			{
				ppnode->_left = subR;
			}
			else
			{
				ppnode->_right = subR;
			}
			subR->_parent = ppnode;
		}

		//4. 更新平衡因子
		parent->_bf = 0;
		subR->_bf = 0;
	}

右单旋的原理根左单旋基本一致
C++ AVL树(更新中)_第14张图片
subLR变成parent的左节点
再将parent变成subL的右节点
更新平衡因子
代码如下:

//右单旋
	void RotateR(Node*parent)
	{
		Node*subL = parent->_left;
		Node*subLR = subL->_right;
		//1.将subLR变成parent的左节点
		parent->_left = subLR;
		//subLR可能是NULL,不是NULL才链接
		if (subLR)
			subLR->_parent = parent;

		//2.再将parent变成subL的右节点
		Node*ppnode = parent->_parent;//因为parent不一定是根节点,所以需要记录爷爷节点
		subL->_right = parent;
		parent->_parent = subL;

		//3.链接parent指针
		if (ppnode == nullptr)
		{
			//如果是根节点
			_root = subL;
			_root->_parent = nullptr;
		}
		else
		{
			//反之不是
			if (ppnode->_left == parent)
			{
				ppnode->_left = subL;
			}
			else
			{
				ppnode->_right = subL;
			}
			subL->_parent = ppnode;
		}

		//4.修改平衡因子
		//parent和subL的平衡因子都变成0
		parent->_bf=subL->_bf=0;
	}

左右单旋的使用时机是

if (parent->_bf == 2 && cur->_bf == 1)
{
	//右边比较高,左单旋
	RotateL(parent);
}
else if (parent->_bf == -2 && cur->_bf == -1)
{
	//左边比较高,右单旋
	RotateR(parent);
}

5. 左右双旋

双旋的抽象图是这样的
C++ AVL树(更新中)_第15张图片
接下来,我们照样分为h=0/1/2,三种情况分析


C++ AVL树(更新中)_第16张图片
h==0的情况其实就是单旋时,在b位置插入节点的情况。此时如果只是左单旋,无法解决问题
C++ AVL树(更新中)_第17张图片


C++ AVL树(更新中)_第18张图片
同样,只左单旋无法解决问题


h==2的情况和单旋时讲解的类似

C++ AVL树(更新中)_第19张图片

双旋

左右双旋
C++ AVL树(更新中)_第20张图片

我们举h=1的情况,插入节点后,AVL树变得不平衡。
我们先对30进行左旋,将左边变得更高
然后再对90右旋,让右边变平衡
最后还需要更新平衡因子

因为旋转后的平衡因子不一定都为0,所以两次单旋后,还需要再更新平衡因子
C++ AVL树(更新中)_第21张图片

有这样三种情况
对应的代码是这样的

//左右双旋
	void RotateLR(Node*parent)
	{
		Node*subL = parent->_left;
		Node*subLR = subL->_right;
		int bf = subLR->_bf;
		//先对subL进行左旋
		RotateL(subL);
		//再对parent右旋
		Rotate(parent);

		//更新平衡因子
		if (bf == 1)
		{
			parent->_bf = 0;
			subL->_bf = -1;
			subLR->_bf = 0;
		}
		else if (bf == -1)
		{
			parent->_bf = 1;
			subL->_bf = 0;
			subLR->_bf = 0;
		}
		else if (bf == 0)
		{
			parent->_bf = 0;
			subL->_bf = 0;
			subLR->_bf = 0;
		}
		else
		{
			//出现其他情况代表出问题了
			assert(false);
		}
	}

右左双旋
右左双旋就是先对subR右旋
再对parent左旋
最后更新平衡因子
对应代码如下:

//右左双旋
	void RotateRL(Node*parent)
	{
		Node*subR = parent->_right;
		Node*subRL = subR->_left;
		int bf = subRL->_bf;
		//先对subR进行右旋
		RotateR(subR);
		//再对parent左旋
		RotateL(parent);

		//更新平衡因子
		if (bf == 1)
		{
			parent->_bf = -1;
			subR->_bf = 0;
			subRL->_bf = 0;
		}
		else if (bf == -1)
		{
			parent->_bf = 0;
			subR->_bf = 1;
			subRL->_bf = 0;
		}
		else if (bf == 0)
		{
			parent->_bf = 0;
			subR->_bf = 0;
			subRL->_bf = 0;
		}
		else
		{
			//出现其他情况代表出问题了
			assert(false);
		}
	}

二者的使用情况如下:

if (parent->_bf == 2 && cur->_bf == -1)
{
	//右左双旋
	RotateRL(parent);
}
else if (parent->_bf == -2 && cur->_bf == 1)
{
	//左右双旋
	RotateLR(parent);
}
else
{
	//出现别的情况
	assert(false);
}

6. 完整代码

	//插入节点
	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);
		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 == 1 || parent->_bf == -1)
			{
				//需要继续向上更新
				cur = parent;
				parent = parent->_parent;
			}
			else if (parent->_bf == 2 || parent->_bf == -2)
			{
				//不需要继续更新,需要旋转

				//旋转:1.让AVL树变得更平衡  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 if (parent->_bf == 0)
			{
				//更平衡了,不需要继续向上更新
				return true;
			}
			else
			{
				//出现别的情况,说明当先AVL树出问题了,直接报错
				assert(false);
			}
		}

		return true;
	}

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

		//1. 将subRL变成parent的右节点
		parent->_right = subRL;
		if (subRL)
			subRL->_parent = parent;

		
		//记录当前子树的父节点
		Node*ppnode = parent->_parent;

		//2. 将parent变成subR的左节点
		subR->_left = parent;
		parent->_parent = subR;

		//3. 链接ppnode
		if (ppnode == nullptr)
		{
			//如果是ppnode是空,代表parent是根节点

			//更新根
			_root = subR;
			_root->_parent = nullptr;
		}
		else
		{
			if (ppnode->_left == parent)
			{
				ppnode->_left = subR;
			}
			else
			{
				ppnode->_right = subR;
			}
			subR->_parent = ppnode;
		}

		//4. 更新平衡因子
		parent->_bf = 0;
		subR->_bf = 0;
	}


	//右单旋
	void RotateR(Node*parent)
	{
		Node*subL = parent->_left;
		Node*subLR = subL->_right;
		//1.将subLR变成parent的左节点
		parent->_left = subLR;
		//subLR可能是NULL,不是NULL才链接
		if (subLR)
			subLR->_parent = parent;

		//2.再将parent变成subL的右节点
		Node*ppnode = parent->_parent;//因为parent不一定是根节点,所以需要记录爷爷节点
		subL->_right = parent;
		parent->_parent = subL;

		//3.链接parent指针
		if (ppnode == nullptr)
		{
			//如果是根节点
			_root = subL;
			_root->_parent = nullptr;
		}
		else
		{
			//反之不是
			if (ppnode->_left == parent)
			{
				ppnode->_left = subL;
			}
			else
			{
				ppnode->_right = subL;
			}
			subL->_parent = ppnode;
		}

		//4.修改平衡因子
		//parent和subL的平衡因子都变成0
		parent->_bf=subL->_bf=0;
	}

	//左右双旋
	void RotateLR(Node*parent)
	{
		Node*subL = parent->_left;
		Node*subLR = subL->_right;
		int bf = subLR->_bf;
		//先对subL进行左旋
		RotateL(subL);
		//再对parent右旋
		RotateR(parent);

		//更新平衡因子
		if (bf == 1)
		{
			parent->_bf = 0;
			subL->_bf = -1;
			subLR->_bf = 0;
		}
		else if (bf == -1)
		{
			parent->_bf = 1;
			subL->_bf = 0;
			subLR->_bf = 0;
		}
		else if (bf == 0)
		{
			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;
		//先对subR进行右旋
		RotateR(subR);
		//再对parent左旋
		RotateL(parent);

		//更新平衡因子
		if (bf == 1)
		{
			parent->_bf = -1;
			subR->_bf = 0;
			subRL->_bf = 0;
		}
		else if (bf == -1)
		{
			parent->_bf = 0;
			subR->_bf = 1;
			subRL->_bf = 0;
		}
		else if (bf == 0)
		{
			parent->_bf = 0;
			subR->_bf = 0;
			subRL->_bf = 0;
		}
		else
		{
			//出现其他情况代表出问题了
			assert(false);
		}
	}

四. 完整代码

#pragma once
#include
#include
using namespace std;

//三叉链
template<class K,class V>
struct AVLTreeNode
{
	AVLTreeNode<K, V>*_left;//左指针
	AVLTreeNode<K, V>*_right;//右指针
	AVLTreeNode<K, V>*_parent;//双亲指针

	pair<K, V>_kv;//KV值

	int _bf;//平衡因子   高度差    右子树高度-左子树高度
	
	//构造
	AVLTreeNode(const pair<K,V>&kv)
		:_left(nullptr)
		,_right(nullptr)
		,_parent(nullptr)
		,_kv(kv)
		,_bf(0)
	{

	}
};

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);
		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 == 1 || parent->_bf == -1)
			{
				//需要继续向上更新
				cur = parent;
				parent = parent->_parent;
			}
			else if (parent->_bf == 2 || parent->_bf == -2)
			{
				//不需要继续更新,需要旋转

				//旋转:1.让AVL树变得更平衡  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 if (parent->_bf == 0)
			{
				//更平衡了,不需要继续向上更新
				return true;
			}
			else
			{
				//出现别的情况,说明当先AVL树出问题了,直接报错
				assert(false);
			}
		}

		return true;
	}

	//中序遍历
	void InOrder()
	{
		_InOrder(_root);
		cout << endl;
	}

	//任意节点的高度
	int Height(Node*root)
	{
		if (root == nullptr)
			return 0;

		int HeightL = Height(root->_left);
		int HeightR = Height(root->_right);

		return HeightL > HeightR ? HeightL + 1 : HeightR + 1;
	}

	//是否是平衡二叉树
	bool IsBalance()
	{
		return _IsBalance(_root);
	}

private:

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

		//1. 将subRL变成parent的右节点
		parent->_right = subRL;
		if (subRL)
			subRL->_parent = parent;

		
		//记录当前子树的父节点
		Node*ppnode = parent->_parent;

		//2. 将parent变成subR的左节点
		subR->_left = parent;
		parent->_parent = subR;

		//3. 链接ppnode
		if (ppnode == nullptr)
		{
			//如果是ppnode是空,代表parent是根节点

			//更新根
			_root = subR;
			_root->_parent = nullptr;
		}
		else
		{
			if (ppnode->_left == parent)
			{
				ppnode->_left = subR;
			}
			else
			{
				ppnode->_right = subR;
			}
			subR->_parent = ppnode;
		}

		//4. 更新平衡因子
		parent->_bf = 0;
		subR->_bf = 0;
	}


	//右单旋
	void RotateR(Node*parent)
	{
		Node*subL = parent->_left;
		Node*subLR = subL->_right;
		//1.将subLR变成parent的左节点
		parent->_left = subLR;
		//subLR可能是NULL,不是NULL才链接
		if (subLR)
			subLR->_parent = parent;

		//2.再将parent变成subL的右节点
		Node*ppnode = parent->_parent;//因为parent不一定是根节点,所以需要记录爷爷节点
		subL->_right = parent;
		parent->_parent = subL;

		//3.链接parent指针
		if (ppnode == nullptr)
		{
			//如果是根节点
			_root = subL;
			_root->_parent = nullptr;
		}
		else
		{
			//反之不是
			if (ppnode->_left == parent)
			{
				ppnode->_left = subL;
			}
			else
			{
				ppnode->_right = subL;
			}
			subL->_parent = ppnode;
		}

		//4.修改平衡因子
		//parent和subL的平衡因子都变成0
		parent->_bf=subL->_bf=0;
	}

	//左右双旋
	void RotateLR(Node*parent)
	{
		Node*subL = parent->_left;
		Node*subLR = subL->_right;
		int bf = subLR->_bf;
		//先对subL进行左旋
		RotateL(subL);
		//再对parent右旋
		RotateR(parent);

		//更新平衡因子
		if (bf == 1)
		{
			parent->_bf = 0;
			subL->_bf = -1;
			subLR->_bf = 0;
		}
		else if (bf == -1)
		{
			parent->_bf = 1;
			subL->_bf = 0;
			subLR->_bf = 0;
		}
		else if (bf == 0)
		{
			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;
		//先对subR进行右旋
		RotateR(subR);
		//再对parent左旋
		RotateL(parent);

		//更新平衡因子
		if (bf == 1)
		{
			parent->_bf = -1;
			subR->_bf = 0;
			subRL->_bf = 0;
		}
		else if (bf == -1)
		{
			parent->_bf = 0;
			subR->_bf = 1;
			subRL->_bf = 0;
		}
		else if (bf == 0)
		{
			parent->_bf = 0;
			subR->_bf = 0;
			subRL->_bf = 0;
		}
		else
		{
			//出现其他情况代表出问题了
			assert(false);
		}
	}

	//中序遍历
	void _InOrder(Node*root)
	{
		if (root == nullptr)
			return;

		_InOrder(root->_left);
		cout << root->_kv.first << " ";
		_InOrder(root->_right);
	}

	//验证是否平衡
	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;

		//高度差
		int diff = rightHeight - leftHeight;

		if (diff != root->_bf || diff > 1 || diff < -1)
			return false;

		//任意节点都要平衡
		return _IsBalance(root->_left) && _IsBalance(root->_right);
	}
private:
	Node*_root=nullptr;
};

结束语

本篇博客没有详细讲解AVL树节点的删除,后续继续更新
删除本身跟插入类似,大致步骤是先找到节点,然后中和二叉搜索树的删除和AVL树的插入
如果删除的不是叶子节点,要考虑托孤,即找其他节点替代原先位置;然后再调节平衡因子
注意:平衡因子的调节,如果调节后parent的平衡因子为1或-1,说明高度没有变为0才说明高度改变,需要继续向上更新。

本篇内容到此就结束了,感谢你的阅读!

如果有补充或者纠正的地方,欢迎评论区补充,纠错。如果觉得本篇文章对你有所帮助的话,不妨点个赞支持一下博主,拜托啦,这对我真的很重要。
在这里插入图片描述

你可能感兴趣的:(C++学习笔记,数据结构与算法,c++,算法,数据结构)