稀疏矩阵的三元组表示相关的算法库采用程序的多文件组织形式,包括两个文件:
1.头文件:tup.h,包含定义稀疏矩阵的三元组表示数据结构的代码、宏定义、要实现算法的函数的声明;
#ifndef TUP_H_INCLUDED#define TUP_H_INCLUDED#define M 6#define N 7#define MaxSize 100 //矩阵中非零元素最多个数typedef int ElemType;typedef struct{ int r; int c; ElemType d; } TupNode; typedef struct{ int rows; int cols; int nums; TupNode data[MaxSize];} TSMatrix; void CreatMat(TSMatrix &t,ElemType A[M][N]); bool Value(TSMatrix &t,ElemType x,int i,int j); bool Assign(TSMatrix t,ElemType &x,int i,int j); void DispMat(TSMatrix t);void TranTat(TSMatrix t,TSMatrix &tb);#endif // TUP_H_INCLUDED
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
2.源文件:tup.cpp,包含实现各种算法的函数的定义
#include "stdio.h"#include "tup.h"void CreatMat(TSMatrix &t,ElemType A[M][N]) //从一个二维稀疏矩阵创建其三元组表示{ int i,j t.rows=M t.cols=N t.nums=0 for (i=0 { for (j=0 if (A[i][j]!=0) //只存储非零元素 { t.data[t.nums].r=i t.data[t.nums].c=j t.data[t.nums].d=A[i][j] t.nums++ } }}bool Value(TSMatrix &t,ElemType x,int i,int j) //三元组元素赋值{ int k=0,k1 if (i>=t.rows || j>=t.cols) return false while (k<t.nums && i>t.data[k].r) k++ while (k<t.nums && i==t.data[k].r && j>t.data[k].c) k++ if (t.data[k].r==i && t.data[k].c==j) //存在这样的元素 t.data[k].d=x else //不存在这样的元素时插入一个元素 { for (k1=t.nums-1 { t.data[k1+1].r=t.data[k1].r t.data[k1+1].c=t.data[k1].c t.data[k1+1].d=t.data[k1].d } t.data[k].r=i t.data[k].c=j t.data[k].d=x t.nums++ } return true}bool Assign(TSMatrix t,ElemType &x,int i,int j) //将指定位置的元素值赋给变量{ int k=0 if (i>=t.rows || j>=t.cols) return false while (k<t.nums && i>t.data[k].r) k++ while (k<t.nums && i==t.data[k].r && j>t.data[k].c) k++ if (t.data[k].r==i && t.data[k].c==j) x=t.data[k].d else x=0 return true}void DispMat(TSMatrix t) //输出三元组{ int i if (t.nums<=0) //没有非零元素时返回 return printf("\t%d\t%d\t%d\n",t.rows,t.cols,t.nums) printf("\t------------------\n") for (i=0 printf("\t%d\t%d\t%d\n",t.data[i].r,t.data[i].c,t.data[i].d)}void TranTat(TSMatrix t,TSMatrix &tb) //矩阵转置{ int p,q=0,v tb.rows=t.cols tb.cols=t.rows tb.nums=t.nums if (t.nums!=0) //当存在非零元素时执行转置 { for (v=0 for (p=0 if (t.data[p].c==v) { tb.data[q].r=t.data[p].c tb.data[q].c=t.data[p].r tb.data[q].d=t.data[p].d q++ } }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
3.在同一项目(project)中建立一个源文件(如main.cpp),编制main函数,完成相关的测试工作。 例:
int main(){ TSMatrix t,tb; int x,y=10; int A[6][7]= { {0,0,1,0,0,0,0}, {0,2,0,0,0,0,0}, {3,0,0,0,0,0,0}, {0,0,0,5,0,0,0}, {0,0,0,0,6,0,0}, {0,0,0,0,0,7,4} }; CreatMat(t,A); printf("b:\n"); DispMat(t); if (Assign(t,x,2,5)==true) //调用时返回true printf("Assign(t,x,2,5)=>x=%d\n",x); else //调用时返回false printf("Assign(t,x,2,5)=>参数错误\n"); Value(t,y,2,5); printf("执行Value(t,10,2,5)\n"); if (Assign(t,x,2,5)==true) //调用时返回true printf("Assign(t,x,2,5)=>x=%d\n",x); else //调用时返回false printf("Assign(t,x,2,5)=>参数错误\n"); printf("b:\n"); DispMat(t); TranTat(t,tb); printf("矩阵转置tb:\n"); DispMat(tb); return 0;}
【项目 - 稀疏矩阵相加】
采用三元组存储稀疏矩阵,设计两个稀疏矩阵相加的运算算法
提示1:两个行数、列数相同的矩阵可以相加
提示2:充分利用已经建立好的算法库解决问题
[参考解答1](程序中使用的头文件”tup.h”见稀疏矩阵的三元组表示算法库)
#include <stdio.h>#include "tup.h"bool MatAdd(TSMatrix a,TSMatrix b,TSMatrix &c){ int i,j; ElemType va,vb,vc; if (a.rows!=b.rows || a.cols!=b.cols) return false; c.rows=a.rows; c.cols=a.cols; c.nums=0; for(i=0; i<M; i++) for(j=0; j<N; j++) { Assign(a,va,i,j); Assign(b,vb,i,j); vc=va+vb; if(vc) Value(c,vc,i,j); } return true;}int main(){ TSMatrix ta,tb,tc; int A[M][N]= { {0,0,1,0,0,0,0}, {0,2,0,0,0,0,0}, {3,0,0,0,0,0,0}, {0,0,0,5,0,0,0}, {0,0,0,0,6,0,0}, {0,0,0,0,0,7,4} }; int B[M][N]= { {0,0,10,0,0,0,0}, {0,0,0,20,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,50,0,0,0}, {0,0,20,0,0,0,0}, {0,0,0,10,0,0,4} }; CreatMat(ta,A); CreatMat(tb,B); printf("A:\n"); DispMat(ta); printf("B:\n"); DispMat(tb); if(MatAdd(ta, tb, tc)) { printf("A+B:\n"); DispMat(tc); } else { printf("相加失败\n"); } return 0;}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
[参考解答2]
下面给出的解答,没有利用算法库中已经实现的Assign和Value两个基本运算,而是直接e采取了更为直接的方法去完成。用i和j两个变量扫描三元组a和b,按行序优先的原则进行处理,将结果存放于c中。当a的当前元素和b的当前元素的行号和列号均相等时,将它们的值相加,只有在相加值不为0时,才在c中添加一个新的元素。
#include <stdio.h>#include "tup.h"bool MatAdd(TSMatrix a,TSMatrix b,TSMatrix &c){ int i=0,j=0,k=0 ElemType v if (a.rows!=b.rows || a.cols!=b.cols) return 0 c.rows=a.rows c.cols=a.cols while (i<a.nums && j<b.nums) //处理a和b中的每个元素 { if (a.data[i].r==b.data[j].r) //行号相等时 { if(a.data[i].c<b.data[j].c) //a元素的列号小于b元素的列号 { c.data[k].r=a.data[i].r c.data[k].c=a.data[i].c c.data[k].d=a.data[i].d k++ i++ } else if (a.data[i].c>b.data[j].c)//a元素的列号大于b元素的列号 { c.data[k].r=b.data[j].r c.data[k].c=b.data[j].c c.data[k].d=b.data[j].d k++ j++ } else //a元素的列号等于b元素的列号 { v=a.data[i].d+b.data[j].d if (v!=0) //只将不为0的结果添加到c中 { c.data[k].r=a.data[i].r c.data[k].c=a.data[i].c c.data[k].d=v k++ } i++ j++ } } else if (a.data[i].r<b.data[j].r) //a元素的行号小于b元素的行号 { c.data[k].r=a.data[i].r c.data[k].c=a.data[i].c c.data[k].d=a.data[i].d k++ i++ } else //a元素的行号大于b元素的行号 { c.data[k].r=b.data[j].r c.data[k].c=b.data[j].c c.data[k].d=b.data[j].d k++ j++ } } while (i<a.nums) //a中尚有元素时 { c.data[k].r=a.data[i].r c.data[k].c=a.data[i].c c.data[k].d=a.data[i].d k++ i++ } while (j<b.nums) //b中尚有元素时 { c.data[k].r=b.data[j].r c.data[k].c=b.data[j].c c.data[k].d=b.data[j].d k++ j++ } c.nums=k return true}int main(){ TSMatrix ta,tb,tc int A[M][N]= { {0,1,0,0,0,0,0}, {0,2,0,0,0,0,0}, {3,0,0,0,0,0,0}, {0,0,0,5,0,0,0}, {0,0,0,0,6,0,0}, {0,0,0,0,0,7,4} } int B[M][N]= { {0,0,10,0,0,0,0}, {0,0,0,20,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,50,0,0,0}, {0,0,20,0,0,0,0}, {0,0,0,10,0,0,4} } CreatMat(ta,A) CreatMat(tb,B) printf("A:\n") DispMat(ta) printf("B:\n") DispMat(tb) if(MatAdd(ta, tb, tc)) { printf("A+B:\n") DispMat(tc) } else { printf("相加失败\n") } return 0}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
对比两种方案,“参考解答1”利用Assign和Value两个基本运算的方案,可以在只知道“矩阵加法是对应位置的元素相加”的基础上就可以求解;而“参考解答2”则不得不关注在数据存储层面的细节,以致于矩阵加法的规则都不容易看出来了。“参考解答2”中繁杂的代码,违反了程序设计中诸多的原则(例如模块化),相对“参考解答1”的简洁中透出的优雅,该不是学习者效仿的思维。
附:1楼评论中带bug的解答,原参考解答2。重点观察少了while (i<a.nums)
、while (j<b.nums)
两个循环,当a和b的最后一个元素不在同一行同一列时,会丢数据的。这个bug的漏网,和main函数中采用的测试数据不够好有关,让两个矩阵非0元素在同一行同一列,忽略了“边界”数据的重要性。
与此同时,再次体会参考解答1的好处,缺少了一层抽象,对应的就是处处要考虑细节。智者千虑,必有一失,还是要运用上工程中的原则为好。
#include <stdio.h>#include "tup.h"bool MatAdd(TSMatrix a,TSMatrix b,TSMatrix &c){ int i=0,j=0,k=0 ElemType v if (a.rows!=b.rows || a.cols!=b.cols) return 0 c.rows=a.rows c.cols=a.cols while (i<a.nums && j<b.nums) //处理a和b中的每个元素 { if (a.data[i].r==b.data[j].r) //行号相等时 { if(a.data[i].c<b.data[j].c) //a元素的列号小于b元素的列号 { c.data[k].r=a.data[i].r c.data[k].c=a.data[i].c c.data[k].d=a.data[i].d k++ i++ } else if (a.data[i].c>b.data[j].c)//a元素的列号大于b元素的列号 { c.data[k].r=b.data[j].r c.data[k].c=b.data[j].c c.data[k].d=b.data[j].d k++ j++ } else //a元素的列号等于b元素的列号 { v=a.data[i].d+b.data[j].d if (v!=0) //只将不为0的结果添加到c中 { c.data[k].r=a.data[i].r c.data[k].c=a.data[i].c c.data[k].d=v k++ } i++ j++ } } else if (a.data[i].r<b.data[j].r) //a元素的行号小于b元素的行号 { c.data[k].r=a.data[i].r c.data[k].c=a.data[i].c c.data[k].d=a.data[i].d k++ i++ } else //a元素的行号大于b元素的行号 { c.data[k].r=b.data[j].r c.data[k].c=b.data[j].c c.data[k].d=b.data[j].d k++ j++ } c.nums=k } return true}int main(){ TSMatrix ta,tb,tc int A[M][N]= { {0,0,1,0,0,0,0}, {0,2,0,0,0,0,0}, {3,0,0,0,0,0,0}, {0,0,0,5,0,0,0}, {0,0,0,0,6,0,0}, {0,0,0,0,0,7,4} } int B[M][N]= { {0,0,10,0,0,0,0}, {0,0,0,20,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,50,0,0,0}, {0,0,20,0,0,0,0}, {0,0,0,10,0,0,4} } CreatMat(ta,A) CreatMat(tb,B) printf("A:\n") DispMat(ta) printf("B:\n") DispMat(tb) if(MatAdd(ta, tb, tc)) { printf("A+B:\n") DispMat(tc) } else { printf("相加失败\n") } return 0}