AVL树:
二叉搜索树虽可以缩短查找的效率,但
如果数据有序或接近有序二叉搜索树将退化为单支树,查找元素相当于在顺序表中搜索元素,效率低下
。因此,两位俄罗斯的数学家
G.M.Adelson-Velskii
和
E.M.Landis
在
1962
年
发明了一种解决上述问题的方法:
当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之
差的绝对值不超过
1(
需要对树中的结点进行调整
)
,即可降低树的高度,从而减少平均搜索长度。
一棵
AVL
树或者是空树,或者是具有以下性质的二叉搜索树:
它的左右子树都是
AVL
树
左右子树高度之差
(
简称平衡因子
)
的绝对值不超过
1(-1/0/1)
如果一棵二叉搜索树是高度平衡的,它就是
AVL
树。如果它有
n
个结点,其高度可保持在O(log2n)
,搜索时
间复杂度
O(log2n
)
。
AVL树的插入:
AVL
树就是在二叉搜索树的基础上引入了平衡因子,因此
AVL
树也可以看成是二叉搜索树。那么
AVL
树的插入过程可以分为两步:
1.
按照二叉搜索树的方式插入新节点
2.
调整节点的平衡因子
AVL树的旋转:
如果在一棵原本是平衡的
AVL
树中插入一个新节点,可能造成不平衡,此时必须调整树的结构,使之平衡
化。根据节点插入位置的不同,
AVL
树的旋转分为四种:
1.
新节点插入较高左子树的左侧
---
左左:右单旋
2.
新节点插入较高右子树的右侧
---
右右:左单旋
3.
新节点插入较高左子树的右侧
---
左右:先左单旋再右单旋
4. 新节点插入较高右子树的左侧---右左:先右单旋再左单旋
参考右左双旋。
总结:假如以
pParent
为根的子树不平衡,即
pParent
的平衡因子为
2
或者
-2
,分以下情况考虑
1. pParent
的平衡因子为
2
,说明
pParent
的右子树高,设
pParent
的右子树的根为
pSubR
当
pSubR
的平衡因子为
1
时,执行左单旋
当
pSubR
的平衡因子为
-1
时,执行右左双旋
2. pParent
的平衡因子为
-2
,说明
pParent
的左子树高,设
pParent
的左子树的根为
pSubL
当
pSubL
的平衡因子为
-1
是,执行右单旋
当
pSubL
的平衡因子为
1
时,执行左右双旋
旋转完成后,原
pParent
为根的子树个高度降低,已经平衡,不需要再向上更新。
AVL树的删除:删除情况较为复杂,通常AVL树的考察重点是插入,下面的删除代码与插入代码呼应,可以体会揣摩。
AVL树的性能:
AVL
树是一棵绝对平衡的二叉搜索树,其要求每个节点的左右子树高度差的绝对值都不超过
1
,这样可以保证查询时高效的时间复杂度,即log2N
。但是如果要对
AVL
树做一些结构修改的操作,性能非常低下,比如:
插入时要维护其绝对平衡,旋转的次数比较多,更差的是在删除时,有可能一直要让旋转持续到根的位置。
因此:如果需要一种查询高效且有序的数据结构,而且数据的个数为静态的
(
即不会改变
)
,可以考虑
AVL
树,
但一个结构经常修改,就不太适合。
#include<iostream>
#include<vector>
#include<stack>
using namespace std;
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) {}
bool Insert(const Type& x)
{
return Insert(root, x);
}
bool Remove(const Type& key)
{
return Remove(root, key);
}
protected:
bool Insert(AVLNode<Type>*& t, const Type& x);
bool Remove(AVLNode<Type>*& t, const Type& key);
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 RotateLR(AVLNode<Type>*& ptr)
{
AVLNode<Type>* subL, * subR;
subR = ptr;
subL = ptr->leftChild;
ptr = subL->rightChild;
//L
subL->rightChild = ptr->leftChild;
ptr->leftChild = subL;
//调整 subL bf
if (ptr->bf <= 0)
subL->bf = 0;
else
subL->bf = -1;
//R
subR->leftChild = ptr->rightChild;
ptr->rightChild = subR;
//调整 subR bf
if (ptr->bf >= 0)
subR->bf = 0;
else
subR->bf = 1;
ptr->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 RotateRL(AVLNode<Type>*& ptr)
{
AVLNode<Type>* subL, * subR;
subL = ptr;
subR = ptr->rightChild;
ptr = subR->leftChild;
//R
subR->leftChild = ptr->rightChild;
ptr->rightChild = subR;
if (ptr->bf >= 0)
subR->bf = 0;
else
subR->bf = 1;
//L
subL->rightChild = ptr->leftChild;
ptr->leftChild = subL;
if (ptr->bf <= 0)
subL->bf = 0;
else
subL->bf = -1;
}
private:
AVLNode<Type>* root;
};
template<class Type>
bool AVLTree<Type>::Insert(AVLNode<Type>*& t, const Type& x)
{
//1 先按照BST树插入结点
AVLNode<Type>* p = t;
AVLNode<Type>* pr = nullptr;
stack<AVLNode<Type>*>st;
while (p != nullptr)
{
if (x == p->data)
return false;
pr = p;
st.push(pr);
if (x < p->data)
p = p->leftChild;
else
p = p->rightChild;
}
p = new AVLNode<Type>(x);
if (pr == nullptr)
{
t = p;
return true;
}
if (p->data < pr->data)
pr->leftChild = p;
else
pr->rightChild = p;
//2 调整平衡
while (!st.empty())
{
pr = st.top();
st.pop();
if (pr->leftChild == p)
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)
{
//cout << "RotateR." << endl;
RotateR(pr);
}
else
{
//cout << "PotateLR." << endl;
RotateLR(pr);
}
}
else
{
if (p->bf > 0)
{
//cout << "RotateL." << endl;
RotateL(pr);
}
else
{
//cout << "RotateRL." << endl;
RotateRL(pr);
}
}
break;
}
}
if (st.empty())
t = pr;
else
{
AVLNode<Type>* q = st.top();
if (pr->data < q->data)
q->leftChild = pr;
else
q->rightChild = pr;
}
return true;
}
template<class Type>
bool AVLTree<Type>::Remove(AVLNode<Type>*& t, const Type& key)
{
//1根据BST删除节点
AVLNode<Type>* pr = nullptr;
AVLNode<Type>* p = t, * q = nullptr;
AVLNode<Type>* Nil = new AVLNode<Type>(0);
stack<AVLNode<Type>*>st;
while (p != nullptr)
{
if (p->data == key)
break;
pr = p;
st.push(pr);
if (key < p->data)
p = p->leftChild;
else
p = p->rightChild;
}
if (p == nullptr)
return false;
if (p->leftChild != nullptr && p->rightChild != nullptr)
{
q = p->leftChild;
pr = p;
st.push(pr);
while (q->rightChild != nullptr)
{
pr = q;
st.push(pr);
q = q->rightChild;
}
p->data = q->data;
p = q;
}
//p是要删除的节点,q是p的子女节点
if (p->leftChild != nullptr)
q = p->leftChild;
else if (p->rightChild != nullptr)
q = p->rightChild;
else
q = Nil;
bool isLeftChild = false;
if (pr == nullptr)
t = q;
else
{
if (p == pr->leftChild)
{
if (q != Nil)
pr->leftChild = q;
else
pr->leftChild = nullptr;
isLeftChild = true;
}
else if (q != Nil)
pr->rightChild = q;
else
pr->rightChild = nullptr;
}
//2平衡BST树
while (!st.empty())
{
pr = st.top();
st.pop();
if (q == pr->leftChild || isLeftChild)
pr->bf++;
else
pr->bf--;
//考察pr平衡因子
if (pr->bf == 1 || pr->bf == -1)
break;
else if (pr->bf == 0)
q = pr;
else
{
//|bf|=2
//让q指向pr较高的子树
if (pr->bf < 0)
q = pr->leftChild;//左树高
else
q = pr->rightChild;//右树高
if (q->bf == 0)
{
if (pr->bf < 0)
{
RotateR(pr);
pr->bf = 1;
pr->rightChild->bf = -1;
}
else
{
RotateL(pr);
pr->bf = -1;
pr->leftChild->bf = 1;
}
}
else if (pr->bf < 0)
{
if (q->bf < 0) // /
{
RotateR(pr);
}
else
{
RotateLR(pr);//<
}
}
else if (pr->bf > 0)
{
if (q->bf < 0)
{
RotateRL(pr); //>
}
else
{
RotateL(pr);// \
}
}
//重新连接
if (st.empty())
t = pr;
else
{
q = st.top();
if (pr->data < q->data)
q->leftChild = pr;
else
q->rightChild = pr;
}
break;
}
}
delete p;
return true;
}
void test01()
{
vector<int> iv{ 16,3,7,11,9,26,18,14,15 };
AVLTree<int>avl;
for (const auto& e : iv)
avl.Insert(e);
avl.Remove(3);
avl.Remove(9);
//avl.Remove(7);
cout << "OK" << endl;
}
void main()
{
test01();
system("pause");
}