第六章(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      //根据需要设置不同的初值
#endif

typedef 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 ;
 } 
#endif

 return 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 ;
}


0 0