AVL树【C++】

目录

前言:

[1 AVL树的概念:](#1 AVL树的概念:)

[2 AVL树更新平衡因子流程:](#2 AVL树更新平衡因子流程:)

[2.1 插入节点](#2.1 插入节点)

[2.2 继续向上更新平衡因子](#2.2 继续向上更新平衡因子)

[2.3 更新结束](#2.3 更新结束)

[3 AVL的旋转](#3 AVL的旋转)

[3.1 右单旋](#3.1 右单旋)

[右旋 RotateR 实现步骤](#右旋 RotateR 实现步骤)

关键代码逻辑示例

[3.2 左单旋](#3.2 左单旋)

[左旋 RotateL 实现步骤](#左旋 RotateL 实现步骤)

关键代码逻辑示例

[3.3 右左双旋](#3.3 右左双旋)

RL双旋(右左双旋)实现步骤

平衡因子更新规则

代码实现示例

[3.4 左右双旋](#3.4 左右双旋)

左右双旋(LR旋转)实现步骤

代码实现示例

[4 判断树是否平衡](#4 判断树是否平衡)

[5 源码实现](#5 源码实现)


前言:

因为二叉搜索树虽然可以缩短查找效率,但如果数据有序或者接近,二叉搜索树将退化为单只树,查找元素相当于在顺序表中搜索元素,效率低下。

下面的AVL树将解决该问题:

1 AVL树的概念:

一棵AVL树或者是空树,或者是具有以下性质的二叉搜索树:

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

这里的加入平衡因子的计算是右 - 左

2 AVL树更新平衡因子流程:

AVL更新平衡因子及其判断这棵树是否需要平衡处理的流程如下:

插入一个节点(可能会影响该节点的祖先节点)

  1. 按照搜索树规则插入
  2. 更新插入节点的祖先节点的平衡因子

a 插入在父节点的左边,父节点的平衡因子--

b 插入在父节点的右边,父节点的平衡因子++

新节点插入后进行判断父亲节点的平衡因子:

c 父节点平衡因子 == 0,父节点所在子树高度不变,不在继续往上更新,插入结束

d 父节点平衡因子 == 1 / -1,父节点所在子树高度变了,继续往上更新

e 父节点平衡因子 == 2 / -2,父节点所在子树已经不平衡了,需要旋转处理

更新中不可能出现其他值,因为插入节点之前是AVL树。

2.1 插入节点

插入新节点cur

2.2 继续向上更新平衡因子

2.3 更新结束

当继续向上更新到cur指向根节点,parent指向空 更新平衡因子结束;

或者当bf == 2 进行旋转调整后,更新平衡因子结束。

AVL树插入节点更新平衡因子逻辑代码:

cpp 复制代码
	bool Insert(const pair<K,V>& kv)
	{
		if (_root == nullptr)
		{
			_root = new Node(kv);
			return true;
		}
		Node* parent = nullptr;	//记录走过的上一个节点的位置
		Node* cur = _root;

		//1 查找要插入的位置
		while (cur)
		{
			if (cur->_kv.first < kv.first)
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (cur->_kv.first > kv.first)
			{
				parent = cur;
				cur = cur->_left;
			}
			else
			{
				return false;	//key 已经有了
			}
		}

		//2 找到空位置,链接插入新节点
		
		//error 因为 cur是局部变量出了作用域就销毁了,没有形成链接
		//cur = new Node(key);
		//return true;

		//链接方法
		//找到空位置,还需要找到该节点的父亲位置
		cur = new Node(kv);
		//判断链接在左边还是在右边
		if (kv.first > parent->_kv.first)
		{
			parent->_right = cur;
		}
		else
		{
			parent->_left = cur;
		}
		//因为这里的使用的是三叉链表
		cur->_parent = parent;	//记录新插入节点的父亲节点

		
		//3 更新平衡因子
		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) 
			{
				//当前子树有问题,需要进行旋转调整平衡


				break; //旋转后平衡退出
			}
			else 
			{
				assert(false);
			}

		}

		return true;

	}

3 AVL的旋转

当平衡因子是 2 或则 -2 时,需要进行旋转来调整平衡

常见的不平衡的四种情况:

3.1 右单旋

右单旋的场景:

当插入新节点是单纯的左边高,通过右单旋可以达到平衡

h == 0是可以直观的看到左边子树高于右边子树,这里就是单纯的左边高,需要进行右单旋转

h == 1新增节点导致的也是单纯的左边高

接下来通过抽象图来分析:

这里的新增节点也是单纯的左边高

右单旋方法:

因为这里是左边高,所以使用右单旋转来维持平衡

旋转方法:右旋, 把b子树变成60(不平衡点)的左边,再把60变成30的右边

右旋 RotateR 实现步骤

暂存关键节点指针

提取父节点 parent 的左孩子 subL 以及 subL 的右子树 subLR,用于后续指针调整。若 subL 为空则旋转无法进行。

调整子树挂载关系

将 subLR 挂载为 parent 的新左子树。若 subLR 非空,需同步更新其父指针指向 parent,确保双向链接正确性。

核心旋转操作

将 parent 节点作为 subL 的右子树挂载,并更新两者的父子指针关系。此步骤完成节点位置交换,形成右旋后的拓扑结构。

处理上层父节点链接

检查 parent 是否为根节点:

  • 若为根节点,直接将 subL 设为新根,其父指针置空;
  • 若非根节点,需判断 parent 原属于其父节点 ppNode 的左或右分支,将 subL 顶替至对应位置,并更新 subL 的父指针指向 ppNode。

更新平衡因子

旋转后 subL 与 parent 的平衡因子均重置为 0,因左子树高度差已通过旋转消除。


关键代码逻辑示例

右单旋逻辑代码:

cpp 复制代码
	void RotateR(Node* parent)
	{
		Node* subL = parent->_left;
		Node* subLR = subL->_right;

		//注意:
		//当subLR子树不为空的时候,修正三叉链表
		parent->_left = subLR;
		if (subLR)	//这里的subLR可能为空,所以需要判断一下
		{
			subLR->_parent = parent;
		}

		subL->_right = parent;

		//这里因为不平衡点也可能是一个子树,所以这里要记录它的父节点
		Node* ppNode = parent->_parent;
		parent->_parent = subL;

		//如果不平衡点是根节点,其父节点直接置空
		if (parent == _root)
		{
			_root = subL;
			_root->_parent = nullptr;
		}
		else
		{
			//如果不平衡点不是是根节点
			if (ppNode->_left == parent)
			{
				ppNode->_left = subL;
			}
			else
			{
				ppNode->_right = subL;
			}

			subL->_parent = ppNode;
		}

		//更新平衡因子
		subL->_bf = parent->_bf = 0;
	}

3.2 左单旋

左单旋的场景:

当插入新节点是单纯的右边高,通过左单旋调整平衡

左单旋方法:

因为这里是单纯的右边高,所以使用左单旋转来维持平衡

旋转方法:左单旋, 把b子树变成30(不平衡点)的右边,再把30变成60的左边

左旋 RotateL 实现步骤

暂存关键节点

提取父节点 parent 的右孩子 subR 和 subR 的左子树 subRL。这两个节点是旋转过程中的关键桥梁,后续操作依赖它们的临时存储。

转接子树关系

将 subRL 挂载为 parent 的右孩子。若 subRL 非空,需同步更新其父指针指向 parent,确保子树父子关系双向绑定。

完成旋转核心操作

将 parent 挂载到 subR 的左孩子位置,建立 subR 与 parent 的父子关系。此时原结构中的右子树 subR 上升为新的局部根节点。

处理上层父节点对接

检查 parent 是否为整棵树的根节点:

  • 若为根节点,直接将 subR 设为新根,并将其父指针置空。
  • 若非根节点,通过 ppNode(原 parent 的父节点)判断 parent 原属左/右分支,将 subR 顶替 parent 的位置,并绑定 subR 与 ppNode 的父子关系。

平衡因子重置

旋转后,subR 和 parent 的平衡因子均置为 0。此操作针对右右失衡场景,旋转后局部子树高度恢复平衡。


关键代码逻辑示例

cpp 复制代码
	//左单旋转
	void RotateL(Node* parent)
	{
		Node* subR = parent->_right;
		Node* subRL = subR->_left;

		//三叉链表修改指向
		parent->_right = subRL;
		if (subRL)
		{
			subRL->_parent = parent;
		}
		subR->_left = parent;

		//这里的不平衡点可能是子树,所以需要修改不平衡点的父节点
		Node* ppNode = parent->_parent;
		parent->_parent = subR;

		//(1 如果不平衡点是根节点 其父节点直接置空)
		if (parent == _root)
		{
			_root = subR;
			_root->_parent = nullptr;
		}
		else
		{
			//(2 如果不平衡点不是根节点 重新判断并修改其父节点的指向)
			if (ppNode->_left == parent)
			{
				ppNode->_left = subR;
			}
			else
			{
				ppNode->_right = subR;
			}

			subR->_parent = ppNode;

		}

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

3.3 右左双旋

右左双旋场景:

具体例子分析:

这里的不平衡因子 parent.bf ==2 ,subL.bf == -1 ,右边高进行左单旋转,旋转后变成左边高 parent.bf == -2,subR.bf ==1, 左边高需要进行右单旋,结果我们发现,进入了不平衡循环。

所以这里就不能使用单旋转,需要使用双旋来解决问题。

a) 这里的不平衡形状是个折线,因为这里是右边高,左边高,经过对左边高subR进行右单旋转,变 成不平衡的斜线形状 ,该情况就变成了单纯的右边高(左单旋可以直接处理的情况)

b) 然后对不平衡点进行单纯左单旋后即可达到平衡

右左双旋方法:

a) h == 0 的时候,subRL的平衡因子等于0,没有左右子树,直接进行右左双旋。

b) 在b子树下插入新节点,导致右边高,左边高,subRL的平衡因子等于-1,新节点插入在左子树,引发旋转。

c ) 在c子树下插入新节点,导致右边高,左边高,subRL的平衡因子等于1,新节点插入在右子树,引发旋转。

RL双旋(右左双旋)实现步骤

旋转操作步骤

对父节点parent的右子树失衡(右子树的左子树过重)执行双旋:

  1. 对parent的右孩子subR执行右单旋(RotateR),使subR的左子树subRL上升为局部根节点。
  2. 对原根节点parent执行左单旋(RotateL),最终以subRL为新的根节点完成平衡。

平衡因子更新规则

平衡因子的调整基于旋转前subRL节点的初始值(bf),分为三种情况:

情况1:subRL.bf = -1

  • 新节点插入在subRL的左子树。
  • 更新后:
    subRL.bf = 0
    subR.bf = 1
    parent.bf = 0

情况2:subRL.bf = 1

  • 新节点插入在subRL的右子树。
  • 更新后:
    subRL.bf = 0
    subR.bf = 0
    parent.bf = -1

情况3:subRL.bf = 0

  • subRL为新增节点(无子树)。
  • 更新后:
    subRL.bf = 0
    subR.bf = 0
    parent.bf = 0

非法平衡因子(非-1/0/1)应触发断言异常。


代码实现示例

cpp 复制代码
	//右左双旋
	void RotateRL(Node* parent)
	{
		//用于更新平衡因子
		Node* subR = parent->_right;
		Node* subRL = subR->_left;

		int bf = subRL->_bf;

		//首先这里的右单旋是对旋转点的右孩子节点进行右单旋
		RotateR(parent->_right);
		//然后再对不平衡的节点进行左单旋
		RotateL(parent);

		//接下来是更新平衡因子
		if (bf == -1)
		{
			//当subRL的平衡因子等于-1,新节点插入在左子树
			//直接更新平衡因子
			subRL->_bf = 0;
			subR->_bf = 1;
			parent->_bf = 0;
		}
		else if (bf == 1)
		{
			//当subRL的平衡因子等于1,新节点插入在右子树
			subRL->_bf = 0;
			subR->_bf = 0;
			parent->_bf = -1;
		}
		else if (bf == 0)
		{

			//当subRL的平衡因子等于0,没有左右子树
			subRL->_bf = 0;
			subR->_bf = 0;
			parent->_bf = 0;
		}
		else
		{
			assert(false);
		}
	}

3.4 左右双旋

左右双旋场景:

当出现左边高,右边的高的情况,需要进行左右双旋处理

左右双旋方法:

a) subLR的平衡因子等于0说明是新增的节点(没有左右子树)。

b )在b子树下插入新节点,导致左边高,右边高,subLR的平衡因子等于-1说明是在subLR的左子树进行插入的,引发旋转。

c ) 在c子树下插入新节点,导致左边高,右边高,subLR的平衡因子等于1说明是在subLR的右子树进行插入的,引发旋转。

左右双旋(LR旋转)实现步骤

核心场景

父节点parent左子树偏高、左子树的右子树偏高(左子树的右孩子过重),属于LR失衡,必须先对左子树左单旋,再对父节点右单旋完成修正。

执行步骤

  1. 预存关键指针与原始平衡因子
    保存父节点左孩子subL、subL的右孩子subLR,提前记录subLR旋转前的平衡因子bf,用于后续更新。
  2. 两步旋转
    ① 对parent的左孩子subL执行左单旋 ,把LR结构转为LL结构;
    ② 对根节点parent执行右单旋,完成整体平衡。
  3. 依据subLR原始bf分三种情况更新平衡因子
    1. bf = -1:新节点插在subLR左子树
      subLR=0、subL=0、parent=1
    2. bf = 1:新节点插在subLR右子树
      subLR=0、subL=-1、parent=0
    3. bf = 0:subLR就是新插入节点
      subLR、subL、parent三者平衡因子全部置0
  4. 非法数值触发断言,做容错校验。

代码实现示例

cpp 复制代码
	//左右双旋
	void RotateLR(Node* parent)
	{

		//用于更新平衡因子
		Node* subL = parent->_left;
		Node* subLR = subL->_right;
		//这里使用subLR的平衡因子来判断平衡因子的更新的几种情况
		int bf = subLR->_bf;	//因为旋转会导致subLR->_bf平衡因子更新,这里先记录subLR的平衡因子


		//这里因为是左边高,右边高
		//1)以不平衡节点的左孩子节点为旋转点进行左单旋
		RotateL(parent->_left);
		//2)经过单纯的左单旋后,变成单纯的左边高,再以不平衡点作为旋转点进行右单旋
		RotateR(parent);
		//旋转后,进行平衡因子的更新
		if (bf == -1)
		{
			//当subLR的平衡因子等于-1说明是在subLR的左子树进行插入的
			subLR->_bf = 0;
			subL->_bf = 0;
			parent->_bf = 1;
		}
		else if (bf == 1)
		{
			//subLR的平衡因子等于1说明是在subLR的右子树进行插入的
			subLR->_bf = 0;
			subL->_bf = -1;
			parent->_bf = 0;
		}
		else if (bf == 0)
		{
			//subLR的平衡因子等于0说明是新增的节点(没有左右子树)
			subLR->_bf = 0;
			subL->_bf = 0;
			parent->_bf = 0;
		}
		else
		{
			assert(false);
		}

	}

4 判断树是否平衡

通过判断左右子树的高度差是否小于2,还可以再加上判断AVL树的平衡因子是否正确 来判断是否平衡

cpp 复制代码
	//判断是否树是否平衡
	bool _IsBalance(Node* root)
	{
		if (root == nullptr)
		{
			return true;
		}

		//判断左右子树的高度差是否小于2
		int leftHeight = _Height(root->_left);
		int rightHeight = _Height(root->_right);
		if (abs(rightHeight- leftHeight) >= 2) 
		{
			return false;
		}

		//判断AVL树的平衡因子是否正确
		if ((rightHeight - leftHeight) != root->_bf)
		{
			//如果当前子树的高度左右子树的高度差 是否等于当前节点平衡因子
			cout << root->_kv.first<<"false" << endl;
			return false;
		}

		//继续递归判断左右子树
		return _IsBalance(root->_left) && _IsBalance(root->_right);

	}

补充:

计算AVL树高:

cpp 复制代码
	//计算树的高度
	int _Height(Node* root) 
	{
		if (root == nullptr) 
		{
			return 0;
		}

		return max(_Height(root->_left),_Height(root->_right)) + 1;
	}

计算该树的总结点个数:

cpp 复制代码
	//计算插入节点个数
	int _Size(Node* root)
	{
		
		return root == nullptr ? 0 : _Size(root->_left) + _Size(root->_right) + 1;
	}

AVL树删除逻辑:

1 按照搜索树规则进行删除

2 删除后更新平衡因子

3 出现不平衡通过旋转调整

当出现bug的时候,可以采用下方的方法:

借助打印和日志来快速锁定范围

5 源码实现

AVL树完整源码实现如下:

cpp 复制代码
#pragma once
#include<assert.h>
#include<iostream>
#include<vector>
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;

	int _bf;	 //balance factor 平衡因子

	//等价下方形式
	//AVLTreeNode<K, V>* _left;
	//AVLTreeNode<K, V>* _right;
	//K _key;
	//V _value;


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

template<class K, class V>
class AVLTree
{
public:
	typedef AVLTreeNode<K, V> Node;
	//插入
	bool Insert(const pair<K, V>& kv)
	{
		if (_root == nullptr)
		{
			_root = new Node(kv);
			return true;
		}
		Node* parent = nullptr;	//记录走过的上一个节点的位置
		Node* cur = _root;

		//1 查找要插入的位置
		while (cur)
		{
			if (cur->_kv.first < kv.first)
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (cur->_kv.first > kv.first)
			{
				parent = cur;
				cur = cur->_left;
			}
			else
			{
				return false;	//key 已经有了
			}
		}

		//2 找到空位置,链接插入新节点

		//error 因为 cur是局部变量出了作用域就销毁了,没有形成链接
		//cur = new Node(key);
		//return true;

		//链接方法
		//找到空位置,还需要找到该节点的父亲位置
		cur = new Node(kv);
		//判断链接在左边还是在右边
		if (kv.first > parent->_kv.first)
		{
			parent->_right = cur;
		}
		else
		{
			parent->_left = cur;
		}
		//因为这里的使用的是三叉链表
		cur->_parent = parent;	//记录新插入节点的父亲节点


		//3 更新平衡因子
		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)
				{
					//右左双旋
					//不平衡是一个折线(右边高,左边高)
					RotateRL(parent);

				}
				else if (parent->_bf == -2 && cur->_bf == 1)
				{
					//双旋
					//(先左边高,右边高,折线)
					RotateLR(parent);

				}

				break; //旋转后平衡退出
			}
			else
			{
				assert(false);
			}

		}

		return true;

	}

	//查找
	Node* Find(const K& key)
	{
		Node* cur = _root;
		while (cur)
		{
			if (key > cur->_kv.first)
			{
				cur = cur->_right;
			}
			else if (key < cur->_kv.first)
			{
				cur = cur->_left;
			}
			else
			{
				return cur;
			}
		}
		return nullptr;	//找不到返回空
	}



	//中序遍历
	//通常使用 友元或者缺省参数或者套一层
	//这里使用套一层
	void InOrder()
	{
		_InOrder(_root);
	}

	//右单旋转
	void RotateR(Node* parent)
	{
		Node* subL = parent->_left;
		Node* subLR = subL->_right;

		//注意:
		//当subLR子树不为空的时候,修正三叉链表
		parent->_left = subLR;
		if (subLR)	//这里的subLR可能为空,所以需要判断一下
		{
			subLR->_parent = parent;
		}

		subL->_right = parent;

		//这里因为不平衡点也可能是一个子树,所以这里要记录它的父节点
		Node* ppNode = parent->_parent;
		parent->_parent = subL;

		//如果不平衡点是根节点,其父节点直接置空
		if (parent == _root)
		{
			_root = subL;
			_root->_parent = nullptr;
		}
		else
		{
			//如果不平衡点不是是根节点
			if (ppNode->_left == parent)
			{
				ppNode->_left = subL;
			}
			else
			{
				ppNode->_right = subL;
			}

			subL->_parent = ppNode;
		}

		//更新平衡因子
		subL->_bf = parent->_bf = 0;
	}

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

		//三叉链表修改指向
		parent->_right = subRL;
		if (subRL)
		{
			subRL->_parent = parent;
		}
		subR->_left = parent;

		//这里的不平衡点可能是子树,所以需要修改不平衡点的父节点
		Node* ppNode = parent->_parent;
		parent->_parent = subR;

		//(1 如果不平衡点是根节点 其父节点直接置空)
		if (parent == _root)
		{
			_root = subR;
			_root->_parent = nullptr;
		}
		else
		{
			//(2 如果不平衡点不是根节点 重新判断并修改其父节点的指向)
			if (ppNode->_left == parent)
			{
				ppNode->_left = subR;
			}
			else
			{
				ppNode->_right = subR;
			}

			subR->_parent = ppNode;

		}

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

	//右左双旋
	void RotateRL(Node* parent)
	{
		//用于更新平衡因子
		Node* subR = parent->_right;
		Node* subRL = subR->_left;

		int bf = subRL->_bf;

		//首先这里的右单旋是对旋转点的右孩子节点进行右单旋
		RotateR(parent->_right);
		//然后再对不平衡的节点进行左单旋
		RotateL(parent);

		//接下来是更新平衡因子
		if (bf == -1)
		{
			//当subRL的平衡因子等于-1,新节点插入在左子树
			//直接更新平衡因子
			subRL->_bf = 0;
			subR->_bf = 1;
			parent->_bf = 0;
		}
		else if (bf == 1)
		{
			//当subRL的平衡因子等于1,新节点插入在右子树
			subRL->_bf = 0;
			subR->_bf = 0;
			parent->_bf = -1;
		}
		else if (bf == 0)
		{

			//当subRL的平衡因子等于0,没有左右子树
			subRL->_bf = 0;
			subR->_bf = 0;
			parent->_bf = 0;
		}
		else
		{
			assert(false);
		}
	}

	//左右双旋
	void RotateLR(Node* parent)
	{

		//用于更新平衡因子
		Node* subL = parent->_left;
		Node* subLR = subL->_right;
		//这里使用subLR的平衡因子来判断平衡因子的更新的几种情况
		int bf = subLR->_bf;	//因为旋转会导致subLR->_bf平衡因子更新,这里先记录subLR的平衡因子


		//这里因为是左边高,右边高
		//1)以不平衡节点的左孩子节点为旋转点进行左单旋
		RotateL(parent->_left);
		//2)经过单纯的左单旋后,变成单纯的左边高,再以不平衡点作为旋转点进行右单旋
		RotateR(parent);
		//旋转后,进行平衡因子的更新
		if (bf == -1)
		{
			//当subLR的平衡因子等于-1说明是在subLR的左子树进行插入的
			subLR->_bf = 0;
			subL->_bf = 0;
			parent->_bf = 1;
		}
		else if (bf == 1)
		{
			//subLR的平衡因子等于1说明是在subLR的右子树进行插入的
			subLR->_bf = 0;
			subL->_bf = -1;
			parent->_bf = 0;
		}
		else if (bf == 0)
		{
			//subLR的平衡因子等于0说明是新增的节点(没有左右子树)
			subLR->_bf = 0;
			subL->_bf = 0;
			parent->_bf = 0;
		}
		else
		{
			assert(false);
		}

	}

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


	int Height()
	{
		return _Height(_root);
	}

	int Size() 
	{
		return _Size(_root);
	}
		



private:

	//计算插入节点个数
	int _Size(Node* root)
	{
		
		return root == nullptr ? 0 : _Size(root->_left) + _Size(root->_right) + 1;
	}

	//计算树的高度
	int _Height(Node* root) 
	{
		if (root == nullptr) 
		{
			return 0;
		}

		return max(_Height(root->_left),_Height(root->_right)) + 1;
	}

	//判断是否树是否平衡
	bool _IsBalance(Node* root)
	{
		if (root == nullptr)
		{
			return true;
		}

		//判断左右子树的高度差是否小于2
		int leftHeight = _Height(root->_left);
		int rightHeight = _Height(root->_right);
		if (abs(rightHeight- leftHeight) >= 2) 
		{
			return false;
		}

		//判断AVL树的平衡因子是否正确
		if ((rightHeight - leftHeight) != root->_bf)
		{
			//如果当前子树的高度左右子树的高度差 是否等于当前节点平衡因子
			cout << root->_kv.first<<"false" << endl;
			return false;
		}

		//继续递归判断左右子树
		return _IsBalance(root->_left) && _IsBalance(root->_right);

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


	Node* _root = nullptr;
};


void TestAVLTree() 
{
	//int a[] = {5,3,7,1,4,6,8,0,2};
	//AVLTree<int, int> t1;
	//for (auto e : a) 
	//{
	//	t1.Insert({e,e});
	//}

	//t1.InOrder();

	int a[] = {8,3,1,10,6,4,7,14,13};
	//int a[] = {1,3,8,6,10,4};
	//int a[] = {4,2,6,1,3,5,15,7,16,14};	//双旋测试
	AVLTree<int, int> t1;
	for (auto e : a) 
	{
		cout << "Insert:" << e << "->" << t1.IsBalance() << endl;
		t1.Insert({e,e});
	}

	t1.InOrder();
	cout << t1.IsBalance() << endl;


}

void TestAVLTree2()
{
	//随机数测试
	const int N = 1000000;
	vector<int> v;
	v.reserve(N);
	srand(time(0));
	for (size_t i = 0; i < N;i++)
	{
		v.push_back(rand()+i);
	}

	size_t begin2 = clock();
	AVLTree<int, int> t;
	for (auto e : v)
	{
		t.Insert(make_pair(e,e));
	}

	size_t end2 = clock();
	
	cout << "Insert:" << end2 - begin2 << endl;
	cout << t.IsBalance() << endl;

	//计算一下树的高度和节点的个数
	cout <<"Tree Height:" << t.Height() << endl;
	cout <<"Tree Size:" << t.Size() << endl;


}