1、AVL树的概念
2、AVL树的实现
1、AVL树的概念
AVL树又名平衡二叉树,实际上也是一颗二叉搜索树,只不过需要满足特定的条件:就是要保证左右子树的高度之差(简称为平衡因子)的绝对值不超过1。它搜索的时间复杂度为O(log2n)。
如图就是一颗建议的AVL树,我们规定平衡因子的值为右子树高度减去左子树高度。
2、AVL树的实现
AVL树节点的定义:
template<class T>
struct AVLTreeNode
{
AVLTreeNode(const T& data)
: _pLeft(nullptr), _pRight(nullptr), _pParent(nullptr)
, _data(data), _bf(0)
{}
AVLTreeNode<T>* _pLeft; // 该节点的左孩子
AVLTreeNode<T>* _pRight; // 该节点的右孩子
AVLTreeNode<T>* _pParent; // 该节点的双亲
T _data;
int _bf; // 该节点的平衡因子
};
AVL树的插入:
AVL树实际上是在二叉搜索树的基础上引入了平衡因子的概念,因此插入要做的可以分为两步:
1、按照二叉搜索树的方式插入
2、调节节点的平衡因子
bool Insert(const T& data)
{
// 1. 先按照二叉搜索树的规则将节点插入到AVL树中
// ...
// 2. 新节点插入后,AVL树的平衡性可能会遭到破坏,此时就需要更新平衡因子,并检测是否破坏了AVL树 的平衡性
pCur插入后,pParent的平衡因子一定需要调整,在插入之前,pParent
的平衡因子分为三种情况:-1,0, 1, 分以下两种情况:
1. 如果pCur插入到pParent的左侧,只需给pParent的平衡因子-1即可
2. 如果pCur插入到pParent的右侧,只需给pParent的平衡因子+1即可
此时:pParent的平衡因子可能有三种情况:0,正负1, 正负2
1. 如果pParent的平衡因子为0,说明插入之前pParent的平衡因子为正负1,插入后被调整
成0,此时满足 AVL树的性质,插入成功
2. 如果pParent的平衡因子为正负1,说明插入前pParent的平衡因子一定为0,插入后被更
新成正负1,此时以pParent为根的树的高度增加,需要继续向上更新
3. 如果pParent的平衡因子为正负2,则pParent的平衡因子违反平衡树的性质,需要对其进
行旋转处理
*/
while (pParent)
{
// 更新双亲的平衡因子
if (pCur == pParent->_pLeft)
pParent->_bf--;
else
pParent->_bf++;
// 更新后检测双亲的平衡因子
if (0 == pParent->_bf)
{
break;
}
else if (1 == pParent->_bf || -1 == pParent->_bf)
{
// 插入前双亲的平衡因子是0,插入后双亲的平衡因为为1 或者 -1 ,说明以双亲
为根的二叉树
// 的高度增加了一层,因此需要继续向上调整
pCur = pParent;
pParent = pCur->_pParent;
}
else
{
// 双亲的平衡因子为正负2,违反了AVL树的平衡性,需要对以pParent
// 为根的树进行旋转处理
if(2 == pParent->_bf)
{
// ...
}
else
{
// ...
}
}
}
return true;
}
这里的旋转操作需要拿出来单独解析,根据节点插入位置的不同,AVL树的旋转总共分为四种:
1、节点插入较高左子树的左侧(左左,右单旋)
![](https://i-blog.csdnimg.cn/blog_migrate/fb6528e5c2e13c37f12fb7c6c49b3050.png)
此时也需考虑一些情况:
如果30节点有右孩子,那么就需要将它的右孩子放在60节点的左孩子处(因为30节点的右孩子一定比30大但比60小)
![](https://i-blog.csdnimg.cn/blog_migrate/447c15bce30e6ab4b883e9fab614a6e3.png)
也要考虑到60是根节点还是子树的情况,需要更新根节点或者记录60节点的双亲
void _RotateR(PNode pParent)
{
// pSubL: pParent的左孩子
// pSubLR: pParent左孩子的右孩子
PNode pSubL = pParent->_pLeft;
PNode pSubLR = pSubL->_pRight;
// 旋转完成之后,30的右孩子作为双亲的左孩子
pParent->_pLeft = pSubLR;
// 如果30的左孩子的右孩子存在,更新亲双亲
if(pSubLR)
pSubLR->_pParent = pParent;
// 60 作为 30的右孩子
pSubL->_pRight = pParent;
// 因为60可能是棵子树,因此在更新其双亲前必须先保存60的双亲
PNode pPParent = pParent->_pParent;
// 更新60的双亲
pParent->_pParent = pSubL;
// 更新30的双亲
pSubL->_pParent = pPParent;
// 如果60是根节点,根新指向根节点的指针
if(NULL == pPParent)
{
_pRoot = pSubL;
pSubL->_pParent = NULL;
}
else
{
// 如果60是子树,可能是其双亲的左子树,也可能是右子树
if(pPParent->_pLeft == pParent)
pPParent->_pLeft = pSubL;
else
pPParent->_pRight = pSubL;
}
// 根据调整后的结构更新部分节点的平衡因子
pParent->_bf = pSubL->_bf = 0;
}
2、节点插入较高右子树的右侧(右右,左单旋)
这种情况实际就是上一种情况的类比,换了个方向:
需要注意的事项与实现也与上一种情况相同。
3、节点插入较高左子树的右侧(左右,先左单旋再右单旋)
![](https://i-blog.csdnimg.cn/blog_migrate/feefb7241dfc140b518c0158a2d42769.png)
// 旋转之前,60的平衡因子可能是-1/0/1,旋转完成之后,根据情况对其他节点的平衡因子进
行调整
void _RotateLR(PNode pParent)
{
PNode pSubL = pParent->_pLeft;
PNode pSubLR = pSubL->_pRight;
// 旋转之前,保存pSubLR的平衡因子,旋转完成之后,需要根据该平衡因子来调整其他节
点的平衡因子
int bf = pSubLR->_bf;
// 先对30进行左单旋
_RotateL(pParent->_pLeft);
// 再对90进行右单旋
_RotateR(pParent);
if(1 == bf)
pSubL->_bf = -1;
else if(-1 == bf)
pParent->_bf = 1;
}
4、节点插入较高右子树的左侧(右左,先右单旋再左单旋)
完整代码实现:
#include<iostream>
#include<assert.h>
using namespace std;
#include <vector>
template<class K, class V>
struct AVLTreeNode
{
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
{
typedef AVLTreeNode<K, V> Node;
public:
bool Insert(const pair<K, V>& kv)
{
if (_root == nullptr)
{
_root = new Node(kv);
return true;
}
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
if (cur->_kv.first < kv.first)
{
parent = cur;
cur = cur->_right;
}
else if (cur->_kv.first > kv.first)
{
parent = cur;
cur = cur->_left;
}
else
{
return false;
}
}
cur = new Node(kv);
if (parent->_kv.first < kv.first)
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
cur->_parent = parent;
// ... 控制平衡
// 更新平衡因子
while (parent)
{
if (cur == parent->_left)
{
parent->_bf--;
}
else // if (cur == parent->_right)
{
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)
{
RotateL(parent);
}
else if (parent->_bf == -2 && cur->_bf == -1)
{
RotateR(parent);
}
else if (parent->_bf == 2 && cur->_bf == -1)
{
RotateRL(parent);
}
else if (parent->_bf == -2 && cur->_bf == 1)
{
RotateLR(parent);
}
break;
}
else
{
assert(false);
}
}
return true;
}
void RotateL(Node* parent)
{
++_rotateCount;
Node* cur = parent->_right;
Node* curleft = cur->_left;
parent->_right = curleft;
if (curleft)
{
curleft->_parent = parent;
}
cur->_left = parent;
Node* ppnode = parent->_parent;
parent->_parent = cur;
if (parent == _root)
{
_root = cur;
cur->_parent = nullptr;
}
else
{
if (ppnode->_left == parent)
{
ppnode->_left = cur;
}
else
{
ppnode->_right = cur;
}
cur->_parent = ppnode;
}
parent->_bf = cur->_bf = 0;
}
void RotateR(Node* parent)
{
++_rotateCount;
Node* cur = parent->_left;
Node* curright = cur->_right;
parent->_left = curright;
if (curright)
curright->_parent = parent;
Node* ppnode = parent->_parent;
cur->_right = parent;
parent->_parent = cur;
if (ppnode == nullptr)
{
_root = cur;
cur->_parent = nullptr;
}
else
{
if (ppnode->_left == parent)
{
ppnode->_left = cur;
}
else
{
ppnode->_right = cur;
}
cur->_parent = ppnode;
}
parent->_bf = cur->_bf = 0;
}
void RotateRL(Node* parent)
{
Node* cur = parent->_right;
Node* curleft = cur->_left;
int bf = curleft->_bf;
RotateR(parent->_right);
RotateL(parent);
if (bf == 0)
{
cur->_bf = 0;
curleft->_bf = 0;
parent->_bf = 0;
}
else if (bf == 1)
{
cur->_bf = 0;
curleft->_bf = 0;
parent->_bf = -1;
}
else if (bf == -1)
{
cur->_bf = 1;
curleft->_bf = 0;
parent->_bf = 0;
}
else
{
assert(false);
}
}
void RotateLR(Node* parent)
{
Node* cur = parent->_left;
Node* curright = cur->_right;
int bf = curright->_bf;
RotateL(parent->_left);
RotateR(parent);
if (bf == 0)
{
parent->_bf = 0;
cur->_bf = 0;
curright->_bf = 0;
}
else if (bf == -1)
{
parent->_bf = 1;
cur->_bf = 0;
curright->_bf = 0;
}
else if (bf == 1)
{
parent->_bf = 0;
cur->_bf = -1;
curright->_bf = 0;
}
}
int Height()
{
return Height(_root);
}
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 IsBalance()
{
return IsBalance(_root);
}
bool IsBalance(Node* root)
{
if (root == nullptr)
return true;
int leftHight = Height(root->_left);
int rightHight = Height(root->_right);
if (rightHight - leftHight != root->_bf)
{
cout << "平衡因子异常:" << root->_kv.first << "->" << root->_bf << endl;
return false;
}
return abs(rightHight - leftHight) < 2
&& IsBalance(root->_left)
&& IsBalance(root->_right);
}
private:
Node* _root = nullptr;
public:
int _rotateCount = 0;
};