首先我们需要了解一下AVL树概念:
二叉树虽然可以提高搜索的效率,但是当数据有序接近有序二叉树将退化为单支树,查找元素相当于在顺序表中搜索元素,效率低下,因此便有人提出了AVL树的概念,当向二叉树插入新的节点后,如果可以保证每个节点的左右子树高度之差得到绝对值不超过1,即可降低树的高度,从而减少平均搜索长度
接下来我们就来简易搭建一下构架:
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>
{
typedef AVLTreeNodeM<K,V> Node;
public:
bool Insert(const pair<K,V>& kv)
{
if(_root==nullptr)
{
_root=new Node(kv);
return true;
}
Node* parent=nullptr;
Node* cur=_root;
while(cur)
{
if(cur->_kv.first<kv.first)
{
parent=cur;
cur=cur->_right;
}
else if(cur->_kv.first>kv.first)
{
parent=cur;
cur=cur->_left;
}
else//二者相同的情况
{
return false;
}
}
cur=new Node(kv);
if(parent->_kv.first<kv.first)
{
parent->_right=cur;
}
else if(parnet->kv.first>kv.first)
{
parent->_left=cur;
}
cur->_parent=parent;
return true;
}
private:
Node* _root=nullptr;
}
这里我们bf设置为0即可,接下来我么就来对平衡因子进行编写:
更新平衡因子的规则:
(1)新增在右,parent->bf++;新增在左,parent->bf--;
(2)更新后,parent->bf==1 or -1,说明parent之前是0,(注意:在这里parent之前一定不是2或者-2,否则之前就是不平衡的),说明左右子树高度相同,插入后有一边高,parent的高度变了,需要继续往上更新
(3)更新后,parent->bf==0,说明此时就不需要继续往上更新
(4)如果更新后,parent->bt==2或者-2,说明说明原来就是1或者-1,已经是平衡的临界值
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>
{
typedef AVLTreeNodeM<K,V> Node;
public:
bool Insert(const pair<K,V>& kv)
{
if(_root==nullptr)
{
_root=new Node(kv);
return true;
}
Node* parent=nullptr;
Node* cur=_root;
while(cur)
{
if(cur->_kv.first<kv.first)
{
parent=cur;
cur=cur->_right;
}
else if(cur->_kv.first>kv.first)
{
parent=cur;
cur=cur->_left;
}
else//二者相同的情况
{
return false;
}
}
cur=new Node(kv);
if(parent->_kv.first<kv.first)
{
parent->_right=cur;
}
else if(parnet->kv.first>kv.first)
{
parent->_left=cur;
}
cur->_parent=parent;
//平衡因子编写
while(parent)
{
if(cut==parent->_right)
{
parent->_bf++;
}
else
{
parent->_bf--;
}
if(parent->_bf==0)
{
break;
}
if(abs(parent>_bf)==1)
{
parent=parent->_parent;
cur=cur->_parent;
}
else if(abs(parent->_bf)==2)
{
//说明parent的子树已经不平衡了,需要旋转处理
}
else
{
assert(false);//理论上是不会到这里的
}
}
return true;
}
private:
Node* _root=nullptr;
}
接下来我们一起来了解一下旋转机制:
首先原则就是:
(1)旋转为平衡树
(2)保持搜索树原则
接下来我们就逐个讲解一下各个旋转规则:、
一.左单旋:
首先我们要知道为什么要叫做左旋转,其实根本就是右边高了,导致平衡因子变大,具体图如下:
最右边的子树加1,此时60的平衡因子就变作1,30就变作2,此时就需要旋转。具体调节方法如上图;
其实也就是只要最右边加成员,就会发生左旋:
一.左旋
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>
{
typedef AVLTreeNodeM<K,V> Node;
public:
bool Insert(const pair<K,V>& kv)
{
if(_root==nullptr)
{
_root=new Node(kv);
return true;
}
Node* parent=nullptr;
Node* cur=_root;
while(cur)
{
if(cur->_kv.first<kv.first)
{
parent=cur;
cur=cur->_right;
}
else if(cur->_kv.first>kv.first)
{
parent=cur;
cur=cur->_left;
}
else//二者相同的情况
{
return false;
}
}
cur=new Node(kv);
if(parent->_kv.first<kv.first)
{
parent->_right=cur;
}
else if(parnet->kv.first>kv.first)
{
parent->_left=cur;
}
cur->_parent=parent;
//平衡因子编写
while(parent)
{
if(cut==parent->_right)
{
parent->_bf++;
}
else
{
parent->_bf--;
}
if(parent->_bf==0)
{
break;
}
if(abs(parent>_bf)==1)
{
parent=parent->_parent;
cur=cur->_parent;
}
else if(abs(parent->_bf)==2)
{
//说明parent的子树已经不平衡了,需要旋转处理
if(parent->_bf==2 &&cur->bf==0)
{
Rotatel(parent);
}
break;
}
else
{
assert(false);//理论上是不会到这里的
}
}
return true;
}
private:
void Rotatel(Node* parent)
{
Node* subR=parent->_right;
Node* suRL=subR->_left;
parent->_right=subRL;
if(subPL)
{
subRL->_parent=parent;
}
Node* ppNode=parent->_parent;
subR->_left=parent;
parent->_parent=subR;
if(parent==_root)//如果父母就是根
{
_root=subR;
subR->_parent=nullptr;
}
else//如果父母不是根,而是子树
{
if(ppNode->_left=parent)
{
ppNode->_left=subR;
}
else
{
ppNode->_right=subR;
}
subR->_parent=ppNode;
}
subR->_bf=parent->_bf=0;
}
private:
Node* _root=nullptr;
}
二.右旋
具体图如下:
void RotateR(Node* parent)
{
Node* subL=parent->_left;
Node* subLR=subL->_right;
parent->_left=subLR;
if(subLR)
{
subLR->_parent=parent;
}
Node* ppNode=parent->_parent;
subL->_right=parent;
parent->_parent=subL;
if(_root==parent)
{
_root=subL;
subL->_parent=nullptr;
}
else
{
if(ppNode->_left==_parent)
{
ppNode->_left=subL;
}
else
{
ppNode->_right=subL;
}
subL->_parent=ppNode;
}
subL->_bf=parent->_bf=0;
}
前提条件如下:
if((parent->_bf==-2) && (cur->_bf==-1))
{
RotateR(parent);
}
三.双旋
(1)左右双旋
void RotateLR(Node* parent)
{
Node* subL=parent->_left;
Node* subLR=subL->_right;
int bf=subLR->_bf;
RotateL(parent->_left);
RotateR(parent);
subLR->_bf=0;
if(bf==1)
{
parent->_bf=0;
subL->_bf=-1;
}
else if(bf==-1)
{
parent->_bf=1;
subL->_bf=0;
}
else if(bf==0)
{
parent->_bf=0;
subL->_bf=0;
}
else
{
assert(false);
}
}
(2)右左双旋
void RotateRL(Node* parent)
{
Node* subR=parent->_right;
Node* subRL=subR->_left;
int bf=subRL->_bf;
RotateR(parent->_left);
RotateL(parent);
if(bf==1)
{
subR->_bf=0;
parent->_bf=-1;
subRL->_bf=0;
}
else if(bf==-1)
{
subR->_bf=1;
parent->_bf=0;
subRL->_bf=0;
}
else if(bf==0)
{
parent->_bf=0;
subR->_bf=0;
}
else
{
assert(false);
}
}
最后我们来了解一下旋转的价值与意义:
1.使当前这棵树平衡
2.降低树的高度