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

更新平衡因子

旋转后 subLparent 的平衡因子均重置为 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 的右孩子 subRsubR 的左子树 subRL。这两个节点是旋转过程中的关键桥梁,后续操作依赖它们的临时存储。

转接子树关系

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

完成旋转核心操作

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

处理上层父节点对接

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

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

平衡因子重置

旋转后,subRparent 的平衡因子均置为 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. 预存关键指针与原始平衡因子
    保存父节点左孩子subLsubL的右孩子subLR,提前记录subLR旋转前的平衡因子bf,用于后续更新。
  2. 两步旋转
    ① 对parent的左孩子subL执行左单旋 ,把LR结构转为LL结构;
    ② 对根节点parent执行右单旋,完成整体平衡。
  3. 依据subLR原始bf分三种情况更新平衡因子
    1. bf = -1:新节点插在subLR左子树
      subLR=0subL=0parent=1
    2. bf = 1:新节点插在subLR右子树
      subLR=0subL=-1parent=0
    3. bf = 0subLR就是新插入节点
      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;


}