二叉平衡树(AVL树)
AVL树其实就是在二叉搜索树的基础上,引入平衡因子的概念,通过旋转来调整平衡因子,使得二叉树始终平衡,效率更高.
特点:
AVL树的性能:
AVL树是一棵绝对平衡的二叉搜索树,其要求每个节点的左右子树的高度差的绝对值不超过1,这样就可以保证.
查询时高效的时间复杂度:log2(N),但是如果AVL树做一些结构修改的操作,性能就非常低下:
插入时要维护其绝对平衡,旋转的次数比较多,更差的是在删除时,有可能一直要让旋转到根的位置
因此:如果需要一种查询高效且有序的数据结构,而且数据的个数为静态的(即不会改变),则可以考虑AVL树.
实现思路:
数据结构:这里不仅需要左右子树,因为涉及到大量的平衡因子调节,所有还需要保存父节点的指针,要用到三叉链的结构.
template
struct AVLNode {
int _val;
int _bf; //平衡因子
AVLNode* _left;
AVLNode* _right;
AVLNode* _parent;
AVLNode(const T& val = T())
:_val(val)
,_bf(0)
,_left(nullptr)
,_right(nullptr)
_parent(nullptr)
{}
};
查找:
AVL树的本质其实还是二叉搜索树,所有查找的部分与二叉搜索树的相同,直接复用,不用修改.
直接从根节点出发,,比根节点小则查找左子树,比根节点大则查找右子树.相同则直接返回.如果遍历完还没有找到,则说明想要查找的节点不在此树中,返回nullptr.
Node* Find(const K& key)
{
//根据二叉搜索树的性质,从根节点出发,比根节点大则查找右子树,比根节点小则查找左子树
Node* cur = _root;
while (cur)
{
//比根节点大则查找右子树
if (key > cur->_kv.first)
{
cur = cur->_right;
}
//比根节点小则查找左子树
else if (key < cur->_kv.first)
{
cur = cur->_left;
}
//相同则返回
else
{
return cur;
}
}
//遍历完则说明查找不到,返回false
return nullptr;
}
插入(查找+插入+旋转):
插入分三个步骤:
平衡因子
平衡因子,其实就是左右子树的高度差.AVL树通过控制高度差不超过2,来实现平衡.
当某节点平衡因子为0时,说明它的左右子树平衡
当平衡因子为1或者-1时,说明左右子树存在高度差,其父节点可能存在不平衡,需要向上继续判断.
当平衡因子为2或者-2时,说明此事不平衡,需要旋转处理.
AVL树的插入调整:
假如以parent为根的子树不平衡,即parent的平衡因子为2或者-2,分一下情况考虑:
parent的平衡因子为2,说明parent的右子树高,设parent的右子树的根为subR
(1).当subR的平衡因子为1时,即右边的右边高,执行左单旋;
左旋的步骤:
void RotateL(){
Node* subR = parent->_right;
Node* subRL = subR->_left;
subR->_left = parent;
parent->_right = subRL;
if(subRL){
subRL->_parent = parent;
}
//连接subR与祖父节点
if(parent == _root){
_root = subR;
subR->_parent = nullptr;
}else{
Node* g = parent->_parent;
subR->_parent = g;
if(g->_left == parent){
g->_left = subR;
}else{
g->_right = subR;
}
}
parent->_parent = subR;
parent->_bf = subR->_bf = 0;
}
(2).当subR的平衡因子为-1时,即右边的左边高,执行右左双旋;
注意:红蓝节点分别为两种插入情况
右左双旋的步骤:
if(parent->_bf == 2 && cur->_bf == -1){
//右边的左边高:右旋+左旋
Node* subR = parent->_right;
Node* subRL = subR->_left;
int bf = subRL->_bf;
//右旋+左旋
RotateR(cur);
RotateL(parent);
//更新平衡因子
if(bf == 1){
parent->_bf = -1;
subR->_bf = 0;
}else{
parent->_bf = 0;
subR->_bf = 1;
}
}
2.parent的平衡因子为-2,说明parent的左子树高,设parent的左子树的根为subL
(1).当subL的平衡因子为-1时,即左边的左边高,执行右单旋;
右旋的步骤:
//右旋:
void RotateR(Node* parent) {
Node* subL = parent->_left;
Node* subLR = subL->_right;
subL->_right = parent;
parent->_left = subLR;
if (sunLR) {
subLR->_parent = parent;
}
if (parent == root) {
_root = subL;
subL->_parent = nullptr;
}
else {
Node* g = parent->_parent;
subL->_parent = g;
if (g->_left == parent) {
g->_left = subL;
}
else {
g->_right = subL;
}
}
//再连接parent的_parent
parent->_parent = subL;
parent->_bf = subL->_bf = 0;
}
(2).当subL的平衡因子为1时,即左边的右边高,执行左右双旋;
注意:红蓝节点分别为两种插入情况
左右双旋的步骤:
if(parent->_bf == -2 && cur->_bf == 1){
//左边的右边高:左旋+右旋
Node* subL = parent->_left;
Node* subLR = subL->_right;
int bf = subLR->_bf; //保存subLR的平衡因子,用来判断更新subL和parent的平衡因子
//左旋+右旋:
RotateL(cur);
RotateR(parent);
//更新平衡因子:
if(bf == 1){
parent->_bf = 0;
subL->_bf = -1;
}else{
parent->_bf = 1;
subL->_bf = 0;
}
}
旋转完成后,原parent为根的子树高度降低,已经平衡,不需要再向上更新.
删除:
AVL树的删除极为复杂,但是思路还是很简单.
1.按照二叉搜索树的规则进行删除
2.更新平衡因子,并且进行旋转来调整(最坏的情况下可能会一直调整到根节点)
完整代码实现:
#include
using namespace std;
template
struct AVLNode {
T _value;
AVLNode* _left;
AVLNode* _right;
AVLNode* _parent;
int _bf; //平衡因子
AVLNode(const T& val = T())
:_value(val)
, _left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _bf(0)
{}
};
template
class AVLTree {
public:
typedef AVLNode Node;
AVLTree()
:_root(nullptr)
{}
//搜索树的插入
bool insert(const T& val) {
//如果根为空
if (_root == nullptr) {
_root = new Node(val);
return true;
}
//查找插入的位置
Node* cur = _root;
Node* parent = nullptr;
while (cur) {
parent = cur;
if (cur->_value == val)
return false;
else if (cur->_value < val)
cur = cur->_left;
else
cur = cur->_right;
}
//插入
cur = new Node(val);
if (parent->_value < val)
parent->_right = cur;
else
parent->_left = cur;
cur->_parent = parent;
//更新+调整
while (parent) {
//更新parent平衡因子
if (parent->_left == cur)
--parent->_bf;
else
++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) {
//左边的左边高,需要右旋
RotateR(parent);
}
else if (parent->_bf == 2 && cur->_bf == 1) {
//右边的右边高,需要左旋
RotateL(parent);
}
else if (parent->_bf == 2 && cur->_bf == -1) {
//右边的左边高,需要右旋+左旋
Node* subR = parent->_right;
Node* subRL = subR->_left;
int bf = subRL->_bf;
//以cur为轴左旋
RotateR(cur);
//以parent为轴右旋
RotateL(parent);
//调整平衡因子
if (bf == 1) {
subR->_bf = 0;
parent->_bf = -1;
}
else if (bf == -1) {
subR->_bf = 1;
parent->_bf = 0;
}
}
else if (parent->_bf == -2 && cur->_bf == 1) {
//左边的右边高
Node* subL = parent->_left;
Node* subLR = subL->_right;
int bf = subLR->_bf;
RotateL(cur);
RotateR(parent);
if (bf == 1) {
parent->_bf = 0;
subL->_bf = -1;
}
else if (bf == -1) {
parent->_bf = 1;
subL->_bf = 0;
}
}
break;
}
}
return true;
}
//右旋:
void RotateR(Node* parent) {
Node* subL = parent->_left;
Node* subLR = subL->_right;
subL->_right = parent;
parent->_left = subLR;
if (subLR) {
subLR->_parent = parent;
}
//先连接subL的_parent
if (parent == _root) {
_root = subL;
subL->_parent = nullptr;
}
else {
Node* g = parent->_parent;
subL->_parent = g;
if (g->_left == parent)
g->_left = subL;
else
g->_right = subL;
}
//再连接parent的_parent
parent->_parent = subL;
parent->_bf = subL->_bf = 0;
}
//左旋:
void RotateL(Node* parent) {
Node* subR = parent->_right;
Node* subRL = subR->_left;
subR->_left = parent;
parent->_right = subRL;
if (subRL)
subRL->_parent = parent;
if (parent == _root) {
_root = subR;
subR->_parent = nullptr;
}
else {
Node* g = parent->_parent;
subR->_parent = g;
if (g->_left==parent)
g->_left = subR;
else
g->_right = subR;
}
parent->_parent = subR;
parent->_bf = subR->_bf = 0;
}
void inorder() {
_inorder(_root);
cout << endl;
}
void _inorder(Node* root){
if (root) {
_inorder(root->_left);
cout << root->_value << " ";
_inorder(root->_right);
}
}
bool isBalance()
{
return _isBalance(_root);
}
bool _isBalance(Node* root)
{
if (root == nullptr)
return true;
//左右子树高度差是否和平衡因子相等
int subL = Height(root->_left);
int subR = Height(root->_right);
if (root->_bf != subR - subL)
{
cout << "节点:" << root->_value << "异常: bf: " << root->_bf << " 高度差:" << subR - subL << endl;
return false;
}
//平衡因子的绝对值知否小于2
return abs(root->_bf) < 2
&& _isBalance(root->_left)
&& _isBalance(root->_right);
}
int Height(Node* root)
{
if (root == nullptr)
return 0;
int left = Height(root->_left);
int right = Height(root->_right);
return left > right ? left + 1 : right + 1;
}
private:
Node* _root;
};