AVL树探秘

时间:2022-09-19 16:46:34

本文首发于我的公众号 Linux云计算网络(id: cloud_dev) ,专注于干货分享,号内有 10T 书籍和视频资源,后台回复 「1024」 即可领取,欢迎大家关注,二维码文末可以扫。

一、AVL树

  AVL树是一种平衡查找树,在前面的两篇文章:二叉搜索树 和 红黑树 中都提到过。由于二叉搜索树在某些特殊情况下是不平衡的(任意一个结点深度过大),因此其一些动态集合操作在最坏情况下的时间复杂度为O(n)。因此提出一些对二叉搜索树效率改进的树结构使最坏时间复杂度降为O(lgn),AVL树和红黑树就是其中的代表,除此之外,还有一些如AA-tree、B-tree、2-3-tree等。使不平衡树变平衡最关键的是找到“平衡条件”,我们已经在前面一篇文章中详述了红黑树的平衡条件是:对节点进行着色,并约束从根节点到任何叶子节点的长度,其中,约定了5条规定,稍显复杂。而AVL树的平衡条件则显得格外简单:只用保证左右子树的高度不超过1即可。

二、AVL树的实现

1、数据结构

节点类:因为需要控制节点的高度,所以高度是一个属性。指针域包括left、right,parent可以包括也可以不要,本文的实现中,我们包括parent。

struct AVLNode {
AVLNode *Parent;
AVLNode *Left;
AVLNode *Right;
int m_nHeight;
int m_nValue;
};

2、节点的平衡

当插入新的节点或者删除节点时,会导致树的不平衡,即其中有节点的左右子树的高度相差>1,这个时候就需要调节树使之平衡。可能出现不平衡的情况总共有以下几种:

////////////////////////////////////////

a   a   a   a
      /    /       \     \
    b     b         b    b
   /       \       /       \
 c         c     c         c
LL         LR    RL        RR

//////////////////////////////////////

  总共就只会出现这四种情况,对这四种情况的分类很多书上有各自的说法。其中1、4和2、3是对称的,我们用LL、LR、RL、RR来分别表示,要使这几种情况平衡,我们只用做简单的旋转操作就OK了,针对1、4,有的说法是做单旋,有的说法是外旋,而2、3,则做双旋或内旋,不管是哪种说法,其本质是不变的。在我们的实现中,采用单旋和双旋,双旋就是做两次单旋:

//单旋
void _LeftRotation( AVLNode *node );
void _RightRotation( AVLNode *node ); //双旋
void _LeftRightRotation( AVLNode *node );
void _RightLeftRotation( AVLNode *node );

3、平衡的修复

  在插入节点和删除节点的时候,会破坏树的平衡条件,这个时候就需要修复。我们采用尽可能少地改动原有代码的原则来修复,这个原则和红黑树的修复操作是一致的,即插入和删除操作我们依然沿用二叉搜索树的实现,只在后面添加修复的代码即可。

  如何修复?首先,插入和删除会破坏节点的高度,所以,应更新结点的高度;其次,插入和删除破坏了树中某些节点的平衡,所以,应针对上面四种情况分别平衡节点。所以,这里就需要两个函数:一个更新结点高度的函数UpdateHeight( AVLNode *node );一个平衡节点的函数: BalanceNode( AVLNode *node )。

void AVLTree::_UpdateHeight( AVLNode *node )
{
AVLNode *l = node->Left, *r = node->Right; if ( l && r )
node->m_nHeight = max( l->m_nHeight, r->m_nHeight ) + ;
else if ( l )
node->m_nHeight = l->m_nHeight + ;
else if ( r )
node->m_nHeight = r->m_nHeight + ;
else node->m_nHeight = ;
}
 //////////////////////////////////////////////////////////////////////////
// a a a a
// / / \ \
// b b b b
// / \ / \
// c c c c
// LL LR RL RR
//////////////////////////////////////////////////////////////////////////
void AVLTree::_BalanceNode( AVLNode *node )
{
int nBlance = _GetBalanceFactor( node );
if ( nBlance > ) { //L
//(1)
//if ( _GetBalanceFactor( node->Left ) < 0 ) //LR
// _LeftRightRotation( node ); //双旋
//else _RightRotation( node ); //LL //单旋 //(2)
if ( _GetBalanceFactor( node->Left ) < )
_LeftRotation( node->Left );
_RightRotation( node );
}
if ( nBlance < - ) { //R
if ( _GetBalanceFactor( node ) > ) { //RL
_RightRotation( node->Right );
}
_LeftRotation( node );
}
} //平衡因子(左右子树的高度差)
int AVLTree::_GetBalanceFactor( AVLNode *node )
{
AVLNode *l = node->Left, *r = node->Right; if ( l && r )
return l->m_nHeight - r->m_nHeight;
else if ( l )
return l->m_nHeight + ;
else if ( r )
return -r->m_nHeight - ;
else return ;
}

基本上该注意的点都提到了,下面附上详细代码实现:

 #ifndef __AVL_TREE_H_
#define __AVL_TREE_H_ class AVLTree
{
private:
struct AVLNode {
AVLNode *Parent;
AVLNode *Left;
AVLNode *Right;
int m_nHeight;
int m_nValue;
};
public:
AVLTree(AVLNode *root = NULL):m_pRoot(root) {}
~AVLTree() {
_RecursiveDeleteNode(m_pRoot);
} bool Search( const int search_value ) const;
bool Insert( const int value );
bool Delete( const int delete_value ); void Print() const; private:
void _RecursiveDeleteNode(AVLNode *node) {
if ( node ) {
_RecursiveDeleteNode( node->Left );
_RecursiveDeleteNode( node->Right );
delete node;
}
node = NULL;
} void _DeleteNode( AVLNode *delete_node );
void _Delete_Transplant( AVLNode *unode, AVLNode *vnode );
void _InsertNode( const int insert_value );
AVLNode * _SearchNode( AVLNode *node, const int search_value ) const; //单旋
void _LeftRotation( AVLNode *node );
void _RightRotation( AVLNode *node ); //双旋
void _LeftRightRotation( AVLNode *node );
void _RightLeftRotation( AVLNode *node ); AVLNode* Minimum( AVLNode *node ); //树高
int _Height ( AVLNode *node );
void _UpdateHeight( AVLNode *node );
//平衡因子
int _GetBalanceFactor( AVLNode *node );
//平衡失去平衡的节点
void _BalanceNode( AVLNode *node ); void _Print ( AVLNode *node ) const; private:
AVLNode *m_pRoot; };
#endif//__AVL_TREE_H_
 #include <iostream>
#include <algorithm>
using namespace std; #include "AVL_Tree.h" bool AVLTree::Search( const int search_value ) const
{
return _SearchNode( m_pRoot, search_value ) != NULL;
} AVLTree::AVLNode * AVLTree::_SearchNode( AVLNode *node, const int search_value ) const
{
while ( node && search_value != node->m_nValue ) {
if ( search_value < node->m_nValue )
node = node->Left;
else
node = node->Right;
}
return node;
} bool AVLTree::Insert( const int value )
{
//该值已存在
if ( Search( value ) )
return false;
else {
_InsertNode( value );
return true;
}
} void AVLTree::_InsertNode( const int insert_value )
{
AVLNode *node = m_pRoot;
AVLNode *temp_node = NULL; //先找到待插入节点的位置
while ( node ) {
temp_node = node;
node = ( insert_value < node->m_nValue )?node->Left:node->Right;
} AVLNode *insert_node = new AVLNode();
insert_node->m_nValue = insert_value; insert_node->Parent = temp_node; //空树
if ( temp_node == NULL )
m_pRoot = insert_node;
else {
if ( insert_value < temp_node->m_nValue )//左子树
temp_node->Left = insert_node;
else
temp_node->Right = insert_node; //右子树
} //更新插入节点的高度和平衡节点
while ( insert_node ) {
_UpdateHeight( insert_node );
_BalanceNode( insert_node );
insert_node = insert_node->Parent;
}
} bool AVLTree::Delete( const int delete_value )
{
AVLNode *delete_node = _SearchNode( m_pRoot, delete_value ); //节点不存在
if ( delete_node == NULL )
return false;
else {
_DeleteNode( delete_node );
return true;
}
} void AVLTree::_DeleteNode( AVLNode *delete_node )
{
if ( delete_node->Left == NULL )
_Delete_Transplant( delete_node, delete_node->Right );
else if ( delete_node->Right == NULL )
_Delete_Transplant( delete_node, delete_node->Left );
else {
AVLNode *min_node = Minimum( delete_node->Right );
if ( min_node->Parent != delete_node ) {
_Delete_Transplant( min_node, min_node->Right );
min_node->Right = delete_node->Right;
min_node->Right->Parent = min_node;
}
_Delete_Transplant( delete_node, min_node );
min_node->Left = delete_node->Left;
min_node->Left->Parent = min_node;
} //更新结点的高度和平衡节点
while ( delete_node ) {
_UpdateHeight( delete_node );
_BalanceNode( delete_node );
delete_node = delete_node->Parent;
}
} void AVLTree::_Delete_Transplant( AVLNode *unode, AVLNode *vnode )
{
if ( unode->Parent == NULL )
m_pRoot = vnode;
else if ( unode == unode->Parent->Left )
unode->Parent->Left = vnode;
else
unode->Parent->Right = vnode;
if ( vnode )
vnode->Parent = unode->Parent;
} AVLTree::AVLNode* AVLTree::Minimum( AVLNode *node )
{
while ( node->Left )
node = node->Left;
return node;
} //树高
int AVLTree::_Height( AVLNode *node )
{
return node->m_nHeight;
} //平衡因子(左右子树的高度差)
int AVLTree::_GetBalanceFactor( AVLNode *node )
{
AVLNode *l = node->Left, *r = node->Right; if ( l && r )
return l->m_nHeight - r->m_nHeight;
else if ( l )
return l->m_nHeight + ;
else if ( r )
return -r->m_nHeight - ;
else return ;
} void AVLTree::_UpdateHeight( AVLNode *node )
{
AVLNode *l = node->Left, *r = node->Right; if ( l && r )
node->m_nHeight = max( l->m_nHeight, r->m_nHeight ) + ;
else if ( l )
node->m_nHeight = l->m_nHeight + ;
else if ( r )
node->m_nHeight = r->m_nHeight + ;
else node->m_nHeight = ;
} //////////////////////////////////////////////////////////////////////////
// a a a a
// / / \ \
// b b b b
// / \ / \
// c c c c
// LL LR RL RR
//////////////////////////////////////////////////////////////////////////
void AVLTree::_BalanceNode( AVLNode *node )
{
int nBlance = _GetBalanceFactor( node );
if ( nBlance > ) { //L
//(1)
//if ( _GetBalanceFactor( node->Left ) < 0 ) //LR
// _LeftRightRotation( node ); //双旋
//else _RightRotation( node ); //LL //单旋 //(2)
if ( _GetBalanceFactor( node->Left ) < )
_LeftRotation( node->Left );
_RightRotation( node );
}
if ( nBlance < - ) { //R
if ( _GetBalanceFactor( node ) > ) { //RL
_RightRotation( node->Right );
}
_LeftRotation( node );
}
} //单旋
//左旋
void AVLTree::_LeftRotation( AVLNode *node )
{
if ( node->Right == NULL )
return; AVLNode *temp_node = node->Right; //补
node->Right = temp_node->Left;
if ( temp_node->Left )
temp_node->Left->Parent = node; //提
temp_node->Parent = node->Parent;
if ( node->Parent == NULL )
m_pRoot = temp_node;
else if ( node == node->Parent->Left )
node->Parent->Left = temp_node;
else node->Parent->Right = temp_node; //降
temp_node->Left = node;
node->Parent = temp_node; _UpdateHeight( node );
_UpdateHeight( temp_node );
} //右旋
void AVLTree::_RightRotation( AVLNode *node )
{
if ( node->Left == NULL )
return; AVLNode *temp_node = node->Left; //补
node->Left = temp_node->Right;
if ( temp_node->Right )
temp_node->Right->Parent = node; //提
temp_node->Parent = node->Parent;
if ( node->Parent == NULL )
m_pRoot = temp_node;
else if ( node == node->Parent->Left )
node->Parent->Left = temp_node;
else node->Parent->Right = temp_node; //降
temp_node->Right = node;
node->Parent = temp_node; _UpdateHeight( node );
_UpdateHeight( temp_node );
} //双旋
//LR
void AVLTree::_LeftRightRotation( AVLNode *node )
{
_LeftRotation( node->Left );
_RightRotation( node );
} //RL
void AVLTree::_RightLeftRotation( AVLNode *node )
{
_RightRotation( node->Right );
_RightRotation( node );
} void AVLTree::Print() const
{
_Print(m_pRoot);
}
//打印
void AVLTree::_Print ( AVLNode *node ) const
{
if ( node->Parent == NULL )
cout << "root: " << node->m_nValue << endl;
else if ( node == node->Parent->Left )
cout << "left: " << node->m_nValue << ", parent: " << node->Parent->m_nValue << endl;
else cout << "right: " << node->m_nValue << ", parent: " << node->Parent->m_nValue << endl;
if ( node->Left )
_Print( node->Left );
if ( node->Right )
_Print( node->Right );
} int main()
{
AVLTree al;
for (int i = ; i < ; i ++) {
al.Insert(i); }
al.Print();
for (int i = ; i < ; i += ) {
al.Delete(i);
al.Print();
}
return ;
}

我的公众号 「Linux云计算网络」(id: cloud_dev),号内有 10T 书籍和视频资源,后台回复 「1024」 即可领取,分享的内容包括但不限于 Linux、网络、云计算虚拟化、容器Docker、OpenStack、Kubernetes、工具、SDN、OVS、DPDK、Go、Python、C/C++编程技术等内容,欢迎大家关注。

AVL树探秘