【C++】2.5 AVL树的实现
·
1. AVL树特点
AVL树是一种自平衡二叉搜索树,其核心特点如下:
- 左右子树高度差不超过1
- 平衡因子:右子树高度 - 左子树高度
- 通过旋转操作维持平衡
2. 模拟实现
2.1 成员结构
代码语言:javascript
AI代码解释
template<class K, class V>
struct treenode
{
std::pair<K, V> _kv;
treenode* _left;
treenode* _right;
treenode* _father; // 指向父节点的指针
int _bf; // 平衡因子
treenode(const std::pair<K, V>& kv)
: _kv(kv)
, _left(nullptr)
, _right(nullptr)
, _father(nullptr)
, _bf(0)
{ }
};
设计要点:
- 和搜索二叉树一样,有左右节点和一个pair键值对
- 由于需要从下到上处理高度差问题,因此需要指向父节点的指针
_bf负责存储平衡因子
2.2 插入操作
插入操作 = 搜索二叉树插入 + 平衡高度调整
节点更新后平衡因子的三种情况:
- 平衡因子 = 0(-1→0 或 1→0):已经平衡,停止更新
- 平衡因子为 ±1(0→±1):会影响父节点,继续向上更新
- 平衡因子为 ±2(-1→-2 或 1→2):不符合AVL树,需要旋转,旋转完后停止更新
插入主逻辑:
代码语言:javascript
AI代码解释
bool insert(const std::pair<K, V>& kv)
{
if (_root == nullptr)
{
_root = new node(kv);
return 1;
}
node* par = nullptr;
node* cur = _root;
while (cur)
{
if (cur->_kv.first < kv.first)
{
par = cur;
cur = cur->_right;
}
else if (cur->_kv.first > kv.first)
{
par = cur;
cur = cur->_left;
}
else
{
return 0; // 键值已存在
}
}
cur = new node(kv);
if (par->_kv.first < kv.first)
{
par->_right = cur;
}
else
{
par->_left = cur;
}
// 回溯更新平衡因子
while (par)
{
if (cur == par->_left) par->_bf--;
else par->_bf++;
if (par->_bf == 0) break;
else if (par->_bf == 1 || par->_bf == -1)
{
cur = par;
par = par->_father;
}
else if (par->_bf == 2 || par->_bf == -2)
{
// 需要旋转
if (par->_bf == -2 && cur->_bf == -1)
{
rotateR(par); // 右单旋
}
else if (par->_bf == -2 && cur->_bf == 1)
{
rotateLR(par); // 左右双旋
}
else if (par->_bf == 2 && cur->_bf == 1)
{
rotateL(par); // 左单旋
}
else if (par->_bf == 2 && cur->_bf == -1)
{
rotateRL(par); // 右左双旋
}
else
{
assert(0);
}
break;
}
else
{
assert(0);
}
}
return 1;
}
3. 旋转操作
由于造成不平衡可能是左子树或右子树,因此先分为左旋和右旋。

3.1 右旋
右旋用于解决左子树过高的问题。造成左子树不平衡的可能是左左子树或左右子树,因此分为:
- 右单旋
- 左右双旋
(1)右单旋
想象有重力:提起左节点,让它变为根节点。
操作步骤:
- 原来的根节点有三个分支
- 将原来左节点的右枝砍断,接到原来的根节点上

右单旋的优点:
- 保持搜索树规则
- 使树变平衡
- 降低树高度
结束后平衡因子变化:根节点变为0,右节点变为0
更多推荐
所有评论(0)