第六章(1).二叉树的顺序存储表示
来源:互联网 发布:异星工厂电路网络 编辑:程序博客网 时间:2024/06/13 12:21
//-----------------二叉树的顺序存储表示(Binary Tree)----------------//
//二叉树也可以用数组来存储,而且如果这是完全二叉树,这种方法不会浪费空间。用这种紧凑排列,如果一个结点的索引为i,
//它的子结点能在索引2i+1和2i+2找到,并且它的父节点(如果有)能在索引floor((i-1)/2)找到(假设根节点的索引为0)。
//这种方法更有利于紧凑存储和更好的访问的局部性,特别是在前序遍历中。然而,它需要连续的存储空间,
//这样在存储高度为h的n个结点组成的一般普通树时将会浪费很多空间。一种最极坏的情况下如果深度为h的二叉树每个节点只有右孩子需要占用2的h次幂减1,
//而实际却只有h个结点,空间的浪费太大,这是顺序存储结构的一大缺点。
#include < stdio.h >
#include < stdlib.h >
#include < string.h >
#include < math.h >#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
//#define OVERFLOW -2 //alredy include by "math.h"!#define MAXTREESIZE 100 //最大结点数
#define CHAR 0
#if CHAR //CHAR is true!( CHAR == 1 )
typedef char TElemType ;
#define N '#' //根据需要设置不同的初值
#else
typedef int TElemType ;
#define N 0 //根据需要设置不同的初值
#endiftypedef int Status;
typedef TElemType SqBiTree[ MAXTREESIZE ] ; //o号单元存储根结点typedef struct
{
int level , order ; //结点的层以及本层的序号(按满二叉数计算)
} Position ;//-------------------------Link Queue---------------------------//要用到链队列的相关操作
typedef int QElemType ;
typedef struct QNode //链结点
{
QElemType data ;
struct QNode *next ;
} QNode , *QueuePtr ;typedef struct
{
QueuePtr front ; //队头指针 (队头出元素)
QueuePtr rear ; //队尾指针 (队尾进元素)
} LinkQueue ;Status InitQueue(LinkQueue *Q) ;
Status EnQueue(LinkQueue *Q, QElemType e) ;
Status DeQueue(LinkQueue *Q, QElemType *e) ;
//-----------------------Basic Fuction!-------------------------//
//Take care! 这里的二叉树T,此时T是数组名,已存在空间,所以进函数时,不必用指针形式!
Status InitBiTree( SqBiTree T )
{
int i = 0 ;for( i = 0 ; i < MAXTREESIZE ; ++ i )
{
T[ i ] = N ; //初值为空( N 可根据需要设置不同的值 )}
return OK ;
}
//ClearBiTree、DestroyBiTree is the same as InitBiTree !
//由于SqBiTree是定长类型,所以无法销毁Status CreateBiTree( SqBiTree T )
{
int i = 0 , l = 0 ;#if CHAR
char str[ MAXTREESIZE ] ; //定义语句不能放在执行语句后哦!(can't be put after "printf")
printf( "The TElemType is char!\n" ) ;
printf( "Input the Tree Node(char),blank is mean NULL Node!: " ) ;
gets( str ) ;
l = strlen( str ) ;for( i = 0 ; i < l ; ++ i )
{
T[ i ] = str[ i ] ;
}
for( i = 1 ; i < l ; ++ i ) //T[ 0 ] 为根结点
{
if( N == T[ ( i + 1 )/2 - 1 ] && N != T[ i ] ) //T[i]为非根结点(非空)且无双亲!T[ ( i + 1 )/2 - 1 ]为双亲结点
{
printf( "%3c既非根节点又无双亲结点(非法)\n" , T[ i ] ) ;
exit( OVERFLOW ) ;
}
}
for( i = l ; i < MAXTREESIZE ; ++ i )
{
T[ i ] = N ;
}
#else
printf( "The TElemType is int!\n" ) ;
printf( "Input the Tree Node(int), 0 is mean NULL Node!: " ) ;while( 1 )
{
scanf( "%d" , &T[ i ] ) ;
if( 999 == T[ i ] )
{
break ;
}
++ i ;
}
for( l = 1 ; l < i ; ++ l )
{
if( N == T[ ( l + 1 )/2 - 1 ] && N != T[ l ] )
{
printf( "%3d既非根节点又无双亲结点(非法)\n" , T[ l ] ) ;
exit( OVERFLOW ) ;
}
}while( i < MAXTREESIZE ) //将空赋值给T的后面的结点
{
T[ i ] = N ; //It's very important later!
++ i ;
}
#endifreturn OK ;
}//--------------------------------------------------------------//
Status Traverse( SqBiTree T , void ( *v )( TElemType ) )
{
int i = 0 , j = 0 ;/* while( i < MAXTREESIZE ) //如此一来,当MAXTREESIZE很大时,最后一个结点后的大量空结点也会参与循环!导致效率低下!
{
if( T[ i ] != N )
{
v( T[ i ]) ;
}
++ i ;
}
*/
i = MAXTREESIZE - 1 ;
while( N == T[ i ] ) //寻找最后一个非空结点
{
-- i ;
}
for( j = 0 ; j <= i ; ++ j )
{
if( N != T[ j ] )
v( T[ j ] ) ;
}
printf( "\n" ) ;
return OK ;
}void visit( TElemType e )
{
#if CHAR //CHAR is true!( CHAR == 1 )
printf( "%3c" , e ) ;
#else
printf( "%3d" , e ) ;
#endif
}Status BiTreeEmpty( SqBiTree T )
{
if( N == T[ 0 ] ) //根结点为空
{
return TRUE ;
}
return FALSE ;
}Status BiTreeDepth( SqBiTree T )
{
int i = 0 , j = -1 ;for( i = MAXTREESIZE - 1 ; i >= 0 ; -- i ) //Find the last Node!
{
if( N != T[ i ] ) //从最后的结点开始的
break ;
}
i ++ ; //为了便于计算!自增后表示节点个数(因为节点从下标0开始),所以下面i>=pow(2,j)有等号do{
j++ ; //if ( j == 0 ) ,then only a root node!
}while( i >= pow( 2 , j ) ) ; //Depth = [log2 N ] + 1 , n 为总结点数! [ x ] mean not above than x!
//pow( 2 , k - 1 ) <= n <= pow( 2 , k ) , n为总结点数,k为深度
return j ;
}Status Root( SqBiTree T , TElemType *e )
{
if( BiTreeEmpty( T ) )
{
printf( "There is no root!\n" ) ;
exit( OVERFLOW ) ;
}
*e = T[ 0 ] ;
return OK ;
}TElemType Value( SqBiTree T , Position p ) //返回p所指的结点的值
{
return T[ (int)pow( 2 , p.level - 1 ) + p.order - 2 ] ; //"int" is needed!
}Status Assign( SqBiTree T , Position p , TElemType e ) //将p所指的结点赋值为e
{
int i = ( int )pow( 2 , p.level - 1 ) + p.order - 2 ;//"( int )pow( 2 , p.level - 1 ) + p.order - 1" on the book!if( e != N && ( N == T[ ( i + 1 )/2 - 1 ] ) ) //所赋的值非空,但所赋的结点不存在双亲结点,所以不能赋值
{
return ERROR ; //T[ ( i + 1 )/2 - 1 ]为双亲结点( different from book,because the element began from T[0] )
}
else
{
if( N == e && ( N != T[ ( i * 2 ) + 1 ] || N != T[ ( i * 2 ) + 2 ] ) ) //T[ ( i * 2 ) + 1 ]、T[ ( i * 2 ) + 2 ]为左右子结点
{
return ERROR ; //所赋结点存在子结点,但所赋的值为空,所以亦不能赋值
}
}
T[ i ] = e ;
return OK ;
}TElemType Parent( SqBiTree T , TElemType e ) //若e为非根结点,则返回它的双亲,否则返回空
{
int i = 0 ;
if( N == T[ 0 ] ) //安全判断必不可少哦!
{
return N ;
}
for( i = 0 ; i < MAXTREESIZE ; ++ i )
{
if( e == T[ i ] )
return T[ ( i + 1 )/2 - 1 ] ;
}
return N ;
}TElemType LeftChid( SqBiTree T , TElemType e ) //返回e结点的的左孩子,否则返回空
{
int i = 0 ;
if( N == T[ 0 ] )
{
return N ;
}for( i = 0 ; i < MAXTREESIZE ; ++ i )
{
if( e == T[ i ] )
return T[ i * 2 + 1 ] ;
}
return N ;
}TElemType RightChid( SqBiTree T , TElemType e ) //返回e结点的的右孩子,否则返回空
{
int i = 0 ;
if( N == T[ 0 ] )
{
return N ;
}for( i = 0 ; i < MAXTREESIZE ; ++ i )
{
if( e == T[ i ] )
return T[ i * 2 + 2 ] ;
}
return N ;
}TElemType LeftSibling( SqBiTree T , TElemType e ) //返回e结点的的左兄弟,否则返回空
{
int i = 0 ;
if( N == T[ 0 ] )
{
return N ;
}for( i = 1 ; i < MAXTREESIZE ; ++ i ) //根结点应排除在外( i==0 ),根结点无左右兄弟
{
if( e == T[ i ] && ( i % 2 == 0 ) ) //找到e结点,且其序号为偶数(即其为右结点)(Take care! Because the node begin from T[0])
return T[ i - 1 ] ;
}
return N ;
}TElemType RightSibling( SqBiTree T , TElemType e ) //返回e结点的的右兄弟,否则返回空
{
int i = 0 ;
if( N == T[ 0 ] )
{
return N ;
}for( i = 1 ; i < MAXTREESIZE ; ++ i )
{
if( e == T[ i ] && ( i % 2 == 1 ) && ( N != T[ i + 1 ] ) )//找到其值为e的左结点,且其存在右兄弟
return T[ i + 1 ] ;
}
return N ;
}void Move( SqBiTree Q , int j , SqBiTree T , int i )
{ //把从Q的j结点开始的子树移为从T的i结点开始的子树if( N != Q[ 2 * j + 1 ] ) //移左子树
{
Move( Q , ( 2 * j + 1 ) , T , ( 2 * i + 1 ) ) ;
}
if( N != Q[ 2 * j + 2 ] ) //移右子树
{
Move( Q , ( 2 * j + 2 ) , T , ( 2 * i + 2 ) ) ;
}
T[ i ] = Q[ j ] ; //移结点
Q[ j ] = N ; //置空
}
Status InsertChild( SqBiTree T , Position p , int LR , SqBiTree c )
{ //根据LR为0或1,插入c为T中p所指结点的左或右子树。p所指结点的原有左或右子树则成为c的右子树
int j = 0 , k = 0 ;int i = ( int )pow( 2 , p.level - 1 ) + p.order - 2 ;
k = i * 2 + 1 + LR ; //k为p所指结点的左或右子结点if( N != T[ k ] )
{
Move( T , k , T , 2 * k + 2 ) ; //把从T的k结点开始的子树移为从k结点的右子树开始的子树
}
Move( c , j , T , k ) ; //把从c的j结点开始的子树移为从T的k结点开始的子树return OK ;
}Status DeleteChild( SqBiTree T , Position p , int LR ) //强悍!
{ //根据LR为0或1,删除T中p所指结点的左或右子树
int j = 0 ;
int k = 1 ;
int i = ( int )pow( 2 , p.level - 1 ) + p.order - 2 ; //p所指结点的位序
LinkQueue Q ;
InitQueue( &Q ) ;if( N == T[ i ] )
{
return ERROR ;
}j = i * 2 + 1 + LR ; //j 为删除子树的根结点所在的位序
while( k )
{
if( N != T[ 2 * j + 1 ] )//删除子树的左子结点非空
{
EnQueue( &Q , 2 * j + 1 ) ;
}
if( N != T[ 2 * j + 2 ] )
{
EnQueue( &Q , 2 * j + 2 ) ;
}
T[ j ] = N ; //删除此结点
k = DeQueue( &Q , &j ) ;//队列非空
}return OK ;
}Status PreOrderTraverse( SqBiTree T , int i , void ( *v )( TElemType ) ) //先序遍历
{
if( N != T[ i ] ) //非空
{
v( T[ i ] ) ;
PreOrderTraverse( T , 2 * i + 1 , v ) ;
PreOrderTraverse( T , 2 * i + 2 , v ) ;
}
return OK ;
}Status InOrderTraverse( SqBiTree T , int i , void ( *v )( TElemType ) ) //中序遍历
{
if( N != T[ i ] ) //非空
{
InOrderTraverse( T , 2 * i + 1 , v ) ;
v( T[ i ] ) ;
InOrderTraverse( T , 2 * i + 2 , v ) ;
}
return OK ;
}Status PostOrderTraverse( SqBiTree T , int i , void ( *v )( TElemType ) ) //后序遍历
{
if( N != T[ i ] ) //非空
{
PostOrderTraverse( T , 2 * i + 1 , v ) ;
PostOrderTraverse( T , 2 * i + 2 , v ) ;
v( T[ i ] ) ;
}
return OK ;
}//-----------------------------Main Fuction!---------------------------------//
int main( )
{
SqBiTree T , L ;
// TElemType e ;
// Position p ;
// p.level = 1 , p.order = 1 ;InitBiTree( T ) ;
CreateBiTree( T ) ;
Traverse( T , visit ) ;
// BiTreeEmpty( T ) ;
// printf( "%3d\n" , BiTreeDepth( T ) ) ;// Root( T , &e ) ;
// visit( e ) ;
// printf( "\n" ) ;// printf( "%3d\n" , Value( T , p ) ) ;
// Assign( T , p , 10 ) ;
// Traverse( T , visit ) ;// printf( "%3d\n" , Parent( T , 5 ) ) ;
// printf( "%3d\n" , LeftChid( T , 2 ) ) ;// InitBiTree( L ) ;
// CreateBiTree( L ) ;
// Traverse( L , visit ) ;
// InsertChild( T , p , 0 , L ) ;
// Traverse( T , visit ) ;// DeleteChild( T , p , 0 ) ;
// Traverse( T , visit ) ;// PreOrderTraverse( T , 0 , visit ) ;
// printf( "\n" ) ;
// InOrderTraverse( T , 0 , visit ) ;
// printf( "\n" ) ;
// PostOrderTraverse( T , 0 , visit ) ;
// printf( "\n" ) ;return 0 ;
}
- 第六章(1).二叉树的顺序存储表示
- (数据结构第六章)二叉树的顺序存储结构
- 二叉树的表示链式表示和顺序存储3.0
- 第六章(2).二叉树链表存储表示
- 数据结构第六章-二叉树顺序存储变链式存储
- 12.完全二叉树的顺序存储表示
- 二叉树的二叉线索存储表示
- 二叉树的建立(顺序存储)
- 二叉树顺序表示的实现
- 二叉树的顺序表示和实现
- 二叉树的顺序存储
- 二叉树的顺序存储
- 二叉树的顺序存储
- 二叉树的顺序存储
- 二叉树的顺序存储
- 二叉树的顺序存储
- 二叉树的顺序存储
- 二叉树的顺序存储
- 第五章(1)数组的顺序表示和实现
- 第五章(2)三元组顺序表
- 第五章(3)行逻辑链接的顺序表
- 第五章(4)十字链表
- 第五章(6).广义表的扩展线性链表存储表示
- 第六章(1).二叉树的顺序存储表示
- 第六章(2).二叉树链表存储表示
- 第六章(5).树的孩子兄弟表示法
- Linux crontab定时执行任务 命令格式与详细例子
- 第六章(6).三叉链表存储树
- 第六章(7).哈夫曼树及其应用
- 第七章(1).图的数组(邻接矩阵)存储表示
- 第七章(2).图的邻接表存储表示
- 第七章(3).图的十字链表存储表示