AVL(Adelson-Velskii和Landis)树 - C语言实现(摘自数据结构与算法分析 C语言描述)
来源:互联网 发布:人工智能程序发展 编辑:程序博客网 时间:2024/04/30 05:37
一、概述
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的相应的子树(称为TLR)中。如果的高度不变,那么插入完成。否则,如果在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 )
0 0
- AVL(Adelson-Velskii和Landis)树 - C语言实现(摘自数据结构与算法分析 C语言描述)
- AVL(Adelson-Velskii和Landis)树 - C语言实现(摘自数据结构与算法分析 C语言描述)
- AVL树(Adelson-Velskii-Landis tree)
- 二叉查找树 - C语言实现(摘自数据结构与算法分析 C语言描述)
- 二叉查找树 - C语言实现(摘自数据结构与算法分析 C语言描述)
- 排序 - C语言实现(摘自数据结构与算法分析C语言描述))
- 栈及其应用 - C语言实现(摘自数据结构与算法分析 C语言描述)
- 队列 - C语言实现(摘自数据结构与算法分析 C语言描述)
- 散列 - C语言实现(摘自数据结构与算法分析 C语言描述)
- 优先队列(堆) - C语言实现(摘自数据结构与算法分析 C语言描述)
- 散列 - C语言实现(摘自数据结构与算法分析 C语言描述)
- 优先队列(堆) - C语言实现(摘自数据结构与算法分析 C语言描述)
- 散列 - C语言实现(摘自数据结构与算法分析 C语言描述)
- 队列 - C语言实现(摘自数据结构与算法分析 C语言描述)
- 栈及其应用 - C语言实现(摘自数据结构与算法分析 C语言描述)
- 队列 - C语言实现(摘自数据结构与算法分析 C语言描述)
- 优先队列(堆) - C语言实现(摘自数据结构与算法分析 C语言描述)
- 排序-c语言实现(摘自数据结构与算法分析c语言实现)
- vim使用技巧——快速编辑篇<转>
- 编译hadoop2x插件
- JAVA跳出多重循环的三种方法
- Windows10:融合仅是两个系统的叠加吗?
- IOS 七种传值方法
- AVL(Adelson-Velskii和Landis)树 - C语言实现(摘自数据结构与算法分析 C语言描述)
- Vivado SDK生成库文件
- mac删除mysql
- tabhost的继承与不继承tabactivity
- 二叉查找树 - C语言实现(摘自数据结构与算法分析 C语言描述)
- 2010.10.08学习总结
- strcpy与strncpy
- 队列 - C语言实现(摘自数据结构与算法分析 C语言描述)
- 栈及其应用 - C语言实现(摘自数据结构与算法分析 C语言描述)