数据结构 稀疏矩阵相乘问题

合集下载

数据结构实验四稀疏矩阵运算

数据结构实验四稀疏矩阵运算

数据结构实验四稀疏矩阵运算1、实验目的掌握三元组法存储稀疏矩阵的方法及相关的基本操作。

2、实验内容∙用三元组法存放稀疏矩阵∙求出矩阵转置结果∙求出矩阵相乘结果∙输出结果矩阵3、实验要求∙用数组存放矩阵的三元组,矩阵的行数和列数及非0数据从键盘输入∙要求采用稀疏矩阵快速转置算法∙若两个矩阵不能相乘则输出“Error”4、试验参考程序typedef s tr uct { // 定义三元组的元素int i, j;int e;} Tr iple;typedef s tr uct { // 定义矩阵Tr iple data[MA XSI ZE + 1];int mu, nu, tu;} TSMa tr ix;typedef s tr uct { // 定义行逻辑连接矩阵Tr iple data[MA XSI ZE + 2];int rpos[MA XROW + 1];int mu, nu, tu;} RLSMatr ix;矩阵输入函数bool InPutT SMat r ix(T SMatr ix & T) {cout << "输入矩阵的行,列和非零元素个数:" << e ndl;cin >> T.mu >> T.nu >> T.tu;cout << "请输出非零元素的位置和值:" << e ndl;for (int k = 1;; k <= T.t u; k++)cin >> T.data[k].i >> T.da ta[k].j >> T.data[k].e;retur n t rue;}请补充完成下列矩阵转置函数、矩阵乘法函数与矩阵输出函数Bool Trans poseSMa tr ix(T SMa t r ix M, T SMat r ix & T){TSMatrix M,T; //定义预转置的矩阵InPutTSMatrix(M, 0); //输入矩阵int num[MAXROW+1];int cpot[MAXROW+1]; // 构建辅助数组int q,p,t;T.tu=M.tu; T.mu=M.nu; T.nu=M.mu;if(T.tu){for(int col=1;col<=M.nu;col++) num[col]=0;for(t=1;t<=M.tu;t++) ++num[M.data[t].j];cpot[1]=1;for(int i=2;i<=M.nu;i++) cpot[i]=cpot[i-1]+num[i-1]; // 求出每一列中非零元素在三元组中出现的位置for(p=1;p<=M.tu;p++){col=M.data[p].j; q=cpot[col];T.data[q].i=col; T.data[q].j=M.data[p].i;T.data[q].e=M.data[p].e; ++cpot[col];}}cout<<"输入矩阵的转置矩阵为"<<endl;OutPutSMatrix(T);return true;}Bool MultSMatr ix(RLSMatr ix M, RL SMatr ix N,RL SMat r ix & T){RLSMatrix M,N,Q; // 构建三个带“链接信息”的三元组表示的数组InPutTSMatrix(M,1); // 用普通三元组形式输入数组InPutTSMatrix(N,1);Count(M); Count(N);if(M.nu!=N.mu) return false;Q.mu=M.mu; Q.nu=N.nu; Q.tu=0; // Q初始化int ctemp[MAXROW+1]; // 辅助数组int arow,tp,p,brow,t,q,ccol;if(M.tu*N.tu){ // Q是非零矩阵for( arow=1;arow<=M.mu;arow++){///memset(ctemp,0,N.nu);for(int x=1;x<=N.nu;x++) // 当前行各元素累加器清零ctemp[x]=0;Q.rpos[arow]=Q.tu+1; // 当前行的首个非零元素在三元组中的位置为此行前所有非零元素+1 if(arow<M.mu) tp=M.rpos[arow+1];else tp=M.tu+1;for(p=M.rpos[arow];p<tp;p++){ // 对当前行每个非零元素进行操作brow=M.data[p].j; // 在N中找到i值也操作元素的j值相等的行if(brow<N.mu) t=N.rpos[brow+1];else t=N.tu+1;for(q=N.rpos[brow];q<t;q++){ // 对找出的行当每个非零元素进行操作ccol=N.data[q].j;ctemp[ccol] += M.data[p].e*N.data[q].e; // 将乘得到对应值放在相应的元素累加器里面}}for(ccol=1;ccol<=Q.nu;ccol++) // 对已经求出的累加器中的值压缩到Q中if(ctemp[ccol]){if(++Q.tu>MAXSIZE) return false;Q.data[Q.tu].e=ctemp[ccol];Q.data[Q.tu].i=arow;Q.data[Q.tu].j=ccol;}}OutPutSMatrix(Q);return true;}}boo l O utP utSMatrix(T SMat r ix T){// 输出矩阵,按标准格式输出int m,n,k=1;fo r(m=0;m<T.mu;m++){fo r(n=0;n<T.nu;n++){if((T.d a ta[k].i-1)==m&&(T.d a ta[k].j-1)==n){co ut.w id th(4);co ut<<T.d a ta[k++].e;}e ls e{co ut.w id th(4); co ut<<"0"; }}co ut<<e nd l;}re turn true;}}并建立ma in()函数对上述函数进行测试。

稀疏矩阵乘法 并行

稀疏矩阵乘法 并行

稀疏矩阵乘法并行全文共四篇示例,供读者参考第一篇示例:稀疏矩阵乘法是一种重要的数值计算问题,它在很多领域都有着广泛的应用,比如图像处理、机器学习等。

由于稀疏矩阵的特性是大部分元素都是0,只有少量非零元素,所以传统的矩阵乘法算法在处理稀疏矩阵时会浪费大量的计算资源。

为了解决这个问题,人们提出了一种并行计算的方法,即利用多个处理器同时计算矩阵乘法,从而提高计算效率。

在并行计算中,稀疏矩阵乘法也有着自己的特点和挑战。

稀疏矩阵的非零元素分布在整个矩阵中,处理起来比较困难。

矩阵乘法的计算量随着非零元素的增加而增加,所以需要合理地分配计算资源和任务。

稀疏矩阵乘法的并行计算需要考虑通信开销和负载均衡,以充分利用多个处理器的计算能力。

为了解决上述问题,人们提出了一些并行的稀疏矩阵乘法算法。

其中比较有代表性的是基于CSR(Compressed Sparse Row)格式的算法。

CSR格式是一种压缩存储稀疏矩阵的方法,它将矩阵分成三部分:非零元素数组、列索引数组和行偏移数组。

基于CSR格式的算法在并行计算中能够有效地减少通信开销,提高计算效率。

还有一些其他的并行稀疏矩阵乘法算法,比如基于COO (Coordinate)格式、基于Ecoo(Ellpack-Chebyshev)格式等。

这些算法都有着自己的特点和适用场景,可以根据具体的问题选择合适的算法。

在并行计算中,负载均衡是一个非常重要的问题。

负载不均衡会导致一些处理器的计算资源被浪费,影响整体的计算效率。

为了解决负载均衡问题,人们提出了一些方法,比如动态任务分配、静态任务划分、自适应任务调度等。

这些方法能够根据任务的计算量和数据分布特点,合理地分配任务,从而提高计算效率。

除了负载均衡,通信开销也是一个需要考虑的重要问题。

在并行计算中,处理器之间需要进行通信,传递计算结果和数据,这会导致一定的开销。

为了减小通信开销,人们提出了一些方法,比如数据压缩、异步通信、消息合并等。

基于mpi实现稀疏矩阵的乘法

基于mpi实现稀疏矩阵的乘法

基于MPI实现稀疏矩阵的乘法1. 引言稀疏矩阵是指大部分元素为零的矩阵,与之相对应的是稠密矩阵,其中大部分元素非零。

由于稀疏矩阵中有大量的零元素,传统的矩阵乘法算法在计算稀疏矩阵乘法时效率较低。

为了提高计算效率,我们可以利用并行计算的思想,使用MPI (Message Passing Interface)来实现稀疏矩阵的乘法。

MPI是一种用于编写并行程序的标准通信库,它定义了一组函数和语义,用于在多个进程之间进行通信和同步操作。

通过将任务划分为多个进程,每个进程负责处理一部分数据,并通过消息传递进行通信和协调,可以实现并行计算。

本文将介绍如何使用MPI实现稀疏矩阵的乘法算法。

首先我们会介绍稀疏矩阵的表示方法和存储格式,然后详细说明基于MPI的稀疏矩阵乘法算法的实现过程。

2. 稀疏矩阵的表示和存储格式稀疏矩阵有多种表示方法,常用的有三元组表示法、行压缩存储(CSR)和列压缩存储(CSC)。

三元组表示法将稀疏矩阵中非零元素的行、列和值分别存储在三个数组中。

这种表示方法简单直观,但对于大型稀疏矩阵来说,空间效率较低。

行压缩存储(CSR)是一种常用的稀疏矩阵存储格式。

在CSR格式中,我们将稀疏矩阵拆分为三个数组:值数组(values)、列指针数组(col_indices)和行偏移量数组(row_offsets)。

其中,值数组存储非零元素的值,列指针数组存储非零元素所在的列索引,行偏移量数组记录每一行第一个非零元素在值数组和列指针数组中的索引。

通过这种方式,我们可以快速访问稀疏矩阵中的非零元素。

列压缩存储(CSC)与CSR类似,只是将列指针数组变为行指针数组,将行偏移量数组变为列偏移量数组。

CSC格式适合于按列访问稀疏矩阵。

在本文中,我们将使用CSR格式来表示稀疏矩阵,并基于该格式实现稀疏矩阵的乘法算法。

3. 基于MPI的稀疏矩阵乘法算法基于MPI的稀疏矩阵乘法算法可以分为以下几个步骤:1.初始化MPI环境:在开始进行并行计算之前,需要初始化MPI环境,获取进程数量和进程编号等信息。

两个稀疏矩阵乘法

两个稀疏矩阵乘法

稀疏矩阵乘法是一种针对稀疏矩阵的乘法运算,由于稀疏矩阵中非零元素较少,因此可以利用这一特性进行优化计算,提高计算效率。

以下是两个稀疏矩阵乘法的详细介绍:稀疏矩阵的定义:稀疏矩阵是一个矩阵,其中大多数元素都是零。

在存储和计算时,为了节省空间和时间,我们可以只存储非零元素,并采用特殊的数据结构来表示这种矩阵。

稀疏矩阵乘法的原理:稀疏矩阵乘法的原理与普通矩阵乘法相似,只是由于稀疏矩阵中非零元素较少,所以在计算时可以只考虑这些非零元素,而忽略零元素。

具体来说,对于两个稀疏矩阵A和B的乘积C,我们可以按照元素的位置关系,逐个计算A中的非零元素与B中的非零元素的乘积,并将结果加到C中相应位置上。

稀疏矩阵乘法的算法步骤:
读入两个稀疏矩阵A和B。

初始化结果矩阵C为零矩阵。

遍历A中的每一个非零元素(i,j),如果A(i,j)非零,则按照元素的位置关系,计算A(i,j)与B中相应位置的元素的乘积,并将结果加到C中相应位置上。

返回结果矩阵C。

稀疏矩阵乘法的优化:由于稀疏矩阵中非零元素较少,因此在计算时可以采用一些优化策略来提高计算效率。

例如,可以采用压缩存储技术来减少存储空间的使用;可以采用并
行计算技术来提高计算速度;还可以采用一些迭代算法来加速计算过程。

总之,稀疏矩阵乘法是一种针对稀疏矩阵的特殊运算方法,由于其具有较高的计算效率和较低的空间复杂度,因此在科学计算、工程领域和数据处理等方面得到了广泛应用。

稀疏矩阵乘法

稀疏矩阵乘法

稀疏矩阵乘法给定两个 A 和 B,返回AB的结果。

您可以假设A的列数等于B的⾏数。

本参考程序来⾃九章算法,由 @Roger 提供。

题⽬解法:时间复杂度分析:假设矩阵A,B均为 n x n 的矩阵,矩阵A的稀疏系数为a,矩阵B的稀疏系数为b,a,b∈[0, 1],矩阵越稀疏,系数越⼩。

⽅法⼀:暴⼒,不考虑稀疏性Time (n^2 * (1 + n)) = O(n^2 + n^3)Space O(1)⽅法⼆:改进,仅考虑A的稀疏性Time O(n^2 * (1 + a * n) = O(n^2 + a * n^3)Space O(1)⽅法三(最优):进⼀步改进,考虑A与B的稀疏性Time O(n^2 * (1 + a * b * n)) = O(n^2 + a * b * n^3)Space O(b * n^2)⽅法四:另外⼀种思路,将矩阵A, B⾮0元素的坐标抽出,对⾮0元素进⾏运算和结果累加Time O(2 * n^2 + a * b * n^4) = O(n^2 + a * b * n^4)Space O(a * n^2 + b * n^2)解读:矩阵乘法的两种形式,假设 A(n, t) * B(t, m) = C(n, m)// 形式⼀:外层两个循环遍历C (常规解法)for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {for (int k = 0; k < t; k++) {C[i][j] += A[i][k] * B[k][j];}}}// 或者写成下⾯这样⼦for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {int sum = 0;for (int k = 0; k < t; k++) {sum += A[i][k] * B[k][j];}C[i][j] = sum;}}// 形式⼆:外层两个循环遍历Afor (int i = 0; i < n; i++) {for (int k = 0; k < t; k++) {for (int j = 0; j < m; j++) {C[i][j] += A[i][k] * B[k][j];}}}两种⽅法的区别代码上的区别(表象):调换了第⼆三层循环的顺序核⼼区别(内在):形式⼀以C为核⼼进⾏遍历,每个C[i][j]只会被计算⼀次,就是最终答案。

拓展阅读3——稀疏矩阵的相乘

拓展阅读3——稀疏矩阵的相乘

稀疏矩阵的相乘*两个矩阵相乘的经典算法是大家所熟悉的,设Q=M×N其中,M 是m 1×n 1矩阵,N 是m 2×n 2矩阵。

当n 1=m 2时有:for (i=1;i<=m1;++i )for(j=1;j<=n2;++j){Q[i][j]=0;for(k=1;k<=n1;++k)Q[i][j]+=M[i][k]×N[k][j];}此算法的时间复杂度是O(m 1×n 1×n 2)。

当矩阵变成稀疏矩阵,并且用三元组表作存储结构时,上面这个算法就不能用了,下面我们讨论稀疏矩阵三元组表的相乘算法。

已知稀疏矩阵A(m 1× n 1)和B(m 2× n 2),求乘积C(m 1× n 2)。

稀疏矩阵A 、B 、C 及它们对应的三元组表A.data 、B.data 、C.data 如图1所示。

A=⎥⎥⎥⎦⎤⎢⎢⎢⎣⎡000203008005 B=⎥⎥⎥⎥⎦⎤⎢⎢⎢⎢⎣⎡-01500720 C=⎥⎥⎥⎦⎤⎢⎢⎢⎣⎡-40150108 115148233312ij v 114523712221-v j i 42315221021811-v j i 图1 稀疏矩阵相乘图例由矩阵乘法规则知:C (i ,j )=A(i,1)×B(1,j)+A(i,2)×B(2,j)+…+A(i,n)×B(n,j)=)11(),(),(2,11n j m i j k B k i A n k ≤≤≤≤⨯∑=矩阵用二维数组表示时,在经典算法中,不论A(i,k)与B(k,j)的值是否为零,都要进行一次乘法运算,而在三元组表示的稀疏矩阵相乘时,只需从A.data 和B.data 中找到A.data 中列值与B.data 中行值相等的各对元素相乘并将结果累加即可。

为此需要在B.data 中找到矩阵B 第k 行中所有非零元素,跟矩阵转置改进算法相同的原理,我们引入num 和rpot 两个向量。

稀疏矩阵乘法的时间复杂度

稀疏矩阵乘法的时间复杂度

稀疏矩阵乘法的时间复杂度稀疏矩阵乘法的时间复杂度,这话一说出来,可能有些朋友会皱眉头,觉得这又是个高深的数学问题。

但实际上,咱们今天就来聊聊这个看似复杂的事情,轻松点、幽默点,让大家都能明白。

咱们得搞清楚什么是稀疏矩阵。

简单来说,就是矩阵里有很多的零。

想象一下,你在看一张桌子,上面摆着很多碗,只有几个碗里有东西,其他的都是空的。

这样的矩阵就叫稀疏矩阵。

其实在很多实际应用中,稀疏矩阵的出现是非常常见的,特别是在图像处理、机器学习和数据科学中,真是频繁得让人惊叹。

咱们就要说说稀疏矩阵乘法。

说白了,就是把两个稀疏矩阵相乘。

这个过程其实可以看作是把两个“空碗”组合成一个新碗,看看能不能得到一些“有料”的东西。

由于很多位置上都是零,所以在计算的时候,咱们可以聪明点,干脆不去计算那些零的位置,省得浪费时间和精力,简直就是把“事半功倍”发挥到了极致。

这一招可不是什么秘笈,很多程序员和数学家都用得特别溜。

不过,时间复杂度是个什么鬼呢?简单来说,它就是描述算法运行时间的一个指标。

想象一下,咱们去市场买菜,时间复杂度就像是你去菜市场的路程,如果你走的路特别绕,那肯定花的时间就长;如果你选了一条最近的路,当然就能更快到达。

对于稀疏矩阵乘法来说,时间复杂度跟矩阵的稀疏程度和大小有很大关系。

一般来说,如果你有一个稀疏矩阵A和B,那么它们相乘的复杂度大致是O(NzA + NzB),Nz代表非零元素的数量。

别被这些符号吓到,通俗点说,就是看你非零元素有多少,越多计算的时间就越长。

再说个形象的例子。

想象你在一个派对上,跟一群朋友聊得火热,结果你发现只有几个人是你特别想交流的。

如果你一个一个去找他们,肯定费时费力。

但是如果你能知道他们在哪,直接冲过去,效率简直翻倍。

稀疏矩阵乘法就像这样,只找非零的元素,省去那些冗余的时间,简直太聪明了。

再来聊聊实际应用。

稀疏矩阵在机器学习中可是大显身手。

比如在推荐系统里,用户和物品的评分矩阵常常都是稀疏的,绝大多数用户根本没给某些物品打过分。

用三元组表示稀疏矩阵的乘法

用三元组表示稀疏矩阵的乘法

该结点除了( row , col , value )以外,还要有以下两个链域:
right: down: 用于链接同一列中的下一个非零元素。
row Down
col
Value right
第十二讲
1 1 3
1 4 5
2 2 -1
3 1 3
图5.23 十字链表的结构
第十二讲
十字链表的结构类型说明如下:
typedef struct OLNode
第十二讲
用三元组表实现稀疏矩阵的乘法运算
第十二讲
两个矩阵相乘也是矩阵的一种常用的运算。设矩阵 M 是
m1×n1 矩阵, N 是 m2×n2 矩阵;若可以相乘,则必须满足矩
阵 M 的列数 n1 与矩阵 N 的行数 m2 相等,才能得到结果矩阵 Q=M×N(一个m1×n2的矩阵)。
数学中矩阵Q中的元素的计算方法如下:
矩阵不仅节约了空间,而且使得矩阵某些运算的运算时间比经
典算法还少。但是在进行矩阵加法、减法和乘法等运算时,有 时矩阵中的非零元素的位置和个数会发生很大的变化。如
A=A+B, 将矩阵B加到矩阵A上,此时若还用三元组表表示法,
势必会为了保持三元组表“以行序为主序”而大量移动元素。
第十二讲
在十字链表中,矩阵的每一个非零元素用一个结点表示,
0 1 N 2 0
2 0 4 0
0 Q 1 0
6 0 4
图5.17 Q=M×N
第十二讲
图5.18 矩阵M、N、Q的三元组表
第十二讲
经典算法中,不论 M [ i ][ k ]、 N [ k ][ j ]是否为零,
for(k=1; k<=n1; k++)
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

#include<stdio.h>
#include<stdlib.h>
#define OK 1
#define ERROR 0
#define MAXSIZE 25 //最多非0元素的个数
#define MAXR 5 //rpos所能处理的最大行数
#define MAXC 5 //系数矩阵相乘时,保留临时列结果的数组temp[MAXC] typedef struct NODE{ //定义稀疏矩阵结点
int i;
int j;
int data;
} Node;
typedef struct MATRIX{ //定义稀疏矩阵(可以快速访问)
int mu, nu, tu;
Node matrix[MAXSIZE+1];
int rpos[MAXR+1];
} Matrix;
int CreatSMatrix( Matrix* M ); //创建一个矩阵(由用户输入原始矩阵,转化为稀疏矩阵方式储存)
int Print( Matrix M ); //打印一个稀疏矩阵
int Mul_SMatrix( Matrix M, Matrix N, Matrix *Q); //两个稀疏矩阵相乘
main(){
printf("计科四班刘辉学号:41012169");
printf("\n");
printf("稀疏矩阵相乘");
printf("\n\n");
Matrix A1, A2, A3; //定义矩阵
CreatSMatrix( &A1 );
CreatSMatrix( &A2 );
if( A1.nu==A2.mu ){ //判断能否相乘
Mul_SMatrix( A1, A2, &A3 );
printf("两矩阵相乘得:\n"); Print(A3);
}
system("pause");
}
//稀疏矩阵相乘
int Mul_SMatrix( Matrix M, Matrix N, Matrix *Q)
{
int i,Mj;
int arow, Mlim, Nlim, Mcol, Nrow;
int ctemp[MAXC];
Q->tu=0;
//初始化Q
Q->mu=M.mu; Q->nu=M.nu;
if(M.tu*N.tu!=0){
//非零矩阵
for(arow=1; arow<=M.mu; arow++){
for(i=1; i<=M.nu; i++)//清空累加器
ctemp[i]=0;
Q->rpos[arow]=Q->tu+1; //给Q->rpos[]数组赋值
Mlim = arow<M.mu ? M.rpos[arow+1] : M.tu+1;
//M中第arow行在结点数组中的范围
for( Mcol=M.rpos[arow]; Mcol<Mlim; Mcol++ ){
//遍历M中第arow行的每一个j
Mj=M.matrix[Mcol].j;
Nlim = Mj<N.mu ? N.rpos[Mj+1] : N.tu+1;//在N中找到行号i等于M中的列号j的位置
for( Nrow=N.rpos[Mj]; Nrow<Nlim; Nrow++ )//乘积元素在Q中的列号
ctemp[N.matrix[Nrow].j] += M.matrix[Mcol].data * N.matrix[Nrow].data;
}
for(i=1; i<=Q->nu; i++){//列号对应元素不为零,赋值
if( ctemp[i] ){
if( ++Q->tu > MAXSIZE )
return 0;
Q->matrix[Q->tu].i = arow;
Q->matrix[Q->tu].j = i;
Q->matrix[Q->tu].data = ctemp[i];
}
}
}
}
return 1;
}
//构建稀疏矩阵
int CreatSMatrix( Matrix* M ){
int temp, i,j;
printf("输入矩阵的行列数:");
scanf("%d,%d", &M->mu,&M->nu);
M->tu=0;
printf("按行序输入矩阵:\n");
for( i=1; i<=M->mu; i++){
M->rpos[i]=M->tu+1; //每计算完一行,给rpos[]赋值
for( j=1; j<=M->nu; j++){
scanf("%d",&temp );
if( temp ){ //非0值保存
M->matrix[M->tu+1].i= i;
M->matrix[M->tu+1].j= j;
M->matrix[M->tu+1].data=temp;
M->tu++;
}
}
}
return OK;
}
//打印稀疏矩阵
int Print( Matrix M){
int i;
if(M.tu==0){
printf("空矩阵\n\n");
return ERROR;
}
printf("i\tj\tdata\n");
for( i=1; i<=M.tu; i++ )
printf("%d\t%d\t%d\n", M.matrix[i].i,M.matrix[i].j,M.matrix[i].data);
return OK;
}
运行结果:。

相关文档
最新文档