数据结构实践——稀疏矩阵相加

    xiaoxiao2026-03-31  6

    本文针对数据结构基础系列网络课程(5):数组与广义表的实践项目。

    【项目 - 稀疏矩阵相加】   采用三元组存储稀疏矩阵,设计两个稀疏矩阵相加的运算算法 提示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的行列数与a的相同 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; }

    [参考解答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; //c的行列数与a的相同 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;//将a元素添加到c中 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; //将b元素添加到c中 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; //将a元素添加到c中 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; //将b元素添加到c中 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;//将a元素添加到c中 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; //将b元素添加到c中 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”利用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; //c的行列数与a的相同 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;//将a元素添加到c中 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; //将b元素添加到c中 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; //将a元素添加到c中 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; //将b元素添加到c中 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; } 相关资源:稀疏矩阵加法
    最新回复(0)