跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++算法

AVL 树核心原理与 C++ 模拟实现详解

AVL 树通过维护平衡因子解决二叉搜索树退化为链表的问题,确保 O(logn) 操作复杂度。详细阐述 AVL 树定义、插入删除逻辑、四种旋转策略及平衡因子更新规则,并提供 C++ 完整模拟实现代码与验证方法,适合深入理解自平衡二叉搜索树底层机制。

奇形怪状发布于 2026/3/26更新于 2026/9/1060 浏览
AVL 树核心原理与 C++ 模拟实现详解

AVL 树概述

在算法实践中,二叉搜索树(BST)常因极端数据退化导致性能下降。当插入有序序列时,树结构会退化成链表,查询效率从理论上的 $O( log n)$ 跌至 $O(n)$。AVL 树作为一种严格平衡的二叉搜索树,通过引入平衡因子机制,确保任意节点的左右子树高度差不超过 1,从而维持整体结构的平衡。

核心概念

AVL 树是空树或满足以下性质的二叉搜索树:

  1. 左右子树均为 AVL 树。
  2. 每个节点的平衡因子(左右子树高度差)绝对值不超过 1。

其增删查改的时间复杂度均稳定在 $O( log n)$。

节点结构与插入逻辑

实现前需定义包含平衡因子的节点结构。插入新节点后,需沿路径向上更新祖先节点的平衡因子。若某节点平衡因子变为 2 或 -2,则触发旋转操作以恢复平衡。

template<class K, class V>
struct AVLTreeNode {
    pair<K, V> _kv;
    AVLTreeNode<K, V>* _left;
    AVLTreeNode<K, V>* _right;
    AVLTreeNode<K, V>* _parent;
    int _bf; // 平衡因子

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

插入时的平衡因子更新策略如下:

  • 新节点在左子树,父节点平衡因子减 1。
  • 新节点在右子树,父节点平衡因子加 1。
  • 若更新后平衡因子为 0,说明该子树高度未变,停止更新。
  • 若为 ±1,继续向上传播。
  • 若为 ±2,当前子树失衡,需执行旋转。

旋转操作详解

旋转是修复失衡的核心手段,分为单旋和双旋。旋转过程中必须保持二叉搜索树的性质,同时修正相关节点的平衡因子。

左旋 (Right Rotation)

适用于'右右'失衡情况。将根节点的左孩子提升为新根,原根节点变为左孩子的右孩子。

void RotateR(Node* parent) {
    Node* cur = parent->_left;
    Node* curright = cur->_right;
    
    parent->_left = curright;
    if (curright) curright->_parent = parent;
    
    Node* ppnode = parent->_parent;
    cur->_right = parent;
    parent->_parent = cur;
    
    if (ppnode == nullptr) {
        _root = cur;
        cur->_parent = nullptr;
    } else {
        if (ppnode->_left == parent) ppnode->_left = cur;
        else ppnode->_right = cur;
        cur->_parent = ppnode;
    }
    
    parent->_bf = cur->_bf = 0;
}

右旋 (Left Rotation)

适用于'左左'失衡情况。将根节点的右孩子提升为新根,原根节点变为右孩子的左孩子。

void RotateL(Node* parent) {
    Node* cur = parent->_right;
    Node* curleft = cur->_left;
    
    parent->_right = curleft;
    if (curleft) curleft->_parent = parent;
    
    Node* ppnode = parent->_parent;
    cur->_left = parent;
    parent->_parent = cur;
    
    if (parent == _root) {
        _root = cur;
        cur->_parent = nullptr;
    } else {
        if (ppnode->_left == parent) ppnode->_left = cur;
        else ppnode->_right = cur;
        cur->_parent = ppnode;
    }
    
    parent->_bf = cur->_bf = 0;
}

双旋 (LR & RL)

当失衡形态为折线型(如'左右'或'右左')时,需先对子节点进行反向旋转,再对父节点进行主旋转。双旋后的平衡因子修正较为复杂,需根据插入位置判断。

void RotateRL(Node* parent) {
    Node* cur = parent->_right;
    Node* curleft = cur->_left;
    int bf = curleft->_bf;
    
    RotateR(parent->_right);
    RotateL(parent);
    
    if (bf == 0) {
        cur->_bf = 0; curleft->_bf = 0; parent->_bf = 0;
    } else if (bf == 1) {
        cur->_bf = 0; curleft->_bf = 0; parent->_bf = -1;
    } else if (bf == -1) {
        cur->_bf = 1; curleft->_bf = 0; parent->_bf = 0;
    }
}

验证与练习

验证 AVL 树是否正确,不能仅依赖平衡因子字段(可能更新出错),应通过计算实际高度差来校验。中序遍历有序只能证明是二叉搜索树,无法证明平衡性。

验证代码示例:

int Height(Node* root) {
    if (root == nullptr) return 0;
    int leftH = Height(root->_left);
    int rightH = Height(root->_right);
    return leftH > rightH ? leftH + 1 : rightH + 1;
}

bool IsBalance(Node* root) {
    if (root == nullptr) return true;
    int leftH = Height(root->_left);
    int rightH = Height(root->_right);
    if (abs(rightH - leftH) != abs(root->_bf)) return false;
    return abs(rightH - leftH) < 2 && IsBalance(root->_left) && IsBalance(root->_right);
}

思考题

现有一棵无重复关键字的平衡二叉树(AVL 树),对其进行中序遍历可得到一个降序序列。下列关于该平衡二叉树的叙述中,正确的是? A. 根结点的度一定为 2 B. 树中最小元素一定是叶结点 C. 最后插入的元素一定是叶结点 D. 树中最大元素一定是无左子树

答案:D。解析:中序遍历降序意味着比较逻辑反转,此时最大元素位于最左侧,因此没有左子树。

目录

  1. AVL 树概述
  2. 核心概念
  3. 节点结构与插入逻辑
  4. 旋转操作详解
  5. 左旋 (Right Rotation)
  6. 右旋 (Left Rotation)
  7. 双旋 (LR & RL)
  8. 验证与练习
  9. 思考题

更多推荐文章

查看全部
  • 网络安全零基础入门指南:学习误区、路线与自学利弊分析
  • Ubuntu 20.04 安装微信教程
  • 基于 Python 和 Pygame 的彩球碰撞动画实现
  • 基于 AIGC 与 Photoshop 的 Spine 2D 角色拆件补图工作流
  • BFS 实现拓扑排序:原理与 LeetCode 实战
  • 基于 Python 的旅行数据可视化与分析系统
  • Python-Skill Bridge 实现 Python 与 Virtuoso Skill 无缝连接
  • Vivado 入门实战:基于 Verilog 的 D 触发器设计与烧录
  • Dify 与 MySQL 集成实战:基于 MCP 协议的数据交互方案
  • 春晚机器人热,股市为何不买账?
  • 网络安全入门指南:从基础原理到实战进阶
  • C++ AVL 树:概念、结构与旋转实现
  • 电影推荐与票房预测系统:基于 Python + Flask + 机器学习
  • RAG:大模型时代的检索增强生成技术
  • Python 爬虫实战:爬取微信公众号历史推文
  • WhisperLive:实时语音转文字解决方案
  • Kubernetes: 使用 kubectl 插件 ketall 查看所有 API 对象资源
  • 数据结构:树与堆
  • 网络安全学习平台盘点:七个从新手到进阶的资源
  • 滑动窗口算法结合例题详解

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online