目录
0.前置知识:BS树
代码实现部分对和BS树相似的部分会省略。
1. AVL树的核心概念
1.1 平衡二叉搜索树的必要性
普通二叉搜索树(BST)在极端情况下会退化为链表,时间复杂度恶化至O(N)。AVL树通过强制平衡约束,将树高度严格控制在O(log N),确保所有操作的高效性。
1.2 AVL树的定义
- 平衡条件:任意节点左右子树高度差绝对值≤1
- 平衡因子(Balance Factor):
合法取值范围:{-1, 0, 1}
1.3 历史背景
由前苏联科学家Adelson-Velsky和Landis于1962年提出,论文《An algorithm for the organization of information》首次描述这一数据结构。
2. 数据结构与节点定义
2.1 节点结构(C++实现)
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; // 平衡因子
// 构造函数
AVLTreeNode(const std::pair<K, V>& kv)
: _kv(kv), _left(nullptr), _right(nullptr),
_parent(nullptr), _bf(0) {}
};
2.2 树类框架
template<class K, class V>
class AVLTree
{
typedef AVLTreeNode<K, V> Node;
public:
// 接口方法
bool Insert(const std::pair<K, V>& kv);
Node* Find(const K& key);
// ...
private:
Node* _root = nullptr;
// 旋转工具方法
void RotateL(Node* parent); // 左单旋
void RotateR(Node* parent); // 右单旋
void RotateLR(Node* parent); // 左右双旋
void RotateRL(Node* parent); // 右左双旋
};
3. 插入操作与平衡因子更新
3.1 插入流程
3.2 平衡因子更新规则
- 插入右子树:父节点bf++
- 插入左子树:父节点bf–
- 更新终止条件:
bf == 0
:子树高度不变,停止更新bf == ±1
:子树高度变化,继续向上回溯bf == ±2
:触发旋转调整
3.3 关键代码实现
bool Insert(const std::pair<K, V>& kv) {
// ... BST插入逻辑
//...
// 平衡因子更新循环
while (parent) {
if (cur == parent->_left)
parent->_bf--;
else
parent->_bf++;
if (parent->_bf == 0)
break;
else if (abs(parent->_bf) == 1)
{
cur = parent;
parent = parent->_parent;
}
else if (abs(parent->_bf) == 2)
{
// 触发旋转
if (parent->_bf == 2)
{
if (cur->_bf == 1)
RotateL(parent);
else
RotateRL(parent);
}
else
{
if (cur->_bf == -1)
RotateR(parent);
else
RotateLR(parent);
}
break;
}
}
return true;
}
4. 旋转操作:从理论到代码
4.1 右单旋(LL型失衡)
触发条件:
父节点bf = -2,左子节点bf = -1
代码实现:
void RotateR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
// 调整节点关系
parent->_left = subLR;
if (subLR) subLR->_parent = parent;
subL->_right = parent;
Node* ppNode = parent->_parent;
parent->_parent = subL;
// 处理父节点链接
if (!ppNode)
_root = subL;
else if (ppNode->_left == parent)
ppNode->_left = subL;
else
ppNode->_right = subL;
subL->_parent = ppNode;
// 更新平衡因子
parent->_bf = subL->_bf = 0;
}
4.2 左单旋(RR型失衡)
触发条件:
父节点bf = 2,右子节点bf = 1
代码实现:
void RotateL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
parent->_right = subRL;
if(subRL)
subRL->_parent = parent;
Node* parentParent = parent->_parent;
subR->_left = parent;
parent->_parent = subR;
if (parentParent == nullptr)
{
_root = subR;
subR->_parent = nullptr;
}
else
{
if (parent == parentParent->_left)
{
parentParent->_left = subR;
}
else
{
parentParent->_right = subR;
}
subR->_parent = parentParent;
}
parent->_bf = subR->_bf = 0;
}
5. 双旋场景深度剖析
5.1 左右双旋(LR型失衡)
场景分析:
当插入节点导致父节点bf=-2,且左子节点bf=1时,需要先对左子树左旋,再对父节点右旋。
代码实现:
void RotateLR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
int bf = subLR->_bf;
RotateL(subL);
RotateR(parent);
// 平衡因子修正
if (bf == 0)
{
parent->_bf = subL->_bf = 0;
}
else if (bf == -1)
{
parent->_bf = 1;
subL->_bf = 0;
}
else
{
subL->_bf = -1;
parent->_bf = 0;
}
subLR->_bf = 0;
}
5.2右左双旋(RL型失衡)
情况与左右双旋类似。
代码实现:
void RotateRL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
int bf = subRL->_bf;
RotateR(parent->_right);
RotateL(parent);
if (bf == 0)
{
subR->_bf = 0;
subRL->_bf = 0;
parent->_bf = 0;
}
else if (bf == 1)
{
subR->_bf = 0;
subRL->_bf = 0;
parent->_bf = -1;
}
else if (bf == -1)
{
subR->_bf = 1;
subRL->_bf = 0;
parent->_bf = 0;
}
else
{
assert(false);
}
}
6. 平衡检测与测试策略
6.1 递归验证算法
bool IsBalance() {
return _IsBalanceTree(_root);
}
int _Height(Node* root) {
if (!root) return 0;
return 1 + std::max(_Height(root->_left),
_Height(root->_right));
}
bool _IsBalanceTree(Node* root) {
if (!root) return true;
int leftH = _Height(root->_left);
int rightH = _Height(root->_right);
if (rightH - leftH != root->_bf) {
std::cout << "平衡因子异常:" << root->_kv.first;
return false;
}
return abs(leftH - rightH) < 2
&& _IsBalanceTree(root->_left)
&& _IsBalanceTree(root->_right);
}
7. 性能分析与工程实践
7.1 时间复杂度对比
操作 | BST最坏 | AVL树 | 红黑树 |
---|---|---|---|
插入 | O(N) | O(logN) | O(logN) |
删除 | O(N) | O(logN) | O(logN) |
查找 | O(N) | O(logN) | O(logN) |
7.2 压力测试
void StressTest() {
AVLTree<int, int> tree;
const int N = 1000000;
// 随机插入
for (int i = 0; i < N; ++i) {
tree.Insert({rand(), i});
}
assert(tree.IsBalance());
// 查询性能测试
auto start = clock();
for (int i = 0; i < N; ++i) {
tree.Find(rand());
}
cout << "Query Time:" << clock() - start << "ms";
}
8. 总结
AVL树的优势:
- 严格的平衡保证最优查询性能
- 适合读多写少的场景
如有错误,恳请指正。