1.概念
AVL树称为高度平衡的二叉搜索树,首先要满足二叉搜索树的性质。然后做了一定改进,能够使二叉搜索树及其子树的左右分支的分支高度平衡。这样能够大大的提高查找效率。对于AVL树,如果它有N个结点,其高度可保持在 log 2 N,搜索时间复杂度O(log 2 N )。
具体实现思路为:对每个结点都有一个平衡因子参数(一般为右树高度减去左树高度),当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之差的绝对值不超过1(需要对树中的结点进行调整),即可降低树的高度,从而减少平均搜索长度。
一棵AVL树或者是空树,或者是具有以下性质的二叉搜索树:
- 它的左右子树都是AVL树。
- 左右子树高度之差(简称平衡因子)的绝对值不超过1(-1/0/1)。
如下图:
(a),(b)都是二叉搜索树,但是(a)不是AVL树,(b)为AVL树。

AVL树节点的定义:
template<class Type>
class AVLNode
{
public:
AVLNode() :data(Type()), leftChild(nullptr), rightChild(nullptr), bf(0)
{}
AVLNode(Type d, AVLNode* left = nullptr, AVLNode* right = nullptr)
:data(d), leftChild(left), rightChild(right), bf(0)
{}
~AVLNode()
{}
private:
Type data;
AVLNode* leftChild;
AVLNode* rightChild;
int bf; //平衡因子
};
2.AVL树的插入
AVL树就是在二叉搜索树的基础上引入了平衡因子,因此AVL树也可以看成是二叉搜索树。那么AVL树的插入
过程可以分为两步:
- 按照二叉搜索树的方式插入新节点
- 调整节点的平衡因子
整体插入流程思路:
bool AVLTree<Type>::Insert(AVLNode<Type>*& t, const Type& x)
{
//先按Bst树插入节点
AVLNode<Type>* p = t;
stack< AVLNode<Type>*> stk; //用一个栈记住插入时经过的路线,方便取出父节点
AVLNode<Type>* pr = nullptr; //父节点
while (p != nullptr) { //寻找插入位置
if (x == p->data)
return false;
pr = p;
stk.push(pr);
if (x > p->data) {
p = p->rightChild;
continue;
}
if (x < p->data)
p = p->leftChild;
}
/////已经找到位置,开始插入
p =new AVLNode<Type>(x);
if (pr == nullptr) { //空树则直接创建根节点返回
t = p;
return true;
}
if (x > pr->data)
pr->rightChild = p;
else
pr->leftChild = p;
//////插入完,调整平衡因子/// 若在pr左数插入 pr->bf -1 ; 在pr右树插入 bf->bf +1
while (!stk.empty()) {
pr = stk.top();
stk.pop();
if (pr->leftChild==p) // 左数插入 pr->bf -1
pr->bf --;
else
pr->bf ++;
if (pr->bf == 0) //树是平衡的 返回
break;
else if (pr->bf == 1 || pr->bf == -1) // 向上回溯 pr的父节点处可能不平衡
{
p = pr; //开始下一轮while()循环,判断pr的父节点是否平衡,下一轮的pr为这一轮pr的父节点
}
else { //树不平衡 需要调整 针对不平衡的节点调整
if (pr->bf < 0) {
if (p->bf < 0) { // / 右单旋
RotateR(pr);
}
else { // < 先左旋后右旋
RotateLR(pr);
}
}
else {
if (p->bf > 0) { // \ 左单旋
RotateL(pr);
}
else {// > 先右旋后左旋
RotateRL(pr);
}
}
break;
}
}
其中对于调整平衡因子时 满足(pr->bf == 1 || pr->bf == -1)条件要向上回溯的问题,这里做了简单图解:

其中调整平衡因子时,是根据平衡因子的正负变化来决定采用那种方法调整,如图:

具体调整平衡因子的四种旋转方法如下;
1.右单旋

实现:
void RotateR(AVLNode<Type>*& ptr)
{
AVLNode<Type>* subR = ptr;
ptr = subR->leftChild;
subR->leftChild = ptr->rightChild;
ptr->rightChild = subR;
ptr->bf = subR->bf = 0;
}
图解:
向上回溯到第一个不平衡的节点ptr,然后调整这个不平衡的子树即可,其它平衡的部分不用管。
然后如图设置好ptr subR指针的位置,然后转就完事了。
这里说明一下符号:
ptr 最终要指向需要调整的这个子树的根节点,最后将ptr跟其父节点连接起来,这样是一颗完整的树了。
subL是最终要连到ptr的左树的节点。
sunR是最终要连到ptr右树的节点.

2.左单旋

实现:
void RotateL(AVLNode<Type>*& ptr)
{
AVLNode<Type>* subL = ptr;
ptr = subL->rightChild;
subL->rightChild = ptr->leftChild;
ptr->leftChild = subL;
ptr->bf = subL->bf = 0;
}

3.先右单旋再左单旋
分为两个步骤,先右旋后左旋,比较难的部分是旋转完之后的平衡因子该怎么调整,这里画了图能比较直观点看到。
实现:
void RotateRL(AVLNode<Type>*& ptr){
AVLNode<Type>* subL = ptr;
AVLNode<Type>* subR = ptr->rightChild;
ptr = subR->leftChild;
subR->leftChild =ptr->rightChild;
ptr->rightChild = subR;
//调整subL->bf
if (ptr->bf <= 0)
subL->bf = 0;
else
subL->bf = -1;
subL->rightChild = ptr->leftChild;
ptr->leftChild = subL;
//调整subR->bf
if (ptr->bf >= 0)
subR->bf = 0;
else
subR->bf = 1;
ptr->bf = 0;
}
对于旋转之后如可调整subL->bf和调整subR->bf这里可以通过画图就能找到规律。
共有以下三种情况:



4.先左单旋再右单旋
方法类似先右单旋再左单旋(镜像)。不想画了…
实现:
void RotateLR(AVLNode<Type>*& ptr)
{
AVLNode<Type>* subR = ptr;
AVLNode<Type>* subL = ptr->leftChild;
ptr = subL->rightChild;
subL->rightChild = ptr->leftChild;
ptr->leftChild = subL;
//调整subL->bf
if (ptr->bf <= 0)
subL->bf = 0;
else
subL->bf = -1;
subR->leftChild = ptr->rightChild;
ptr->rightChild = subR;
//调整subR->bf
if (ptr->bf >= 0)
subR->bf = 0;
else
subR->bf = 1;
ptr->bf = 0;
}
完整代码:
template<class Type>
class AVLTree;
template<class Type>
class AVLNode
{
friend class AVLTree<Type>;
public:
AVLNode() :data(Type()), leftChild(nullptr), rightChild(nullptr), bf(0)
{}
AVLNode(Type d, AVLNode* left = nullptr, AVLNode* right = nullptr)
:data(d), leftChild(left), rightChild(right), bf(0)
{}
~AVLNode()
{}
private:
Type data;
AVLNode* leftChild;
AVLNode* rightChild;
int bf;
};
template<class Type>
class AVLTree
{
public:
AVLTree() : root(nullptr)
{}
public:
bool Insert(const Type& x)
{
return Insert(root, x);
}
protected:
bool Insert(AVLNode<Type>*& t, const Type& x);
protected:
void RotateL(AVLNode<Type>*& ptr)
{
AVLNode<Type>* subL = ptr;
ptr = subL->rightChild;
subL->rightChild = ptr->leftChild;
ptr->leftChild = subL;
ptr->bf = subL->bf = 0;
}
void RotateR(AVLNode<Type>*& ptr)
{
AVLNode<Type>* subR = ptr;
ptr = subR->leftChild;
subR->leftChild = ptr->rightChild;
ptr->rightChild = subR;
ptr->bf = subR->bf = 0;
}
void RotateLR(AVLNode<Type>*& ptr)
{
AVLNode<Type>* subR = ptr;
AVLNode<Type>* subL = ptr->leftChild;
ptr = subL->rightChild;
subL->rightChild = ptr->leftChild;
ptr->leftChild = subL;
//调整subL bf
if (ptr->bf <= 0)
subL->bf = 0;
else
subL->bf = -1;
subR->leftChild = ptr->rightChild;
ptr->rightChild = subR;
//调整subR bf
if (ptr->bf >= 0)
subR->bf = 0;
else
subR->bf = 1;
ptr->bf = 0;
}
void RotateRL(AVLNode<Type>*& ptr){
AVLNode<Type>* subL = ptr;
AVLNode<Type>* subR = ptr->rightChild;
ptr = subR->leftChild;
subR->leftChild =ptr->rightChild;
ptr->rightChild = subR;
//调整subL bf
if (ptr->bf <= 0)
subL->bf = 0;
else
subL->bf = -1;
subL->rightChild = ptr->leftChild;
ptr->leftChild = subL;
//调整subR bf
if (ptr->bf >= 0)
subR->bf = 0;
else
subR->bf = 1;
ptr->bf = 0;
}
private:
AVLNode<Type>* root;
};
template<class Type>
bool AVLTree<Type>::Insert(AVLNode<Type>*& t, const Type& x)
{
//先按Bst树插入节点
AVLNode<Type>* p = t;
stack< AVLNode<Type>*> stk; //用一个栈记住插入时经过的路线
AVLNode<Type>* pr = nullptr;
while (p != nullptr) { //寻找插入位置
if (x == p->data)
return false;
pr = p;
stk.push(pr);
if (x > p->data) {
p = p->rightChild;
continue;
}
if (x < p->data)
p = p->leftChild;
}
/////插入
p =new AVLNode<Type>(x);
if (pr == nullptr) { //空树则直接创建根节点返回
t = p;
return true;
}
if (x > pr->data)
pr->rightChild = p;
else
pr->leftChild = p;
//////////调整平衡因子/// 左数插入 bf -1 ; 右树插入 bf +1
while (!stk.empty()) {
pr = stk.top();
stk.pop();
if (pr->leftChild==p) // 左数插入 bf -1
pr->bf --;
else
pr->bf ++;
if (pr->bf == 0) //树是平衡的 返回
break;
else if (pr->bf == 1 || pr->bf == -1) // 向上回溯 上面可能会不平衡
{
p = pr;
}
else { //树不平衡 需要调整 针对不平衡的节点调整
if (pr->bf < 0) {
if (p->bf < 0) { // / 右单旋
RotateR(pr);
}
else { // < 先左旋后右旋
RotateLR(pr);
}
}
else {
if (p->bf > 0) { // \ 左单旋
RotateL(pr);
}
else {// > 先右旋后左旋
RotateRL(pr);
}
}
break;
}
}
//连接
if (stk.empty())
t = pr;
else
{
AVLNode<Type>* q = stk.top();
if (pr->data < q->data)
q->leftChild = pr;
else
q->rightChild = pr;
}
return true;
}
int main()
{
vector<int> iv{ 16, 3, 7, 11, 9, 26, 18, 14, 15 };
AVLTree<int> avl;
for (const auto& e : iv)
avl.Insert(e);
return 0;
}

288





