数据结构稀疏矩阵运算器课程设计报告书.docx

上传人:b****2 文档编号:12647267 上传时间:2023-04-21 格式:DOCX 页数:23 大小:246.36KB
下载 相关 举报
数据结构稀疏矩阵运算器课程设计报告书.docx_第1页
第1页 / 共23页
数据结构稀疏矩阵运算器课程设计报告书.docx_第2页
第2页 / 共23页
数据结构稀疏矩阵运算器课程设计报告书.docx_第3页
第3页 / 共23页
数据结构稀疏矩阵运算器课程设计报告书.docx_第4页
第4页 / 共23页
数据结构稀疏矩阵运算器课程设计报告书.docx_第5页
第5页 / 共23页
点击查看更多>>
下载资源
资源描述

数据结构稀疏矩阵运算器课程设计报告书.docx

《数据结构稀疏矩阵运算器课程设计报告书.docx》由会员分享,可在线阅读,更多相关《数据结构稀疏矩阵运算器课程设计报告书.docx(23页珍藏版)》请在冰豆网上搜索。

数据结构稀疏矩阵运算器课程设计报告书.docx

数据结构稀疏矩阵运算器课程设计报告书

 

科技大学

数据结构课程设计说明书

 

题目:

稀疏矩阵运算器设计

学生:

学号:

专业:

计算机科学与技术

班级:

计09-1班

指导教师:

月峰

 

2011年6月24日

 

稀疏矩阵运算器设计

摘要

摘要:

设计一稀疏矩阵运算器。

实现转置,相加,相乘的功能。

用“带行逻辑信息”的三元组顺序表表示稀疏矩阵,实现两个矩阵相转置、相加和相乘的运算,采用分级的设计方法,分别设计出转置、加、乘运算器的子程序,相加运算时只要依次扫描两矩阵的行号和列号,若相等则相加后存入结果矩阵,不等时则存入较小的。

相减运算与相加运算相同,同样比较两矩阵的行号和列号,只是不等时,若第一个小,则存入第一个的元素,若第二个小,则存入其相反数。

相乘运算要先判断两矩阵能否相乘。

通过给顶的行号和列号找出原矩阵对应的元素值。

当在三元组表示中找到时返回其元素值,找不到时,说明该位置为0,因此返回0。

然后利用该函数计算出C的行号i和列号j处的元素值,若该值不为0,则存入矩阵,否则不存入。

通过实验表明本程序能够进行稀疏矩阵的相加,相减,相乘运算。

具备矩阵的加、减、乘功能。

 

关键词:

转置运算器;相加运算器;相乘运算器

稀疏矩阵运算器设计I

摘要II

第一章需求分析1

第二章概要设计2

第三章设计步骤6

3.1函数说明6

3.2设计步骤7

第四章设计理论分析方法20

4.1算法一:

矩阵转置20

4.2算法二:

矩阵加法20

4.3算法三:

矩阵乘法21

第五章程序调试23

第六章心得体会25

参考文献26

 

第一章需求分析

1.稀疏矩阵是指那些多数元素为零的矩阵。

利用“稀疏”特点进行存储和计算可以大大节省存储空间,提高计算效率。

实现一个能进行稀疏矩阵基本运算的运算器。

2.以“带行逻辑信息”的三元组顺序表表示稀疏矩阵,实现矩阵转置,求逆,实现两个矩阵相加、相减和相乘的运算。

稀疏矩阵的输入形式采用三元组表示,而运算结果的矩阵则以通常的阵列形式列出。

3.演示程序以用户和计算机的对话方式执行,数组的建立方式为边输入边建立。

4.由题目要求可知:

首先应输入矩阵的行数和列数,并判别给出的两个矩阵的行、列数对于所要求作的运算是否相匹配。

5.程序可以对三元组的输入顺序不加以限制;根据对矩阵的行列,三元组作直接插入排序,从而进行运算时,不会产生错误。

6.在用三元组表示稀疏矩阵时,相加、乘积和相减所得结果矩阵应该另生成;矩阵求逆时,为了算法方便,使用二维数组存放。

7.程序在VC6.0环境下设计。

程序执行的命令为:

1.稀疏矩阵转置;2.稀疏矩阵加法;;3.稀疏矩阵乘法;4.退出

的工作。

 

第二章概要设计

1.抽象数据类型稀疏矩阵的定义如下:

ADTSparseMatrix{

数据对象:

D={aij|i=1,2,…,m;j=1,2,…,n;

aij∈ElemSet,m和n分别为矩阵的行数和列数}

数据关系:

R={Row,Col}

Row={﹤ai,j,ai,j+1﹥|1≤i≤m,1≤j≤n-1}

Col={﹤ai,j,ai+1,j﹥|1≤i≤m-1,1≤j≤n}

基本操作:

create(TSMatrix&TM)

操作结果:

创建稀疏矩阵矩阵TM

LocateELem(TSMatrixM,inti,intj,inte)

初始条件:

稀疏矩阵M存在

操作结果:

稀疏矩阵中是否存在非零元素A[i][j],若存在返回e

disp(TSMatrixTM)

初始条件:

稀疏矩阵TM存在

操作结果:

通常形式输出稀疏矩阵

InsertSortMatrix(TSMatrix&TM)

初始条件:

稀疏矩阵TM存在

操作结果:

根据对矩阵的行列,三元组TM作直接插入排序

TransposeSMatrix(TSMatrixM,TSMatrix&T)

初始条件:

稀疏矩阵M和T存在

操作结果:

求稀疏矩阵M转置的稀疏矩阵T

AddTSM(TSMatrixA,TSMatrixB,TSMatrix&C)

初始条件:

稀疏矩阵A,B和C存在

操作结果:

稀疏矩阵的加法运算:

C=A+B

SubTSM(TSMatrixA,TSMatrixB,TSMatrix&C)

初始条件:

稀疏矩阵A,B和C存在

操作结果:

稀疏矩阵的减法运算:

C=A-B

MultSMatrix(TSMatrixA,TSMatrixB,TSMatrix&C)

初始条件:

稀疏矩阵A,B和C存在

操作结果:

稀疏矩阵的乘法运算:

C=A×B

NiMatrix(TSMatrix&TM)

初始条件:

稀疏矩阵TM存在

操作结果:

稀疏矩阵求逆

}ADTSparseMatrix;

2.主程序:

voidmain()

{初始化;

do{

接受命令;

选择处理命令;

}while(命令!

=“退出”)

}

3.本程序有四个模块,调用关系如下:

主程序模块

 

 

图2.1

4本程序的流程图

 

开始

 

 

 

图2.2

第3章设计步骤

3.1函数说明

稀疏矩阵的三元组顺序表存储表示:

typedefstruct//定义三元组的元素

{

inti,j;

intv;

}Triple;

classtripletable

{//设计类来描述稀疏矩阵及其操作

public:

aaa*pdata;

tripledata[maxsize];

intrpos[maxsize];tripletable();

~tripletable();

voidconvert();

voidadd();

voidmulti();

private:

intm;

intn;

intt;

inta;

};

主要函数:

tripletable();

~tripletable();

voidconvert();

voidadd();

voidmulti();

voidmain();

3.2设计步骤:

设计一个矩阵类实现矩阵的运算:

classtripletable(包含矩阵的各种运算函数)。

输入矩阵(以三元组形式输入非零元)

{

intk;

tripletableA,B;

cout<<"输入稀疏矩阵A的行数,列数和非零元个数:

";

cin>>A.m>>A.n>>A.t;

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

{

printf("输入第%d个非0元素的行数,列数和值:

",k);

cin>>A.data[k].i>>A.data[k].j>>A.data[k].v;

}

输出矩阵:

intc[100][100]={0};

for(k=1;k<=B.t;k++)

{

c[B.data[k].i][B.data[k].j]=B.data[k].v;

}

cout<<"转置(加法,乘法)结果为:

"<

for(k=1;k<=B.n;k++)

{

for(intl=1;l<=B.m;l++)

cout<

cout<

}

}

转置矩阵:

voidtripletable:

:

convert()//矩阵的转置

{

intk;

tripletableA,B;

cout<<"输入稀疏矩阵A的行数,列数和非零元个数:

";

cin>>A.m>>A.n>>A.t;

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

{

printf("输入第%d个非0元素的行数,列数和值:

",k);

cin>>A.data[k].i>>A.data[k].j>>A.data[k].v;

}

B.m=A.m;B.n=A.n;B.t=A.t;

if(B.t)

{

intq=1,col;

for(col=1;col<=A.n;++col)

for(intp=1;p<=A.t;++p)

if(A.data[p].j==col)

{

B.data[q].i=A.data[p].j;

B.data[q].j=A.data[p].i;

B.data[q].v=A.data[p].v;

++q;

}

}

intshuru[100][100]={0};

for(k=1;k<=B.t;k++)

{

shuru[B.data[k].j][B.data[k].i]=B.data[k].v;

}

cout<<"输入为:

"<

for(k=1;k<=B.m;k++)

{

for(intl=1;l<=B.n;l++)

cout<

cout<

}

intresult[100][100]={0};

for(k=1;k<=B.t;k++)

{

result[B.data[k].i][B.data[k].j]=B.data[k].v;

}

cout<<"结果为:

"<

for(k=1;k<=B.n;k++)

{

for(intl=1;l<=B.m;l++)

cout<

cout<

}

}

以上主要设计思想:

通过三元组输入一个矩阵A,为了找到A的每一列中所有非零元素,需要对其三元组表A.data从第一行起整个扫描一遍,由于A.data是以A的行序为主序来存放每个非零元的,由此得到的恰是B.data的应有的顺序。

加法矩阵:

voidtripletable:

:

add()//矩阵的加法

{

intk;

tripletableA,B;

cout<<"输入稀疏矩阵A的行数,列数和非零元个数:

";

cin>>A.m>>A.n>>A.t;

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

{

printf("输入第%d个非0元素的行数,列数和值:

",k);

cin>>A.data[k].i>>A.data[k].j>>A.data[k].v;

}

cout<<"输入稀疏矩阵B的行数,列数和非零元个数:

";

cin>>B.m>>B.n>>B.t;

for(k=1;k<=B.t;k++)

{

printf("输入第%d个非0元素的行数,列数和值:

",k);

cin>>B.data[k].i>>B.data[k].j>>B.data[k].v;

}

if(A.m!

=B.m||A.n!

=B.n)

{

cout<<"输入错误:

A与B的行数或列数不相同,请重新输入"<

return;

}

inta[100][100]={0};

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

{

a[A.data[k].i][A.data[k].j]=A.data[k].v;

}

cout<<"A输入为:

"<

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

{

for(intl=1;l<=A.n;l++)

cout<

cout<

}

intb[100][100]={0};

for(k=1;k<=B.t;k++)

{

b[B.data[k].i][B.data[k].j]=B.data[k].v;

}

cout<<"B输入为:

"<

for(k=1;k<=B.m;k++)

{

for(intl=1;l<=B.n;l++)

cout<

cout<

}

intc[100][100]={0};

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

{

for(intl=1;l<=A.n;l++)

{

c[k][l]=a[k][l]+b[k][l];

}

}

cout<<"加法结果C为:

"<

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

{

for(intl=1;l<=A.n;l++)

cout<

cout<

}

}

以上主要设计思想:

此功能由函数add()实现,当用户选择该功能时系统即提示用户初始化要进行加法的两个矩阵的信息。

然后检测这两个矩阵是否符合矩阵相加的规则,如果符合,进行加法。

否则重新输入第二个矩阵来保证两个矩阵可以相加。

最后输出结果。

乘法矩阵:

voidtripletable:

:

multi()//矩阵的乘法

{

intk;

tripletableA,B,C;

cout<<"输入稀疏矩阵A的行数,列数和非零元个数:

";

cin>>A.m>>A.n>>A.t;

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

{

printf("输入第%d个非0元素的行数,列数和值:

",k);

cin>>A.data[k].i>>A.data[k].j>>A.data[k].v;

}

introw=1;

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

{

while(row<=A.data[k].i)

{

A.rpos[row++]=k;

}

}

while(row<=A.m)A.rpos[row++]=A.t+1;

cout<<"输入稀疏矩阵B的行数,列数和非零元个数:

";

cin>>B.m>>B.n>>B.t;

for(k=1;k<=B.t;k++)

{

printf("输入第%d个非0元素的行数,列数和值:

",k);

cin>>B.data[k].i>>B.data[k].j>>B.data[k].v;

}

row=1;

for(k=1;k<=B.t;k++)

{

while(row<=B.data[k].i)

{

B.rpos[row++]=k;

}

}

while(row<=B.m)B.rpos[row++]=B.t+1;

if(A.n!

=B.m)

{

cout<<"输入错误:

A的列数不等于B的行数,请重新输入"<

return;

}

C.m=A.m;C.n=B.n;C.t=0;

intarow,p,q,ccol,t,tp;

if(A.t*B.t!

=0)

{

for(arow=1;arow<=A.m;++arow)

{

intctemp[maxsize]={0};

C.rpos[arow]=C.t+1;

if(arow

else{tp=A.t+1;}

for(p=A.rpos[arow];p

{

intbrow=A.data[p].j;

if(brow

else{t=B.t+1;}

for(q=B.rpos[brow];q

{

ccol=B.data[q].j;

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

}

}

for(ccol=1;ccol<=C.n;++ccol)

{

if(ctemp[ccol])

{

if(++C.t>maxsize)return;

C.data[C.t].i=arow;

C.data[C.t].j=ccol;

C.data[C.t].v=ctemp[ccol];

}

}

}

}

inta[100][100]={0};

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

{

a[A.data[k].i][A.data[k].j]=A.data[k].v;

}

cout<<"A输入为:

";

cout<

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

{

for(intl=1;l<=A.n;l++)

cout<

cout<

}

intb[100][100]={0};

for(k=1;k<=B.t;k++)

{

b[B.data[k].i][B.data[k].j]=B.data[k].v;

}

cout<<"B输入为:

"<

for(k=1;k<=B.m;k++)

{

for(intl=1;l<=B.n;l++)

cout<

cout<

}

intc[100][100]={0};

for(k=1;k<=C.t;k++)

{

c[C.data[k].i][C.data[k].j]=C.data[k].v;

}

cout<<"乘法结果C为:

"<

for(k=1;k<=C.m;k++)

{

for(intl=1;l<=C.n;l++)

cout<

cout<

}

}

以上主要设计思想为:

此功能由函数multi()实现。

当用户选择该功能,系统提示输入要进行相乘的两个矩阵的详细信息。

然后检测两者是否可以相乘,如果不能,则重新初始化第二个矩阵。

先对矩阵B进行逐行处理,先求得累计求和的中间结果(C的每一行),然后再压缩存储到c.data中去,最后得到结果。

 

第四章设计理论分析方法

4.1算法一:

矩阵转置

转置运算时一种最简单的矩阵运算,对于一个m*n的矩阵M,他的转置矩阵T是一个n*m的矩阵,且T(i,j)=M(j,i),1<=i<=n,1<=j<=m。

显然,一个稀疏矩阵的转置矩阵仍然是稀疏矩阵。

(1)将矩阵的行列值相互交换;

(2)将每个三元组中的i和j相互调换;(3)重排三元组之间的次序便可实现矩阵的转置。

一般矩阵转置算法为

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

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

T[col][row]=M[row][col];

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

在此,需要附设num和cpot两个向量。

Num[col]表示矩阵M中第col列中非零元的个数,cpot[col]指示M中第col列的第一个非零元在b.data中的恰当位置。

cpot[1]=1

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

这就是快速转置。

4.2算法二:

矩阵加法

稀疏矩阵使用三元组存储,则运算时只需考虑非零元的值即可。

两个矩阵相加

首先必须保证M.mu=N.mu&&M.nu=N.nu即同行同列的矩阵才能相加。

for(k=1;k<=M.tu;k++)

for(i=1;i<=N.tu;i++)

if(M.data[k].i==N.data[i].i&&

M.data[k].j==N.data[i].j)

Q.data[count].e=M.data[k].e+N.data[i].e;

flag[i]=true;

如果非零元位置一样就直接相加

if(i>N.tu)

Q.data[count].e=M.data[k].e;

如果没有找到与M非零元位置一样的元素就直接把M中的非零元赋值给矩阵Q。

for(k=1;k<=N.tu;k++)

if(!

flag[k])

Q.data[count].e=N.data[k].e;

如果N中的元素没有被查找,则直接把N中的非零元赋值给矩阵Q。

4.3算法三:

矩阵乘法

矩阵乘法采用“带行信息”的三元组存储。

经典算法如下:

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[j][k]*N[k][j];

}

稀疏矩阵相乘前提:

M.nu=N.mu

大致步骤描述如下:

Q初始化;

If(Q是非零矩阵)

{//逐行求积

for(arow=1;arrow<=M.mu;++arow)

{//处理M的每一行

ctemp[]=0;//累加器清零

计算Q中第arow行的积并存入ctemp[]中;

将ctemp[]中非零元压缩存储到Q.data;

}

}

 

第五章程序调试

整个程序主要运用了矩阵运算的规则,利用创建三元组表,分析数据,行列是否匹配,稀疏矩阵的转置,稀疏矩阵的相加,稀疏矩阵的相乘。

(1)稀疏矩阵的转置

图5.1

(2)稀疏矩阵的加法

图5.2

(3)稀疏矩阵的乘法:

图5.3

 

第六章心得体会

通过此次课程设计,使我更加扎实的掌握了有关稀疏矩阵方面的知识,在设计过程中虽然遇到了一些问题,但经过一次又一次的思考,一遍又一遍的检查终于找出了原因所在,也暴露出了前期我在这方面的知识欠缺和经验不足。

实践出真知,通过亲自动手制作,使我们掌握的知识不再是纸上谈兵。

过而能改,善莫大焉。

在课程设计过程中,不断发现错误,不断改正,不断领悟,不断获取。

最终的检测调试环节,本身就是在践行“过而能改,善莫大焉”的知行观。

这次课程设计终于顺利完成了,在设计中遇到了很多问题,最后在老师和同学的指导下,终于游逆而解。

在今后社会的发展和学习实践过程中,一定要不懈努力,不能遇到问题就想到要退缩,一定要不厌其烦的发现问题所在,然后一一进行解决,只有这样,才能成功的做成想做的事,才能在今后的道路上劈荆斩棘,而不是知难而退,那样永远不可能收获成功,收获喜悦,也永远不可能得到社会及他人对你的认可!

 

参考文献

[1]谭浩强著.C程序设计(第三版)[M].:

清华大学,2009.5

[2]严蔚敏、吴伟民主编《数据结构(C语言版)》[M].清华大学2004.11

[3].建学等编著《数据结构课程设计案例精编(用C/C++描述)》[M],清华大学2007.2

[4].殷人昆主编《数据结构:

用面向对象方法与C++语言描述》[M], 清华大学2007.6

 

 

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 初中教育 > 学科竞赛

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1