又是一个实验题:三元数组存储稀疏矩阵,同时实现基本的加法,减法,乘法,求逆
思路:
首先规范好输入情况
明确三元数组的数据结构和输入特征( 行优先输入
)
将稀疏矩阵建立成三元数组和三元数组转化输出
数组的加法,减法(
根据输入的行与列来判断是否可以进行
最后的运算结果仍是稀疏矩阵
输出结果为矩阵
)
思路实现
明确三元数组的数据结构和输入特征( 行优先输入
)
typedef struct { int row; int col; ElementType value; }Triple; typedef struct { Triple data[MAXSIZE]; int rows,cols,nums;//非零起 }TSMatrix;
将稀疏矩阵建立成三元数组和三元数组转化输出
PtrTSMatrix CreatMatrix( void ) { int count = 0; PtrTSMatrix Matrix; Matrix = ( PtrTSMatrix )malloc( sizeof( TSMatrix ) ); if( Matrix == NULL ) { printf("Not Space "); exit( 0 ); } printf("输入行与列 "); scanf("%d%d",&Matrix->rows,&Matrix->cols); printf("输入矩阵的元素的行,列,值( -1 结束 ,行优先) "); scanf("%d%d%d",&Matrix->data[count].row,&Matrix->data[count].col,&Matrix->data[count].value); while( Matrix->data[count].row != -1 ) { count++; scanf("%d%d%d",&Matrix->data[count].row,&Matrix->data[count].col,&Matrix->data[count].value); if( Matrix->data[count].row < Matrix->data[count-1].row && Matrix->data[count].row!=-1 ) { printf("未按行输出: "); getchar(); exit(0); }//if }//while Matrix->nums = count; return Matrix; }/* CreatMatrix */ /* print the matrix Matrix by using matrix */ void PrintMatrix( PtrTSMatrix Matrix ) { int i,j; int count = 0; for( i=0; i<Matrix->rows; i++ ) { for( j=0; j<Matrix->cols; j++ ) { if( count<Matrix->nums && i==Matrix->data[count].row-1 && j==Matrix->data[count].col-1 ) { printf("%2d",Matrix->data[count].value); count++; } else { printf("%2d",0); }//if-else }//for printf(" "); }//for }/* PrintMatrix */ PtrTSMatrix CreatMatrix( void ) { int count = 0; PtrTSMatrix Matrix; Matrix = ( PtrTSMatrix )malloc( sizeof( TSMatrix ) ); if( Matrix == NULL ) { printf("Not Space "); exit( 0 ); } printf("输入行与列 "); scanf("%d%d",&Matrix->rows,&Matrix->cols); printf("输入矩阵的元素的行,列,值( -1 结束 ,行优先) "); scanf("%d%d%d",&Matrix->data[count].row,&Matrix->data[count].col,&Matrix->data[count].value); while( Matrix->data[count].row != -1 ) { count++; scanf("%d%d%d",&Matrix->data[count].row,&Matrix->data[count].col,&Matrix->data[count].value); if( Matrix->data[count].row < Matrix->data[count-1].row && Matrix->data[count].row!=-1 ) { printf("未按行输出: "); getchar(); exit(0); }//if }//while Matrix->nums = count; return Matrix; }/* CreatMatrix */
数组的加法,减法(
根据输入的行与列来判断是否可以进行
最后的运算结果仍是稀疏矩阵
)
一般人最先想到的是两个for循环吧,那么算法的效率为 O( M *N ),我将算法稍稍改进了一下,优化到了 O(M+N ),具体思路如下
1 | 1 | 1 |
2 | 2 | 2 |
3 | 3 | 3 |
x |
y |
vaule |
类似上面那个三元组,在一个矩阵中想要确认位置需要x,y两个数据,实际上我可以把它回归到它在内存中存储得形式,即是线性存储,每一元素有唯一得一个对应值(假设矩阵为3×3),这样在就可以在一次循环中比较了
1 | 1 |
5 | 2 |
9 | 3 |
flag | vaule |
while( 没有一个三元组被遍历完 )
{
if(俩个三元组位置相同)
{
将两个三元组得位置信息和和传递给新的三元组
两个三元组都向后移一位
}
elseif( 其中一个三元组的元素在另一个之前 )
{
将位于前面得元素的位置信息和值传给新得三元组
向后移一位
}
}
/* Plus A and B ,return C */ PtrTSMatrix AddMatrix( PtrTSMatrix A, PtrTSMatrix B ) { int i=0,j=0;//标记追逐 A B PtrTSMatrix C;//存放和 if( A->rows!=B->rows || A->cols!=B->cols ) { return NULL; } C = ( PtrTSMatrix )malloc(sizeof( TSMatrix )); C->rows = A->rows; C->cols = A->cols; C->nums = -1; //初始化 while( i<A->nums && j<B->nums ) { if( A->data[i].row*A->cols+A->data[i].col == B->data[j].row*B->cols+B->data[j].col ) { if( A->data[i].value+B->data[j].value != 0 ) { C->nums++; C->data[C->nums].col = A->data[i].col; C->data[C->nums].row = A->data[i].row; C->data[C->nums].value = A->data[i].value+B->data[j].value; } i++; j++;//标记后移 } else if( A->data[i].row*A->cols+A->data[i].col < B->data[j].row*B->cols+B->data[j].col ) { C->nums++; C->data[C->nums].col = A->data[i].col; C->data[C->nums].row = A->data[i].row; C->data[C->nums].value = A->data[i].value; i++; } else { C->nums++; C->data[C->nums].col = B->data[j].col; C->data[C->nums].row = B->data[j].row; C->data[C->nums].value = B->data[j].value; j++; }//if-else }//while, if( i == A->nums ) { while( j < B->nums ) { C->nums++; C->data[C->nums].col = B->data[j].col; C->data[C->nums].row = B->data[j].row; C->data[C->nums].value = B->data[j].value; j++; } } else { while( i < A->nums ) { C->nums++; C->data[C->nums].col = A->data[i].col; C->data[C->nums].row = A->data[i].row; C->data[C->nums].value = A->data[i].value; i++; } }//if-else C->nums++; return C; }//AddMatrix
矩阵乘法的实现:
。
原文链接 (详细的解释了原理和B矩阵的两个辅助矩阵构造,但对于算法的实现没有详讲)
总得来说,在稀疏矩阵中,C=A乘B是对应行和对应列中非零值的事,例如在A 中 i 行中的第一个非零值 A[i][j],可以和它相乘的只有B的 j 行的非零值B[j][k],而且相乘结果还是放在C[i][k]中,这样把A中的非零值都与
如果给你一张纸来计算A×B,你肯定会先是A的第一行和B的第一列相乘,放在C[0][0]的位置,之后是和B的第二列相乘,放在C[0][1]中,当B的列算到头后,再从A的第二行开始,是吧?但要让计算机对三元组这样操作显然不行,因为你很难确定B三元组的任意一列(当然你要转置,我自然不说什么)。
那么该怎么做呢?
A 0 1 0 1 B 1 0 0 C = ?
0 0 1 0 3 2 0
0 1 0
0 0 2
首先从A中取的第一个值,这个值是 [ 1 2 1 ]([]内的值分别表示其x,y,vaule),那么在整个乘法过程中能和这个值相乘的也只有B中的第二行的[ 2 1 3 ] ,[ 2 2 2]
并且是放在C的第一行中的不同列的。那么能这么干嘛
(1).从A三元组中按顺序取一值 [ x y z ],那么找到对应的B的y
PtrTSMatrix AddMatrix( PtrTSMatrix A, PtrTSMatrix B ) { int i=0,j=0;//标记追逐 A B PtrTSMatrix C;//存放和 if( A->rows!=B->rows || A->cols!=B->cols ) { return NULL; } C = ( PtrTSMatrix )malloc(sizeof( TSMatrix )); C->rows = A->rows; C->cols = A->cols; C->nums = -1; //初始化 while( i<A->nums && j<B->nums ) { if( A->data[i].row*A->cols+A->data[i].col == B->data[j].row*B->cols+B->data[j].col ) { if( A->data[i].value+B->data[j].value != 0 ) { C->nums++; C->data[C->nums].col = A->data[i].col; C->data[C->nums].row = A->data[i].row; C->data[C->nums].value = A->data[i].value+B->data[j].value; } i++; j++;//标记后移 } else if( A->data[i].row*A->cols+A->data[i].col < B->data[j].row*B->cols+B->data[j].col ) { C->nums++; C->data[C->nums].col = A->data[i].col; C->data[C->nums].row = A->data[i].row; C->data[C->nums].value = A->data[i].value; i++; } else { C->nums++; C->data[C->nums].col = B->data[j].col; C->data[C->nums].row = B->data[j].row; C->data[C->nums].value = B->data[j].value; j++; }//if-else }//while, if( i == A->nums ) { while( j < B->nums ) { C->nums++; C->data[C->nums].col = B->data[j].col; C->data[C->nums].row = B->data[j].row; C->data[C->nums].value = B->data[j].value; j++; } } else { while( i < A->nums ) { C->nums++; C->data[C->nums].col = A->data[i].col; C->data[C->nums].row = A->data[i].row; C->data[C->nums].value = A->data[i].value; i++; } }//if-else C->nums++; return C; }//AddMatrix
下面是可直接编译运行的代码:
/************************************************************************* > File Name: Matrix.c > Author: zh > Mail: 574932286@qq.com > Created Time: 2014年10月16日 星期四 13时37分05秒 一: 完成稀疏矩阵的建立i 二: 15:33 稀疏矩阵的加法 10,16 8:30 继续实现 10.19 15:07 继续 三: 10.20 00:44 稀疏矩阵得乘法 ************************************************************************/ #include<stdlib.h> #include<stdio.h> #define MAXSIZE 100 typedef int ElementType; typedef struct { int row; int col; ElementType value; }Triple; typedef struct { Triple data[MAXSIZE]; int rows,cols,nums;//非零起 }TSMatrix; typedef TSMatrix * PtrTSMatrix; PtrTSMatrix CreatMatrix( void ); void PrintMatrix( PtrTSMatrix Matrix ); PtrTSMatrix AddMatrix( PtrTSMatrix A, PtrTSMatrix B ); PtrTSMatrix MinusMatrix( PtrTSMatrix A, PtrTSMatrix B ); PtrTSMatrix MultiMatrix( PtrTSMatrix A, PtrTSMatrix B ); /* Make a Matrix,use the triple array */ PtrTSMatrix CreatMatrix( void ) { int count = 0; PtrTSMatrix Matrix; Matrix = ( PtrTSMatrix )malloc( sizeof( TSMatrix ) ); if( Matrix == NULL ) { printf("Not Space "); exit( 0 ); } printf("输入行与列 "); scanf("%d%d",&Matrix->rows,&Matrix->cols); printf("输入矩阵的元素的行,列,值( -1 结束 ,行优先) "); scanf("%d%d%d",&Matrix->data[count].row,&Matrix->data[count].col,&Matrix->data[count].value); while( Matrix->data[count].row != -1 ) { count++; scanf("%d%d%d",&Matrix->data[count].row,&Matrix->data[count].col,&Matrix->data[count].value); if( Matrix->data[count].row < Matrix->data[count-1].row && Matrix->data[count].row!=-1 ) { printf("未按行输出: "); getchar(); exit(0); }//if }//while Matrix->nums = count; return Matrix; }/* CreatMatrix */ /* print the matrix Matrix by using matrix */ void PrintMatrix( PtrTSMatrix Matrix ) { int i,j; int count = 0; for( i=0; i<Matrix->rows; i++ ) { for( j=0; j<Matrix->cols; j++ ) { if( count<Matrix->nums && i==Matrix->data[count].row-1 && j==Matrix->data[count].col-1 ) { printf("%2d",Matrix->data[count].value); count++; } else { printf("%2d",0); }//if-else }//for printf(" "); }//for }/* PrintMatrix */ /* Plus A and B ,return C */ PtrTSMatrix AddMatrix( PtrTSMatrix A, PtrTSMatrix B ) { int i=0,j=0;//标记追逐 A B PtrTSMatrix C;//存放和 if( A->rows!=B->rows || A->cols!=B->cols ) { return NULL; } C = ( PtrTSMatrix )malloc(sizeof( TSMatrix )); C->rows = A->rows; C->cols = A->cols; C->nums = -1; //初始化 while( i<A->nums && j<B->nums ) { if( A->data[i].row*A->cols+A->data[i].col == B->data[j].row*B->cols+B->data[j].col ) { if( A->data[i].value+B->data[j].value != 0 ) { C->nums++; C->data[C->nums].col = A->data[i].col; C->data[C->nums].row = A->data[i].row; C->data[C->nums].value = A->data[i].value+B->data[j].value; } i++; j++;//标记后移 } else if( A->data[i].row*A->cols+A->data[i].col < B->data[j].row*B->cols+B->data[j].col ) { C->nums++; C->data[C->nums].col = A->data[i].col; C->data[C->nums].row = A->data[i].row; C->data[C->nums].value = A->data[i].value; i++; } else { C->nums++; C->data[C->nums].col = B->data[j].col; C->data[C->nums].row = B->data[j].row; C->data[C->nums].value = B->data[j].value; j++; }//if-else }//while, if( i == A->nums ) { while( j < B->nums ) { C->nums++; C->data[C->nums].col = B->data[j].col; C->data[C->nums].row = B->data[j].row; C->data[C->nums].value = B->data[j].value; j++; } } else { while( i < A->nums ) { C->nums++; C->data[C->nums].col = A->data[i].col; C->data[C->nums].row = A->data[i].row; C->data[C->nums].value = A->data[i].value; i++; } }//if-else C->nums++; return C; }//AddMatrix /* A mius B get C */ PtrTSMatrix MinusMatrix( PtrTSMatrix A, PtrTSMatrix B ) { int i=0,j=0;//标记追逐 A B PtrTSMatrix C;//存放和 if( A->rows!=B->rows || A->cols!=B->cols ) { return NULL; } C = ( PtrTSMatrix )malloc(sizeof( TSMatrix )); C->rows = A->rows; C->cols = A->cols; C->nums = -1; //初始化 while( i<A->nums && j<B->nums ) { if( A->data[i].row*A->cols+A->data[i].col == B->data[j].row*B->cols+B->data[j].col ) { if( A->data[i].value-B->data[j].value != 0 ) { C->nums++; C->data[C->nums].col = A->data[i].col; C->data[C->nums].row = A->data[i].row; C->data[C->nums].value = A->data[i].value-B->data[j].value; } i++; j++;//标记后移 } else if( A->data[i].row*A->cols+A->data[i].col < B->data[j].row*B->cols+B->data[j].col ) { C->nums++; C->data[C->nums].col = A->data[i].col; C->data[C->nums].row = A->data[i].row; C->data[C->nums].value = A->data[i].value; i++; } else { C->nums++; C->data[C->nums].col = B->data[j].col; C->data[C->nums].row = B->data[j].row; C->data[C->nums].value = B->data[j].value; j++; }//if-else }//while, if( i == A->nums ) { while( j < B->nums ) { C->nums++; C->data[C->nums].col = B->data[j].col; C->data[C->nums].row = B->data[j].row; C->data[C->nums].value = B->data[j].value; j++; } } else { while( i < A->nums ) { C->nums++; C->data[C->nums].col = A->data[i].col; C->data[C->nums].row = A->data[i].row; C->data[C->nums].value = A->data[i].value; i++; } }//if-else C->nums++; return C; }/* MiinusMatrix */ /* get the answer of A multiply B */ PtrTSMatrix MultiMatrix( PtrTSMatrix A, PtrTSMatrix B ) { PtrTSMatrix C; int num[MAXSIZE]={0};//第K行得非零元素得个数 int cpot[MAXSIZE]={0};//k行得第一个非零元素在三元组得位置 int i,j; int count = 0; int temp[MAXSIZE]={0}; if( A->cols != B->cols ) { return NULL; }//if ,输入检验 C = (PtrTSMatrix)malloc( sizeof(TSMatrix) ); C->rows = A->rows; C->cols = B->cols; for( i=0; i<B->nums; i++) { num[B->data[i].row-1]++;//m if( i!=0 && B->data[i-1].row!=B->data[i].row ) { cpot[B->data[i-1].row-1] = i; } } for( i=0; i<A->nums; i++ ) { if( i!=0 && A->data[i].row != A->data[i-1].row ) { for( j=0; j < B->cols; j++ ) { if( temp[j] != 0 ) { C->data[count].row = A->data[i-1].row; C->data[count].col = j+1; C->data[count].value = temp[j]; count++; } }//for,赋值 for( j=0; j<B->cols; j++ ) { temp[j] = 0; }//for,初始化 }//if for( j=0; j<num[A->data[i].col]; j++) { temp[ B->data[ cpot[A->data[i].col]+j ].col ] = + A->data[i].value*B->data[ cpot[A->data[i].col]+j ];//高度注意,自己写一下 }//for }//for return C; }//MultiMatrix int main(void) { PtrTSMatrix A,B,C,D,E; A = CreatMatrix(); B = CreatMatrix(); C = AddMatrix( A, B ); D = MinusMatrix( A , B ); E = MultiMatrix( A, B ); printf(" "); PrintMatrix( C ); printf(" "); PrintMatrix( D ); printf(" "); PrintMatrix( E ); return 0; }