彻底吃透AVL树 | 原理、四大旋转图解、C++完整实现(初学者保姆级教程)
适用人群:数据结构初学者、期末备考、面试刷题零基础同学
核心优势:无晦涩公式、全程图文拆解、每个操作单独讲解、C++代码全覆盖+逐段注释、重点标注,看完彻底掌握AVL树
一、前置知识:为什么需要AVL树?(BST的致命缺陷)
1.1 二叉搜索树(BST)核心规则
普通二叉搜索树必须满足三个条件:
-
任意节点的左子树所有节点值 < 当前节点值
-
任意节点的右子树所有节点值 > 当前节点值
-
左右子树也必须是合法的二叉搜索树
1.2 BST 最大痛点:退化成链表
如果我们插入有序数据(1,2,3,4,5,6),普通BST会彻底失衡,变成一条斜链:
此时树的查询、插入、删除时间复杂度,从理想的 O(logn) 暴跌为 O(n),完全失去树形结构的高效优势。
AVL树的诞生目的:在保留BST左小右大特性的前提下,强制树保持平衡,杜绝斜链问题,保证操作效率永久稳定在 O(logn)。
二、AVL树核心基础概念
2.1 AVL树完整定义
AVL树是最早的自平衡二叉搜索树,同时满足两个核心条件:
-
是合法的二叉搜索树(左小右大)
-
任意节点的左右子树高度差绝对值不超过 1
2.2 节点高度(必懂基础)
行业统一约定规则:
-
空节点(nullptr)高度 = 0
-
叶子节点(无左右孩子)高度 = 1
-
普通节点高度公式:max(左子树高度, 右子树高度) + 1
2.3 平衡因子(AVL树的灵魂)
计算公式:平衡因子 = 左子树高度 - 右子树高度
AVL树铁律:所有节点平衡因子只能是 -1、0、1
-
BF = 1:左子树偏高
-
BF = 0:左右子树等高(最平衡)
-
BF = -1:右子树偏高
只要 |BF| > 1(等于2或-2),树判定为失衡,必须通过旋转操作修复平衡。
三、四大失衡场景 + 逐一手绘图解
所有AVL树失衡,只会出现 LL、RR、LR、RL 四种情况,对应固定旋转方案,无例外!
旋转核心原则:不破坏BST左小右大规则,仅调整节点位置,修复高度平衡。
3.1 LL 左左失衡(单次右旋)
触发条件:在「根节点左子树的左子树」插入节点,导致根节点BF=2
失衡结构:
修复方案:右旋操作
操作步骤:
-
将左孩子Y提升为新根节点
-
把Y原本的右子树,挂载到Z的左孩子位置
-
原根Z变为Y的右子树
-
更新所有受影响节点的高度
平衡后结构:
3.2 RR 右右失衡(单次左旋)
触发条件:在「根节点右子树的右子树」插入节点,导致根节点BF=-2
失衡结构:
修复方案:左旋操作
操作步骤:
-
将右孩子Y提升为新根节点
-
把Y原本的左子树,挂载到Z的右孩子位置
-
原根Z变为Y的左子树
-
更新节点高度
平衡后结构:
3.3 LR 左右失衡(先左旋、后右旋)
触发条件:在「根节点左子树的右子树」插入节点,交叉型失衡,根节点BF=2
失衡结构:
修复方案:两次旋转
-
第一步:对左子树Y做左旋,将结构转为LL型失衡
-
第二步:对根节点Z做右旋,彻底修复平衡
最终平衡结构:
3.4 RL 右左失衡(先右旋、后左旋)
触发条件:在「根节点右子树的左子树」插入节点,交叉型失衡,根节点BF=-2
失衡结构:
修复方案:两次旋转
-
第一步:对右子树Y做右旋,将结构转为RR型失衡
-
第二步:对根节点Z做左旋,修复平衡
最终平衡结构:
3.5 旋转速记口诀(必背)
-
LL 左左失衡 → 单次右旋
-
RR 右右失衡 →单次左旋
-
LR 左右失衡 → 先左后右双旋
-
RL 右左失衡 → 先右后左双旋
四、C++ 完整AVL树实现
代码包含:节点定义、高度计算、平衡因子、四大旋转、节点插入、节点删除、中序遍历,兼容所有C++编译器,无报错、可直接编译运行。
#include <iostream>
#include <algorithm>
using namespace std;
// AVL树节点结构定义
struct Node
{
int val; // 节点存储数值
Node* left; // 左孩子指针
Node* right; // 右孩子指针
int height; // 节点高度
// 构造函数:新建节点默认高度为1(叶子节点)
Node(int v) : val(v), left(nullptr), right(nullptr), height(1) {}
};
// 获取节点高度(空节点高度为0)
int getHeight(Node* node)
{
if (node == nullptr)
return 0;
return node->height;
}
// 计算节点平衡因子
int getBalance(Node* node)
{
if (node == nullptr)
return 0;
return getHeight(node->left) - getHeight(node->right);
}
// 左旋操作:解决RR型失衡
Node* leftRotate(Node* root)
{
Node* newRoot = root->right;
Node* temp = newRoot->left;
// 执行左旋
newRoot->left = root;
root->right = temp;
// 更新高度:先子节点、后父节点
root->height = 1 + max(getHeight(root->left), getHeight(root->right));
newRoot->height = 1 + max(getHeight(newRoot->left), getHeight(newRoot->right));
return newRoot;
}
// 右旋操作:解决LL型失衡
Node* rightRotate(Node* root)
{
Node* newRoot = root->left;
Node* temp = newRoot->right;
// 执行右旋
newRoot->right = root;
root->left = temp;
// 更新高度
root->height = 1 + max(getHeight(root->left), getHeight(root->right));
newRoot->height = 1 + max(getHeight(newRoot->left), getHeight(newRoot->right));
return newRoot;
}
// AVL树插入节点(自动平衡)
Node* insert(Node* root, int val)
{
// 递归终止:创建新节点
if (root == nullptr)
return new Node(val);
// 1. 标准BST插入逻辑
if (val < root->val)
root->left = insert(root->left, val);
else if (val > root->val)
root->right = insert(root->right, val);
else
return root; // 不允许重复节点
// 2. 更新当前节点高度
root->height = 1 + max(getHeight(root->left), getHeight(root->right));
// 3. 判断失衡并修复
int balance = getBalance(root);
// LL失衡
if (balance > 1 && val < root->left->val)
return rightRotate(root);
// RR失衡
if (balance < -1 && val > root->right->val)
return leftRotate(root);
// LR失衡
if (balance > 1 && val > root->left->val)
{
root->left = leftRotate(root->left);
return rightRotate(root);
}
// RL失衡
if (balance < -1 && val < root->right->val)
{
root->right = rightRotate(root->right);
return leftRotate(root);
}
return root;
}
// 辅助函数:寻找子树最小节点(删除专用)
Node* minValueNode(Node* node)
{
Node* cur = node;
while (cur->left != nullptr)
cur = cur->left;
return cur;
}
// AVL树删除节点(删除后自动平衡)
Node* deleteNode(Node* root, int val)
{
if (root == nullptr)
return root;
// 1. 标准BST删除查找
if (val < root->val)
root->left = deleteNode(root->left, val);
else if (val > root->val)
root->right = deleteNode(root->right, val);
else
{
// 情况1:单个子节点或叶子节点
if (root->left == nullptr || root->right == nullptr)
{
Node* temp = root->left ? root->left : root->right;
if (temp == nullptr)
{
temp = root;
root = nullptr;
}
else
*root = *temp;
delete temp;
}
// 情况2:存在左右两个子节点
else
{
Node* temp = minValueNode(root->right);
root->val = temp->val;
root->right = deleteNode(root->right, temp->val);
}
}
if (root == nullptr)
return root;
// 2. 更新高度
root->height = 1 + max(getHeight(root->left), getHeight(root->right));
// 3. 修复删除后的失衡
int balance = getBalance(root);
if (balance > 1 && getBalance(root->left) >= 0)
return rightRotate(root);
if (balance > 1 && getBalance(root->left) < 0)
{
root->left = leftRotate(root->left);
return rightRotate(root);
}
if (balance < -1 && getBalance(root->right) <= 0)
return leftRotate(root);
if (balance < -1 && getBalance(root->right) > 0)
{
root->right = rightRotate(root->right);
return leftRotate(root);
}
return root;
}
// 中序遍历:验证AVL树(结果一定升序)
void inOrder(Node* root)
{
if (root == nullptr)
return;
inOrder(root->left);
cout << root->val << " ";
inOrder(root->right);
}
// 主函数测试
int main()
{
Node* root = nullptr;
// 批量插入测试数据
int arr[] = {10, 20, 30, 40, 50, 25};
int n = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i < n; i++)
root = insert(root, arr[i]);
cout << "插入数据后AVL树中序遍历:";
inOrder(root);
cout << endl;
// 测试删除节点
root = deleteNode(root, 30);
cout << "删除30后AVL树中序遍历:";
inOrder(root);
cout << endl;
return 0;
}
五、代码运行结果
插入数据后AVL树中序遍历:10 20 25 30 40 50 删除30后AVL树中序遍历:10 20 25 40 50
结果为严格升序,证明BST特性完好,且全程无失衡,平衡修复生效!
六、初学者核心重点&易错点总结
6.1 核心考点
-
AVL树是高度平衡的BST,高度差≤1,效率稳定O(logn)
-
平衡因子合法值:-1、0、1,超差必旋转
-
四种失衡对应固定旋转方式,无其他情况
6.2 高频易错点
-
旋转操作后必须更新节点高度(90%新手出错点)
-
高度更新顺序:先下层子节点,后上层父节点
-
删除节点比插入更容易失衡,必须全覆盖四种平衡判断
-
AVL树中序遍历一定是升序,可用于验证代码正确性
更多推荐
所有评论(0)