行逻辑链接的矩阵乘法

 

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 }

 

posted @ 2019-10-13 23:23  jiamian22  阅读(1051)  评论(0编辑  收藏  举报