AVLTree前言:二叉搜索树虽可以缩短查找的效率,但如果数据有序或接近有序二叉搜索树将退化为单支树,查找元素相当于在顺序表中搜索元素,效率低下。因此,两位俄罗斯的数学家G.M.Adelson-Velskii和E.M.Landis在1962年
发明了一种解决上述问题的方法:当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之差的绝对值不超过1(需要对树中的结点进行调整),即可降低树的高度,从而减少平均搜索长度。
目录:
- AVLTree特性
- AVLTree定义
- AVLTree插入
- 插入第一步
- 插入第二步
- AVLTree旋转过程
- 单旋转的抽象图
- 单旋旋转过程
- 双旋转抽象图
- 双旋转抽象过程
- AVLTree实现
AVLTree特性
- 一棵AVL树或者是空树,或者是具有以下性质的二叉搜索树:
- 它的左右子树都是AVL树左右子树高度之差(简称平衡因子)的绝对值不超过1(-1/0/1)
如果一棵二叉搜索树是高度平衡的,它就是AVL树。如果它有n个结点,其高度可保持在 O ( l o g 2 n ) O(log_2 n) O(log2n),搜索时间复杂度O( l o g 2 n log_2 n log2n)
AVLTree定义
template<class T>
struct AVLTreeNode
{
AVLTreeNode(const T& data = T())
: _pLeft(nullptr)
, _pRight(nullptr)
, _pParent(nullptr)
, _data(data)
, _bf(0)
{}
AVLTreeNode<T>* _pLeft;
AVLTreeNode<T>* _pRight;
AVLTreeNode<T>* _pParent;
T _data;
int _bf; // 节点的平衡因子
};
AVLTree插入
AVL树就是在二叉搜索树的基础上引入了平衡因子,因此AVL树也可以看成是二叉搜索树。那么
AVL树的插入过程可以分为两步:
- 按照二叉搜索树的方式插入新节点
- 调整节点的平衡因子
第一步的过程:
按照二叉搜索树的方式插入新节点
第二步的过程:
调整节点的平衡因子
旋转过程
旋转有四种旋转:左单旋,右单旋,左右双旋,右左双旋
单旋转的抽象图
AVLTree的抽象图是抽象子树的高度
长方形代表所有平衡的子树
左单旋、右单旋抽象图
单旋旋转过程
代码实现:要注意的点
- grandparent是否为根
- curLeft是否为空
- 不仅要更新左右孩子指针,还有更新父亲指针
- 一共涉及四个结点的改动:
1.grandparent的parent
2.grandparent
3.cur
4.curLeft
右单旋类似于左单旋
左右单旋实现代码如下
// 右单旋
void RotateR(Node* pParent)
{
Node* grandparent = pParent->_pParent;
Node* cur = pParent->_pLeft;
Node* curRight = cur->_pRight;
cur->_pRight = pParent;
cur->_pParent = grandparent;
pParent->_pLeft = curRight;
pParent->_pParent = cur;
if (curRight)
curRight->_pParent = pParent;
if (pParent == _pRoot)
{
_pRoot = cur;
}
else
{
if (grandparent->_pLeft == pParent)
{
grandparent->_pLeft = cur;
}
else
{
grandparent->_pRight = cur;
}
}
pParent->_bf = cur->_bf = 0;
}
// 左单旋
void RotateL(Node* pParent)
{
Node* grandparent = pParent->_pParent;
Node* cur = pParent->_pRight;
Node* curLeft = cur->_pLeft;
cur->_pLeft = pParent;
cur->_pParent = grandparent;
pParent->_pRight = curLeft;
pParent->_pParent = cur;
if (curLeft)
curLeft->_pParent = pParent;
if (pParent == _pRoot)
{
_pRoot = cur;
}
else
{
if (grandparent->_pLeft == pParent)
{
grandparent->_pLeft = cur;
}
else
{
grandparent->_pRight = cur;
}
}
pParent->_bf = cur->_bf = 0;
}
双旋转抽象图
第一种情况
第二种情况
左边为左右双旋,右边为右左双旋
双旋旋转过程
右左单旋类似于左右单旋
双旋实现代码如下
// 右左双旋
void RotateRL(Node* pParent)
{
Node* cur = pParent->_pRight;
Node* curLeft = cur->_pLeft;
if (curLeft->_bf == 1)
{
RotateR(cur);
RotateL(pParent);
curLeft->_bf = 0;
pParent->_bf = -1;
cur->_bf = 0;
}
else if (curLeft->_bf == -1)
{
RotateR(cur);
RotateL(pParent);
cur->_bf = 1;
pParent->_bf = curLeft->_bf = 0;
}
else
{
RotateR(cur);
RotateL(pParent);
pParent->_bf = curLeft->_bf = cur->_bf = 0;
}
}
// 左右双旋
void RotateLR(Node* pParent)
{
Node* cur = pParent->_pLeft;
Node* curRight = cur->_pRight;
if (curRight->_bf == 1)
{
RotateL(cur);
RotateR(pParent);
cur->_bf = -1;
curRight->_bf = pParent->_bf = 0;
}
else if (curRight->_bf == -1)
{
RotateL(cur);
RotateR(pParent);
cur->_bf = curRight->_bf = 0;
pParent->_bf = 1;
}
else
{
RotateL(cur);
RotateR(pParent);
pParent->_bf = curRight->_bf = cur->_bf = 0;
}
}
AVLTree代码实现如下
template<class T>
struct AVLTreeNode
{
AVLTreeNode(const T& data = T())
: _pLeft(nullptr)
, _pRight(nullptr)
, _pParent(nullptr)
, _data(data)
, _bf(0)
{}
AVLTreeNode<T>* _pLeft;
AVLTreeNode<T>* _pRight;
AVLTreeNode<T>* _pParent;
T _data;
int _bf; // 节点的平衡因子
};
// AVL: 二叉搜索树 + 平衡因子的限制
template<class T>
class AVLTree
{
typedef AVLTreeNode<T> Node;
public:
AVLTree()
: _pRoot(nullptr)
{}
// 在AVL树中插入值为data的节点
bool Insert(const T& data)
{
if (_pRoot == nullptr)
{
_pRoot = new Node(data);
return true;
}
Node* cur = _pRoot;
Node* parent = nullptr;
while (cur)
{
if (cur->_data < data)
{
parent = cur;
cur = cur->_pRight;
}
else if (cur->_data > data)
{
parent = cur;
cur = cur->_pLeft;
}
else
{
return false;
}
}
cur = new Node(data);
if (parent->_data > cur->_data)
{
parent->_pLeft = cur;
}
else
{
parent->_pRight = cur;
}
cur->_pParent = parent;
while (parent)
{
if (parent->_pRight == cur)
{
parent->_bf++;
}
else
{
parent->_bf--;
}
if (parent->_bf == 0)
{
break;
}
else if (parent->_bf == -1 || parent->_bf == 1)
{
cur = parent;
parent = parent->_pParent;
}
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)
{
RotateRL(parent);
}
else if (parent->_bf == -2 && cur->_bf == -1)
{
RotateR(parent);
}
else if (parent->_bf == -2 && cur->_bf == 1)
{
RotateLR(parent);
}
break;
// AVL树的验证
bool IsAVLTree()
{
return _IsAVLTree(_pRoot);
}
}
else
{
assert("违反平衡因子规则");
}
}
}
private:
// 根据AVL树的概念验证pRoot是否为有效的AVL树
bool _IsAVLTree(Node* pRoot)
{
if (pRoot == nullptr)
return true;
int leftH = _Height(pRoot->_pLeft);
int rightH = _Height(pRoot->_pRight);
if (leftH - rightH > 1 || leftH - rightH < -1)
return false;
_IsAVLTree(pRoot->_pLeft);
_IsAVLTree(pRoot->_pRight);
return true;
}
size_t _Height(Node* pRoot)
{
if (pRoot == nullptr)
return 0;
int leftH = _Height(pRoot->_pLeft) + 1;
int rightH = _Height(pRoot->_pRight) + 1;
if (leftH > rightH)
{
return leftH;
}
else
{
return rightH;
}
}
// 右单旋
void RotateR(Node* pParent)
{
Node* grandparent = pParent->_pParent;
Node* cur = pParent->_pLeft;
Node* curRight = cur->_pRight;
cur->_pRight = pParent;
cur->_pParent = grandparent;
pParent->_pLeft = curRight;
pParent->_pParent = cur;
if (curRight)
curRight->_pParent = pParent;
if (pParent == _pRoot)
{
_pRoot = cur;
}
else
{
if (grandparent->_pLeft == pParent)
{
grandparent->_pLeft = cur;
}
else
{
grandparent->_pRight = cur;
}
}
pParent->_bf = cur->_bf = 0;
}
// 左单旋
void RotateL(Node* pParent)
{
Node* grandparent = pParent->_pParent;
Node* cur = pParent->_pRight;
Node* curLeft = cur->_pLeft;
cur->_pLeft = pParent;
cur->_pParent = grandparent;
pParent->_pRight = curLeft;
pParent->_pParent = cur;
if (curLeft)
curLeft->_pParent = pParent;
if (pParent == _pRoot)
{
_pRoot = cur;
}
else
{
if (grandparent->_pLeft == pParent)
{
grandparent->_pLeft = cur;
}
else
{
grandparent->_pRight = cur;
}
}
pParent->_bf = cur->_bf = 0;
}
// 右左双旋
void RotateRL(Node* pParent)
{
Node* cur = pParent->_pRight;
Node* curLeft = cur->_pLeft;
if (curLeft->_bf == 1)
{
RotateR(cur);
RotateL(pParent);
curLeft->_bf = 0;
pParent->_bf = -1;
cur->_bf = 0;
}
else if (curLeft->_bf == -1)
{
RotateR(cur);
RotateL(pParent);
cur->_bf = 1;
pParent->_bf = curLeft->_bf = 0;
}
else
{
RotateR(cur);
RotateL(pParent);
pParent->_bf = curLeft->_bf = cur->_bf = 0;
}
}
// 左右双旋
void RotateLR(Node* pParent)
{
Node* cur = pParent->_pLeft;
Node* curRight = cur->_pRight;
if (curRight->_bf == 1)
{
RotateL(cur);
RotateR(pParent);
cur->_bf = -1;
curRight->_bf = pParent->_bf = 0;
}
else if (curRight->_bf == -1)
{
RotateL(cur);
RotateR(pParent);
cur->_bf = curRight->_bf = 0;
pParent->_bf = 1;
}
else
{
RotateL(cur);
RotateR(pParent);
pParent->_bf = curRight->_bf = cur->_bf = 0;
}
}
private:
Node* _pRoot;
};