C++ AVL树

一、AVL树的核心概念

1.1 为何需要AVL树?

普通二叉搜索树(BST)在理想情况下具有O(log n)的查询效率,但在极端情况下(如插入有序序列)会退化为链表,导致时间复杂度恶化为O(n)。这种现象被称为"单枝树"或"歪脖子树"。AVL树通过引入自平衡机制,确保任意节点的左右子树高度差绝对值不超过1,从而维持树的平衡性。

1.2 AVL树的数学特性

AVL树满足以下两个条件:

  • 左右子树均为AVL树
  • 任意节点的左右子树高度差 ∈ {-1, 0, 1}

这种严格的高度平衡特性使得AVL树的高度h与节点数n满足:

cpp 复制代码
h ≈ 1.44 log₂(n+2) - 0.328

相比BST的最坏情况,AVL树将查找、插入、删除的时间复杂度稳定在O(log n)级别。

二、AVL树的结构设计

2.1 节点定义

cpp 复制代码
template <class K, class V>
struct AVLTreeNode {
    pair<K, V> _kv;            // 键值对存储
    AVLTreeNode* _left;        // 左子节点
    AVLTreeNode* _right;       // 右子节点
    AVLTreeNode* _parent;      // 父节点(三叉链结构)
    int _bf;                   // 平衡因子(Balance Factor)

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

关键设计点

  • 采用三叉链结构(包含parent指针)
  • 平衡因子_bf = 右子树高度 - 左子树高度
  • KV模型支持键值对存储

2.2 核心成员函数

cpp 复制代码
template <class K, class V>
class AVLTree {
public:
    bool Insert(const pair<K, V>& kv);  // 插入操作
    bool Remove(const K& key);          // 删除操作
    Node* Find(const K& key);           // 查找操作
private:
    Node* _root = nullptr;
    // 平衡维护相关辅助函数
    void RotateLeft(Node* parent);      // 左旋
    void RotateRight(Node* parent);     // 右旋
    void UpdateHeight(Node* node);      // 高度更新
};

三、旋转操作详解

3.1 基础旋转

3.1.1 左旋(Left Rotation)

条件:右子树高度 - 左子树高度 ≥ 2

cpp 复制代码
template <typename K, typename V>
void AVLTree<K,V>::RotateLeft(Node* parent) {
    Node* subR = parent->right;
    Node* subRL = subR->left;
    
    parent->right = subRL;
    if (subRL) subRL->parent = parent;

    Node* ppNode = 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;
    }

    // 更新平衡因子
    UpdateHeight(parent);
    UpdateHeight(subR);
}
3.1.2 右旋(Right Rotation)

触发条件 :左子树高度 - 右子树高度 ≥ 2
操作步骤与左旋对称。

3.2 复合旋转

3.2.1 左-右旋(Left-Right Rotation)

场景 :父节点左倾,左子节点右倾
处理步骤

  1. 对左子节点进行左旋
  2. 对父节点进行右旋
3.2.2 右-左旋(Right-Left Rotation)

场景 :父节点右倾,右子节点左倾
处理步骤

  1. 对右子节点进行右旋
  2. 对父节点进行左旋

四、插入操作实现

4.1 插入流程

cpp 复制代码
bool AVLTree<K,V>::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 (cur->_kv.first > 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; // 已平衡
        if (parent->_bf == 1 || parent->_bf == -1) {
            // 继续向上更新
            cur = parent;
            parent = parent->_parent;
        } else {
            // 需要旋转
            if (parent->_bf == 2) {
                if (parent->_right->_bf == 1) {
                    RotateLeft(parent);
                } else {
                    RotateRight(parent->_right);
                    RotateLeft(parent);
                }
            } else { // parent->_bf == -2
                if (parent->_left->_bf == -1) {
                    RotateRight(parent);
                } else {
                    RotateLeft(parent->_left);
                    RotateRight(parent);
                }
            }
            break; // 旋转后子树高度不变,无需继续更新
        }
    }
    return true;
}

AVL树通过平衡策略,在动态数据处理场景中展现出卓越的性能稳定性。尽管其旋转操作实现相对复杂,但其O(log n)的稳定时间复杂度使其成为许多高性能系统的首选数据结构。

相关推荐
zephyr051 分钟前
数据结构-并查集
数据结构
稚南城才子,乌衣巷风流35 分钟前
动态树(Dynamic Tree)数据结构详解
数据结构·算法
大不点wow36 分钟前
Java序列化与反序列化:让对象走出JVM
java·开发语言·jvm
阿里嘎多学长36 分钟前
2026-07-22 GitHub 热点项目精选
开发语言·程序员·github·代码托管
小保CPP39 分钟前
OpenCV C++将多张图像合并为webp动图
c++·人工智能·opencv·计算机视觉
噢,我明白了41 分钟前
Java中日期和字符串的处理
java·开发语言·日期
爱刷碗的苏泓舒41 分钟前
C 语言 if-else 与 switch-case 分支语句对比
c语言·开发语言
-银雾鸢尾-1 小时前
C#中的泛型约束
开发语言·c#
zander2581 小时前
114. 二叉树展开为链表
数据结构·链表·深度优先
雪碧透心凉_1 小时前
while 循环与循环嵌套
开发语言·python