一、AVLTree的定义
AVLTree
高度平衡的搜索二叉树
一棵平衡树,或是空树,或是具有以下性质的二叉搜索树:左子树和右子树都是AVL树,且左右子树的高度之差的绝对值不超过1
平衡因子:右树的高度 - 左树的高度值就是该根节点的平衡因子
例如:11这个节点的左树的高度为2,右树的高度为3,3 - 2 = 1,所以该根节点的平衡因子是1
而根据定义AVLTree的每一个节点都要满足左右子树的高度之差的绝对值不超过1这个条件
二、AVLTree的意义
上篇文章中我们实现了搜索二叉树,搜索二叉树查找的时间复杂度为O(N)而不是我们想象的O(logN)
这是因为这棵树有可能是以下情况
此时当我们查找key = 8时,该树的效率就应该是遍历一边该树,查找的时间复杂度为O(N),而为了解决这个效率问题,我们引入AVLTree来解决
因为AVLTree是一颗平衡二叉树,每个根节点左右子树的高度差不大于1,如此搜索的效率就加快为O(logN)
但如何实现以上条件的平衡呢,这就需要,我们在插入的时候不断向上判断平衡因子,当平衡因子不满足条件的时候,就触发了旋转的条件,而如何旋转才能既不破坏该树是搜索二叉树,同时又满足该树是平衡二叉树,这就需要分类讨论如何旋转
三、平衡二叉树的左旋、右旋、双旋
1. 左单旋
void RotateL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
parent->_right = subRL;
subR->_left = parent;
Node* parentparent = parent->_parent;
if(subRL)
subRL->_parent = parent;
parent->_parent = subR;
if (parent == _root)
{
subR->_parent = nullptr;
_root = subR;
}
else
{
subR->_parent = parentparent;
if (parentparent->_left == parent)
{
parentparent->_left = subR;
}
else
{
parentparent->_right = subR;
}
}
parent->_bf = subR->_bf = 0;
}
2.右单旋
void RotateR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
parent->_left = subLR;
subL->_right = parent;
Node* parentparent = parent->_parent;
if (subLR)
{
subLR->_parent = parent;
}
parent->_parent = subL;
if (parent == _root)
{
subL->_parent = nullptr;
_root = subL;
}
else
{
subL->_parent = parentparent;
if (parentparent->_left == parent)
{
parentparent->_left = subL;
}
else
{
parentparent->_right = subL;
}
}
parent->_bf = subL->_bf = 0;
}
3.右左旋
如果我们在子树b或子树c中插入一个新节点后parent节点的平衡因子变为2,此时不管是左单旋,还是右单旋,之后都不能真正解决问题
这时候需要右单旋subR,再左单旋parent
右左旋之后因为并没有修正平衡因子,需要手动根据具体情况修正
值得注意的一点是,我们在完成操作之后,该树回到了未插入之前的高度,插入之前整棵树的高度是h+2,在经过两次旋转变换之后,该树的高度仍然是h+2,所以没必要继续向上调整平衡因子
void RotateRL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
int bf = subRL->_bf;
RotateR(parent->_right);
RotateL(parent);
if (bf == 0)
{
parent->_bf = 0;
subRL->_bf = 0;
subR->_bf = 0;
}
else if(bf == -1)
{
parent->_bf = 0;
subRL->_bf = 0;
subR->_bf = 1;
}
else if (bf == 1)
{
parent->_bf = -1;
subRL->_bf = 0;
subR->_bf = 0;
}
else
{
assert(false);
}
}
4.左右旋
如果我们在子树b或子树c中插入一个新节点后parent节点的平衡因子变为2,此时不管是左单旋,还是右单旋,之后都不能真正解决问题
这时候需要左单旋subL,再右单旋parent
左右旋之后因为并没有修正平衡因子,需要手动根据具体情况修正
值得注意的一点是,我们在完成操作之后,该树回到了未插入之前的高度,插入之前整棵树的高度是h+2,在经过两次旋转变换之后,该树的高度仍然是h+2,所以没必要继续向上调整平衡因子
void RotateLR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
int bf = subLR->_bf;
RotateL(parent->_left);
RotateR(parent);
if (bf == 0)
{
subL->_bf = 0;
subLR->_bf = 0;
parent->_bf = 0;
}
else if (bf == -1)
{
subL->_bf = 0;
subLR->_bf = 0;
parent->_bf = 1;
}
else if (bf == 1)
{
subL->_bf = -1;
subLR->_bf = 0;
parent->_bf = 0;
}
else
{
assert(false);
}
}
四、AVLTree的插入
插入位置的寻找和搜索二叉树基本一致,关键是如何根据平衡因子调整该树成为平衡二叉树
bool Insert(const pair<K, V> kv)
{
if (_root == nullptr)
{
_root = new Node(kv);
}
Node* cur = _root;
Node* parent = nullptr;
while (cur)
{
if (cur->_kv.first > kv.first)
{
parent = cur;
cur = cur->_left;
}
else if (cur->_kv.first < kv.first)
{
parent = cur;
cur = cur->_right;
}
else
{
return false;
}
}
if (parent->_kv.first > kv.first)
{
parent->_left = new Node(kv);
cur = parent->_left;
cur->_parent = parent;
}
else
{
parent->_right = new Node(kv);
cur = parent->_right;
cur->_parent = parent;
}
while (parent)
{
if (cur == parent->_left)
{
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)
{
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);
}
}
}
五、整体代码(包含验证代码)
#include<iostream>
#include<assert.h>
#include<random>
using namespace std;
template<class K,class V>
struct AVLTreeNode
{
AVLTreeNode<K, V>* _left;
AVLTreeNode<K, V>* _right;
AVLTreeNode<K, V>* _parent;
pair<K, V> _kv;
int _bf;
AVLTreeNode(const pair<K,V> kv)
:_left(nullptr)
,_right(nullptr)
,_parent(nullptr)
,_kv(kv)
,_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);
}
Node* cur = _root;
Node* parent = nullptr;
while (cur)
{
if (cur->_kv.first > kv.first)
{
parent = cur;
cur = cur->_left;
}
else if (cur->_kv.first < kv.first)
{
parent = cur;
cur = cur->_right;
}
else
{
return false;
}
}
if (parent->_kv.first > kv.first)
{
parent->_left = new Node(kv);
cur = parent->_left;
cur->_parent = parent;
}
else
{
parent->_right = new Node(kv);
cur = parent->_right;
cur->_parent = parent;
}
while (parent)
{
if (cur == parent->_left)
{
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)
{
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);
}
}
}
void RotateL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
parent->_right = subRL;
subR->_left = parent;
Node* parentparent = parent->_parent;
if(subRL)
subRL->_parent = parent;
parent->_parent = subR;
if (parent == _root)
{
subR->_parent = nullptr;
_root = subR;
}
else
{
subR->_parent = parentparent;
if (parentparent->_left == parent)
{
parentparent->_left = subR;
}
else
{
parentparent->_right = subR;
}
}
parent->_bf = subR->_bf = 0;
}
void RotateR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
parent->_left = subLR;
subL->_right = parent;
Node* parentparent = parent->_parent;
if (subLR)
{
subLR->_parent = parent;
}
parent->_parent = subL;
if (parent == _root)
{
subL->_parent = nullptr;
_root = subL;
}
else
{
subL->_parent = parentparent;
if (parentparent->_left == parent)
{
parentparent->_left = subL;
}
else
{
parentparent->_right = subL;
}
}
parent->_bf = subL->_bf = 0;
}
void RotateRL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
int bf = subRL->_bf;
RotateR(parent->_right);
RotateL(parent);
if (bf == 0)
{
parent->_bf = 0;
subRL->_bf = 0;
subR->_bf = 0;
}
else if(bf == -1)
{
parent->_bf = 0;
subRL->_bf = 0;
subR->_bf = 1;
}
else if (bf == 1)
{
parent->_bf = -1;
subRL->_bf = 0;
subR->_bf = 0;
}
else
{
assert(false);
}
}
void RotateLR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
int bf = subLR->_bf;
RotateL(parent->_left);
RotateR(parent);
if (bf == 0)
{
subL->_bf = 0;
subLR->_bf = 0;
parent->_bf = 0;
}
else if (bf == -1)
{
subL->_bf = 0;
subLR->_bf = 0;
parent->_bf = 1;
}
else if (bf == 1)
{
subL->_bf = -1;
subLR->_bf = 0;
parent->_bf = 0;
}
else
{
assert(false);
}
}
bool IsBalance()
{
return _IsBalance(_root);
}
void InOrder()
{
_InOrder(_root);
cout << endl;
}
private:
int TreeHeight(Node* root)
{
if (root == nullptr)
{
return 0;
}
int leftheight = TreeHeight(root->_left);
int rightheight = TreeHeight(root->_right);
return leftheight > rightheight ? leftheight + 1 : rightheight + 1;
}
bool _IsBalance(Node* root)
{
if (root == nullptr)
{
return true;
}
int leftheight = TreeHeight(root->_left);
int rightheight = TreeHeight(root->_right);
return abs(leftheight - rightheight) >= 2 ? false : true && _IsBalance(root->_left) && _IsBalance(root->_right);
}
void _InOrder(Node* root)
{
if (root == nullptr)
{
return;
}
_InOrder(root->_left);
cout << root->_kv.first << " ";
_InOrder(root->_right);
}
Node* _root = nullptr;
};
测试代码
int main()
{
srand((unsigned int)time(NULL));
AVLTree<int, int> t;
for (int i = 0; i < N; i++)
{
int sum = rand();
t.Insert(make_pair(sum, sum));
if (t.IsBalance())
{
cout << "插入数据为 " << sum << "插入后该树仍然平衡" << endl;
}
else
{
cout << "插入数据为—" << sum << "插入后该树不平衡" << endl;
}
}
cout << t.IsBalance() << endl;
}