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

AVL 树原理与 C++ 实现

AVL 树是一种高度平衡的二叉搜索树,其左右子树高度差的绝对值不超过 1,从而保证增删查改的时间复杂度为 O(logN)。核心维护机制是平衡因子,即右子树高度减去左子树高度。当插入节点导致平衡因子超出 [-1, 1] 范围时,需通过左旋、右旋或双旋操作恢复平衡。内容涵盖 AVL 树的结构设计、插入逻辑及四种旋转场景的处理方法,并提供完整的 C++ 代码示例。

菩提发布于 2026/2/6更新于 2026/10/2480 浏览
AVL 树原理与 C++ 实现

AVL 树

1. AVL 树

1.1 AVL 的概念

AVL 树可以是一个空树。它的左右子树都是 AVL 树,且左右子树的高度差的绝对值不超过 1。AVL 树是一颗高度平衡搜索二叉树,通过控制高度差去控制平衡。

AVL 树整体结点数量和分布和完全二叉树类似,高度可以控制在 logN,那么增删查改的效率也可以控制在 O(logN),相比普通二叉搜索树有了本质的提升。

1.2 平衡因子

结点的平衡因子 = 右子树的高度减去左子树的高度。也就是说任何结点的平衡因子等于 0、1 或 -1。AVL 树并不是必须要存储平衡因子,但是有了平衡因子可以更方便我们去进行观察和控制树是否平衡,就像一个风向标一样。

为什么 AVL 树是高度平衡搜索二叉树,要求高度差不超过 1,而不是高度差是 0 呢?因为例如两个和四个结点无法达到高度差为 0 的完全平衡状态。

2. AVL 树的实现

2.1 AVL 树的结构

template<class K, class V>
struct AVLTreeNode {
    std::pair<K, V> _kv;
    AVLTreeNode<K, V>* _left;
    AVLTreeNode<K, V>* _right;
    AVLTreeNode<K, V>* _parent;
    int _bf; // balance factor

    AVLTreeNode(const std::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:
    bool Insert(const std::pair<K, V>& kv);
private:
    Node* _root = nullptr;
    void RotateLeft(Node* parent);
    void RotateRight(Node* parent);
    void UpdateBF(Node* node);
};

2.2 AVL 树的插入

bool AVLTree::Insert(const std::pair<K, V>& kv) {
    if (_root == nullptr) {
        _root = new Node(kv);
        return true;
    }

    Node* parent = nullptr;
    Node* cur = _root;

    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 exists
        }
    }

    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) {
                RotateLeft(parent);
            } else if (parent->_bf == -2 && cur->_bf == -1) {
                RotateRight(parent);
            } else if (parent->_bf == 2 && cur->_bf == -1) {
                RotateLR(parent);
            } else if (parent->_bf == -2 && cur->_bf == 1) {
                RotateRL(parent);
            }
            break;
        } else {
            assert(false);
        }
    }
    return true;
}

2.3 旋转

2.3.1 旋转的原则
  1. 保持搜索树的规则(中序遍历有序)。
  2. 让旋转的树从不满足平衡条件变为平衡,其次降低旋转树的高度。

旋转总共分为四种:左单旋、右单旋、左右双旋、右左双旋。

void AVLTree::RotateLeft(Node* parent) {
    Node* subR = parent->_right;
    Node* subRL = subR->_left;

    Node* ppNode = parent->_parent;
    parent->_right = subRL;
    if (subRL) subRL->_parent = parent;

    subR->_left = parent;
    parent->_parent = subR;

    if (ppNode == nullptr) {
        _root = subR;
        subR->_parent = nullptr;
    } else {
        if (ppNode->_left == parent) ppNode->_left = subR;
        else ppNode->_right = subR;
        subR->_parent = ppNode;
    }

    // 更新平衡因子
    parent->_bf = 0;
    subR->_bf = 0;
}

void AVLTree::RotateRight(Node* parent) {
    Node* subL = parent->_left;
    Node* subLR = subL->_right;

    Node* ppNode = parent->_parent;
    parent->_left = subLR;
    if (subLR) subLR->_parent = parent;

    subL->_right = parent;
    parent->_parent = subL;

    if (ppNode == nullptr) {
        _root = subL;
        subL->_parent = nullptr;
    } else {
        if (ppNode->_left == parent) ppNode->_left = subL;
        else ppNode->_right = subL;
        subL->_parent = ppNode;
    }

    parent->_bf = 0;
    subL->_bf = 0;
}

void AVLTree::RotateLR(Node* parent) {
    Node* subL = parent->_left;
    Node* subLR = subL->_right;
    int bf = subLR->_bf;

    RotateLeft(subL);
    RotateRight(parent);

    if (bf == 1) {
        subL->_bf = 0;
        parent->_bf = -1;
    } else if (bf == -1) {
        subL->_bf = 1;
        parent->_bf = 0;
    } else {
        subL->_bf = 0;
        parent->_bf = 0;
    }
    subLR->_bf = 0;
}

void AVLTree::RotateRL(Node* parent) {
    Node* subR = parent->_right;
    Node* subRL = subR->_left;
    int bf = subRL->_bf;

    RotateRight(subR);
    RotateLeft(parent);

    if (bf == 1) {
        subR->_bf = 0;
        parent->_bf = 1;
    } else if (bf == -1) {
        subR->_bf = -1;
        parent->_bf = 0;
    } else {
        subR->_bf = 0;
        parent->_bf = 0;
    }
    subRL->_bf = 0;
}

目录

  1. AVL 树
  2. 1. AVL 树
  3. 1.1 AVL 的概念
  4. 1.2 平衡因子
  5. 2. AVL 树的实现
  6. 2.1 AVL 树的结构
  7. 2.2 AVL 树的插入
  8. 2.3 旋转
  9. 2.3.1 旋转的原则

更多推荐文章

查看全部
  • Python 中秋月相可视化实战:从算法计算到 Web 渲染
  • OpenClaw 安装与飞书机器人接入教程
  • SpringBoot+Vue 智能推荐卫生健康系统平台设计与实现
  • 基于 Java SSM 的网上挂号系统设计与实现
  • STL 转 STEP 工具 stltostp 使用指南
  • AI 变现真相:为何掌握百种工具仍难盈利?
  • Java 核心语法与并发编程实战:66 个常用代码示例
  • Java 大数据在智能家居环境监测与智能调节中的应用实战
  • Python Django 跨境电商产品推荐与展示系统
  • YOLOv12 环境配置、训练与推理实战详解
  • Android Framework 核心源码解析与移动开发技术趋势
  • Python 数据分析实战:分类分析与决策树实现
  • OpenManus 开源自主规划智能体详解
  • 大型语言模型实践:语言理解与生成技术详解
  • TRAE 与 VSCode 中的 Git 分支管理与协作流程
  • 程序员如何系统掌握数据结构与算法
  • MMDetection3D 核心 Backbone、Neck、数据集及模型算法详解
  • 低代码诞生的背景:企业软件复杂度的累积
  • AI 红包封面制作与变现:技术门槛与商业逻辑分析
  • Java 对象的序列化和反序列化

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如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