//三元组顺序表又称有序的双下标法,它的特点是:非零元在表中按行序列有序存储,因此便于进行依行顺序处理的矩阵运算。
//然而若需要按行号存取某一行的非零元,则需要从头开始查找。
//为便于随机存取任意一行的非零元,则需知道每一行的第一个非零元在三元组表中的位置。
//为此,可将上节快速转置矩阵的算法中创建的,指示“行”信息的辅助数组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 ;
}