AVL(Adelson-Velskii和Landis)树 - C语言实现(摘自数据结构与算法分析 C语言描述)...

一、概述

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)来处理。

图2 单旋转(LL型)

图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编译测试通过。

附件下载:http://download.youkuaiyun.com/detail/shuxiao9058/4212421#avltree_20120401.tar.gz




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值