Description
对于一个稀疏矩阵,当需要频繁的随机存取任意一行的非零元时,则需要知道每一行的第一个非零元在三元组表中的位置。为此,可以将算法5.2中用来指示“行”信息的辅助数组cpot固定在稀疏矩阵的存储结构中。这种“带行链接信息”的三元组表即为行逻辑链接的顺序表。其类型描述如下:

针对存储于行逻辑链接顺序表的稀疏矩阵,其矩阵相乘的算法与经典算法有所不同。因此,对于两个稀疏矩阵相乘(Q=M×N)的过程可以大致描述如下:

请使用行逻辑链接的顺序表实现两个稀疏矩阵的乘法。
Input
输入的第一行是两个整数r1和c1(r1<200, c1<200, r1*c1 <= 12500),分别表示一个包含很多0的稀疏矩阵的行数和列数。接下来有r1行,每行有c1个整数,用空格隔开,表示第一个稀疏矩阵的各个元素。
之后的一行有两个整数r2和c2(c1=r2<200, c2<200, r2*c2 <= 12500),分别表示一个包含很多0的稀疏矩阵的行数和列数。接下来有r2行,每行有c2个整数,用空格隔开,表示第二个稀疏矩阵的各个元素。
Output
输出两个矩阵的乘积。输出共有r1行,每行有c2个整数,每个整数后输出一个空格。请注意行尾输出换行。
Sample Input
4 5 0 0 0 69 78 0 0 5 0 0 0 0 0 0 0 0 91 2 0 82 5 6 0 18 0 0 0 0 0 0 67 0 0 0 0 0 0 0 0 41 0 0 47 62 0 0 0 0 0 0 0 35
Sample Output
0 0 3243 4278 0 2730 0 0 0 0 0 205 0 0 0 0 0 0 0 0 6097 0 0 2952
HINT
提示:对于稀疏矩阵M和N,其相乘的基本操作是:对于M中每个元素M.data[p](p=1,2,...,M.tu),找到N中所有满足条件M.data[p].j=N.data[q].i的元素N.data[q],从而求得M.data[p]与M.data[q]的乘积。需要注意的是,这个乘积只是Q[i][j]中的一部分,需要将其累加从而得到最终的结果。另外需要注意的是,两个稀疏矩阵相乘的乘积并不一定是稀疏矩阵。总结:采用行逻辑链接的顺序表通过使用非零元的行信息,使稀疏矩阵的存储和使用效能进一步提高。尤其是对于稀疏矩阵相乘, 这种算法省去了非常多无谓的计算。
1 #include <stdio.h>
2 #include <string.h>
3 #include <iostream>
4 #include <string>
5 #include <math.h>
6 #include <algorithm>
7 #include <vector>
8 #include <stack>
9 #include <queue>
10 #include <set>
11 #include <map>
12 const int INF=0x3f3f3f3f;
13 typedef long long LL;
14 const int mod=1e9+7;
15 const int maxn=1e4+2510;
16 using namespace std;
17
18 typedef struct
19 {
20 int row;//行
21 int col;//列
22 int val;//值
23 }Triple;
24
25 typedef struct
26 {
27 Triple data[maxn];//三元组
28 int rpos[maxn];//每一行的第一个非零元在三元组表中的位置
29 int rows;//矩阵的总行数
30 int cols;//矩阵的总列数
31 int nums;//矩阵的非零元素个数
32 }Matrix;
33
34 void MulMatrix(Matrix A,Matrix B,Matrix *C)
35 {
36 if(A.cols!=B.rows)//如果矩阵A的列数与矩阵B的行数不等,则不能做矩阵乘运算
37 return ;
38 C->rows=A.rows;
39 C->cols=B.cols;
40 C->nums=0;
41 if(A.nums*B.nums==0)//如果其中任意矩阵的元素个数为零,做乘法元素没有意义,全是0
42 return ;
43 int ccol;
44 for(int arow=1;arow<=A.rows;arow++)
45 {
46 int temp[maxn]={0};//创建一个临时存储乘积结果的数组,且初始化为0,遍历每次都需要清空
47 C->rpos[arow]=C->nums+1;
48 int tp;
49 if(arow<A.rows)
50 tp=A.rpos[arow+1];//获取矩阵A的下一行第一个非零元素在data数组中位置
51 else
52 tp=A.nums+1;//若当前行是最后一行,则取最后一个元素+1
53 //遍历当前行的所有的非0元素
54 for(int p=A.rpos[arow];p<tp;p++)
55 {
56 int brow=A.data[p].col;//取该非0元素的列数,便于去B中找对应的做乘积的非0元素
57 int t;
58 // 判断如果对于A中非0元素,找到矩阵B中做乘法的那一行中的所有的非0元素
59 if(brow<B.rows)
60 t=B.rpos[brow+1];
61 else
62 t=B.nums+1;
63 //遍历找到的对应的非0元素,开始做乘积运算
64 for(int q=B.rpos[brow];q<t;q++)
65 {
66 //得到的乘积结果,每次和temp数组中相应位置的数值做加和运算
67 ccol=B.data[q].col;
68 temp[ccol]+=A.data[p].val*B.data[q].val;
69 }
70 }
71 //矩阵C的行数等于矩阵A的行数,列数等于矩阵B的列数,所以,得到的temp存储的结果,也会在C的列数的范围内
72 for(ccol=1;ccol<=C->cols;ccol++)
73 {
74 //由于结果可以是0,而0不需要存储,所以在这里需要判断
75 if(temp[ccol])
76 {
77 C->nums++;
78 if(C->nums > maxn)
79 return;
80 C->data[C->nums].val=temp[ccol];
81 C->data[C->nums].row=arow;
82 C->data[C->nums].col=ccol;
83 }
84 }
85 }
86 }
87
88 int main()
89 {
90 Matrix A,B,C;
91 scanf("%d %d",&A.rows,&A.cols);
92 A.nums=0;
93 for(int i=1;i<=A.rows;i++)
94 {
95 A.rpos[i]=A.nums+1;
96 for(int j=1;j<=A.cols;j++)
97 {
98 int x;
99 scanf("%d",&x);
100 if(x)
101 {
102 A.nums++;
103 A.data[A.nums].row=i;
104 A.data[A.nums].col=j;
105 A.data[A.nums].val=x;
106 }
107 }
108 }
109 scanf("%d %d",&B.rows,&B.cols);
110 B.nums=0;
111 for(int i=1;i<=B.rows;i++)
112 {
113 B.rpos[i]=B.nums+1;
114 for(int j=1;j<=B.cols;j++)
115 {
116 int x;
117 scanf("%d",&x);
118 if(x)
119 {
120 B.nums++;
121 B.data[B.nums].row=i;
122 B.data[B.nums].col=j;
123 B.data[B.nums].val=x;
124 }
125 }
126 }
127 MulMatrix(A,B,&C);
128 int cnt=1;
129 for(int i=1;i<=C.rows;i++)//输出转置后的矩阵
130 {
131 for(int j=1;j<=C.cols;j++)
132 {
133 int a,b;
134 a=C.data[cnt].row;
135 b=C.data[cnt].col;
136 if(a==i&&b==j)
137 {
138 printf("%d ",C.data[cnt].val);
139 cnt++;
140 }
141 else
142 printf("%d ",0);
143 }
144 printf("\n");
145 }
146 return 0;
147 }