一、概述
AVL(Adelson-Velskii和Landis)树是带有平衡条件的二叉查找树。一颗AVL树是其每个节点的左子树和右子树的高度最多差1的二叉查找树(空树的高度定义为-1),如图1所示,只有左边的二叉查找树是AVL树。
图1 两颗二叉查找树,只有左边的树是AVL树
二、实现
AVL树中的每个节点都有一个平衡因子(Balance Factor,以下用BF表示),它表示这个节点的左、右子树的高度差,也就是左子树的高度减去右子树的高度的值。AVL树上所有节点的BF值只可能是-1、0和1.反之,只要二叉查找数上一个节点的BF的绝对值大于1,则该二叉树就不是平衡二叉树。
如何构造一颗平衡二叉树呢?动态地调整二叉查找数平衡的方法为:每插入一个节点后,首先检查是否破坏了树的平衡性,如果因插入节点而破坏了二叉查找树的平衡,则找出离插入点最近的不平衡节点,然后将该不平衡节点为根的子树进行旋转操作,我们称该不平衡节点为旋转根,让我们把必须重新平衡的节点叫做α,以该旋转根为根的子树称为最小不平衡的子树,失衡状态可归纳为4种,他们对应着4种旋转类型:
1. 对α的左儿子的左子树进行一次插入(LL);
2. 对α的左儿子的右子树进行一次插入(LR);
3. 对α的右儿子的左子树进行一次插入(RL);
4. 对α的右儿子的右子树进行一次插入(RR);
情形1和4是关于α点的镜像对称,而2和3是关于α点的镜像对称。因此,理论上只有两种情况,当然从编程的角度来看还是四种情形。
第一种情况是插入发生在“外边”的情况(即左-左的情况或右-右的情况),该情况通过对树的一次单旋转(single rotation,如图2)而完成调整;第二种情况是插入发生在“内部”的情形(即左-右的情况或右-左的情况),该情况通过稍微复杂些的双旋转(double rotation,如图3)来处理。
![](https://img-my.csdn.net/uploads/201204/01/1333288837_2249.jpg)
图2 单旋转(LL型)
![](https://img-my.csdn.net/uploads/201204/01/1333288972_4035.jpg)
图3 双旋转(LR型)
旋转运算的实质,把树做任何一种旋转(LL、LR、RL、RR):
◎ 新树保持了原来的中序周游顺序;
◎ 旋转处理器中仅需改变少数指针;
◎ 而且新的子树高度为h+2,保持插入前子树的高度不变;
◎ 原来二叉树在α节点上的其余部分(如还有的话)总是保持平衡的。
总结:除几种情形外,编程的细节是相当简单的。为将关键字是X的一个新节点插入到一颗AVL树T中去,我们递归地将X插入到T的相应的子树(称为
T
LR)中。如果的高度不变,那么插入完成。否则,如果在
T中出现高度不平衡,那么我们根据
X以及
T和中的关键字作适当的但旋转或双旋转,更新这些高度(并解决好与树的其余部分的连接),从而完成插入。
文件名:avltree.h
#ifndef _AvlTree_H
typedef int ElementType;
struct AvlNode;
typedef struct AvlNode *Position;
typedef struct AvlNode *AvlTree;
AvlTree MakeEmpty( AvlTree T );
Position Find( ElementType X, AvlTree T );
Position FindMin( AvlTree T );
Position FindMax( AvlTree T );
AvlTree Insert( ElementType X, AvlTree T );
AvlTree Delete( ElementType X, AvlTree T );
ElementType Retrieve( Position P );
static Position SingleRotateWithRight( Position K1 );
static Position SingleRotateWithLeft( Position K2 );
static Position DoubleRotateWithLeft( Position K3 );
static Position DoubleRotateWithRight( Position K4 );
ElementType Max( ElementType a, ElementType b );
void PrintElement( AvlTree T );
void PreOrder( AvlTree T );
void InOrder( AvlTree T );
void PostOrder( AvlTree T );
#endif /* _AvlTree_H */
文件名:avltree.c
#include "avltree.h"
#include "fatal.h"
struct AvlNode
{
ElementType Element;
AvlTree Left;
AvlTree Right;
int Height;
};
ElementType
Max( ElementType a, ElementType b )
{
return (a > b ? a : b);
}
static int
Height( Position P )
{
if ( P == NULL )
return -1;
else
return P->Height;
}
AvlTree
MakeEmpty( AvlTree T )
{
if ( T != NULL )
{
MakeEmpty( T->Left );
MakeEmpty( T->Right );
free( T );
}
return NULL;
}
Position
Find( ElementType X, AvlTree T )
{
if( T == NULL )
return NULL;
if( X < T->Element )
return Find( X, T->Left );
else
if( X > T->Element )
return Find( X, T->Right );
else
return T;
}
Position
FindMin( AvlTree T )
{
if( T == NULL )
return NULL;
else
if( T->Left == NULL )
return T;
else
return FindMin( T->Left );
}
Position
FindMax( AvlTree T )
{
if( T != NULL )
while( T->Right != NULL )
T = T->Right;
return T;
}
AvlTree
Delete( ElementType X, AvlTree T )
{
printf( "Sorry; delete is unimplemented; %d remains\n", X );
return T;
}
ElementType
Retrieve( Position P )
{
return P->Element;
}
AvlTree
Insert ( ElementType X, AvlTree T )
{
if ( T == NULL )
{
/* Create and return a one-node tree */
T = malloc( sizeof( struct AvlNode ) );
if ( T == NULL )
FatalError( "Out of space!!!" );
else
{
T->Element = X; T->Height = 0;
T->Left = T->Right = NULL;
}
}
else
if ( X < T->Element )
{
T->Left = Insert( X, T->Left );
if ( Height( T->Left ) - Height( T->Right ) == 2 )
if ( X < T->Left->Element )
T = SingleRotateWithLeft( T );
else
T = DoubleRotateWithLeft( T );
}
else
if ( X > T->Element )
{
T->Right = Insert( X, T->Right );
if ( Height( T->Right ) - Height( T->Left ) == 2 )
if ( X > T->Right->Element )
T = SingleRotateWithRight( T );
else
T = DoubleRotateWithRight( T );
}
/* Else X is in the tree already;we'll do nothing */
T->Height = Max( Height( T->Left ), Height( T->Right ) ) + 1;
return T;
}
/* This function can be called only if K2 has a left child */
/* Perform a rotate between a node(K2) and its left child */
/* Update heights, then return new root */
static Position
SingleRotateWithLeft( Position K2 )
{
Position K1;
K1 = K2->Left;
K2->Left = K1->Right;
K1->Right = K2;
K2->Height = Max( Height( K2->Left ),
Height( K2->Right ) ) +1;
K1->Height = Max( Height( K1->Left ),
K2->Height ) +1;
return K1; /* New root */
}
/* This function can be called only if K1 has a right child */
/* Perform a rotate between a node(K1) and its right child */
/* Update heights, then return new root */
static Position
SingleRotateWithRight( Position K1 )
{
Position K2;
K2 = K1->Right;
K1->Right = K2->Left;
K2->Left = K1;
K1->Height = Max( Height( K1->Left ),
Height( K1->Right ) ) + 1;
K2->Height = Max( Height( K2->Right ),
K1->Height ) + 1;
return K2; /* New root */
}
/* This function can be called only if K3 has a left */
/* child and K3's left child has a right child */
/* Do the left-right double rotation */
/* Update heights,then return new root */
static Position
DoubleRotateWithLeft( Position K3 )
{
/* Rotate between K1 and K2 */
K3->Left = SingleRotateWithRight( K3->Left );
/* Rotate between K3 and K2 */
return SingleRotateWithLeft( K3 );
}
/* This function can be called only if K1 has a right */
/* child and K1's right child has a left child */
/* Do the left-right double rotation */
/* Update heights,then return new root */
static Position
DoubleRotateWithRight( Position K1 )
{
/* Rotate between K3 and K2 */
K1->Right = SingleRotateWithLeft( K1->Right );
/* Rotate between K1 and K2 */
return SingleRotateWithRight( K1 );
}
void
PrintElement( AvlTree T )
{
printf( "%3d ", Retrieve( T ) );
}
void
PreOrder( AvlTree T )
{
if (T != NULL )
{
PrintElement( T );
PreOrder( T->Left );
PreOrder( T->Right );
}
}
void
InOrder( AvlTree T )
{
if (T != NULL )
{
InOrder( T->Left );
PrintElement( T );
InOrder( T->Right );
}
}
void
PostOrder( AvlTree T )
{
if ( T != NULL )
{
PostOrder( T->Left );
PostOrder( T->Right );
PrintElement( T );
}
}
文件名:main.c
#include "avltree.h"
#include <stdio.h>
int main()
{
AvlTree T = NULL;
int i, n;
ElementType tmp;
printf( "Number of Elements:" );
scanf( "%d", &n );
for ( i = 0; i < n; i++)
{
scanf( "%d", &tmp );
T = Insert( tmp, T );
}
printf( "\nPreOrder :" );
PreOrder( T );
printf( "\nInOrder :" );
InOrder( T );
printf( "\nPostOrder:" );
PostOrder( T );
printf( "\n" );
return 0;
}
附录:上述代码中用到了Error、FatalError等函数,其实现如下(即fatal.h文件):
#include <stdio.h>
#include <stdlib.h>
#define Error( Str ) FatalError( Str )
#define FatalError( Str ) fprintf( stderr, "%s\n", Str ), exit( 1 )
备注:本文摘自《数据结构与算法分析 C语言描述 Mark Allen Weiss著》,代码经gcc编译测试通过。