C++:图解AVL平衡二叉树的原理
1. AVL树的性质
AVL树是一种平衡二叉树,一棵AVL树或者是空树,或者是具有以下性质的二叉搜索树:
- 它的左右子树都是AVL树
- 左右子树高度之差(简称平衡因子)的绝对值不超过1(-1/0/1)
- 上图是一个带平衡因子的平衡二叉树(右子树高度差为正,左子树高度差为负)
- 定义一个AVL树的节点类模板
template<class T>//构建AVL树节点类模板
struct AVLTreeNode
{
AVLTreeNode(const T& val = T())
:left(nullptr)
, right(nullptr)
, parent(nullptr)//回溯用的双亲
, data(val)
, bf(0)//平衡因子
{}
AVLTreeNode<T>* left;
AVLTreeNode<T>* right;
AVLTreeNode<T>* parent;
T data;
int bf;
};
2. AVL树的操作
- 查找操作:因为AVL树总是保持平衡的,所以查找操作和二叉搜索树完全一致
- 插入操作:AVL的插入操作和二叉搜索树的插入操作是相似的,只不过在插入后需要对树的高度进行调整,因此就需要用到旋转操作中调整的操作。
- 删除操作:AVL树的删除操作和二叉查找树也相似,只不过删除元素后要检查树是否失去平衡,如果失衡就需要重新调整平衡,并更新平衡因子的值。
- 旋转操作:AVL树中由于平衡因子的作用,当在一个AVL树中插入新节点时,很可能会导致AVL树的平衡结构被破坏,具体表现为平衡因子不为(0/1/-1),此时就必须要对AVL树的结构进行调整,调整的方法就是旋转树的节点,具体方法如下:
- RR旋转(右子树的右子树上插入结点)
-
LL旋转(左子树的左子树上插入结点)以下的回溯过程图示省略
-
LR旋转(左子树的右子树上插入结点)
-
RL旋转(右子树的左子树上插入结点)
3. AVL树的实现
- 只实现了旋转和插入方法,不包含析构,代码仅用于测试
#include<iostream>
#include<stack>
using namespace std;
template<class Type>
class AVLTree;
//avl node
template<class Type>
class AVLNode
{
friend class AVLTree<Type>;
public:
AVLNode(Type d = Type(), AVLNode<Type>* left = nullptr, AVLNode<Type>* right = nullptr)
: data(d)
, leftChild(left)
, rightChild(right)
, bf(0)
{}
~AVLNode()
{
}
private:
Type data;
AVLNode<Type>* leftChild;
AVLNode<Type>* rightChild;
int bf; //平衡因子
};
//avl tree
template<class Type>
class AVLTree
{
public:
AVLTree() :root(nullptr)
{}
public:
bool Insert(const Type& x)
{
return Insert(root, x);
}
bool Remove(const Type& key)
{
return Remove(root, key);
}
void InOrder()
{
_InOrder(root);
cout << endl;
}
protected:
bool Insert(AVLNode<Type>*& t, const Type& x);
bool Remove(AVLNode<Type>*& t, const Type& key);
void RotateR(AVLNode<Type>*& ptr);
void RotateLR(AVLNode<Type>*& ptr);
void RotateL(AVLNode<Type>*& ptr);
void RotateRL(AVLNode<Type>*& ptr);
private:
void _InOrder(AVLNode<Type>* pRoot)//中序遍历
{
if (pRoot)
{
_InOrder(pRoot->leftChild);
cout << pRoot->data << " ";
_InOrder(pRoot->rightChild);
}
}
AVLNode<Type>* root;
};
//1 调整平衡 2更改bf
template<class Type>
void AVLTree<Type>::RotateR(AVLNode<Type>*& ptr)
{
AVLNode<Type>* subR = ptr;
ptr = subR->leftChild;
subR->leftChild = ptr->rightChild;
ptr->rightChild = subR;
ptr->bf = subR->bf = 0;
}
template<class Type>
void AVLTree<Type>::RotateLR(AVLNode<Type>*& ptr)
{
AVLNode<Type>* subL = ptr->leftChild;
AVLNode<Type>* subR = ptr;
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>
void AVLTree<Type>::RotateL(AVLNode<Type>*& ptr)
{
AVLNode<Type>* subL = ptr;
ptr = subL->rightChild;
subL->rightChild = ptr->leftChild;
ptr->leftChild = subL;
ptr->bf = subL->bf = 0;
}
template<class Type>
void AVLTree<Type>::RotateRL(AVLNode<Type>*& ptr)
{
AVLNode<Type>* subL = ptr;
AVLNode<Type>* subR = ptr->rightChild;
ptr = subR->leftChild;
subR->leftChild = ptr->rightChild;
ptr->rightChild = subR;
//更新subR->bf
if (ptr->bf >= 0)
subR->bf = 0;
else
subR->bf = 1;
subL->rightChild = ptr->leftChild;
ptr->leftChild = subL;
//更新subL->bf
if (ptr->bf == 1)
subL->bf = -1;
else
subL->bf = 0;
ptr->bf = 0;
}
template<class Type>
bool AVLTree<Type>::Insert(AVLNode<Type>*& t, const Type& x)
{
//1 按照BST的规则插入节点
AVLNode<Type>* pr = nullptr;
AVLNode<Type>* p = t;
stack<AVLNode<Type>*> st;
while (p != nullptr)
{
//用于查找x的插入位置
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 (x < pr->data)
pr->leftChild = p;
else
pr->rightChild = p;
//2 如果发生不平衡,需要调整平衡
while (!st.empty())
{
pr = st.top();
st.pop();
if (p == pr->leftChild)
pr->bf--;
else
pr->bf++;
if (pr->bf == 0)
break;
if (pr->bf == 1 || pr->bf == -1) // |bf| == 1 向上回溯
p = pr;
else
{
//|bf| == 2 发生不平衡 调整平衡
if (p == pr->leftChild) //左分支
{
if (p->bf < 0) // /
{
RotateR(pr);
//cout<<"RotateR."<<endl;
}
else // <
{
RotateLR(pr);
//cout<<"RotateLR."<<endl;
}
}
else //右分支
{
if (p->bf > 0) // \
{
RotateL(pr);
//cout<<"RotateL."<<endl;
}
else // >
{
RotateRL(pr);
//cout<<"RotateRL."<<endl;
}
}
break;
}
}
//重新链接
if (st.empty())
t = pr;
else
{
AVLNode<Type>* ppr = st.top();
if (ppr->data > pr->data)
ppr->leftChild = pr;
else
ppr->rightChild = pr;
}
return true;
}
template<class Type>
bool AVLTree<Type>::Remove(AVLNode<Type>*& t, const Type& key)
{
//1 按照bst的规则找到节点并删除
//2 删除节点后,若发生不平衡,需要重新调整并更新bf
}
void main()
{
int ar[] = { 9,26,16,3,7,11,18,14,15 };
int n = sizeof(ar) / sizeof(ar[0]);
AVLTree<int> avl;
for (int i = 0; i < n; ++i)
avl.Insert(ar[i]);
avl.InOrder();
avl.Insert(6);
avl.InOrder();
avl.Insert(12);
avl.InOrder();
avl.Insert(0);
avl.InOrder();
avl.Insert(4);
avl.InOrder();
}