前文说到了二叉搜索树一般情况下有很高的查找效率,平均时间复杂度为O(logN),N为树中的全部节点数。但是二叉搜索树也有缺陷,假如往树中插入的元素有序或者接近有序,二叉搜索树就会退化成单支树,时间复杂度会退化成O(N),这就很不稳定了。那么有没有更好的二叉搜索树呢?
一、什么是AVL树
两位俄罗斯的数学家G.M.Adelson-Velskii和E.M.Landis在1962年发表了一种解决上述问题的方法:当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之差的绝对值不超过1(需要对树中的结点进行调整),即可降低树的高度,从而减少平均搜索长度。在AVL树中任何节点的两个子树的高度最大差别为1,所以它也被称为高度平衡树。增加和删除可能需要通过一次或多次旋转节点来重新平衡这个树。 一棵AVL树或者是空树,或者是具有以下性质的二叉搜索树: (1)它的左右子树都是AVL树 (2)左右子树高度之差(简称平衡因子)的绝对值不大于1(-1/0/1)
二、AVL树的实现(插入,旋转,验证)
代码如下:
#include<iostream>
#include<assert.h>
using namespace std
;
template
<class T
>
struct AVLNode
{
AVLNode
<T
>* left
;
AVLNode
<T
>* right
;
AVLNode
<T
>* parent
;
T _val
;
int bf
;
AVLNode(const T
& val
)
:left(nullptr
)
, right(nullptr
)
, parent(nullptr
)
, _val(val
)
, bf(0)
{}
};
template
<class T
>
class AVLTree
{
public
:
typedef AVLNode
<T
> Node
;
typedef Node
* pNode
;
void RotateL(pNode parent
)
{
pNode subR
= parent
->right
;
pNode subRL
= subR
->left
;
subR
->left
= parent
;
parent
->right
= subRL
;
if (subRL
)
subRL
->parent
= parent
;
if (parent
!= root
)
{
pNode grandpa
= parent
->parent
;
if (grandpa
->left
== parent
)
grandpa
->left
= subR
;
else
grandpa
->right
= subR
;
subR
->parent
= grandpa
;
}
else
{
root
= subR
;
subR
->parent
= nullptr
;
}
parent
->parent
= subR
;
parent
->bf
= subR
->bf
= 0;
}
void RotateR(pNode parent
)
{
pNode subL
= parent
->left
;
pNode subLR
= subL
->right
;
subL
->right
= parent
;
parent
->left
= subLR
;
if (subLR
)
subLR
->parent
= parent
;
if (parent
!= root
)
{
pNode grandpa
= parent
->parent
;
if (grandpa
->left
== parent
)
grandpa
->left
= subL
;
else
grandpa
->right
= subL
;
subL
->parent
= grandpa
;
}
else
{
root
= subL
;
subL
->parent
= nullptr
;
}
parent
->parent
= subL
;
parent
->bf
= subL
->bf
= 0;
}
bool
insert(const T
& val
)
{
if (root
== nullptr
)
{
root
= new
Node(val
);
return true
;
}
pNode cur
= root
;
pNode parent
= nullptr
;
while (cur
)
{
parent
= cur
;
if (cur
->_val
== val
)
return false
;
else if (cur
->_val
> val
)
cur
= cur
->left
;
else
cur
= cur
->right
;
}
cur
= new
Node(val
);
if (parent
->_val
> val
)
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 (abs(parent
->bf
) == 1)
{
cur
= parent
;
parent
= parent
->parent
;
}
else if (abs(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)
{
pNode subL
= parent
->left
;
pNode subLR
= subL
->right
;
int bf
= subLR
->bf
;
RotateL(cur
);
RotateR(parent
);
if (bf
== 1)
{
parent
->bf
= 0;
subL
->bf
= -1;
}
else if (bf
== -1)
{
subL
->bf
= 0;
parent
->bf
= 1;
}
}
else if (parent
->bf
== 2 && cur
->bf
== -1)
{
pNode subR
= parent
->right
;
pNode subRL
= subR
->left
;
int bf
= subRL
->bf
;
RotateR(cur
);
RotateL(parent
);
if (bf
== 1)
{
subR
->bf
= 0;
parent
->bf
= -1;
}
else if (bf
== -1)
{
subR
->bf
= 1;
parent
->bf
= 0;
}
}
break;
}
else
{
assert(false
);
}
}
return true
;
}
void _inOrder(pNode root
)
{
if (root
)
{
_inOrder(root
->left
);
cout
<< root
->_val
<< " ";
_inOrder(root
->right
);
}
}
void inOrder()
{
_inOrder(root
);
cout
<< endl
;
}
int height(pNode root
)
{
if (root
== nullptr
)
return 0;
int leftHeight
= height(root
->left
);
int rightHeight
= height(root
->right
);
return leftHeight
> rightHeight
? leftHeight
+ 1 : rightHeight
+ 1;
}
bool
_isAVLTree(pNode root
)
{
if (root
== nullptr
)
return true
;
int left
= height(root
->left
);
int right
= height(root
->right
);
if (right
- left
!= root
->bf
)
{
cout
<< "节点" << root
->_val
<< "平衡因子异常" << endl
;
return false
;
}
return abs(root
->bf
) < 2 && _isAVLTree(root
->left
)
&& _isAVLTree(root
->right
);
}
bool
isAVLTree()
{
return _isAVLTree(root
);
}
private
:
pNode root
= nullptr
;
};