稀疏矩阵的三元组顺序表存储及矩阵相乘算法小结

稀疏矩阵的三元组顺序表存储及矩阵相乘算法小结

巧若拙(欢迎转载,但请注明出处:http://blog.csdn.net/qiaoruozhuo

一:稀疏矩阵的三元组顺序表数据结构

typedef int ElemType;

typedef struct

{

intx, y;  //该非零元素的行下标和列下标

ElemTypee; //该非零元素的值

} Triple;

typedef struct

{

Tripledata[MAXSIZE]; //非零元素三元组顺序表

intmu, nu, tu;   //矩阵的行数,列数和非零元素的个数

} TSMatrix;

二:三元组顺序表实现矩阵转置

显然,一个稀疏矩阵的转置矩阵仍然是稀疏矩阵。假设a和b是TSMatrix型的变量,分别表示矩阵M和T。那么,如何由a得到b呢?

从分析a和b之间的差异可见只要做到:1。将矩阵的行列值互换;2。将每个三元组中的i和j互换;3。重排三元组之间的次序便可以实现矩阵的转置。

前两条是容易做到的,关键是如何实现第三条,即如何使b.data中的三元组是以T的行序(M的列序)为主序依次排列的。

可以有两种处理方法:

1, 按照b.data中三元组的次序依次在a.data中找到相应的三元组进行转置。即按照M的列序来进行转置。代码如下:

TSMatrix TransposeSMatrix(TSMatrix M)//三元组顺序表 转置矩阵

{

intk, i, col;

TSMatrixT;

T.mu= M.nu;

T.nu= M.mu;

T.tu= M.tu;

if(T.tu > 0)

{

k= 0;

for(col=1; col<=M.nu; col++) //按照T的行序(M的列序)为主序依次排列

for(i=0; i<M.tu; i++)//扫描M的所有元素

if(M.data[i].y == col)

{

T.data[k].x= M.data[i].y;

T.data[k].y= M.data[i].x;

T.data[k++].e= M.data[i].e;

}

}

returnT;

}

2,按照a.data中三元组的次序进行转置,并将转置后的三元组置入b中恰当的位置。

即预先确定M中每一列(即T中的每一行)的第一个非零元素在b.data中应有的位置。在此,需要附设num和cpot两个数组,num[col-1]表示矩阵M中第col列中非零元素的个数,cpot[col-1]指示M中第col列中第一个非零元素在b.data中的位置,显然有:

cpot[0] = 0;

cpot[col] = cpot[col-1] + num[col-1]  0<col<a.nu

此算法的时间复杂度为O(mu+tu),在M的非零元素的个数tu和mu*nu等数量级时,其时间复杂度为O(mu.nu),和使用二维数组存储进行转置矩阵运算时时间复杂度相同,故称为快速转置。代码如下:

TSMatrix FastTransposeSMatrix(TSMatrixM)  //三元组顺序表快速转置矩阵

{

TSMatrixT;

intk, i, col;

intnum[N] = {0};

intcpot[N] = {0};

T.mu= M.nu;

T.nu= M.mu;

T.tu= M.tu;

if(T.tu > 0)

{

for(i=0; i<M.tu; i++)//扫描M的所有元素

num[M.data[i].y-1]++;//确定矩阵M每一列中非零元素的个数

cpot[0]= 0;

for(col=1; col<M.nu; col++)

cpot[col]= cpot[col-1] + num[col-1];// 确定矩阵M第col列中第一个非零元素在b.data中的位置

for(i=0; i<M.tu; i++)//扫描M的所有元素

{

col= M.data[i].y - 1; //标出该元素所在的列

k= cpot[col];   //k即矩阵M第col列(即T中的第col行)中第一个非零元素在b.data中的位置

T.data[k].x= M.data[i].y;

T.data[k].y= M.data[i].x;

T.data[k].e= M.data[i].e;

cpot[col]++;//矩阵M第col列中第一个非零元素在b.data中的位置向前移动一位

}

}

returnT;

}

三:三元组顺序表实现矩阵相乘

压缩存储的矩阵与用二维数组存储的矩阵在进行乘法运算时最大的不同是,在经典(二维数组存储)算法中,不论M(i,k)和N(k,j)的值是否为零,都要进行一次乘法计算,这样造成很大的浪费。而压缩存储则只需在M.data和N.data中找到相应的元素相乘即可。

这里介绍三种算法。

第一种,通过给定的行号i和列号j找出原矩阵的对应的元素,设计一个函数Value(),当在三元组顺序表中找到该元素时,返回其元素值,否则说明该位置元素值为0,返回0。然后利用该函数计算出C的行号i和列号j处元素的值,若该值不为0,则存入C,否则不存入。代码如下:

int Value(TSMatrix M, int i, int j) //计算出矩阵M的i行j列处元素的值

{

intk = 0;

while(k < M.tu && M.data[k].x <= i) //因为是按行序排列,故不必扫描行号比i大的元素

{

if(M.data[k].x == i && M.data[k].y == j)

returnM.data[k].e;

k++;

}

return0;

}

TSMatrix MultSMatrix(TSMatrix A, TSMatrixB) //三元组顺序表低效矩阵乘法

{

TSMatrixC;

inti, j, k, l, p, s;

C.mu= A.mu;

C.nu= B.nu;

C.tu= 0;

if(A.tu * B.tu != 0)

{

p= 0;

for(i=1; i<=A.mu; i++)

{

for(j=1; j<=B.nu; j++)

{

s= 0;

for(k=1; k<=A.nu; k++)

s+= Value(A, i, k) * Value(B, k, j);

if(s != 0)

{

C.data[p].x= i;

C.data[p].y= j;

C.data[p++].e= s;

}

}

}

C.tu= p;

}

returnC;

}

这种算法的存储空间虽然很少,但时间复杂度为O(A.mu*A.nu*B.nu*(A.tu+B.tu)),比经典的算法时间复杂度还高,因此是一种用时间换空间的方法。

如果我们预先确定矩阵的每一行的第一个非零元素在三元组顺序表中的位置,则可以得到改进的算法。

基本操作是对于A中每个元素A.data[p],找到N中所有满足条件A.data[p].y==B.data[q].x的元素B.data[q],求得A.data[p].e和B.data[q].e的乘积,当然这个乘积的值只是乘积矩阵C[i][j]中的一部分。

为了便于操作,我们可以对每个元素设置一个累计乘积值的变量,使其初值为0,然后扫描A,求得相应元素的乘积值并累积到相应的累计乘积值的变量中。

由于C中元素的行号和A中元素的行号一致,又都是以行序为主序排列的,因此可以对C进行逐行处理。代码如下:

void RPos(TSMatrix M, int rpos[])//确定矩阵的每一行的第一个非零元素在三元组顺序表中的位置

{

intnum[N] = {0};

inti, row;

for(i=0; i<M.tu; i++)//扫描M的所有元素

num[M.data[i].x-1]++;//确定矩阵M每一行中非零元素的个数

rpos[0]= 0;

for(row=1; row<M.mu; row++)

rpos[row]= rpos[row-1] + num[row-1];// 确定矩阵M第row行中第一个非零元素在M.data中的位置

}

TSMatrix FastMultSMatrix_1(TSMatrix A,TSMatrix B)//三元组顺序表快速矩阵乘法之一

{

TSMatrixC;

intArpos[N] = {0}, Brpos[N] = {0};//分别存储矩阵A,B的每一行的第一个非零元素在三元组中的位置

intctemp[N] = {0};//存储正在处理的该行中每一列的乘积值,是一个累积的和值,作为矩阵C在该位置处元素的值

intarow, brow, ccol;

inti, p, q;

intta, tb;

C.mu= A.mu;

C.nu= B.nu;

C.tu= 0;

if(A.tu * B.tu != 0)//若C是非零矩阵

{

RPos(A,Arpos); //确定矩阵A的每一行的第一个非零元素在三元组顺序表中的位置

RPos(B,Brpos); //确定矩阵B的每一行的第一个非零元素在三元组顺序表中的位置

for(arow=1; arow<=A.mu; arow++)//对A进行逐行处理 ,即对C进行逐行处理

{

for(i=0; i<B.nu; i++)//当前各元素累加器清零

ctemp[i]= 0;

if(arow < A.mu) //处理A中第arow行的每一个非零元素,ta指示下一行第一个非零元素的位置

ta= Arpos[arow];

else   //最后一行的下一行第一个非零元素的位置 当然是  A.tu

ta= A.tu;

for(p=Arpos[arow-1]; p<ta; p++)               {

brow= A.data[p].y; //标出该元素的列号,在B中找到与它对应的行号

if(brow < B.mu)

tb= Brpos[brow];

else

tb= B.tu;

for(q=Brpos[brow-1]; q<tb; q++)

{

ccol= B.data[q].y - 1;

ctemp[ccol]+= A.data[p].e * B.data[q].e;

}

}

for(ccol=0; ccol<C.nu; ccol++)//得到C的第arow中每一列(个)元素的值

{

if(ctemp[ccol] != 0)//压缩存储该行非零元

{

if(C.tu == MAXSIZE)

{

printf("三元组溢出!\n" );

exit(1);

}

C.data[C.tu].x= arow; //C的行数等于A的行数

C.data[C.tu].y=ccol + 1; //C的列数等于B的列数

C.data[C.tu++].e= ctemp[ccol]; //C的元素值等于A的行数ctemp[ccol]的累积值

}

}

}

}

returnC;

}

分析上述算法的时间复杂度有如下结果:确定矩阵的每一行的第一个非零元素在三元组顺序表中的位置的时间复杂度为O(A.tu+A.mu+B.tu+B.mu+),累加器ctemp初始化的时间复杂度为O(A.mu*B.nu),C的所有非零元素的时间复杂度为O(A.tu*B.tu/B.mu),进行压缩存储的时间复杂度为O(A.mu*B.tu),因此总的时间复杂度为O(A.mu*B.nu + A.tu*B.tu/B.mu)。当矩阵为稀疏矩阵时,这种算法的时间复杂度接近O(A.mu*B.nu),比经典算法要快。

还有一种快速矩阵乘法,它是先将矩阵B转置,这样矩阵A与B的列数就相同了,矩阵B的行数即矩阵C的列数。此种算法不需要设置数组ctemp[N],只需直接计算该行对应列的元素乘积的总和即可得到矩阵C的值。此算法时间复杂度为O(A.mu*B.nu *MAX(ta,tb)),其中MAX(ta,tb)表示A矩阵和B的转置矩阵中每行非零元素个数的最大值。

算法通俗易懂,代码也很简洁。代码如下:

TSMatrix FastMultSMatrix_2(TSMatrix A,TSMatrix B)//三元组顺序表快速矩阵乘法之二

{

TSMatrixC;

intArpos[N] = {0}, Brpos[N] = {0};//分别存储矩阵A,B的每一行的第一个非零元素在三元组中的位置

intarow, brow, ccol;

inti, p, q, ta, tb;

C.mu= A.mu;

C.nu= B.nu;

C.tu= 0;

if(A.tu * B.tu != 0)//若C是非零矩阵

{

B= FastTransposeSMatrix(B); //求矩阵B的转置矩阵

RPos(A,Arpos); //确定矩阵A的每一行的第一个非零元素在三元组顺序表中的位置

RPos(B,Brpos); //确定矩阵B的每一行的第一个非零元素在三元组顺序表中的位置

for(arow=1; arow<=A.mu; arow++)//对A进行逐行处理 ,即对C进行逐行处理

{

ta= (arow < A.mu) ? Arpos[arow] : A.tu;

for(brow=1; brow<=B.mu; brow++)

{

C.data[C.tu].e= 0;

p= Arpos[arow-1];

tb= (brow < B.mu) ? Brpos[brow] : B.tu;

q= Brpos[brow-1];

while(p < ta && q < tb)

{

if(A.data[p].y < B.data[q].y)

p++;

elseif (A.data[p].y > B.data[q].y)

q++;

else

C.data[C.tu].e+= A.data[p++].e * B.data[q++].e; //C的元素值等于该行对应列的元素乘积的总和

}

if(C.data[C.tu].e != 0)

{

C.data[C.tu].x= arow;

C.data[C.tu++].y= brow;

}

}

}

}

returnC;

}

时间: 2024-10-20 23:37:52

稀疏矩阵的三元组顺序表存储及矩阵相乘算法小结的相关文章

稀疏矩阵的三元组顺序表存储结构表示及实现

#define MAX_SIZE 100 struct Triple { int i, j;//行下标,列下标 ElemType e;//非零元素值 }; struct TSMatrix { Triple data[MAX_SIZE + 1];//非零元三元组表,data[0]未用 int mu, nu, tu;//矩阵的行数,列数,非零元个数 }; int comp(int c1, int c2){//比较这个数c1和c2的大小关系 if (c1 < c2) return -1; if (c1

稀疏矩阵的三元组顺序表的C语言实现

对于没有排序功能的集合来说,都可以使用java.util.Collections.sort()方法进行排序,它除了集合对象以外,还需要提供一个比较器.如果列表中的元素全部都是相同的类型,并且这个类实现了Comparable接口,就可以简单的调用Collections.sort()方法,如果这个类没有实现comparable接口,那么可以创建一个比较器传递一个Comparator实例作为Sort()的第二个参数进行排序,另外,如果不想使用默认的分类顺序进行排序,同样也可以传递一个Comparato

用C语言实现顺序表的插入和删除算法

什么是线性表? 线性表是n个数据元素的有限序列.根据线性表的显现方式,线性表又分为顺序表(数据元素在内存中的存储空间是连续的)和链表(数据元素在内存中的存储空间是不连续的). 线性表如何用C语言实现?线性表可以进行哪些操作? 在C语言中,线性表通过结构体的方式来实现.结构体中定义了线性表的存储空间地址,当前长度,和当前分配的存储容量.操作包含在指定位置插入某一元素.删除指定元素.查找指定的元素等.在这里重点介绍插入和删除算法. 下面就是关于这一部分内容的陈述. 线性表的C语言实现 需要先定义好的

顺序表之就地逆置算法

1 #include<stdio.h> 2 #define MAX 10 3 typedef int ElementType; 4 int length=0; 5 int value; 6 typedef struct { 7 ElementType i; 8 int length; 9 ElementType data[MAX]; 10 }Sorder; 11 int main(){ 12 Sorder L; 13 //往顺序表中塞入数据 14 for(int i=0;i<MAX;i+

C语言 &#183; 矩阵相乘 &#183; 算法提高

算法提高 矩阵相乘 时间限制:1.0s   内存限制:256.0MB 问题描述 小明最近在为线性代数而头疼,线性代数确实很抽象(也很无聊),可惜他的老师正在讲这矩阵乘法这一段内容. 当然,小明上课打瞌睡也没问题,但线性代数的习题可是很可怕的. 小明希望你来帮他完成这个任务. 现在给你一个ai行aj列的矩阵和一个bi行bj列的矩阵, 要你求出他们相乘的积(当然也是矩阵). (输入数据保证aj=bi,不需要判断) 输入格式 输入文件共有ai+bi+2行,并且输入的所有数为整数(long long范围

稀疏矩阵的三元组行逻辑链接的顺序表存储结构表示及实现

#define MAX_SIZE 100 #define MAX_RC 20 struct Triple { int i, j;//行下标,列下标 ElemType e;//非零元素值 }; struct RLSMatrix { Triple data[MAX_SIZE + 1];//非零元三元组表,data[0]未用 int rpos[MAX_RC + 1];//各行第1个非零元素的位置表 int mu, nu, tu;//矩阵的行数,列数,非零元个数 }; int comp(int c1,

三元组顺序表表示的稀疏矩阵的转置和加法运算的实现----《数据结构》

#include<stdio.h> #include<malloc.h> #include<stdlib.h> #include<string.h> #define MAXSIZE 225 #define N 9 typedef struct{ int i,j; int e; }Triple; typedef struct{ Triple data[MAXSIZE+1]; int mu,nu,tu; }TSMatrix; int CreatSMatrix(T

矩阵压缩存储之三元组顺序表

形态: 实现: /***************************************** 稀疏矩阵的三元组顺序表存储表示 by Rowandjj 2014/5/3 ******************************************/ #include<IOSTREAM> using namespace std; #define MAXSIZE 12500//非零元个数的最大值 typedef int ElemType; typedef struct _DATA_

javascript实现数据结构: 稀疏矩阵之三元组线性表表示

稀疏矩阵(Sparse Matrix):对于稀疏矩阵,目前还没有一个确切的定义.设矩阵A是一个n*m的矩阵中有s个非零元素,设  δ=s/(n*m),称δ为稀疏因子, 如果某一矩阵的稀疏因子δ满足δ≦0.05时称为稀疏矩阵, 稀疏矩阵的压缩存储 对于稀疏矩阵,采用压缩存储方法时,只存储非0元素.必须存储非0元素的行下标值.列下标值.元素值.因此,一个三元组(i, j, aij)唯一确定稀疏矩阵的一个非零元素. 上图的稀疏矩阵A的三元组线性表为: ( (1,2,12), (1,3,9), (3,1