AVL树:
是一棵高度平衡的搜索二叉树;
什么是搜索二叉树?
一棵二叉树中任意父节点都大于自己的左子树上的每一个子节点,小于自己右子树上的每一个节点的树是搜索二叉树。
搜索二叉树的 中序遍历(左中右)得到一个从小都大的有序序列,这些在二叉搜索树中都有讲解。
搜索二叉树最大的优点就是查找快,时间复杂度O(lgN)
那么既然有了二叉搜索树,为什么还要一个AVL树?
我们可以这样理解,AVL树是二叉搜索树的升级版,它弥补了二叉搜索树的不足,同时具备二叉搜索树的优点,我们具体来分析一下。
如果一棵二叉树呈现一边倒的情况,如图所示:
这个时候,我们就需要调整这棵树的结构,让它的时间复杂度依然保持在O(lgN),如图:
这就是AVL树的意义,接下来我们具体分析下它是如何调整的。
AVL树结构:(搜索树+平衡因子 )
AVL树的性质:
1)左子树和右子树的高度之差的绝对值不超过1;
2)树中的每个左子树和右子树都是AVL树;
3)每个节点都有一个平衡因子,任一节点的平衡因子是-1,0,1;(每个节点的平衡因子=右子树高度-左子树高度)
时间复杂度是:log以2为底N的对数
节点类型:
平衡因子发生改变的三种情况:(分别举一个例子来分析)
① 插入结点在右边:++_bf,这种呈现一种 “右-右型”
我们以10为中心,将9挪动下来,10放上去,有一种 “左旋” 的感觉。(左单旋)
② 插入结点在左边:- -_bf,这种呈现 右–左型“”
这里我们做了两步操作,先以10为中心,“向右旋转”,把11挪到下面去,把10挪动到上面去,然后再使用 “左旋转”,以10为中心,将9挪到下面来,10放上去,拆分步骤如下(右左双旋):
③ 插入结点任意一边:_bf不变
以上情况分析总结如下:
** 1) if 有父亲结点|_bf| == 2/-2就要发生旋转;
2) if 有父节点|_bf| == 1/-1高度改变,继续向上更新平衡因子,直到出现2/-2旋转,或者出现0停止;
3) if 有父节点|_bf| == 0时,停止更新平衡因子;**
旋转问题:
在删除插入等操作以后,AVL树会发生以下旋转方式来调整自己的高度:左单旋,右单旋,左右双旋,右左双旋;
左单旋:
右单旋同理;
左右双旋:
右左双旋:
** 如果是右左双旋,那么父节点的平衡因子就是2。
如果是左右双旋,那么父节点的平衡因子就是-2。**
左右双旋具体情况分析:
如果看完还是不理解,就记住下面两幅图吧,记住每个节点的位置:
综上所述,针对左右双旋做了一个总结:
针对右左双旋总结如下:
总结一下,当父亲平衡因子是-2时:
** 若curR == 0时,旋转后平衡因子parent = 0, cur = 0;
若curR == -1时,旋转后平衡因子parent = 1,cur = 0;
若curR == 1时,旋转后平衡因子parent == 0, cur = -1;**
右左双旋同理;
代码示例:
#include<string>
template <class K,class V>
struct AVLTreeNode
{
K _key;
V _value;
AVLTreeNode<K,V>* _left;
AVLTreeNode<K,V>* _right;
AVLTreeNode<K,V>* _parent;
int _bf;//平衡因子
AVLTreeNode(const K& key,const V& value)
:_key(key),_value(value),_left(NULL),_right(NULL),_parent(NULL),_bf(0)
{}
};
template <class K,class V>
class AVLTree
{
typedef AVLTreeNode<K,V> Node;
protected:
Node* _root;
public:
AVLTree()
:_root(NULL)
{}
~AVLTree()
{
_Destroy(_root);
}
bool Insert(const K& key,const V& value)
{
return _Insert(key,value);
}
void Inorder()
{
cout<<"中序遍历AVL树:"<<endl;
_InOrder(_root);
cout<<endl;
}
private:
//结点插入与旋转有关
bool _Insert(const K& key,const V& value)
{
if(NULL == _root)
{
_root = new Node(key,value);
return true;
}
Node* cur = _root;
Node* parent = cur;
while(cur)
{
if(cur->_key == key)
{
return false;
}
else if(cur->_key < key)
{
parent = cur;
cur = cur->_right;
}
else
{
parent = cur;
cur = cur->_left;
}
}
//开始插入结点
cur = new Node(key,value);
if(parent->_key > key)
{
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)
{
cur = parent;
parent = parent->_parent;
}
else//parent==2/-2开始旋转
{
if(parent->_bf == 2)//右树高
{
if(cur->_bf == 1)
{
//左单旋
RotateL(parent);
}
else
{
//cur->_bf == -1是右左双旋
RotateRL(parent);
}
}
else//parent->_bf == -2,左树高
{
if(cur->_bf == -1)
{
//右单旋
RotateR(parent);
}
else
{
//cur->_bf == 1,这是左右双旋
RotateLR(parent);
}
}
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;
}
Node* pparent = parent->_parent;
parent->_parent = subL;
subL->_parent = pparent;
if(pparent == NULL)//说明此时是根节点
{
_root = subL;
}
else
{
if(pparent->_left == parent)
{
pparent->_left = subL;
}
else
{
pparent->_right = 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;
}
Node* pparent = parent->_parent;
parent->_parent = subR;
subR->_parent = pparent;
if(pparent == NULL)
{
_root = subR;
}
else
{
if(pparent->_left == parent)
{
pparent->_left = subR;
}
else
{
pparent->_right = subR;
}
}
parent->_bf = subR->_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)
{
subR->_bf = parent->_bf = 0;
}
else if(bf == -1)
{
parent->_bf = 0;
subR->_bf = 1;
}
else
{
parent->_bf = -1;
subR->_bf = 0;
}
subRL->_bf = 0;
}
//左右双旋
void RotateLR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
int bf = subLR->_bf;//提前存储好我们的curR的平衡因子
RotateL(parent->_left);
RotateR(parent);
if(bf == 0)
{
subL->_bf = parent->_bf = 0;
}
else if(bf == -1)
{
subL->_bf = 0;
parent->_bf = 1;
}
else
{
parent->_bf = 0;
subL->_bf = -1;
}
subLR->_bf = 0;
}
void _InOrder(Node* root)
{
if(NULL == root)
{
return;
}
_InOrder(root->_left);
cout<<root->_key<<","<<root->_value<<" ";
_InOrder(root->_right);
}
void _Destroy(Node* root)
{
if(NULL == root)
{
return;
}
_Destroy(root->_left);
_Destroy(root->_right);
delete root;
}
};