1.AVL树是最早发明的自平衡二叉树。AVL树是一颗空树or一个棵左右子树都为符合AVL树,且左右两边子树的高度差的绝对值不大于1。
2.对于实现AVL树,我们这里引入了平衡因子(banlance factor 简写为bf)这个概念帮助我们实现AVL树。AVL树的每一个节点都有平衡因子,平衡因子=右子树的高度-左子树高度。
3.其实AVL树是实现不一定要用平衡因子,只是使用平衡因子可以更好的帮助我们观察与控制AVL树的平衡
1.平衡因子=右子树高度-左子树高度
2.只有当左右子树发生了高度变化才会更新平衡因子
3.插入左子树时,平衡因子--。插入有子树时,平衡因子++
4.parent的平衡因子是否变化决定了是否继续向上更新

1.当更新之后parent的bf等于0,说明更新之前parent子树是一边高一边低(-1->0 or 1->0),更新之后使其两边都一样高,parent子树并没有高度变化,不会影响parent的父亲节点,所以停止更新
2.当更新之后parent的|bf|=1,说明更新之前parent子树左右两边一样高(0 -> 1)更新之后使左右两边一边高一边低,parent子树的高度发生改变,会影响parent的父亲节点,所以继续向上更新
3.当更新之后parent的|bf|=2,已经破坏平衡,停止更新,并调整结构使其重新达到平衡
4.一直更新直到更新到根节点,停止更新

template<class K, class V>
struct AVLTreeNode
{
// 需要parent指针,后续更新平衡因子可以看到
pair<K, V> _kv;
AVLTreeNode<K, V>* _left;
AVLTreeNode<K, V>* _right;
AVLTreeNode<K, V>* _parent;
int _bf; // balance factor 平衡因子
AVLTreeNode(const pair<K, V>& kv)
:_kv(kv)
, _left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _bf(0)
{}
};
template<class k, class v>
class AVLTree
{
public:
//typedef AVLTreeNode<k, v> Node;
using Node = AVLTreeNode<k, v>;
//
//
//
//
private:
Node* _root = nullptr;
}当|bf|=0直接停止更新,当|bf|=1时使用循环直接向上更新,这两个情况后续我会在代码中直接展现不过多讨论。我们真正需要关注的是当|bf|=2时,我们应该如何调整使其重新回归平衡
由于左边插入节点导致左边高度太高,我们可以将parent向右旋转,让其左右高度平衡。旋转的核心是subRL这个节点,subR<subRL<parent。旋转之后仍满足搜索二叉树的规则,并且控制了高度
调整完成,更新各个节点的平衡因子后,就停止更新了

//右单旋
void RotateR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
Node* pParent = parent->_parent;
subL->_right = parent;
parent->_parent = subL;
parent->_left = subLR;
if(subLR)
subLR->_parent = parent;
//判断:若旋转的节点为根,则代表这是一颗完整的树,不需要处理
//若旋转的节点不为根,则代表这是一颗子树,需要连接至上面的树
if (pParent == nullptr)
{
_root=subL;
subL->_parent = nullptr;
}
else
{
if (pParent->_left == parent)
{
pParent->_left = subL;
subL->_parent = pParent;
}
else
{
pParent->_right = subL;
subL->_parent = pParent;
}
}
//更新平衡因子
subL->_bf = parent->_bf = 0;
}与右单旋同理,只是方向反了一下
//左单旋
void RotateL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
parent->_right = subRL;
if(subRL)
subRL->_parent = parent;
Node* pParent = parent->_parent;
subR->_left = parent;
parent->_parent = subR;
if (pParent == nullptr)
{
_root = subR;
subR->_parent= nullptr;
}
else
{
if (pParent->_left == parent)
{
pParent->_left = subR;
}
else
{
pParent->_right = subR;
}
subR->_parent = pParent;
}
//更新平衡因子
subR->_bf = parent->_bf = 0;
}先给出一个简单情况帮助我们理解一下,左右双旋与前面的右单旋的区别与联系。由图我们可以看出,左右双选与右单旋都是左边高,仅仅是插入的位置不同

总的来说左右双旋的插入位置在subL的右边,如图所示。但是subL的右子树也存在左右子树所以我们应该要分类讨论一下这个细节

新增节点插在e时:

新增节点插在f时:

由图我们可以看到,其实对于左右双旋来说,插在e还是f点对结果的影响就是subL与parent的平衡因子不同,旋转的步骤是一模一样的。所以我们不管是插入在e还是f,对于左边双旋的步骤都为:1.左旋subL 2.右旋parent 3.记录subLR旋转前的平衡因子,判断插入的位置,根据插入的位置来更新平衡因子
//左右双旋
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 = 0;
subL->_bf = 0;
subLR->_bf = 0;
}
else if (bf == 1)
{
parent->_bf = 0;
subL->_bf = -1;
subLR->_bf = 0;
}
else if (bf == -1)
{
parent->_bf = 1;
subL->_bf = 0;
subLR->_bf = 0;
}
else
{
assert(false);
}
}右左双选的步骤与左右双选的步骤一模一样,只是方向反了。这里就不画图演示了,具体步骤为:1.右旋subR 2.左旋parent 3.记subRL旋转前的平衡因子,判断插入的位置,根据插入的位置来更新平衡因子
//右左双旋
void RotateRL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
int bf = subRL->_bf;
//直接复用右左单旋
RotateR(subR);
RotateL(parent);
if (bf == 0)
{
parent->_bf = 0;
subR->_bf = 0;
subRL->_bf = 0;
}
else if (bf == 1)
{
parent->_bf = -1;
subR->_bf = 0;
subRL->_bf = 0;
}
else if (bf == -1)
{
parent->_bf = 0;
subR->_bf = 1;
subRL->_bf = 0;
}
else
{
assert(false);
}
}AVL的搜索与搜索二叉树的搜索无异,这里我们直接给出
Node* Find(const K& key)
{
Node* cur = _root;
while (cur)
{
if (cur->_kv.first < key)
{
cur = cur->_right;
}
else if (cur->_kv.first > key)
{
cur = cur->_left;
}
else
{
return cur;
}
}
return nullptr;
}完整代码如下
#pragma once
#include<iostream>
#include<assert.h>
#include<vector>
using namespace std;
template<class K, class V>
struct AVLTreeNode
{
// 需要parent指针,后续更新平衡因子可以看到
pair<K, V> _kv;
AVLTreeNode<K, V>* _left;
AVLTreeNode<K, V>* _right;
AVLTreeNode<K, V>* _parent;
int _bf; // balance factor 平衡因子
AVLTreeNode(const pair<K, V>& kv)
:_kv(kv)
, _left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _bf(0)
{}
};
template<class k, class v>
class AVLTree
{
public:
//typedef AVLTreeNode<k, v> Node;
using Node = AVLTreeNode<k, v>;
bool Insert(const pair<k,v>& kv)
{
Node* cur = _root;
Node* parent = cur;
if (cur == nullptr)
{
_root = new Node(kv);
return true;
}
while(cur)
{
if (cur->_kv.first > kv.first) //pair重载了大小于运算符
{
parent = cur;
cur = cur->_left;
}
else if (cur->_kv.first < kv.first)
{
parent = cur;
cur = cur->_right;
}
else
return false;
}
if (parent->_kv.first > kv.first)
{
cur = new Node(kv);
parent->_left = cur;
}
else
{
cur = new Node(kv);
parent->_right = cur;
}
//连接到父亲节点
cur->_parent = parent;
//控制平衡
//更新平衡因子
while (parent)
{
if (parent->_left == cur)
parent->_bf--;
else
parent->_bf++;
if (parent->_bf == 0)
{
break;
}
else if (parent->_bf == 1 || parent->_bf == -1)
{
cur = parent;
parent = parent->_parent;
}
else if (parent->_bf == 2 || parent->_bf == -2)
{
//进行旋转
if (parent->_bf == -2 && cur->_bf == -1)//右单旋(单纯的左边高)
{
RotateR(parent);
}
else if(parent->_bf==2&&cur->_bf==1)//左单选(单纯的右边高)
{
RotateL(parent);
}
else if (parent->_bf==-2&&cur->_bf==1)//左右双旋:先左单旋再右单旋(不单纯的左边高)
{
RotateLR(parent);
}
else if (parent->_bf==2&&cur->_bf==-1)//右左双旋:先右单旋再左单旋(不单纯的右边高)
{
RotateRL(parent);
}
else
{
assert(false);
}
break;
}
else
{
assert(false);
//预防未知错误的编程逻辑
}
}
return true;
}
//右单旋
void RotateR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
Node* pParent = parent->_parent;
subL->_right = parent;
parent->_parent = subL;
parent->_left = subLR;
if(subLR)
subLR->_parent = parent;
//判断:若旋转的节点为根,则代表这是一颗完整的树,不需要处理
//若旋转的节点不为根,则代表这是一颗子树,需要连接至上面的树
if (pParent == nullptr)
{
_root=subL;
subL->_parent = nullptr;
}
else
{
if (pParent->_left == parent)
{
pParent->_left = subL;
subL->_parent = pParent;
}
else
{
pParent->_right = subL;
subL->_parent = pParent;
}
}
//更新平衡因子
subL->_bf = parent->_bf = 0;
}
//左单旋
void RotateL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
parent->_right = subRL;
if(subRL)
subRL->_parent = parent;
Node* pParent = parent->_parent;
subR->_left = parent;
parent->_parent = subR;
if (pParent == nullptr)
{
_root = subR;
subR->_parent= nullptr;
}
else
{
if (pParent->_left == parent)
{
pParent->_left = subR;
}
else
{
pParent->_right = subR;
}
subR->_parent = pParent;
}
//更新平衡因子
subR->_bf = parent->_bf = 0;
}
//左右双旋
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 = 0;
subL->_bf = 0;
subLR->_bf = 0;
}
else if (bf == 1)
{
parent->_bf = 0;
subL->_bf = -1;
subLR->_bf = 0;
}
else if (bf == -1)
{
parent->_bf = 1;
subL->_bf = 0;
subLR->_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)
{
parent->_bf = 0;
subR->_bf = 0;
subRL->_bf = 0;
}
else if (bf == 1)
{
parent->_bf = -1;
subR->_bf = 0;
subRL->_bf = 0;
}
else if (bf == -1)
{
parent->_bf = 0;
subR->_bf = 1;
subRL->_bf = 0;
}
else
{
assert(false);
}
}
Node* Find(const K& key)
{
Node* cur = _root;
while (cur)
{
if (cur->_kv.first < key)
{
cur = cur->_right;
}
else if (cur->_kv.first > key)
{
cur = cur->_left;
}
else
{
return cur;
}
}
return nullptr;
}
private:
Node* _root = nullptr;
};如有纰漏还请各位大佬斧正