目录
不会就画图!不会就画图!不会就画图!
一、AVL树
二叉搜索树如果接近有序,就接近单只,查找效率极低
所以,为了解决这个缺点,控制平衡,所以推出了AVL树
1962年,两位俄罗斯数学家搞出来的,用名字首字母命名
AVL树也叫二叉搜索平衡树
特点:左右子树都是AVL树,左右子树高度差绝对值不超过1(也叫平衡因子)
平衡因子不一定是1,这只是一种实现方案
为什么不是相等,而是不超过1?因为做不到,例如2/4个节点,就不行
二、旋转
一、分析
1、按照搜索树的规则插入
2、更新插入节点的祖先节点的平衡因子
1)插入父亲的左边,父亲平衡因子--
2)插入父亲的左边,父亲平衡因子--
此时,父亲节点平衡因子变化,有三种情况:
a、父亲平衡因子==0,父亲所在子树高度不变,不必往上更新,插入结束
b、父亲平衡因子==1/-1,父亲所在子树高度变化,需要往上更新祖先平衡因子
c、父亲平衡因子==2/-2,父亲所在子树已经不平衡,需要旋转处理
以上情况,为所有变化情况
变化后的平衡因子只可能会出现0/1//-1-2/2的情况
不可能出现其他情况
为什么?
有兴趣的可以看以下过程
插入左边,父亲平衡因子--;插入右边,父亲平衡因子++(默认右边-左边为平衡因子)
如果插入后,父亲节点变为0
说明两种情况:
1、原来为1,插入左边,--,变为0,依旧平衡
2,原来为-1,插入右边,++,变为0,依旧平衡
不用继续往上更新,插入把矮的那边填上了
如果插入后,父亲节点变为1/-1
也说明两种情况:
1、原来为0,插入左边,--,变为-1,高度变化为-1
2,原来为0,插入右边,++,变为1,高度变化为1
需要继续往上更新,因为以父节点所在的子树的高度已经发生了变化
进而影响了上面的平衡
因为,插入前的AVL树本身就是一个平衡树,平衡因子都是0/-1/1
插入后高度变化,要么左边多一个,要么右边多一个
左边多一个,父节点--;右边多一个,父亲节点++
所以,就只可能在0/1/-1的基础上++/--
所以,结果只可能是0/1/-1/2/-2
因此,
高度变为1/-1,一定是从0++/--变来的
如果高度为-2/2,就说明当前树不平衡了,需要旋转调整
那么,什么时候需要调整呢?
当父节点的平衡因子出现2/-2的时候,就不符合AVL树平衡,需调整
如果父亲平衡因子为0,不必继续往上更新,因为不影响上面的平衡
二、旋转处理
这里需要用到左单旋、右单旋的概念
什么时候左旋?什么时候右旋?
左边高了,右单旋;右边高了,左单旋
具体是什么样子呢?
插入左边/右边,更新父节点的平衡因子--/++
然后一直往上更新祖先节点的平衡因子,直到为空
期间,如果遇到某一个祖先节点平衡因子变为2/-2,旋转
当parent为-2时,说明左子树高度高,插入的左子树,此时cur必定为-1;需要右旋
当parent为2时,说明右子树高度高,插入的右子树,此时cur必定为1,需要左旋
对应的情况,把parent节点作为参数,传入对应的左旋和右旋的逻辑函数实现
(相对命名法,相对于某个对象命名)
parent、subL(相对parent的left)、subLR(相对subL的R)
注意:
subRL可能为空
parent可能为根节点,也可能不是根节点
1、右单旋
2、左单旋:
3、双旋:2 -1/ -2 1
右左旋
左右旋
不是单纯的左边高、右边高
三、原码
#pragma once
#pragma once
#include<iostream>
#include<assert.h>
#include<vector>
#include<time.h>
using namespace std;
namespace myspace
{
template<class K, class V >
struct AVLreeNode
{
AVLreeNode<K, V>* _left;
AVLreeNode<K, V>* _right;
AVLreeNode<K, V>* _parent;
pair<K, V> _kv;
int _bf;//balence factor
AVLreeNode(const pair<K,V>& kv)
:_left(nullptr)
, _right(nullptr)
, _parent(nullptr)
,_kv(kv)
,_bf(0)
{
}
};
template<class K, class V>
class AVLTree
{
typedef AVLreeNode<K, V> Node;
public:
//插入
bool Insert(const pair<K,V>& kv)
{
if (_root == nullptr)
{
_root = new Node(kv);
return true;
}
Node* cur = _root;
Node* parent = nullptr;
while (cur)
{
if (kv.first < cur->_kv.first)
{
parent = cur;
cur = cur->_left;
}
else if (kv.first > cur->_kv.first)
{
parent = cur;
cur = cur->_right;
}
else//找到相等key
{
return false;
}
}
cur = new Node(kv);
if (kv.first < parent->_kv.first )//插入左
{
parent->_left =cur;
}
else //插入右
{
parent->_right = cur;
}
cur->_parent = parent;
//插入完毕
//往上更新祖先平衡因子
while (parent)
{
if (parent->_left == cur)
{
parent->_bf--;
}
else
{
parent->_bf++;
}
if (parent->_bf == 0)
{
break;
}
else if(parent->_bf == 1 || parent->_bf == -1)//-1/1
{
//继续向上更新
cur = parent;
parent = parent->_parent;
}
else if (parent->_bf == 2 || parent->_bf == -2)//2/-2
{
//旋转处理
if (parent->_bf == -2 && cur->_bf == -1)
{
//右旋
RotateR(parent);
}
else if (parent->_bf == -2 && cur->_bf == 1)
{
//双旋
RotateLR(parent);
}
else if (parent->_bf == 2 && cur->_bf == 1)
{
//左旋
RotateL(parent);
}
else if (parent->_bf == 2 && cur->_bf == -1)
{
//双旋转
RotateRL(parent);
}
break;
}
else
{
return false;
}
}
return true;
}
//右旋
void RotateR( Node* parent)
{
//此时parent已经为-2,cur为-1
Node* subL = parent->_left;
Node* subLR = subL->_right;
parent->_left = subLR;
if (subLR)//subLR可能为空
{
subLR->_parent = parent;
}
subL->_right = parent;
Node* ppNode = parent->_parent;
parent->_parent = subL;
//注意修改顺序
if (parent == _root)
{
_root = subL;
_root->_parent = nullptr;
}
else
{
if (ppNode->_left == parent)
{
ppNode->_left = subL;
}
else
{
ppNode->_right = subL;
}
subL->_parent = ppNode;
}
subL->_bf = parent->_bf = 0;
}
//左旋
void RotateL( Node* parent)
{
//此时parent已经为2,cur为1
Node* subR = parent->_right;
Node* subRL = subR->_left;
parent->_right = subRL;
if (subRL)
{
subRL->_parent = parent;
}
subR->_left = parent;
Node* ppNode = parent->_parent;
parent->_parent = subR;
if (parent == _root)
{
_root = subR;
_root->_parent = nullptr;
}
else
{
if (ppNode->_left == parent)
{
ppNode->_left = subR;
}
else
{
ppNode->_right = subR;
}
subR->_parent = ppNode;
}
subR->_bf = parent->_bf = 0;
}
//右左旋
void RotateRL( Node* parent)
{
//对折线型插入,进行判断控制
//插入之后,进行控制
Node* subR = parent->_right;
Node* subRL = subR->_left;
int bf = subRL->_bf;
RotateR(subR);
RotateL(parent);
subRL->_bf = 0;
if (bf == 1)//右边插入,右节点给了右边
{
subR->_bf = 0;
parent->_bf = 0;
}
else if (bf == -1)//左边插入
{
subR->_bf = 0;
parent->_bf = 1;
}
else //字节本身,只有三个节点情况
{
subR->_bf = 0;
parent->_bf = 0;
}
}
//左右旋
void RotateLR( Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
int bf = subLR->_bf;
RotateL(subL);
RotateR(parent);
subLR->_bf = 0;
if (bf == 1)//右边插入
{
subL->_bf = 0;
parent->_bf = -1;
}
else if (bf == -1)//插入左边
{
subL->_bf = 1;
parent->_bf = 0;
}
else
{
subL->_bf = 0;
parent->_bf = 0;
}
}
//查找
Node* find(const K& key)
{
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
if (cur->_kv.first == key)
{
return cur;
}
if (key < cur->_kv.first)
{
parent = cur;
cur = cur->_left;
}
else
{
parent = cur;
cur = cur->_right;
}
}
//走到这,没有找到
return nullptr;
}
//中序
void Inorder()
{
_Inorder(_root);
cout << endl;
}
int size()
{
return _size(_root);
}
bool isBalance()
{
return _is_balance(_root);
}
int Height()
{
return _Height(_root);
}
private:
bool _is_balance(Node* root)
{
if (root == nullptr)
{
return true;
}
//判断平衡:左右两树相减
//求得每一棵树的左右子树高度差
int leftHight = _Height(root->_left);
int rightHeight = _Height(root->_right);
if (abs( leftHight - rightHeight ) >= 2 )//说明不平衡
{
cout << "insert->" <<root->_kv.first << endl;//输出是那个节点出问题
return false;
}
//顺便检查每一个节点的平衡因子
if (rightHeight - leftHight != root->_bf)
{
cout << root->_kv.first << endl;//平衡因子出问题节点位置
return false;
}
return _is_balance(root->_left) && _is_balance(root->_right);
}
int _Height(Node* root)
{
//求高度?
//左树和右树的高度差
if (root == nullptr)
{
return 0;
}
/* int leftHeight = _Height(root->_left) + 1;
int rightHeight = _Height(root->_right) + 1;
return max(leftHeight, rightHeight);*/
return max(_Height(root->_left), _Height(root->_right)) + 1;
}
int _size(Node* root)
{
return root == nullptr ? 0 : _size(root->_left) + _size(root->_right) + 1;
}
void _Inorder(Node* root)
{
if (root == nullptr)
{
return;
}
_Inorder(root->_left);
cout << root->_kv.first << ":" << root->_kv.second << endl;
_Inorder(root->_right);
}
private:
Node* _root = nullptr;
};
void AVLTreetest()
{
int a[] = { 1,2,3};
AVLTree<int, int> t;
for (auto e : a)
{
t.Insert({ e,e });
}
t.Inorder();
cout << t.size() << endl;
cout << t.Height() << endl;
}
void AVLTreetest1()
{
int a[] = { 8, 3, 1, 10, 6, 4};
AVLTree<int, int> t;
for (auto e : a)
{
t.Insert({ e,e });
}
int b = 0;
t.Inorder();
cout << t.isBalance() << endl;
}
void AVLTreetest2()
{
int n = 10000000;//1000万个节点
srand(time(0));
vector<int> v;
v.reserve(n);
for (int i =0 ;i<n;++i)
{
v.push_back(rand() + i);
}
size_t T1 = clock();
AVLTree<int, int> t;
for (auto e : v)
{
t.Insert(make_pair(e,e));
}
size_t T2 = clock();
size_t T3 = clock();
for (auto e : v)
{
t.find(e);
}
size_t T4 = clock();
cout << "insert:" << T2 - T1 << endl;
cout << "find:" << T4 - T3 << endl;
}
}