C++ : AVL 树之 左右双旋(第三章)
一、什么是 LR 双旋?解决什么问题?
LR 双旋是处理 LR 失衡 的组合操作 —— 当某节点的左子树高度比右子树高 2(parent.bf=-2
),但左孩子的右子树更高(subL.bf=1
)时,直接右单旋无效,需要先对左孩子做左单旋,把结构转化为 LL 失衡,再对原 parent 做右单旋。
简单说:左子树 “先左后右拐”(LR),先把 “拐弯处” 的节点(subLR)提上来,把结构掰成 “纯左偏”(LL),再用右单旋平衡。
二、LR 失衡场景特征
A[parent:6, bf=-2] --> B[subL:4, bf=1] // subL的右子树更高A --> C[右子树:7, bf=0]B --> D[subL的左子树:3, bf=0]B --> E[subLR:5, bf=0] // 拐弯处节点,导致LR失衡E --> F[插入点:比如5的左/右] // 插入引发失衡
- 核心特征:
parent.bf=-2
,subL.bf=1
,失衡由subL的右子树(subLR)
过高引发; - 问题:直接对 parent 做右单旋会导致 subLR 的子树 “挂错地方”,无法平衡。
三、LR 双旋步骤拆解
LR 双旋分 “两步走”:先旋子树,再旋父节点。
步骤 1:对 subL 做左单旋(掰直结构)
目标:把 subLR(5)提为 subL(4)的父节点,将 LR 结构转化为 LL 结构。
- 执行
RotateL(subL)
(对节点 4 做左单旋):- subLR(5)的左孩子(若有)交给 subL(4)当右孩子;
- subL(4)降为 subLR(5)的左孩子;
- subLR(5)成为原 parent(6)的左孩子。
步骤 2:对 parent 做右单旋(平衡树)
目标:把 subLR(5)提为 parent(6)的父节点,完成平衡。
- 执行
RotateR(parent)
(对节点 6 做右单旋):- subLR(5)的右孩子交给 parent(6)当左孩子;
- parent(6)降为 subLR(5)的右孩子;
- subLR(5)对接 pparent(若有),成为新根(若 parent 原是根)。
最终平衡结构:
subLR:5, bf=0
subL:4, bf=0
parent:6, bf=0
左子树:3, bf=0
右子树:7, bf=0
四、LR 双旋代码解析
void RotateLR(Node* parent) // 左右单旋(先左旋subL,再右旋parent)
{Node* subL = parent->_left; // 原左孩子Node* subLR = subL->_right; // 拐弯处节点(关键)int bf = subLR->_bf; // 保存subLR原始bf,决定旋转后bf值// 步骤1:对subL做左单旋,转化为LL失衡RotateL(subL);// 步骤2:对parent做右单旋,完成平衡RotateR(parent);// 关键:根据subLR原始bf更新三个节点的bfif (bf == 1){// subLR的左子树过高:subL(4)的右子树高,bf=-1;其他归0subL->_bf = -1;subLR->_bf = 0;parent->_bf = 0;}else if (bf == -1){// subLR的右子树过高:parent(6)的左子树高,bf=1;其他归0subL->_bf = 0;subLR->_bf = 0;parent->_bf = 1;}else if (bf == 0){// subLR是叶子节点:三者bf均归0subL->_bf = 0;subLR->_bf = 0;parent->_bf = 0;}else{assert(false); // 非法bf,排查错误}
}
五、bf 更新逻辑详解(为什么分三种情况?)
subLR 的原始 bf 决定了旋转后子树的高度差:
- bf=1:subLR 的左子树过高(插入点在 subLR 左侧)→ 旋转后 subL(4)的右子树比左子树高 1,故
subL.bf=-1
; - bf=-1:subLR 的右子树过高(插入点在 subLR 右侧)→ 旋转后 parent(6)的左子树比右子树高 1,故
parent.bf=1
; - bf=0:subLR 是叶子节点(插入点就是 subLR)→ 旋转后三者子树高度相等,bf 均为 0。
六、LR 双旋核心总结
- 适用场景:LR 失衡(
parent.bf=-2
,subL.bf=1
); - 核心逻辑:先左旋 subL “掰直” 成 LL,再右旋 parent 平衡;
- 关键注意:必须保存 subLR 的原始 bf,用于旋转后精准更新平衡因子
总之,对于左右双旋还是得自己画图理解,需要从具体到抽象,最后得出结论,送上一句话,绝知此事要躬行
附上AVL树源码:
#include <iostream>
#include <string>
#include <assert.h>
using namespace std;
//AVL Tree;
namespace ym
{
template<class K, class V>
class AVLTreeNode
{
public:
pair<K, V> _kv;
AVLTreeNode<K, V>* _left;
AVLTreeNode<K, V>* _right;
AVLTreeNode<K, V>* _parent;
int _bf;
AVLTreeNode(const pair<K, V>& kv)
:_kv(kv)
, _left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _bf(0)
{
}
};
//K->key(比较一般使用关键词key)
template<class K, class V>
class AVLTree
{
using Node = AVLTreeNode<K, V>;
public:
AVLTree() = default; //强制生成默认构造
bool Insert(const pair<K, V>& kv)
{
if (_root == nullptr)
{
_root = new Node(kv);
return true;
}
else
{
Node* parent = nullptr;
Node* pcur = _root;
while (pcur)
{
if (pcur->_kv.first < kv.first)
{
parent = pcur;
pcur = pcur->_right;
}
else if (pcur->_kv.first > kv.first)
{
parent = pcur;
pcur = pcur->_left;
}
else
{
return false;
}
}
pcur = new Node(kv);
if (parent->_kv.first < kv.first)
{
parent->_right = pcur;
}
else
{
parent->_left = pcur;
}
// 链接父亲
pcur->_parent = parent;
//更新平衡因子
while (parent)
{
if (pcur == parent->_left)
{
parent->_bf--;
}
else
{
parent->_bf++;
}
if (parent->_bf == 0)
{
break; //任然是AVL树
}
else if (parent->_bf == -1 || parent->_bf == 1)
{
pcur = parent;
parent = parent->_parent; //继续更新
}
else if (parent->_bf == -2 || parent->_bf == 2)
{
//旋转
if (parent->_bf == -2 && pcur->_bf == -1) //左边多且只插入到左子树的情况,即左边为h + 1, 右边为h,插入左边(h + 1)的左边
{
RotateR(parent);
}
else if (parent->_bf == 2 && pcur->_bf == 1)
{
RotateL(parent);
}
else if (parent->_bf == -2 && pcur->_bf == 1)
{
RotateLR(parent);
}
else if (parent->_bf == 2 && pcur->_bf == -1)
{
RotateRL(parent);
}
else
{
assert(false);
}
//退出
break;
}
else //如果在之前就已经不是AVL树,则返回assert报错
{
assert(false);
}
}
return true;
}
}
// 单旋是纯粹的一边高
void RotateR(Node* parent) //左边多,右单旋
{
Node* subL = parent->_left; //左边
Node* subLR = subL->_right; //左边的右边
Node* pparent = parent->_parent; //父亲的父亲节点
// 6(p)
// 4(L) 7
// 3 5(LR)
//(插入)
parent->_left = subLR;
if (subLR) //非空就可以修改
subLR->_parent = parent;
parent->_parent = subL;
subL->_right = parent;
if (parent == _root)
{
_root = subL;
subL->_parent = nullptr;
}
else
{
if (pparent->_left == parent)
{
pparent->_left = subL;
}
else
{
pparent->_right = subL;
}
subL->_parent = pparent;
}
subL->_bf = 0;
parent->_bf = 0;
}
void RotateL(Node* parent) //右边多,左单旋
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
Node* pparent = parent->_parent;
if (subRL)
subRL->_parent = parent;
parent->_right = subRL;
subR->_left = parent;
parent->_parent = subR;
if (_root == parent)
{
subR->_parent = nullptr;
_root = subR;
}
else
{
if (pparent->_left == parent)
{
pparent->_left = subR;
}
else
{
pparent->_right = subR;
}
subR->_parent = pparent;
}
parent->_bf = 0;
subR->_bf = 0;
}
//左右双旋(左拐右拐),先对subL进行左单旋,在对parent进行右单旋即可
// 4
// 3
//Null (2)插入
// 左单旋
// 4
// 3
// 2 NULL
//右单旋
// 3
// 2 4
void RotateLR(Node* parent) //左右单旋
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
int bf = subLR->_bf;
RotateL(subL);
RotateR(parent);
if (bf == 1)
{
subL->_bf = -1;
subLR->_bf = 0;
parent->_bf = 0;
}
else if (bf == -1)
{
subL->_bf = 0;
subLR->_bf = 0;
parent->_bf = 1;
}
else if (bf == 0)
{
subL->_bf = 0;
subLR->_bf = 0;
parent->_bf = 0;
}
else
{
assert(false);
}
}
void RotateRL(Node* parent) //右左单旋
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
int bf = subRL->_bf;
RotateR(subR);
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);
}
}
bool Find(const K& key)
{
Node* pcur = _root;
while (pcur)
{
if (pcur->_kv.first < key)
{
pcur = pcur->_right;
}
else if (pcur->_kv.first > key)
{
pcur = pcur->_left;
}
else
{
return true;
}
}
return false;
}
void InOrder()
{
_InOrder(_root);
}
int Height()
{
return _Height(_root);
}
bool IsBalanceTree()
{
return _IsBalanceTree(_root);
}
private:
void _InOrder(const Node* root)
{
if (root == nullptr)
{
//cout << "Nullptr ";
return;
}
_InOrder(root->_left);
cout << root->_kv.first << ":" << root->_kv.second << endl;
_InOrder(root->_right);
}
int _Height(Node* root)
{
if (root == nullptr)
return 0;
int leftHeight = _Height(root->_left);
int rightHeight = _Height(root->_right);
return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
}
bool _IsBalanceTree(Node* root)
{
//空树也是AVL树
if (nullptr == root)
return true;
//计算pRoot结点的平衡因⼦:即pRoot左右⼦树的⾼度差
int leftHeight = _Height(root->_left);
int rightHeight = _Height(root->_right);
int diff = rightHeight - leftHeight;
//如果计算出的平衡因⼦与pRoot的平衡因⼦不相等,或者
//pRoot平衡因⼦的绝对值超过1,则⼀定不是AVL树
if (abs(diff) >= 2)
{
cout << root->_kv.first << "⾼度差异常" << endl;
return false;
}
if (root->_bf != diff)
{
cout << root->_kv.first << "平衡因⼦异常" << endl;
return false;
}
// pRoot的左和右如果都是AVL树,则该树⼀定是AVL树
return _IsBalanceTree(root->_left) && _IsBalanceTree(root->_right);
}
Node* _root = nullptr;
};
}
void TestAVLTree1()
{
ym::AVLTree<int, int> t;
// 常规的测试⽤例
int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
// 特殊的带有双旋场景的测试⽤例
//int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
for (auto& e : a)
{
t.Insert({ e, e });
}
t.InOrder();
cout << t.IsBalanceTree() << endl;
}
int main()
{
TestAVLTree1();
return 0;
}