




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、合肥学院计算机科学与技术系课程设计报告20082009学年第二学期课程数据结构与算法课程设计名称矩阵的加法运算问题学生姓名«学号学04032039专业班级07网络工程(2)指导教师张贯虹屠菁2009年6月题目:(矩阵的加法运算问题)设计程序完成如下要求:采用十字链表表示稀疏矩阵,并实现矩阵的加法运算。要求:要检查有关运算的条件,并对错误的条件产生报警。一、问题分析和任务定义此程序需要完成如下要求:使用十字链表存储结构存储稀疏矩阵并实现两个矩阵的相加运算。实现本程序需要解决一下几个问题:1、如何用一个十字链表来表示稀疏矩阵。2、十字链表如何创建。3、如何实现稀疏矩阵的加法运算。4、对错
2、误的条件产生警报。5、如何把矩阵输出。本问题的关键和难点在于编写算法实现两个稀疏矩阵的相加运算使得相加后的矩阵仍然是稀疏矩阵。在链表中,每个非0元素可用一个含有五个域的结点表示:其中:i,j,v三个域分别表示该元素所在的行、列和非0元素的值。行指针域rptr用以链接同一行中下一个非0元素;列指针域cptr用以链接同一列中下一个非0元素。存储时,每个非0元既是某个行链表中的一个结点,又是某个列链表中的一个结点;整个矩阵构成了一个十字交叉的链表,如下图:图2稀疏矩阵的十字链表存储示例可用两个分别存储行链表M->rhead口和列链表M->chead口的头指针的一维数组表示十字链表。使用十
3、字链表建立稀疏矩阵后就是矩阵相加的运算问题。对于稀疏矩阵来说,其存储结构决定了它不可以按照普通矩阵的加法来运算。对于两个稀疏矩阵A、B相加,每个位置(i,j)上的和只可能有三种情况:aij+bij、aij(bij=0)、bij(aij=0)。可以将稀疏矩阵Bm*n加到稀疏矩阵Am*n上,若aij+bij不等于0,则只需改变aij的值;若aij+bij等于0,则应从十字链表A中删除aij对应的结点;若和值为bij,则只需在十字链表A中添加一个结点。为实现该过程可以从矩阵的第一行逐行进行。二、数据结构的选择和概要设计十字链表使用的是链接存储的方式。其结点类型为olnode,每个结点中除了描述非0元
4、素所在的行号i、列号j、及非0元素的值v以外,还有两个指针域;行指针域rptr和列指针域cptr。行指针域rptr用以链接同一行中下一个非0元素;列指针域cptr用以链接同一列中下一个非0元素。在十字链表用以olnode类型的一维指针数组rheadm和cheadn来表示所有的行链表和列链表。这两个指针数组及稀疏矩阵中非零元素个数t一起构成crosslist类型。为了实现两个矩阵相加的功能需要创建十字链表M,然后用M来存储矩阵A和矩阵B。判断A、B两个矩阵是否满足相加条件,如果可以相加则逐个比较两个矩阵对应i的行链表A->rheadi与B->rheadi上的每一个结点*a和*b:若两
5、个结点的列号相同(a->j=b->j),则将它们值域中的内容相加(a->=a->v+b->v);若它们的和a->v等于0,则将结点*a从行链表A->rheadi及相应的列链表中删除。若行链表B->rheadi上结点*b的列号小于行链表A->rheadi上结点*a的列号,则将结点*b插到行链表A>rheadi上结点*a之前。根据结点*b的列号将其插入到十字链表A合适的列链表中。若行链表B->rheadi上结点*b的列号大于行链表A->rheadi上结点*a的列号,则令a=a->rptr,并重复以上步骤直到对应的链表比较
6、完毕。另外,为便于插入与删除结点,还应设立一些辅助指针;在A的行链表上设置一个pre指针,使其指向*a的前驱结点;在A的每一个列链表上设置一个指针acolj,它的初始值与列链表的头指针相同,即acolj=A->rheadi。另外题目要求要检查有关运算的条件,并对错误的条件产生报警。这里判断矩阵是否可以相加的条件,需要用到线性代数中矩阵能够相加的条件即:两个待加的矩阵具有相同的行数和列数。因此可已在矩阵执行相加函数前调用判断函数经行判断,符合相加条件则执行相加算法;不符合则提示出错并提供修改的操作。三、详细设计和编码、本程序十字链表的建立和相加算法为设计的核心内容。十字链表创建的过程可描述
7、如下:首先申请一个存放crosslist类型的数据所需要的存储空间。这包括存放各行链表列链表首元素结点地址的行、列指针数组的空间,以及存放稀疏矩阵的非0元素个数所需的存储空间。M=(crosslist*)malloc(sizeof(crosslist);接下来,分别给M->m、M->n、M->t、M->rheadK、M->rheadN赋值:scanf("%d%d%d",&(M->m),&(M->n),&(M->t);for(i=0;i<M->m;i+)M->rheadi=NULL;fo
8、r(i=0;i<M->n;i+)M->cheadi=NULL;然后,输入所有的非0元素的三元组,生成相应的结点,并根据其行号将该结点插入到相应的行链表中:p=(olnode*)malloc(sizeof(olnode);scanf("%d%d%d",&(p->i),&(p->j),&(p->v);如果该行链表为空,或者当前结点的列号比该行链表中第一个结点的列号小,则将该结点作为首元素结点插入到该行链表中。if(M->rheadp->i=NULL)|(M->rheadp->i->j)&g
9、t;(p->j)p->rptr=M->rheadp->i;M->rheadp->i=p;否则,查找该行链表中的各结点的列号,将该结点按列号的顺序插入到该行链表中。elseu=M->rheadp->i;q=M->rheadp->i->rptr;while(q!=NULL)if(q->j>p->j)break;u=q;q=q->rptr;p->rptr=q;u->rptr=p;将该结点插入到相应的列链表中。如果该列链表为空,或者当前结点的行号比该列链表中第一个结点的行号小,则将该结点作为首元素结点
10、插入到该列链表中。if(M->cheadp->j=NULL|M->cheadp->j->i>p->i)p->cptr=M->cheadp->j;M->cheadp->j=p;否则,查找该列链表中的各结点的行号,将该结点按行号的顺序插入到该列链表中。elseu=M->cheadp->j;q=M->cheadp->j->cptr;while(q!=NULL)if(q->i>p->i)break;u=q;q=q->cptr;p->cptr=q;u->cptr=p;
11、用十字链表存储矩阵只是为矩阵的相加提供了可操作的条件,接下来便是执行矩阵的加法算法实现两矩阵的相加。令a和b分别指向A和B的第一行链表:a=A->rheadi;b=B->rheadi;pre=NULL;并且初始化指针acolfor(i=1;i<=A->n;i+)acoli=A->cheadi;逐个比较行链表A->rheadi与B->rheadi上的每一个结点*a和*b,直到链表B->rheadi中所有非0元素结点均比较完毕。若链表A->rheadi已比较完毕,或者结点*b的列号小于结点*a的列号,则在链表A->rheadi中插入一个*
12、b的复制结点:if(a=NULL|a->j>b->j)if(pre=NULL)A->rheadi=p;elsepre->rptr=p;p->rptr=a;pre=p;同时,结点*p也应插入到相应的列链表中。P-刁是*p结点的列号,应将它插入到列链表A->cheadp->j中。i是*p结点的行号,应从acolp->j开始查找*p结点在列链表A->cheadp->j中的前驱结点,并将*p结点插入到相应位置:if(A->cheadp->j=NULL|A->cheadp->j->i>i)p->c
13、ptr=A->cheadp->j;A->cheadp->j=p;elseif(acolp->j!=NULL)while(acolp->j->cptr!=NULL&&acolp->j->cptr->i<i)acolp->j=acolp->j->cptr;p->cptr=acolp->j->cptr;acolp->j->cptr=p;elseacolp->j=p;acolp->j=p;若结点*b的列号大于结点*a的列号,则在链表A->rheadi中查找
14、列号大于*b的列号的结点的前驱结点,并插入一个*b的复制结点*p;即若*a的后继结点的列号大于*b的列号,则将*p插入到*a后:while(a!=NULL&&a->j<b->j)pre=a;a=a->rptr;pre->rptr=p;p->rptr=a;pre=p;同时,结点*p也应插入到相应的列链表中。若结点*b的列号等于结点*a的列号,将*b结点的值加到*a结点上:if(a!=NULL&&a->j=b->j)a->v=a->v+b->v;此时若a->v!=0,则无需其它操作;否则,在十字
15、链表A中删除该结点。在行链表中删除该结点:if(pre=NULL)A->rheadi=a->rptr;elsepre->rptr=a->rptr;p=a;a=a->rptr同时,在列链表A->cheadp->j中删除该结点:if(A->cheadp->j=p)A->cheadp->j=p->cptr;acolp->j=p->cptr;elsewhile(acolp->j->cptr!=p)acolp->j=acolp->j->cptr;acolp->j->cptr=p-
16、>cptr;free(p);若本行不是最后一行,则令a和b指向下一行行链表的首元素结点,重复上述算法;否则,结束算法。四、上机调试1、语法错误及修改:本程序使用到的变量很多即有循环控制变量又有矩阵元素下标、矩阵非零元素个数等。故在编程时出现了多次变量使用不当和未事先声明的错误,经过编译器的提示修改后更正。另外程序中使用的指针也较为复杂,时常有指针指向的空间不存在或者从空的地址里提取数据等情况,在修改了编译器里提示的简单错误并加入对指针判断是否为空的语句后程序得以运行。2、逻辑问题修改和调整:程序调试无误后运行程序,进入测试数据阶段。输入数据时出现程序出错突然终止运行的情况。检查数据是否输
17、入有误,发现数据输入无误。更换其它数据输入仍然出现上述情况。分析原因,可能是创建十字链表的算法出错,找到创建十字链表的源代码带入数据进行手工运行。在调试中发现,用于表示矩阵的行列链表一维数组首元素均以0开始,而矩阵中的各元素下标均以1开始,这样便产生了输入时程序内部的混乱。这样的错误属于算法错误在语法上检查不出来。修改方法,将行列链表一维数组首元素均以1开始与矩阵中的各元素下标保持一致。再次运行程序,顺利的建立了以十字链表为存储结构的稀疏矩阵。但是当运行矩阵相加时又出现了程序突然终止的情况。有了上次调试的经验分析原因,又是算法的逻辑问题出现了错误且出错的地方为十字链表相加的算法函数。因为十字链
18、表相加函数十分复杂,带入数据手工运行工作量太大,而且编程时是按照参考书上的算法描述来写的程序因此,在算法上不太可能又严重的错误。出错的原因可能在某些局部地方出错,例如指针的地址,循环的结束,判断的条件等地方出错。输入数据利用编译器自带的调试功能进行调试,找到出错的位置,再分析错误的原因。经多次输入不同的数据调试后发现在判断结点*a和*b的列号是否相同时,没有对结点*a地址是否为空时进行判断,若果*a地址为空,则这条判断语句就出错无法运行,最终导致程序出错。加入判断*a地址为空的语句及为空时程序执行下面的语句的语句后,使得矩阵相加输出正确的结果。另外发现两个矩阵的某行首元素经过相加后得到的数值为
19、零时,程序将首链表结点删除而导致该行后面的运算出现了错误。经过认真分析算法后加入了判断首地址在相加后是否变为空的语句后,问题得以解决。3、时间,空间性能分析:本程序的空间复杂度主要用于存放十字链表结点的空间和十字链表中行链表和列链表的一维数组的空间。故空间复杂度O(2t+2i+2j),其中t为稀疏矩阵中非零元素个数,i为稀疏矩阵的行数,j为稀疏矩阵的列数。由于使用十字链表作为存储结构,这样相对于用普通的二维数组来存储矩阵的方法节省了大量的空间。另外相加后的矩阵是在A矩阵基础上得到的未开辟新的存储空间,这样又节省了空间。本程序的时间性主要在于建立十字链表的算法时间复杂度和矩阵相加算法的时间复杂度
20、。建立十字链表的算法时间复杂度为O(t*x),其中t为稀疏矩阵中非零元素个数,x为稀疏矩阵中行数和列数较大的值。矩阵相加算法的时间复杂度主要耗费在对十字链表A、B进行逐行扫描上,循环次数主要取决于矩阵A、B中非零元素的个数A->t和B->t。因此,算法的时间复杂度为O(A->t+B->t)。五、用户使用说明运行程序后进入菜单界面,本程序提供了如下操作:1-运行程序、2-数据清零、3-使用说明、4-退出程序。输入阿拉伯数字选择对应的功能。选择1则进入矩阵相加模块,首先输入矩阵A的行数、列数、非零元素个数,行数、列数、非零元素个数以空格隔开;然后输入矩阵各元素的行标、列表、
21、数值,行标、列表、数值以空格隔开,按回车键输入下个元素;再输入矩阵B,输入的方法同上;最后按回车键查看相加结果。选择2将程序中所申请的空间释放,数值清零,便于下次运行程序。选择3查看使用说明,这里不再赘述。选择4则退出程序。六、测试结果测试数据:矩阵A:01020-1123矩阵B:002-1010-20矩阵C=A+B:012100103测试结果截图如下:*d:IyDocu*eirt£t"DEbug矩阵的加法运算问题.exeMMXMMMXMMMXMM灯印用序宜*<*=宜*<*<=1txM冷宜-*人序零明序一籍装运数使退-列为为为为为为.列为为为为=A3 科:
22、,重重素素素知攵素素素素白<1 需元元元元元元霹元元元元鹃1> 5个个个个个个吐寸TTT演2, >?®®EEEEE®®®EEE®" 2 T 1 2 13 122 2 3 3零* TE 3 1 1 2<3,1,1X3,3,3>图3程序运行以下演示程序对错误条件产生报警的截图:3 42 63 10个数:CA *d: ly。口(:11»皿t£77。01111式矩阵的加法电算问题.。©312?主.,TTr232 -3 11 2132ZB数<A个 f -rnJJ-L例知
23、知对知林藉理筵数 :方/3/斗/3/斗,二-v-儿上挈 方丁犯一丁. 矩行机砥机砥矩行合需行合输 1人入1-沙沙4-入入第入第图4程序运行.七、参考文献【1】.王昆仑,李红。数据结构与算法.北京:铁道工业出版社,2007年6月第一版八、附录#include<iostream>#include<malloc.h>usingnamespacestd;# defineK50预设稀疏矩阵的行数# defineN50预设稀疏矩阵的列数# defineNULL0typedefstructnodeinti,j,v;元素的行标、列标、值域structnode*rptr,*cptr;/行
24、指针域、列指针域olnode;结点类型typedefstructolnode*rheadK,*cheadN;/一维数组存放行链表及列链表的首地址intm,n,t;矩阵的行数、列数、非零元素个数crosslist;十字链表类型crosslist*creatcross()创建空十字链表crosslist*M;/声明变量M=(crosslist*)malloc(sizeof(crosslist);为十字链表申请空间cout<<"输入行数列数非零个数:"cin>>M->m>>M->n>>M->t;while(M-&g
25、t;t>(M->m*M->n)判断矩阵是否符合要求cout<<"不符合相加条件!!”<<endl<<"重新输入行数列数非零元素个数:"cin>>M->m>>M->n>>M->t;returnM;返回空十字链表地址crosslist*creatcross2(crosslist*M)/为十字链表赋值存放稀疏矩阵olnode*p,*q,*u;/申请元素结点类型的变量inti,h;for(i=1;i<=M->m;i+)行链表置空M->rheadi=
26、NULL;for(i=1;i<=M->n;i+)M->cheadi=NULL;/列链表置空for(h=1;h<=M->t;h+)/给十字链表中元素赋值p=(olnode*)malloc(sizeof(olnode);/申请结点类型的空间赋值给cout<<"第"<<h<<”个元素为:"cin>>p->i>>p->j>>p->v;while(p->i>M->m|p->j>M->n)/判断输入是否符合要求cout&l
27、t;<"*重新输入第"<<h<<"个元素:"cin>>p->i>>p->j>>p->v;if(M->rheadp->i=NULL)|(M->rheadp->i->j)>(p->j)当该元素所在的行首地址为空或当前结点的列号比该列行链表中第一个结点的行号小p->rptr=M->rheadp->i;/将该结点作为首元素结点插入到该行链表中M->rheadp->i=p;else否则,查找该行链表中的个结点的
28、列号,将该结点按列号的顺序插入到该行链表中u=M->rheadp->i;q=M->rheadp->i->rptr;while(q!=NULL)/指针后移找到比待插入结点列号大的元素地址if(q->j>p->j)break;u=q;q=q->rptr;p->rptr=q;/插入结点u->rptr=p;if(M->cheadp->j=NULL)|(M->cheadp->j->i)>(p->i)/根据列号将该结点插入到相应的列链表中p->cptr=M->cheadp->j;M
29、->cheadp->j=p;elseu=M->cheadp->j;q=M->cheadp->j->cptr;while(q!=NULL)if(q->i>p->i)break;u=q;q=q->cptr;p->cptr=q;u->cptr=p;returnM;/返回十字链表首地址crosslist*matrixpuls(crosslist*A,crosslist*B)/矩阵相加函数olnode*a,*b,*p,*pre,*acolN;/结点类型的指针变量,*a为A矩阵中的结点,*b为B矩阵中的结点,*pre是指向*a的
30、前驱结点inti;for(i=1;i<=A->n;i+)/在矩阵A的每一个列链表上设置一个指针acoli,它的初始值与列链表的头指针相同acoli=A->cheadi;for(i=1;i<=A->m;i+)a=A->rheadi;/将第i行的首地址赋给ab=B->rheadi;/将第i行的首地址赋给bpre=NULL;while(b!=NULL)/当结点b的地址不为空时执行下面循环if(a!=NULL&&a->j=b->j)/如果两结点列号相同a->v=a->v+b->v;/将a、b结点的值域相加并赋给ai
31、f(a->v=0)/若相加后为值为0if(pre=NULL)/a的前驱为空时A->rheadi=a->rptr;/将a结点删除elsepre->rptr=a->rptr;/否则,将a的前驱后移一位p=a;/p指向被删除的结点a=a->rptr;/a后移一位if(A->cheadp->j=p)/p指向的结点为所在列的首元素时A->cheadp->j=p->cptr;/将p从列链表中删除acolp->j=p->cptr;else否则,找到p所在列链表的前驱结点while(acolp->j->cptr!=p)a
32、colp->j=acolp->j->cptr;acolp->j->cptr=p->cptr;/将p从列链表中删除free(p);/释放p指向结点的空间else/若相加后为值不为0pre=a;/pre指向aa=a->rptr;/a后移一位else/如果两结点列号不相同p=(olnode*)malloc(sizeof(olnode);/为p申请空间并将b结点复制给pp->i=b->i;p->j=b->j;p->v=b->v;if(a=NULL|a->j>b->j)/若a地址为空或列号大于b的列号if(p
33、re=NULL)/a的前驱为空时A->rheadi=p;/将p插入到该行头结点之前elsepre->rptr=p;否则,将p插到a结点之前p->rptr=a;pre=p;/a的前驱变为p结点else否则,找到列标大于b结点的a结点while(a!=NULL&&a->j<b->j)pre=a;a=a->rptr;if(a=NULL|a->j>b->j)若a地址为空或列号大于b的列号pre->rptr=p;/将p插到a结点之前p->rptr=a;pre=p;/a的前驱变为p结点else/否则两结点列号相同a-&
34、gt;v=a->v+b->v;/将两节点数值相加赋给aif(a->v=0)/若相加后为值为0if(pre=NULL)/a的前驱为空时A->rheadi=a->rptr;/将a结点删除elsepre->rptr=a->rptr;/否则,将a的前驱后移一位p=a;/p指向被删除的结点a=a->rptr;/a后移一位if(A->cheadp->j=p)/p指向的结点为所在列的首元素时A->cheadp->j=p->cptr;/将p从列链表中删除acolp->j=p->cptr;else/否则,找到p所在列链表的
35、前驱结点while(acolp->j->cptr!=p)acolp->j=acolp->j->cptr;acolp->j->cptr=p->cptr;/将p从列链表中删除free(p);/释放p指向结点的空间else/若相加后为值不为0pre=a;/pre指向aa=a->rptr;/a后移一位break;if(A->cheadp->j=NULL|A->cheadp->j->i>i)/若p结点所在的列首地址为空或p的行标比首节点的行标小p->cptr=A->cheadp->j;/将p插到首
36、结点之前A->cheadp->j=p;/该列的首地址为变pelse/否则,当若p结点所在的列首地址不为空时if(acolp->j!=NULL)while(acolp->j->cptr!=NULL&&acolp->j->cptr->i<i)/在该列中找到比p的列标大的结点地址acolp->j=acolp->j->cptr;p->cptr=acolp->j->cptr;/将p插到该结点之前acolp->j->cptr=p;else/当若p结点所在的列首地址为空时acolp->
37、j=p;/将p结点作为该列首元素acolp->j=p;/将p结点作为该列首元素b=b->rptr;/b结点向后移一位returnA;/返回十字链表首地址intpanduan(crosslist*A,crosslist*B)/判断矩阵是否符合相加条件if(A->m=B->m&&A->n=B->n)return0;/符合返回0elsereturn1;/不符合返回1voidmain()/主函数crosslist*A,*B,*C;olnode*p;inti,Y;charr;while(Y!=4)/菜单cout<<endl;cout<<endl;cout<<"tt*欢迎使用矩阵相加程序*"<<endl;cout<<endl;cout<<endl;cout«endl; cout«endl; cout«"ttcout«"tt cout«"tt cout«"tt1-运2-数3-使4-退行 据 用 出程
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年中国男性内裤项目投资可行性研究报告
- 2025年中国电泳白型材数据监测研究报告
- 2025年中国电动废气阀市场调查研究报告
- 2025年中国玻璃钢浪板市场现状分析及前景预测报告
- 车辆起火考试试题及答案
- 浑南期末考试卷子及答案
- 盲盒机投放地点合作协议
- 2025年现代教育技术应用考试试卷及答案
- 2025年基础护理学专业考研试题及答案分享
- 2025年职称英语考试复习试卷及答案
- 高空作业安全会议记录内容
- 00510秘书实务-自考整合版
- 护理研究中的偏倚及控制
- 小学生的龋齿预防ppt课件
- [复习]边坡客土吹附施工方案
- 冲压试题库及答案文档
- 管理人员责任追究制度
- 自动旋转门PLC控制
- 电影场记表(双机位)
- 毕设高密电法探测及数据处理解释
- 华为保密制度范文
评论
0/150
提交评论