前言:
●在普通二叉搜索树的使用过程中,数据有序插入极易退化成一条单链表,查询、插入的时间复杂度直接劣化为O(N)O(N)O(N),效率大打折扣。为解决二叉搜索树的失衡缺陷,1962年前苏联科学家G. M. Adelson-Velsky 与E. M. Landis 正式提出AVL树,这也是计算机领域诞生的第一款自平衡二叉搜索树。
●AVL树本质依旧是二叉搜索树 ,在此基础上新增了严苛的平衡约束:整棵树为空树,或是左右子树均为合法AVL树,且同一节点左右两棵子树的高度差值绝对值必须≤1 。为了直观管控平衡状态,我们引入平衡因子 :平衡因子 = 右子树高度 − 左子树高度,一颗合法AVL树所有节点的平衡因子只允许为-1、0、1三个数值。

●或许有人会产生疑问:平衡因子全部为0、左右子树高度完全一致,平衡效果不是最优吗?实际场景里该条件无法永久达成,像2个节点、4个节点的树形结构,天然无法做到左右高度完全相等,因此限定高度差不超过1是兼顾合理性与平衡性的最优方案。
●依靠这套平衡机制,AVL树的整体树高被稳定约束在logN\log NlogN区间,插入、删除、查找所有操作的时间复杂度稳定维持O(logN)O(\log N)O(logN),彻底解决了普通BST极端情况下效率崩盘的问题,也成为后续学习红黑树等平衡树结构的重要基石。
一、AVL树的结构
(1)代码:
cpp
template<class K, class V>
struct AVLTreeNode
{
// 需要parent指针,后续更新平衡因子可以看到
pair<K, V> _kv;
AVLTreeNode<K, V>* _left;
AVLTreeNode<K, V>* _right;
AVLTreeNode<K, V>* _parent;
int _bf; // balance factor 平衡因子
AVLTreeNode(const 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:
//...
private:
Node* _root = nullptr;
};
(2)逐段详解
1、AVLTreeNode 节点结构体(每个树节点的成员)
| 成员 | 作用说明 |
|---|---|
pair<K, V> _kv |
存储键值对,K为关键字(用于二叉搜索树排序),V为对应数据 |
_left / _right |
左右孩子指针,搭建二叉树拓扑结构 |
_parent |
父节点指针,核心作用:向上回溯更新祖先节点的平衡因子、失衡时向上查找需要旋转处理的节点 |
int _bf |
平衡因子,标准定义:bf = 右子树高度 - 左子树高度;合法AVL节点bf只能是 -1、0、1 |
| 构造函数 | 初始化键值,左右、父指针全部置空,平衡因子默认初始化为0(新建叶子节点左右都为空,高度差为0) |
2、外层 AVLTree 管理类
typedef AVLTreeNode<K, V> Node;
类型别名,简化代码书写,后续直接用Node代替长长的节点全名。- 公开区域
public:对外接口(插入、删除、查找、遍历等功能函数) - 私有成员
Node* _root = nullptr;
整棵AVL树的根节点指针,初始为空代表空树,封装在private中禁止外部直接修改根节点。
二、AVL树的插入
(1)AVL树插入一个值的大概过程
- 按BST(二叉搜索树)规则插入新节点:比较key找到空位,生成叶子节点,双亲、左右指针绑定,平衡因子初始化为0。
- 沿父节点向上回溯更新平衡因子:新节点在左,祖先bf-1;在右,祖先bf+1。
- 校验平衡因子
- 祖先bf为0:上层高度无变化,直接结束;
- 祖先为±1:继续向上遍历;
- 祖先为±2:节点失衡,进入旋转修正。
- 根据失衡类型执行对应旋转:右旋(RotateR)、左旋(RotateL)、左右旋(RotateLR)、右左旋(RotateRL),旋转后重置相关节点平衡因子。
- 旋转完成,整棵树恢复平衡,插入流程结束。
(2)平衡因更新
基础公式:
平衡因子 bfbfbf = 右子树高度 − 左子树高度
插入节点仅会升高对应分支高度,顺着父节点向上逐层修改bfbfbf:
- 新节点在父节点右子树 :父bf+1bf\boldsymbol{+1}bf+1
- 新节点在父节点左子树 :父bf−1bf\boldsymbol{-1}bf−1
三种终止更新的情况:
1. 更新后 bf = 0
插入补齐了矮的一侧,当前子树总高度不变,上层节点不受影响,更新停止。

- 更新后 bf = 1 / -1
子树高度变大,会继续影响上层祖先,必须向上继续更新。 - 更新后 bf = 2 / -2(失衡)
子树失去平衡,执行对应旋转;旋转后子树高度复原,无需向上更新,插入流程直接结束。

如果一路更新到根节点,根节点bf为±1时直接终止更新。

(3)插入结点及更新平衡因子的代码实现
代码:
cpp
bool Insert(const pair<K, V>& kv)
{
// 1、空树,直接新建根节点
if (_root == nullptr)
{
_root = new Node(kv);
return true;
}
Node* parent = nullptr;
Node* cur = _root;
// 2、BST查找插入位置
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;
}
}
// 3、创建新节点,挂载到父节点左右孩子
cur = new Node(kv);
if (parent->_kv.first < kv.first)
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
cur->_parent = parent;
// 4、向上回溯更新平衡因子
while (parent)
{
// 新节点在左:bf-1;在右:bf+1
if (cur == parent->_left)
parent->_bf--;
else
parent->_bf++;
if (parent->_bf == 0)
{
// 子树高度不变,无需向上更新,直接退出循环
break;
}
else if (parent->_bf == 1 || parent->_bf == -1)
{
// 子树高度升高,继续向上更新祖先bf
cur = parent;
parent = parent->_parent;
}
else if (parent->_bf == 2 || parent->_bf == -2)
{
// 平衡被破坏,需要执行旋转矫正,跳出循环去处理旋转
break;
}
else
{
// 合法AVL不会走到这里,断言报错
assert(false);
}
}
return true;
}
分段讲解
(1)BST标准插入逻辑(前半段代码)
- 树为空:直接new节点作为根节点。
while(cur)遍历树:按照二叉搜索树规则,小值走左、大值走右,记录目标位置的父节点parent。- 遇到相等key:直接return false,AVL不允许重复关键字。
- 找到空位后创建新节点,绑定父子双向指针。
(2)平衡因子更新核心逻辑(while(parent)循环)
① 修改父节点平衡因子
新节点是父节点左孩子 → bf -= 1
新节点是父节点右孩子 → bf += 1
② 三种分支判断(对应之前的更新规则)
- parent->_bf == 0
插入补齐了矮的一侧,当前子树整体高度没变,上层节点不受影响,break结束更新。 - parent->_bf == ±1
当前子树高度增加,会影响上层所有祖先,把parent赋值给cur,继续向上循环更新祖辈平衡因子。 - parent->_bf == ±2
树已经失衡,终止因子更新,跳出循环,后续编写左旋/右旋函数完成树的平衡修复。 - else分支:正常运行不会进入,用
assert(false)捕获异常bug。
三、旋转
旋转主要讲右单旋(RotateR)和左右双旋(RotateLR),剩下的左单旋(RotateL)和右左双旋(RotateRL)和他们大同小异。
(1)右单旋
1、模型讲解
-
模型通用性
以节点10(失衡节点
parent)为根,a、b、c为三棵高度均为h的合法AVL子树,该抽象模型可以囊括所有LL失衡、需要右单旋的全部场景;节点10既可以是整棵树根,也可以只是树内某个局部子树根。 -
失衡产生原因
向
a子树插入新节点 →a高度由h升高为h+1,向上逐层更新平衡因子,最终节点10平衡因子由-1变为-2,左右子树高度差大于1,触发AVL失衡。 -
右单旋核心操作(依托数值有序性:5 < b子树全部值 < 10)
① 将
b(subLR)挂载为失衡节点parent(10)的左子树;② 把原失衡节点
parent(10)设置为subL(5)的右子树;③
subL(5)升级成为该局部树的新根。整套操作全程保留二叉搜索树的有序特性。
总模型:

- 旋转带来的效果
① 树形重新满足AVL平衡约束;
② 该局部树整体高度回落至插入节点前的数值;
③ 若10原本只是上层树的局部子树,本次旋转后无需再向上修正祖先平衡因子,插入流程直接结束。
情况1:

情况2:

情况3:

情况4:

情况···(以此类推)
一定要记住总模型

cpp
void RotateR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
// 1、将subLR挂载到parent左孩子
parent->_left = subLR;
if (subLR)
subLR->_parent = parent;
Node* parentParent = parent->_parent;
// 2、parent降级为subL的右孩子
subL->_right = parent;
parent->_parent = subL;
// 3、subL对接上层节点parentParent
if (parentParent == nullptr)
{
// parent原本是整棵树的根
_root = subL;
subL->_parent = nullptr;
}
else
{
// 判断原parent是上层的左/右孩子,替换成subL
if (parent == parentParent->_left)
{
parentParent->_left = subL;
}
else
{
parentParent->_right = subL;
}
subL->_parent = parentParent;
}
// 4、LL右旋后两个节点平衡因子全部置0
parent->_bf = subL->_bf = 0;
}
讲解:
①定义核心指针
cpp
Node* subL = parent->_left; // parent(失衡点)的左孩子,旋转后上位成为局部新根
Node* subLR = subL->_right; // subL的右子树,需要过继给parent
②交接subLR子树
cpp
parent->_left = subLR;
if (subLR)
subLR->_parent = parent;
把subL原本的右子树subLR,交给失衡节点parent作为左孩子;
subLR不为空时必须修改自身父指针,双向绑定指针。
③parent降级,挂载到subL右侧
cpp
subL->_right = parent;
parent->_parent = subL;
原失衡节点parent变成subL的右子节点,完成上下级互换。
④subL对接上层父节点 parentParent
- if(parentParent == nullptr) :parent是整棵AVL树的根节点,直接把类成员
_root更新为subL - else:判断原来parent是上层节点的左/右分支,用subL替换parent的位置,并赋值subL的父指针
⑤平衡因子刷新
cpp
parent->_bf = subL->_bf = 0;
LL型右旋完成后,parent、subL左右子树高度全部平齐,平衡因子固定归零,上层不需要继续向上更新bf,插入流程直接结束。
(2)左单旋
总模型:

代码展示:
cpp
void RotateL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
parent->_right = subRL;
if(subRL)
subRL->_parent = parent;
Node* parentParent = parent->_parent;
subR->_left = parent;
parent->_parent = subR;
if (parentParent == nullptr)
{
_root = subR;
subR->_parent = nullptr;
}
else
{
if (parent == parentParent->_left)
{
parentParent->_left = subR;
}
else
{
parentParent->_right = subR;
}
subR->_parent = parentParent;
}
parent->_bf = subR->_bf = 0;
}
(3)左右双旋
通过情况1和情况2可以看到,左边高时,如果插入位置不是在a子树,而是插入在b子树,b子树高度从h变成h+1,引发旋转,右单旋无法解决问题 ,右单旋后,我们的树依旧不平衡 。右单旋解决的纯粹的左边高,但是插入在b子树中,10为跟的子树不再是单纯的左边高,对于10是左边高,但是对于5是右边高,需要用两次旋转才能解决 ,以5为旋转点进行一个左单旋,以10为旋转点进行一个右单旋,这棵树这棵树就平衡了。


图1和图2分别为左右双旋中h=0和h=1具体场景分析,下面我们将a/b/c子树抽象为高度h的AVL子树进行分析,另外我们需要把b子树的细节进一步展开为8和左子树高度为h-1的e和f子树,因为我们要对b的父亲5为旋转点进行左单旋,左单旋需要动b树中的左子树。b子树中新增结点的位置不同,平衡因子更新的细节也不同,通过观察8的平衡因子不同,这里我们要分三个场景讨论。
-
场景1:h >= 1时,新增结点插入在e子树,e子树高度从h-1并为h并不断更新8->5->10平衡因子,引发旋转,其中8的平衡因子为-1,旋转后8和5平衡因子为0,10平衡因子为1。

-
场景2:h >= 1时,新增结点插入在f子树,f子树高度从h-1变为h并不断更新8->5->10平衡因子,引发旋转,其中8的平衡因子为1,旋转后8和10平衡因子为0,5平衡因子为-1。

-
场景3:h == 0时,a/b/c都是空树,b自己就是一个新增结点,不断更新5->10平衡因子,引发旋转,其中8的平衡因子为0,旋转后8和10和5平衡因子均为0。

代码:
c
void RotateLR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
int bf = subLR->_bf;
RotateL(parent->_left);
RotateR(parent);
if (bf == 0)
{
subL->_bf = 0;
subLR->_bf = 0;
parent->_bf = 0;
}
else if (bf == -1)
{
subL->_bf = 0;
subLR->_bf = 0;
parent->_bf = 1;
}
else if(bf == 1)
{
subL->_bf = -1;
subLR->_bf = 0;
parent->_bf = 0;
}
else
{
assert(false);
}
}
详细讲解:
1. 函数整体作用
RotateLR:左右双旋 ,用于修正AVL树左子树的右子树插入节点 造成的LR失衡(父节点左孩子偏高、左孩子的右孩子偏高),修复树平衡并正确更新三个关键节点的平衡因子_bf。
2. 变量定义
c
Node* subL = parent->_left; // parent的左孩子(第一次左旋的旋转支点)
Node* subLR = subL->_right; // subL的右孩子,整个失衡结构的中间节点(最终上位的根)
int bf = subLR->_bf; // 记录旋转前subLR的平衡因子,用来区分三种插入场景
3. 双旋转本体
c
RotateL(parent->_left); // 第一步:对parent的左子树执行【左单旋】,把LR型结构转为LL型
RotateR(parent); // 第二步:对parent整体执行【右单旋】,LL型失衡直接修复
左右双旋固定顺序:先左旋左孩子 → 再右旋父节点。
4. 依据bf分场景更新平衡因子(对应上图3种场景)
场景1:bf == 0(原文场景3,h=0,新增节点就是subLR本身)
c
subL->_bf = 0;
subLR->_bf = 0;
parent->_bf = 0;
插入点刚好是subLR节点,旋转后三个节点左右子树等高,平衡因子全部归零。
场景2:bf == -1(原文场景1,节点插入subLR的左子树e)
c
subL->_bf = 0;
subLR->_bf = 0;
parent->_bf = 1;
subLR左子树更高,旋转后:原左孩子subL平衡因子0、中间节点subLR平衡因子0、原父节点parent平衡因子1。
场景3:bf == 1(原文场景2,节点插入subLR的右子树f)
c
subL->_bf = -1;
subLR->_bf = 0;
parent->_bf = 0;
subLR右子树更高,旋转后:原左孩子subL平衡因子-1、中间节点subLR平衡因子0、原父节点parent平衡因子0。
else分支
c
assert(false);
正常插入导致的LR失衡,subLR的bf只可能是-1/0/1,其余数值属于程序异常,断言报错终止程序排查bug。
(4)右左双旋
跟左右双旋类似,下面我们将a/b/c子树抽象为高度h的AVL子树进行分析,另外我们需要把b子树的细节进一步展开为12和左子树高度为h-1的e和f子树,因为我们要对b的父亲15为旋转点进行右单旋,右单旋需要动b树中的右子树。b子树中新增结点的位置不同,平衡因子更新的细节也不同,通过观察12的平衡因子不同,这里我们要分三个场景讨论。
- 场景1:h >= 1时,新增结点插入在e子树,e子树高度从h-1变为h并不断更新12->15->10平衡因子,引发旋转,其中12的平衡因子为-1,旋转后10和12平衡因子为0,15平衡因子为1。

- 场景2:h >= 1时,新增结点插入在f子树,f子树高度从h-1变为h并不断更新12->15->10平衡因子,引发旋转,其中12的平衡因子为1,旋转后15和12平衡因子为0,10平衡因子为-1。

- 场景3:h == 0时,a/b/c都是空树,b自己就是一个新增结点,不断更新15->10平衡因子,引发旋转,其中12的平衡因子为0,旋转后10和12和15平衡因子均为0。

代码:
cpp
void RotateRL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
int bf = subRL->_bf;
RotateR(parent->_right);
RotateL(parent);
if (bf == 0)
{
subR->_bf = 0;
subRL->_bf = 0;
parent->_bf = 0;
}
else if (bf == 1)
{
subR->_bf = 0;
subRL->_bf = 0;
parent->_bf = -1;
}
else if (bf == -1)
{
subR->_bf = 1;
subRL->_bf = 0;
parent->_bf = 0;
}
else
{
assert(false);
}
}
四、AVL树的查找
那二叉搜索树逻辑实现即可,搜索效率为O(logN)O(logN)O(logN)
代码:
c
Node* Find(const K& key)
{
Node* cur = _root;
while (cur)
{
if (cur->_kv.first < key)
{
cur = cur->_right;
}
else if (cur->_kv.first > key)
{
cur = cur->_left;
}
else
{
return cur;
}
}
return nullptr;
}
五、AVL树平衡检测
代码:
cpp
int _Height(Node* root)
{
if (root == nullptr)
return 0;
int leftHeight = _Height(root->_left);
int rightHeight = _Height(root->_right);
return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
}
bool _IsBalanceTree(Node* root)
{
// 空树也是AVL树
if (nullptr == root)
return true;
// 计算root结点的平衡因子:root左右子树的高度差
int leftHeight = _Height(root->_left);
int rightHeight = _Height(root->_right);
int diff = rightHeight - leftHeight;
// 高度差绝对值≥2 → 树失衡,不是合法AVL
if (abs(diff) >= 2)
{
cout << root->_kv.first << "高度差异异常" << endl;
return false;
}
// 代码存储的平衡因子 和 实际计算高度差不一致,说明维护bf出错
if (root->_bf != diff)
{
cout << root->_kv.first << "平衡因子异常" << endl;
return false;
}
// 递归校验左右子树全部平衡,整棵树才是AVL树
return _IsBalanceTree(root->_left) && _IsBalanceTree(root->_right);
}
逐段讲解:
1. _Height 函数:递归计算一棵树的实际高度
cpp
int _Height(Node* root)
{
if (root == nullptr)
return 0;
int leftHeight = _Height(root->_left);
int rightHeight = _Height(root->_right);
return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
}
- 递归基准:空节点高度 = 0
- 后序递归:先算出左子树、右子树高度
- 节点自身高度 = 较高子树高度 + 1(自身节点)
- 用途:校验平衡因子是否正确,不能直接用节点存储的
_bf当作真实高度差
2. _IsBalanceTree:递归校验整棵树是否为标准AVL树
① 基线条件
cpp
if (nullptr == root)
return true;
空树天然满足AVL平衡规则,直接返回true。
② 计算真实平衡差值
cpp
int leftHeight = _Height(root->_left);
int rightHeight = _Height(root->_right);
int diff = rightHeight - leftHeight;
平衡因子定义:右子树高度 − 左子树高度 ,和你旋转代码里_bf定义保持统一。
③ 校验1:高度差是否超标
cpp
if (abs(diff) >= 2)
{
cout << root->_kv.first << "高度差异异常" << endl;
return false;
}
AVL硬性规则:任意节点左右高度差绝对值必须<2,≥2说明旋转逻辑失效,树已经失衡。
④ 校验2:校验代码维护的_bf数值是否准确
cpp
if (root->_bf != diff)
{
cout << root->_kv.first << "平衡因子异常" << endl;
return false;
}
插入/旋转时我们手动修改了每个节点的_bf变量,这里用真实高度差反向核对:
如果存起来的_bf和真实计算的diff对不上,代表更新平衡因子的代码写bug了。
⑤ 递归校验左右子树
cpp
return _IsBalanceTree(root->_left) && _IsBalanceTree(root->_right);
当前节点合法,还要保证左、右两颗子树也全部合法;只有左右都返回true,整棵树才是合格AVL树。
六、完整代码与测试
AVLTree.h:
cpp
#pragma once
#include<iostream>
#include<assert.h>
using namespace std;
template<class K, class V>
struct AVLTreeNode
{
pair<K,V> _kv;
AVLTreeNode<K,V>* _parent;
AVLTreeNode<K, V>* _left;
AVLTreeNode<K, V>* _right;
int _bf;
AVLTreeNode(const pair<K,V>& kv)
:_kv(kv)
,_parent(nullptr)
,_left(nullptr)
,_right(nullptr)
,_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* cur = _root;
Node* parent = nullptr;
while (cur)
{
if (cur->_kv.first<kv.first)
{
parent = cur;
cur = cur->_right;
}
else if(kv.first < cur->_kv.first)
{
parent = cur;
cur = cur->_left;
}
else
{
return false;
}
}
cur = new Node(kv);
if (parent->_kv.first < kv.first)
{
parent->_right = cur;
}
else
{
parent->_left = 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 RotateR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
parent->_left = subLR;
if (subLR)
subLR->_parent = parent;
Node* parentP = parent->_parent;
subL->_right = parent;
parent->_parent = subL;
if (parent == _root)
{
_root = subL;
subL->_parent = nullptr;
}
else
{
if (parentP->_left == parent)
{
parentP->_left = subL;
}
else
{
parentP->_right = subL;
}
subL->_parent = parentP;
}
parent->_bf = subL->_bf = 0;
}
//左单旋
void RotateL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
parent->_right = subRL;
if (subRL)
subRL->_parent = parent;
Node* parentP = parent->_parent;
subR->_left = parent;
parent->_parent = subR;
if (parentP == nullptr)
{
_root = subR;
subR->_parent = nullptr;
}
else
{
if (parent == parentP->_left)
{
parentP->_left = subR;
}
else
{
parentP->_right = subR;
}
subR->_parent = parentP;
}
parent->_bf = subR->_bf = 0;
}
//左右双旋
void RotateLR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
int bf = subLR->_bf;
RotateL(parent->_left);
RotateR(parent);
if (bf == 0)
{
subL->_bf = 0;
subLR->_bf = 0;
parent->_bf = 0;
}
else if (bf == 1)
{
subL->_bf = -1;
subLR->_bf = 0;
parent->_bf = 0;
}
else if (bf == -1)
{
subL->_bf = 0;
subLR->_bf = 0;
parent->_bf = 1;
}
else
{
assert(false);
}
}
//右左双旋
void RotateRL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
int bf = subRL->_bf;
RotateR(parent->_right);
RotateL(parent);
if (bf == 0)
{
subR->_bf = 0;
subRL->_bf = 0;
parent->_bf = 0;
}
else if (bf == 1)
{
subR->_bf = 0;
subRL->_bf = 0;
parent->_bf = -1;
}
else if (bf == -1)
{
subR->_bf = 1;
subRL->_bf = 0;
parent->_bf = 0;
}
else
{
assert(false);
}
}
Node* Find(const K& key)
{
Node* cur = _root;
while (cur)
{
if (cur->_kv.first < key)
{
cur = cur->_right;
}
else if (cur->_kv.first > key)
{
cur = cur->_left;
}
else
{
return cur;
}
}
return nullptr;
}
void InOrder()
{
_InOrder(_root);
cout << endl;
}
int Height()
{
return _Height(_root);
}
int Size()
{
return _Size(_root);
}
bool IsBalanceTree()
{
return _IsBalanceTree(_root);
}
private:
void _InOrder(Node* root)
{
if (root == nullptr)
{
return;
}
_InOrder(root->_left);
cout << root->_kv.first << ":" << root->_kv.second << endl;
_InOrder(root->_right);
}
int _Height(Node* root)
{
if (root == nullptr)
return 0;
int leftHeight = _Height(root->_left);
int rightHeight = _Height(root->_right);
return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
}
int _Size(Node* root)
{
if (root == nullptr)
return 0;
return _Size(root->_left) + _Size(root->_right) + 1;
}
bool _IsBalanceTree(Node* root)
{
if (nullptr == root)
return true;
// 计算pRoot结点的平衡因子:即pRoot左右子树的高度差
int leftHeight = _Height(root->_left);
int rightHeight = _Height(root->_right);
int diff = rightHeight - leftHeight;
// 如果计算出的平衡因子与pRoot的平衡因子不相等,或者
// pRoot平衡因子的绝对值超过1,则一定不是AVL树
if (abs(diff) >= 2)
{
cout << root->_kv.first << "高度差异常" << endl;
return false;
}
if (root->_bf != diff)
{
cout << root->_kv.first << "平衡因子异常" << endl;
return false;
}
// pRoot的左和右如果都是AVL树,则该树一定是AVL树
return _IsBalanceTree(root->_left) && _IsBalanceTree(root->_right);
}
private:
Node* _root=nullptr;
};
test.c:
cpp
#define _CRT_SECURE_NO_WARNINGS
#include"AVLTree.h"
#include<vector>
// 测试代码
void TestAVLTree1()
{
AVLTree<int, int> t;
// 常规的测试用例
//int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
// 特殊的带有双旋场景的测试用例
int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
for (auto e : a)
{
t.Insert({ e, e });
}
t.InOrder();
cout << t.IsBalanceTree() << endl;
}
// 插入一堆随机值,测试平衡,顺便测试一下高度和性能等
void TestAVLTree2()
{
const int N = 100000;
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.IsBalanceTree() << endl;
cout << "Height:" << t.Height() << endl;
cout << "Size:" << t.Size() << endl;
size_t begin1 = clock();
// 确定在的值
/*for (auto e : v)
{
t.Find(e);
}*/
// 随机值
for (size_t i = 0; i < N; i++)
{
t.Find((rand() + i));
}
size_t end1 = clock();
cout << "Find:" << end1 - begin1 << endl;
}
int main()
{
//TestAVLTree1();
TestAVLTree2();
return 0;
}