在之前的学习中,我们了解了二叉搜索树(BST)。虽然 BST 在理想情况下查找效率很高,但当数据有序插入时,树会退化成链表,导致查找效率降至 O(N)。为了解决这个问题,我们需要一种能够自动维持平衡的二叉搜索树——AVL 树。
AVL 树的概念
AVL 树是最早发明的自平衡二叉查找树。它是一棵空树,或者满足以下性质的二叉搜索树:
- 左右子树都是 AVL 树。
- 左右子树的高度差的绝对值不超过 1。
AVL 树得名于其发明者 G. M. Adelson-Velsky 和 E. M. Landis。为了量化平衡状态,我们引入**平衡因子(Balance Factor)**的概念。每个节点都有一个平衡因子,定义为右子树高度减去左子树高度。在 AVL 树中,任何节点的平衡因子只能是 -1、0 或 1。
你可能会问,为什么允许高度差为 1,而不是强制为 0?因为对于某些节点数量(如 2 个或 4 个),完全平衡(高度差为 0)是无法实现的。只要最大高度差控制在 1,整棵树的高度就能保持在 logN 级别,从而保证增删查改的效率稳定在 O(logN)。
AVL 树的实现
AVL 树的核心在于插入后的平衡维护。删除操作较为复杂,这里我们重点讲解插入功能的实现。我们将通过头文件定义结构,并在测试文件中验证逻辑。
节点结构
AVL 树的节点与二叉搜索树类似,但增加了平衡因子 bf 和父节点指针 _parent。
template<class T, class K> struct AVLTreeNode {
pair<T, K> _val;
AVLTreeNode* _left;
AVLTreeNode* _right;
AVLTreeNode* _parent;
int _bf;
AVLTreeNode(const pair<T, K>& x)
:_val(x), _left(nullptr), _right(nullptr), _parent(nullptr), _bf(0) {}
};
使用类模板可以支持存储任意类型的数据,构造函数确保新节点初始化正确。
树的结构封装
template<class T, class K> class AVLTree {
typedef AVLTreeNode<T, K> Node;
public:
// ... 功能函数
private:
Node* root = nullptr;
};
插入与平衡更新
插入过程前半部分与普通 BST 相同,关键在于插入后如何更新平衡因子并处理失衡。
1. 插入步骤
- 按 BST 规则找到插入位置。


