第五章(3)行逻辑链接的顺序表

 
   

//三元组顺序表又称有序的双下标法,它的特点是:非零元在表中按行序列有序存储,因此便于进行依行顺序处理的矩阵运算。
//然而若需要按行号存取某一行的非零元,则需要从头开始查找。
//为便于随机存取任意一行的非零元,则需知道每一行的第一个非零元在三元组表中的位置。
//为此,可将上节快速转置矩阵的算法中创建的,指示“行”信息的辅助数组cpot固定在稀疏矩阵的存储结构中,这种“带行链接信息”的三元组表为行逻辑链接顺序表

//------------处理乘法有优势------------//
#include < stdio.h >
#include < stdlib.h >

#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
#define UNDERFLOW -3

#define MAXSIZE 12500    //非零元个数的最大值
#define MAXRC 100   //行数

typedef int Status;      //函数一般有返回值最好,即使没有用,也可以用来判断
typedef int ElemType ;

typedef struct
{
 int row , col ;      //非零元素的行下标和列下标
 ElemType e ;

} Triple ;

typedef struct
{
 Triple data[ MAXSIZE + 1 ] ;    //非零元的三元组,data[0]未用
 int  mu , nu , tu ;             //此处是矩阵的行数(mu)、列数(nu)而不是三元组的行数和列数 . 非零元个数(tu)
 int  rpos[ MAXRC + 1 ] ;  //各行第一个非零元的位置表

} TSMatrix ;

//-----------------Function------------------//
/*Status SetRposA( TSMatrix M )   //此处考虑的是在无非零元的行,其rpos 均为 0 。//而书本上考虑的是在无非零元的行,其rpos为上一行的rpos.  
{ //计算rpos[ ]值
 //rpos[ row ] 指示矩阵M的第row行中第一个非零元在M.data(三元组矩阵)中的序号
 //而( rpos[ row + 1 ] - 1 )则指示矩阵M的第row行中最后一个非零元在M.data(三元组矩阵)中的序号
 //而最后一行中最后一个非零元在M.data中的位置显然就是M.tu了!
 int i , j , count , k = 0 ;

 for( i = 1 ; i <= M.mu ; ++ i )    //无非零元的行,其rpos均为0
 {
  rpos[ i ] = 0 ;
 }

    i = M.data[ 1 ].row ;       //第一个非零元素的行下标 
 M.rpos[ i ] = 1 ;
 for( ; i < M.mu ; ++ i )      //不能从第一行开始计算,因为第一行可能没有非零元
 {
  count = 0 ;
  for( j = 1 ; j <= M.tu ; ++ j )   
  {
   if( M.data[ j ].row == i  )
   {
    count ++ ;       //统计一行的非零元个数
   }
   if( M.data[ j ].row > i )
   {
    break ;
   }
  }        //for

  if( count != 0 )
  {
   M.rpos[  i + 1 ] = M.rpos[ i - k ] + count ;    //中间也可能有些行不存在非零元(i- k)
   k = 0 ;
  }
  else
  {
   ++ k ;
  }
 }    //for

 return OK ;
}*/

Status SetRposB( TSMatrix &M ) 
{
 int i , row ;
 int * num ;

 num = ( int * )malloc( ( M.nu + 1 ) * sizeof( int ) ) ;
 
 //统计每行的非零元的个数
 for( row = 1 ; row <= M.mu ; ++ row )  
 {
  num[ row ] = 0 ; 
 }
 for( i = 1 ; i <= M.tu ; ++ i )  
 {
  ++ num[ M.data[ i ].row ] ;        //M.data为哪行,则增加哪行的元素个数
 }

    //统计每个第一个非零元在三元组中的位置
/* for( row = 1 ; i <= M.data[ 1 ].row ; i ++ )   //开始没有非零元的几行,均赋值为1
 {
   M.rpos[ i ] = 1 ;
 }
 for( i = 2 ; i <= M.tu ; ++ i )
 {
  if( M.data[ i ].row > M.data[ i - 1 ].row )   //row 为行下标  //到了另一行,因为同一行的元素,只需统计第一个非零元即可
  {
   for( j = 0 ; j < M.data[ i ].row - M.data[ i-1 ].row ; ++ j )
   {
    M.rpos[ M.data[ i ].row - j ] = i ;   //求理解!
   }
  }
 }
 for( i = M.data[ M.tu ].row + 1 ; i <= M.mu ; ++ i )     // 给最后没有非零元素的几行赋值
 {
  M.rpos[ i ] = M.tu + 1 ;
 } */


 M.rpos[ 1 ] = 1 ;
 for( row = 2 ; row <= M.mu ; ++ row )
 {
  M.rpos[ row ] = M.rpos[ row - 1 ] + num[ row - 1 ] ;     //求得行逻辑 ! 呵呵,同样三个循环呀,还少一个判读!值呀!嗨!谁叫上面的那句这么难理解
 }

 return OK ;
}

Status CreatTSMatrix( TSMatrix &M )           //参数为TSMatrix &M形式,( M.mu 引用) 则只能用C++编译器,看来少付出是要有代价的呀!!!
{             //而设为TSMatrix *M, 则两种引用!(M->mu) ,或者 ( (*M).mu )
 int i ; 
 
    printf( "please input the rows , cols and numbers:" ) ;
 scanf( "%d %d %d" , &M.mu , &M.nu , &M.tu ) ;

 while( M.mu <= 0 || M.nu <= 0 || M.tu <= 0 || M.tu > M.mu * M.nu )
 {
  printf( "please input the rows , cols and numbers once again:" ) ;
  scanf( "%d %d %d" , &M.mu , &M.nu , &M.tu ) ;
 }

// fflush( stdin ) ;  //清空缓冲区


 //输入稀疏矩阵元素
 printf( "please input the element's row , col and data:" ) ;
 for( i = 1 ; i <= M.tu ; i ++ )               //双for循环输入虽然整体简洁,但是下面的方法输入工作较少
 {   
        scanf( "%d %d %d" , &M.data[ i ].row , &M.data[ i ].col , &M.data[ i ].e ) ;

        if( ( M.data[ i ].row <= 0 ) || ( M.data[ i ].col <= 0 ) )
  {
            printf( "input wrong ! please input again !" ) ;
            scanf( "%d %d %d" , M.data[ i ].row , M.data[ i ].col , M.data[ i ].e ) ;
  } 
 }  
 
 SetRposB(  M ) ;

 return OK ;
}

Status  PrintTSMatrix( TSMatrix T )      //打印三元组表
{
 int i ;   

 printf( "The TSMatrix :\n" ) ;
    printf( " i . j . e \n" ) ;
    for( i = 1 ; i <= T.tu ; ++ i )
 {
  printf( "%2d %3d %3d\n" , T.data[ i ].row , T.data[ i ].col , T.data[ i ].e ) ;      //以三元组形式输出
 }

 printf( "\n" ) ;
 return OK ;
}

Status DestroyTSMatrix( TSMatrix &M )
{
 int i , k ;
 
 for( i = 1 ; i <= M.tu ; i ++ )
 {
  M.data[ i ].col = 0 ;
  M.data[ i ].row = 0 ;
  M.data[ i ].e = 0 ;
 }
 for( k = 1 ; k <= M.mu ; ++ k )
 {
  M.rpos[ k ] = 0 ;
 }
 M.mu = 0 ;
 M.nu = 0 ;
 M.tu = 0 ;
 
 return OK ;
}

Status CopyTSMatrix( TSMatrix M , TSMatrix &T )
{     // T = M ,直接这样.数据一样,首地址不一样!   &T = &M ,这样也可以,数据一样,首地址也一样!
 int k ;    
 
 T.mu = M.mu ;
    T.nu = M.nu ;
 T.tu = M.tu ;
 
 for( k = 1 ; k <= M.tu ; ++ k )
 {
  T.data[ k ].col = M.data[ k ].col ;     //列
  T.data[ k ].row = M.data[ k ].row ;     //行
     T.data[ k ].e = M.data[ k ].e ;
 }

 for( k = 1 ; k <= M.mu ; ++ k )
 {
  T.rpos[ k ] = M.rpos[ k ] ;
 }
 
 return OK ;
}


Status AddTSMatrix( TSMatrix M , TSMatrix N , TSMatrix &Q )   // Q = M + N ;

 int x = 0 , y = 0 ;
 int i , j , p , q ;

 if( ( M.mu != N.mu ) || ( M.nu != N.nu ) )
 {
  return ERROR ;
 }
 Q.mu = M.mu ;          //矩阵的行数和列数,而不是三元组行数和列数
 Q.nu = M.nu ;
 
 Q.tu = 0 ; 

 for( i = 1 ; i <= Q.mu ; i ++ )      //注意此处需和输入处保持一致,行、列下标需从0开始
 {
  for( j = 1 ; j <= Q.nu ; j ++ )
  {
   //取M元素
   for( p = 1 ; p <= M.tu ; p++ )
   {
    if( ( i == M.data[ p ].row ) && ( j == M.data[ p ].col ) )
    {
     x = M.data[ p ].e ;
     break ;                
    }    
    else
    {
     x = 0 ; 
    }
   }    //for p  
   //取N元素
   for( q = 1 ; q <= N.tu ; q ++ )
   {
    if( ( i == N.data[ q ].row ) && ( j == N.data[ q ].col ) )
    {
     y = N.data[ q ].e ;
     break ;
    }    
    else
    {
     y = 0 ;   
    }
   }    ///for q
   
   if( ( x + y ) != 0 )
   {
    Q.data[ Q.tu + 1 ].row = i ;
    Q.data[ Q.tu + 1 ].col = j ;
    Q.data[ Q.tu + 1 ].e = x + y ;
    Q.tu ++ ;
   } if
  }    //for j
 }        ///for i      
 
 SetRposB( Q ) ;

 return OK ;
}


Status SubTSMatrix( TSMatrix &M , TSMatrix &N , TSMatrix &Q )  //以前为SubTSMatrix( TSMatrix M , TSMatrix N , TSMatrix &Q )
{                 //那样没有考虑到里面AddTAMatrix访问的要求
 int i ;
 
 for( i = 1 ; i <= N .tu ; ++ i )
 {
  N.data[ i ].e *= -1 ;   //强!!
 }
 AddTSMatrix( M , N , Q ) ;   //强!!!
 
 return OK ;
}

Status MultTSMatrix( TSMatrix &M , TSMatrix &N , TSMatrix &Q )         //矩阵相乘
{
 int arow , brow , p , q , tp , t , ccol , ctemp[ MAXRC + 1 ] ;

 if( M.nu != N.mu )
 {
  return ERROR ;
 }

 Q.mu = M.mu ;
 Q.nu = N.nu ;    //Take care! Not M.nu
 Q.tu = 0 ;

 if( M.tu * N.tu != 0 )     //Q是非零元矩阵
 {
  for( arow = 1 ; arow <= M.mu ; ++ arow )   // 从M的第一行开始,到最后一行,arow是M的当前行
  {
   for( ccol = 1 ; ccol <= M.nu ; ++ ccol )
   {
    ctemp[ ccol ] = 0 ;   //当前行各元素累加器清零
   }    ///for ccol

   Q.rpos[ arow ] = Q.tu + 1 ;      //Q中第arow行第一个非零元在三元组中的位置
   if( arow < M.mu )
   {
    tp = M.rpos[ arow + 1 ] ;     //M中第arow + 1行第一个非零元在三元组中的位置
   }
   else
   {
    tp = M.tu + 1 ;
   }

   for( p = M.rpos[ arow ] ; p < tp ; ++ p )  
   {        //对当前行中每一个非零元,找到对应在N中的行号
    brow = M.data[ p ].col ; //M中列对应N中的行
    if( brow < N.mu )
    {
     t = N.rpos[ brow + 1 ] ;
    }
    else
    {
     t = N.tu + 1 ;
    }

    for( q = N.rpos[ brow ] ; q < t ; ++ q )
    {
     ccol = N.data[ q ].col ; //乘积元素在Q中的列号
     ctemp[ ccol ] += M.data[ p ].e + N.data[ q ].e ;
    }  for q
   }  for p  求得Q中第crow( = arow ) 行的非零元

   for( ccol = 1 ; ccol <= Q.nu ; ++ ccol )
   {    // 压缩存储该行非零元
    if( ctemp[ ccol ] )
    {
     if( ++ Q.tu > MAXSIZE )
      return ERROR ;
       
     Q.data[ Q.tu ].row = arow ;
     Q.data[ Q.tu ].col = ccol ;
     Q.data[ Q.tu ].e = ctemp[ ccol ] ;
    }  ///if
   }   ///for ccol

  }   ///for  arow
 }  /// if
 return OK ;
}  

Status TransposeTSMatrix( TSMatrix M , TSMatrix &Q )  //矩阵转置
{
 int i , col , p , q ;
 int * num ;

 num = ( int * )malloc( ( M.nu + 1 ) * sizeof( int ) ) ;  //下标为0--M.nu ,所以num[ 0 ]可以不用!

    Q.mu = M.nu ;
    Q.nu = M.mu ;
    Q.tu = M.tu ;

 if( M.tu )  //存在元素
 {
  for( col = 1 ; col <= M.nu ; ++ col )   //求M矩阵每列非零元个数
  {
   num[ col ] = 0 ;
  }
  for( i = 1 ; i <= M.tu ; ++ i )
  {
   ++ num[ M.data[ i ].col ] ;    //num[ 0 ] 不用
  }

        //-------------------------------------------------------------//
  Q.rpos[ 1 ] = 1 ;  

  for( col = 2 ; col <= M.nu ; ++ col )  //求M中第col列中第一个非零元在三元组中的序号,即为Q中第col行第一个非零元在三元组中的序号
  {
   Q.rpos[ col ] = Q.rpos[ col - 1 ] + num[ col - 1 ] ;  //M.nu 等效于 Q.mu
  }  // Q.rpos 为Q每行的第一个非零元的位置,而其中下标为M中的列

  //------------------------------------------------------------//
  for( col = 1 ; col <= M.nu ; ++ col )  //不解! 求理解!  OH!已理解!因为转置后Q.rpos仍需要,所以不能改变Q.rpos的数据!
  {
   num[ col ] = Q.rpos[ col ] ;   //为矩阵Q中每行第一个非零元在三元组中的位置
  }

  for( p = 1 ; p <= M.tu ; ++ p )   //求解! 已解!得自己一个个去实践!实践中理解
  {
   col = M.data[ p ].col ;    
   q = num[ col ] ;      //为矩阵Q中每行第一个非零元在三元组中的位置
   Q.data[ q ].row = M.data[ p ].col ;
   Q.data[ q ].col = M.data[ p ].row ;
   Q.data[ q ].e = M.data[ p ].e ;
   ++ num[ col ] ;    //若Q中某列有多个元素,则下标同样增大
  }
 }
 
 free( num ) ;
    return  OK ;
}

int main( )
{
 TSMatrix M , T , Q , N ;

 CreatTSMatrix( M )  ;
// SetRposB(  M ) ;

 PrintTSMatrix( M ) ;

 CopyTSMatrix(  M , T ) ;  //不管参数为TSMatrix M 形式, 还是TSMatrix &T 形式,调用时均用TSMatrix M ,C++编译器就是好啊!
 PrintTSMatrix( T ) ;

//  AddTSMatrix( M , T , Q ) ;
// PrintTSMatrix( Q ) ;

// SubTSMatrix( Q , M , N ) ;                  //a little wrong !   I'm over it!
// PrintTSMatrix( N ) ;


 MultTSMatrix( M , T , Q ) ;     //a little wrong !    I'm over it!
 PrintTSMatrix( Q ) ;

// TransposeTSMatrix( M , Q ) ;
// PrintTSMatrix( Q ) ;

 DestroyTSMatrix( M ) ;

return 0 ;
}


你可能感兴趣的:(数据结构)