AVL 树是最早的自平衡二叉搜索树 (1962 年由 Adelson-Velsky 和 Landis 提出),核心特性是 "左右子树高度差(平衡因子)不超过 1",通过旋转操作 在插入 / 删除后维持平衡,确保所有操作的时间复杂度稳定在
O(logn)(树高严格控制为O(logn))。
核心定义与特性
1. 平衡二叉搜索树的定义
一棵二叉搜索树(左小右大)满足以下条件则为 AVL 树:
-
左、右子树均为 AVL 树;
-
左右子树的高度差(平衡因子)的绝对值 ≤ 1。
2. 关键概念
-
平衡因子(BF):节点的左子树高度 - 右子树高度(取值范围:-1、0、1);
-
树高:空树高度为 - 1(或 0,需统一定义),叶子节点高度为 0(或 1),非叶子节点高度 = 1 + max (左子树高度,右子树高度);
-
失衡:节点的平衡因子绝对值 > 1(即 BF=2 或 BF=-2),需通过旋转修复
-
平衡因子的计算在AVL树中,每个节点的平衡因子只能是-1、0或1:
-
-1:表示左子树比右子树高。
-
0:表示左子树和右子树等高。
-
1:表示右子树比左子树高。
例如,假设一个节点的左子树高度为3,右子树高度为2,那么该节点的平衡因子为:3 - 2 = 1。
3.结构体设计
cpp
typedef struct AVLNode
{
ELEMTYPE2 val;
struct AVLNode* leftchild;
struct AVLNode* rightchild;
int height;
}AVLNode;
相应函数
获取高度函数
cpp
int Get_Height(AVLNode*node){
if(node==NULL)return -1;
return node->height;
}
购买节点函数
cpp
AVLNode* AVLBuyNode(int val)
{
//AVLNode* p = new AVLNode();
AVLNode* p = (AVLNode*)malloc(sizeof(AVLNode));
if (p == nullptr)return nullptr;
p->height = 0;
p->leftchild = nullptr;
p->rightchild = nullptr;
p->val = val;
return p;
}
更新高度函数
cpp
void update_Height(AVLNode* node)
{
if (node == NULL)return;
int left = Get_Height(node->leftchild);
int right = Get_Height(node->rightchild);
node->height = left > right ? left + 1 : right + 1;
}
平衡因子计算函数
cpp
int Get_Blancefactor(AVLNode* node)
{
if (node == NULL)return 0;
int left = Get_Height(node->leftchild);
int right = Get_Height(node->rightchild);
return left - right;
}
单左旋函数
cpp
AVLNode* LL_Rotation(AVLNode * node)
{
if (node == NULL)return NULL;
AVLNode* p = node;
AVLNode* p1 = node->rightchild;
p->rightchild = p1->leftchild;
p1->leftchild = p;
update_Height(p);
update_Height(p1);
return p1;
}
单右旋函数
cpp
AVLNode* RR_Rotation(AVLNode* node)
{
if (node == NULL)return NULL;
AVLNode* p = node;
AVLNode* p1 = node->leftchild;
p->leftchild = p1->rightchild;
p1->rightchild = p;
update_Height(p);
update_Height(p1);
return p1;
}
通用旋转函数
cpp
AVLNode* Rotate(AVLNode* Node) {
if (Node == NULL)return NULL;
int banlace = Get_Blancefactor(Node);
if (banlace == 2) {
int leftbanlance = Get_Blancefactor(Node->leftchild);
if (leftbanlance == -1) {
Node->leftchild = LL_Rotation(Node->leftchild);
return RR_Rotation(Node);
}
else if (leftbanlance == 1) {
return RR_Rotation(Node);
}
}
if (banlace == -2) {
int rightbanlance = Get_Blancefactor(Node->rightchild);
if (rightbanlance == -1) {
return LL_Rotation(Node);
}
else if (rightbanlance == 1) {
Node->rightchild = RR_Rotation(Node->rightchild);
return LL_Rotation(Node);
}
}
return Node;
}
初始化函数
cpp
void Init_AVLtree(AVLTree* pTree)
{
assert(pTree != nullptr);
pTree->root = nullptr;
}
插入函数
cpp
bool Insert_AVLTree(AVLTree* pTree, ELEMTYPE2 val) {
pTree->root = Insert_Helper(pTree->root, val);
return true;
}
AVLNode* Insert_Helper(AVLNode* root, ELEMTYPE2 val) {
if (root == NULL) {
AVLNode* p = AVLBuyNode(val);
return p;
}
else if (root->val < val) {
root->rightchild = Insert_Helper(root->rightchild, val);
}
else if (root->val > val) {
root->leftchild = Insert_Helper(root->leftchild, val);
}
update_Height(root);
root = Rotate(root);
return root;
}
##### 删除函数
```cpp
AVLNode* Delete_Helper(AVLNode* root, ELEMTYPE2 val)
{
if (root == NULL)return NULL;
if (root->val > val) {
root->leftchild = Delete_Helper(root->leftchild, val);
}
else if (root->val < val) {
root->rightchild = Delete_Helper(root->rightchild, val);
}
else {
if (root->leftchild == NULL && root->rightchild == NULL) {
free(root);
root = NULL;
return NULL;
}
else if (root->leftchild && root->rightchild) {
AVLNode* p = root->rightchild;
while (p->leftchild) {
p = p->leftchild;
}
root->val = p->val;
root->rightchild=Delete_Helper(root->rightchild, p->val);
}
else {
AVLNode* p1 = root;
root = root->leftchild;
if (root->rightchild !=NULL) {
root = root->rightchild;
}
free(p1);
p1 = NULL;
return root;
}
}
update_Height(root);
root = Rotate(root);
return root;
}
```
##### 查找函数
```cpp
AVLNode* Search_BSTree(AVLTree* pTree, ELEMTYPE2 val)
{
assert(pTree != NULL);
AVLNode* p1 = pTree->root;
while (p1 != NULL) {
if (p1->val < val) {
p1 = p1->rightchild;
}
else if (p1->val > val) {
p1 = p1->leftchild;
}
else {
return p1;
}
}
return NULL;
}
```
##### 打印函数
```cpp
void Show_inorder(AVLTree* root)
{
assert(root != NULL);
AVLNode* p1 = root->root;
stack<AVLNode*>s1;
while (!s1.empty() || p1 != NULL) {
while (p1 != NULL) {
s1.push(p1);
p1 = p1->leftchild;
}
p1 = s1.top();
s1.pop();
printf("%d ", p1->val);
p1 = p1->rightchild;
}
}
```
AVL 树的时间复杂度与性能
时间复杂度
AVL 树的高度始终为 O (log n)(n 为节点数),因此所有操作的时间复杂度均由树的高度决定:
- 插入:O (log n)(BST 插入 O (log n) + 回溯更新高度 O (log n) + 旋转 O (1));
- 删除:O (log n)(BST 删除 O (log n) + 回溯更新高度 O (log n) + 旋转 O (1));
- 查找:O (log n)(与 BST 一致,无额外开销)。
性能特点
- 查找性能稳定:无论插入顺序如何,树始终平衡,查找时间复杂度严格 O (log n);
- 插入 / 删除开销:因需回溯更新高度和旋转,插入 / 删除的常数时间比普通 BST 大,但整体仍为 O (log n);
- 旋转次数少:插入最多需要 1 次旋转(修复一个失衡节点),删除最多需要 O (log n) 次旋转(最坏情况需回溯到根节点)。
AVL 树的优缺点与适用场景
优点
- 绝对平衡:严格保证所有节点的平衡因子绝对值 ≤ 1,查找性能稳定;
- 实现简单:旋转逻辑清晰,仅 4 种旋转情况,易于编码实现;
- 无性能退化:避免了普通 BST 有序插入时退化为链表的问题。
缺点
- 平衡条件严格:为维持绝对平衡,插入 / 删除时频繁旋转,导致插入 / 删除的效率低于红黑树(红黑树是 "近似平衡",旋转次数更少);
- 高度更新开销:每个节点需存储高度信息,插入 / 删除后需回溯更新,额外消耗内存和时间;
- 不适合高频插入 / 删除场景:若场景中插入 / 删除操作远多于查找,AVL 树的性能不如红黑树。
适用场景
- 查找操作频繁,插入 / 删除操作较少的场景(如静态数据查询、字典查询);
- 对查找性能稳定性要求高,不允许性能退化的场景;
- 数据量中等,无需极致插入 / 删除效率的场景。
核心总结
- AVL 树是「绝对平衡的二叉搜索树」,核心通过「平衡因子」和「4 种旋转」维持平衡;
- 平衡因子 = 左子树高度 - 右子树高度,需保证所有节点 BF ∈ {-1, 0, 1};
- 旋转是失衡修复的核心:LL/RR 为基础旋转,LR/RL 为组合旋转,需根据 BF 判定场景;
- 插入流程:BST 插入 → 回溯更新高度 → 检查 BF → 失衡旋转(仅需一次旋转);
- 删除流程:BST 删除 → 回溯更新高度 → 检查 BF → 失衡旋转 → 持续回溯到根;
- 优点是查找性能稳定(O (log n)),缺点是插入 / 删除旋转频繁,适合查找密集型场景。