AVL树概念
二叉搜索树虽可以缩短查找的效率,但如果数据有序或接近有序二叉搜索树将退化为单支树,查找元素相当于在顺序表中搜索元素,效率低下
。因此,两位俄罗斯的数学家
G.M.Adelson-Velskii和E.M.Landis在1962年
发明了一种解决上述问题的方法:当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之差的绝对值不超过1
(需要对树中的结点进行调整),即可降低树的高度,从而减少平均搜索长度。
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)。
AVL树节点的结构
实现的是KV模型
平衡因子的计算方法由第二种方法实现
AVL树的插入
分为三个步骤
1.按照二叉搜索树的方式插入新节点
2.更新整体节点的平衡因子
3.更新平衡因子的过程中判断是否需要旋转
插入新节点
bool Insert(const pair<K, V>& kv)
{
Node* parent = nullptr;
Node* cur = _root;
//如果根为空
if (_root == nullptr)
{
_root = new Node(kv);
return true;
}
//寻找插入位置
while (cur)
{
//如果要插入的值比cur的值小
if (cur->_kv.first > kv.first)
{
//往左找
parent = cur;
cur = cur->_left;
}
//如果要插入的值比cur的值大
else if (cur->_kv.first < kv.first)
{
//往右找
parent = cur;
cur = cur->_right;
}
//如果相等就不再插入
else
{
return false;
}
}
//插入
Node* newnode = new Node(kv);
cur = newnode;
if (parent->_kv.first > kv.first)
{
parent->_left = newnode;
newnode->_parent = parent;
//父母节点更新平衡因子
parent->_bf--;
}
else
{
parent->_right = newnode;
newnode->_parent = parent;
//父母节点更新平衡因子
parent->_bf++;
}
}
更新整体节点的平衡因子
更新整体节点的平衡因子过程中分三种情况:
1.首先在插入的过程中,更新插入节点的父母节点的平衡因子
2.更新以后判断父母节点的平衡因子
(1)更新后父母节点的平衡因子是0
停止更新,说明更新前父母节点的平衡因子是1或者-1,现在变成0也表明了父母节点的左右子树中高度矮的子树插入了新节点
if (parent->_bf == 0)
{
break;
}
(2)更新后父母节点的平衡因子是1或者-1
继续向上更新, 说明更新前父母节点的平衡因子是0,现在是1或者-1,也表明父母节点的左右子树中的一颗树的高度变高了。父母节点所在的子树高度也变高了。
else if (parent->_bf == 1 || parent->_bf == -1)
{
cur = parent;
//继续向上更新
parent = parent->_parent;
if (parent)
{
if (parent->_left == cur)
{
parent->_bf--;
}
else
{
parent->_bf++;
}
}
}
(3)更新后父母节点的平衡因子是2或者-2
说明父母节点所在的子树已经不平衡了需要旋转处理
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)
{
//左右双旋
RotateLR(parent);
}
else if (parent->_bf == 2 && cur->_bf == -1)
{
//右左双旋
RotateRL(parent);
}
else
{
//不可能的情况
assert(false);
}
break;
}
整体的插入代码
//更新整体平衡因子
while (parent)
{
if (parent->_bf == 0)
{
break;
}
else if (parent->_bf == 1 || parent->_bf == -1)
{
cur = parent;
//继续向上更新
parent = parent->_parent;
if (parent)
{
if (parent->_left == cur)
{
parent->_bf--;
}
else
{
parent->_bf++;
}
}
}
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)
{
//左右双旋
RotateLR(parent);
}
else if (parent->_bf == 2 && cur->_bf == -1)
{
//右左双旋
RotateRL(parent);
}
else
{
//不可能的情况
assert(false);
}
break;
}
else
{
//不可能的情况
assert(false);
}
}
旋转处理
旋转处理是为了处理保证二叉搜索树处于平衡状态,每当二叉搜索树不平衡时就会触发旋转。
旋转又分4种分别处理4种不平衡的情况。
右单旋
void RotateR(Node* parent)
{
//要调整的节点
Node* sub = parent;
//要调整的节点的左孩子
Node* subL = parent->_left;
//要调整的节点的左孩子的右孩子
Node* subLR = subL->_right;
//要调整的节点的父母
Node* subparent = sub->_parent;
//重新链接关系
if (subLR)
subLR->_parent = sub;
sub->_left = subLR;
sub->_parent = subL;
subL->_right = sub;
subL->_parent = subparent;
if (_root == sub)
{
_root = subL;
}
else
{
if (subparent->_left == sub)
{
subparent->_left = subL;
}
else
{
subparent->_right = subL;
}
}
subL->_bf = sub->_bf = 0;
}
左单旋
void RotateL(Node* parent)
{
//要调整的节点
Node* sub = parent;
//要调整的节点的右孩子
Node* subR = parent->_right;
//要调整的节点的有孩子的左孩子
Node* subRL = subR->_left;
//要调整的节点的父母
Node* subparent = sub->_parent;
//重新链接关系
if (subRL)
subRL->_parent = sub;
sub->_right = subRL;
sub->_parent = subR;
subR->_left = sub;
subR->_parent = subparent;
if (_root == sub)
{
_root = subR;
}
else
{
if (subparent->_left == sub)
{
subparent->_left = subR;
}
else
{
subparent->_right = subR;
}
}
subR->_bf = sub->_bf = 0;
}
左右双旋
void RotateLR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
int bf = subLR->_bf;
RotateL(parent->_left);
RotateR(parent);
if (bf == -1)
{
parent->_bf = 1;
subL->_bf = 0;
subLR->_bf = 0;
}
else if (bf == 1)
{
parent->_bf = 0;
subLR->_bf = 0;
subL->_bf = -1;
}
else if (bf == 0)
{
parent->_bf = 0;
subLR->_bf = 0;
subL->_bf = 0;
}
else
{
assert(false);
}
}
右左双旋
void RotateRL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
int bf = subRL->_bf;
RotateR(parent->_right);
RotateL(parent);
if (bf == -1)
{
parent->_bf = 0;
subR->_bf = 1;
subRL->_bf = 0;
}
else if (bf == 1)
{
parent->_bf = -1;
subRL->_bf = 0;
subR->_bf = 0;
}
else if (bf == 0)
{
parent->_bf = 0;
subRL->_bf = 0;
subR->_bf = 0;
}
else
{
assert(false);
}
}
AVL树的整体代码
AVL.h
#pragma once
#include<assert.h>
namespace lzf
{
template<class K, class V>
struct AVLTreeNode
{
AVLTreeNode<K, V>* _left;//该节点的左孩子
AVLTreeNode<K, V>* _right;//该节点的右孩子
AVLTreeNode<K, V>* _parent;//该节点的双亲节点
pair<K, V> _kv;//该节点的kv
int _bf;//该节点的平衡因子
//构造函数
AVLTreeNode(const pair<K, V>& kv)
:_left(nullptr)
,_right(nullptr)
,_parent(nullptr)
,_bf(0)
,_kv(kv)
{}
};
template<class K,class V>
class AVLTree
{
typedef AVLTreeNode<K, V> Node;
public:
AVLTree()
:_root(nullptr)
{}
bool Insert(const pair<K, V>& kv)
{
Node* parent = nullptr;
Node* cur = _root;
//如果根为空
if (_root == nullptr)
{
_root = new Node(kv);
return true;
}
//寻找插入位置
while (cur)
{
//如果要插入的值比cur的值小
if (cur->_kv.first > kv.first)
{
//往左找
parent = cur;
cur = cur->_left;
}
//如果要插入的值比cur的值大
else if (cur->_kv.first < kv.first)
{
//往右找
parent = cur;
cur = cur->_right;
}
//如果相等就不再插入
else
{
return false;
}
}
//插入
Node* newnode = new Node(kv);
cur = newnode;
if (parent->_kv.first > kv.first)
{
parent->_left = newnode;
newnode->_parent = parent;
//父母节点更新平衡因子
parent->_bf--;
}
else
{
parent->_right = newnode;
newnode->_parent = parent;
//父母节点更新平衡因子
parent->_bf++;
}
//更新整体平衡因子
while (parent)
{
if (parent->_bf == 0)
{
break;
}
else if (parent->_bf == 1 || parent->_bf == -1)
{
cur = parent;
//继续向上更新
parent = parent->_parent;
if (parent)
{
if (parent->_left == cur)
{
parent->_bf--;
}
else
{
parent->_bf++;
}
}
}
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)
{
//左右双旋
RotateLR(parent);
}
else if (parent->_bf == 2 && cur->_bf == -1)
{
//右左双旋
RotateRL(parent);
}
else
{
//不可能的情况
assert(false);
}
break;
}
else
{
//不可能的情况
assert(false);
}
}
return true;
}
void InOrder()
{
_InOrder(_root);
}
bool IsbalanceTree()
{
return _IsbalanceTree(_root);
}
private:
void RotateR(Node* parent)
{
//要调整的节点
Node* sub = parent;
//要调整的节点的左孩子
Node* subL = parent->_left;
//要调整的节点的左孩子的右孩子
Node* subLR = subL->_right;
//要调整的节点的父母
Node* subparent = sub->_parent;
//重新链接关系
if (subLR)
subLR->_parent = sub;
sub->_left = subLR;
sub->_parent = subL;
subL->_right = sub;
subL->_parent = subparent;
if (_root == sub)
{
_root = subL;
}
else
{
if (subparent->_left == sub)
{
subparent->_left = subL;
}
else
{
subparent->_right = subL;
}
}
subL->_bf = sub->_bf = 0;
}
void RotateL(Node* parent)
{
//要调整的节点
Node* sub = parent;
//要调整的节点的右孩子
Node* subR = parent->_right;
//要调整的节点的有孩子的左孩子
Node* subRL = subR->_left;
//要调整的节点的父母
Node* subparent = sub->_parent;
//重新链接关系
if (subRL)
subRL->_parent = sub;
sub->_right = subRL;
sub->_parent = subR;
subR->_left = sub;
subR->_parent = subparent;
if (_root == sub)
{
_root = subR;
}
else
{
if (subparent->_left == sub)
{
subparent->_left = subR;
}
else
{
subparent->_right = subR;
}
}
subR->_bf = sub->_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 == -1)
{
parent->_bf = 0;
subR->_bf = 1;
subRL->_bf = 0;
}
else if (bf == 1)
{
parent->_bf = -1;
subRL->_bf = 0;
subR->_bf = 0;
}
else if (bf == 0)
{
parent->_bf = 0;
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 == -1)
{
parent->_bf = 1;
subL->_bf = 0;
subLR->_bf = 0;
}
else if (bf == 1)
{
parent->_bf = 0;
subLR->_bf = 0;
subL->_bf = -1;
}
else if (bf == 0)
{
parent->_bf = 0;
subLR->_bf = 0;
subL->_bf = 0;
}
else
{
assert(false);
}
}
void _InOrder(Node* root)
{
if (root == nullptr)
{
return;
}
_InOrder(root->_left);
cout << root->_kv.first << ":" << root->_kv.second << endl;
_InOrder(root->_right);
}
int Hegiht(Node* root)
{
if (root == nullptr)
{
return 0;
}
return Hegiht(root->_left) > Hegiht(root->_right) ? Hegiht(root->_left) + 1 : Hegiht(root->_right) + 1;
}
bool _IsbalanceTree(Node* root)
{
if (root == nullptr)
{
return true;
}
int leftHeight = Hegiht(root->_left);
int rightHeight = Hegiht(root->_right);
if ((rightHeight - leftHeight) != root->_bf)
{
cout << root->_kv.first << "现在bf是:" << root->_bf <<" ";
cout << "应该是:" << (rightHeight - leftHeight) << endl;
return false;
}
return abs(rightHeight - leftHeight) < 2
&& _IsbalanceTree(root->_left)
&& _IsbalanceTree(root->_right);
}
private:
Node* _root;
};
void Test_AVLTree1()
{
AVLTree<int, int> tree;
tree.Insert(make_pair(5, 5));
tree.Insert(make_pair(3, 3));
tree.Insert(make_pair(8, 8));
tree.Insert(make_pair(4, 4));
tree.Insert(make_pair(6, 6));
tree.Insert(make_pair(2, 2));
tree.Insert(make_pair(7, 7));
tree.InOrder();
cout << tree.IsbalanceTree();
}
void Test_AVLTree2()
{
AVLTree<int, int> t;
//int a[] = {5,4,3,2,1,0};
//int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
for (auto e : a)
{
t.Insert(make_pair(e, e));
cout << "Insert" << e << ":" << t.IsbalanceTree() << endl;
}
t.InOrder();
cout << t.IsbalanceTree() << endl;
}
}