当前位置:文档之家› 稀疏矩阵的十字链表加法

稀疏矩阵的十字链表加法

目录前言 (1)正文 (1)1.课程设计的目的和任务 (1)2.课程设计报告的要求 (1)3.课程设计的内容 (2)4.稀疏矩阵的十字链表存储 (2)5.稀疏矩阵的加法思想 (4)6.代码实现 (5)7.算法实现 (5)结论 (8)参考文献 (9)附录 (10)前言采用三元组顺序表存储稀疏矩阵,对于矩阵的加法、乘法等操作,非零元素的插入和删除将会产生大量的数据移动,这时顺序存储方法就十分不便。

稀疏矩阵的链接存储结构称为十字链表,它具备链接存储的特点,因此,在非零元素的个数及位置都会发生变化的情况下,采用链式存储结构表示三元组的线性更为恰当。

正文1.课程设计的目的和任务(1) 使我我们进一步理解和掌握所学的程序的基本结构。

(2) 使我们初步掌握软件开发过程的各个方法和技能。

(3) 使我们参考有关资料,了解更多的程序设计知识。

(4) 使我们能进行一般软件开发,培养我们的能力并提高我们的知识。

2.课程设计报告的要求(1)课程设计目的和任务,为了达到什么要求(2)课程设计报告要求(3)课程设计的内容,都包含了什么东西(4)稀疏矩阵和十字链表的基本概念,稀疏矩阵是怎么用十字链表存储(5)十字链表矩阵的加法(6)代码实现(7)算法检测3.课程设计的内容(1)根据所学知识并自主查找相关资料 (2)进行算法设计与分析(3)代码实现,组建并运行结果查看是否正确 (4)书写课程设计说明书4.稀疏矩阵的十字链表存储稀疏矩阵是零元素居多的矩阵,对于稀疏矩阵,人们无法给出确切的概念,只要非零元素的个数远远小于矩阵元素的总数,就可认为该矩阵是稀疏的。

十字链表有一个头指针hm ,它指向的结点有五个域,如图1所示。

row 域存放总行数m ,col 域存放总列数n ,down 和right 两个指针域空闲不用,next 指针指向第一个行列表头结点。

c o lr o w图1 总表点结点有S 个行列表头结点h[1],h[2],......h[s]。

结点结构与总表头结点相同。

Row 和col 域置0,next 指向下一行列表头结点,right 指向本行第一个非零元素结点,down 指向本列第一个非零元素结点如图2所示。

当最后一个行列表头结点的next 域指向总表头结点的hm 时,就形成循环链表,见图4的第一行。

Nextdownright图2 行列表头结点Nextdownright图3 非零元素结点⎥⎥⎥⎥⎥⎥⎦⎤⎢⎢⎢⎢⎢⎢⎣⎡--=30000000000201007003A 图4 稀疏矩阵非零元素结点结构也有五个域,与其他结点域结构相似,只有next 域为一变体域,可为val 域存放非零元素的值,row 和col 存放行下标值和列下标值,right 指向本行的下一个非零元素结点,down 指向本列的下一个非零元素结点。

稀疏矩阵中同一行的非零元素通过向右域right ,链接成一个带头结点的循环链表。

同一列的非零元素也通过向下域down 。

链接成一个带头结点的循环链表。

因此,每一个非零元素即是第i 行循环链表中的一个结点,又是第j 列循环链表中的一个结点。

这好比处于一个十字交叉路口上,故称这样的链表为十字链表。

例如,对于如图4所示的5行4列的稀疏矩阵A的十字链表如图5所示。

如图5可见,每一列链表的表头结点只需要用一个链域,指向该列中第一个非零元素,而每一行链表的表头结点只需right链域,指向该行中第一个非零元素,恰好他们的row和col域又同时为0,故这两组的表头结点可以合用(即第i行链表和第j列链表共用一个表头结点)这些表头结点本身又可以通过val域相链接(注意:val域在表头结点中为next域,是指向下一个表头结点的链域),加上附加结点(由指针hm指示),又组成一个带表头结点的循环链。

Hm所指结点为整个十字链表的表头结点,其row和col域的值分别为稀疏矩阵的行数和列数,hm为头指针。

由此,只要给定hm指针值,便可取得整个稀疏矩阵的全部信息。

图5 稀疏矩阵A的十字链表5.稀疏矩阵的加法思想如果运用带行指针向量和带列指针向量的存储结构进行系数矩阵的加法运算,设M和N是两个加法矩阵,Q是和矩阵,也就是结果矩阵。

M和N矩阵可以相加的前提条件是:M 和N矩阵是一样的,也就是说行数和列数的个数相同,M和N相加的结果矩阵就是一个一样大小的矩阵。

结果矩阵中每个行单链表也还是需要列号有序,它是对M和N中对应行单链表的按列号有序的合并结果。

当M和N中相应的行单链表的两个结点分别是一样的行号和列号时,如果他们的元素之和为0,就不在结果矩阵中建立结点,只有当元素的和不为0或者列号不一样时,才需要在结果矩阵中建立结点。

如果,M矩阵扫描完,N矩阵还没有扫描完,这个时候,直接就将N矩阵中的剩余的结点插入结果矩阵中。

6.代码实现矩阵中的元素在最后运行的时候由用户自己定义,根据用户输入的稀疏矩阵的行数、列数和非零元个数。

知道稀疏矩阵多少行、多少列以及有多少个非零元,然后依据非零元个数,输入非零元,仍然需要用户自己输入行号、列号以及非零值。

如果输入行数、列数和非零元个数为:5 4 3就表示这是一个5行4列3个非零元的稀疏矩阵用户自己输入行号、列号以及非零值,如:2 3 53 3 35 2 1表示第一个非零元在第2行,第3列,值为5;第二个非零元在第3行,第3列,值为3;第三个非零元在第5行,第2列,值为1。

所以此稀疏矩阵为:00 0 00 0 5 000 3 00 0 0 00 1 0 0再用同样的方法输入一个一样的5行4列的稀疏矩阵,设定行号、列号以及非零元值,利用稀疏矩阵的加法思想,将两个稀疏矩阵加起来得到结果矩阵。

7.算法实现运行开始界面,界面显示输入行数、列数和非零元素个数输入:3 3 3说明这个稀疏矩阵是三行、三列、三个非零元素,然后回车,界面再显示请输入一个非零元三元组<row,col,value>输入三元组:1 1 1说明在第一行、第一列的非零值是1,回车,界面显示输入一个非零元三元组按照上面的程序再依次输入:2 2 23 1 5矩阵A就完成了,然后界面得到稀疏矩阵A然后界面提示请输入行数、列数和非零元个数依照矩阵A的程序模式输入:3 3 41 1 22 1 13 1 13 3 3矩阵B也就完成了,然后界面得到稀疏矩阵B同时界面上也显示A+B=得到的结果矩阵结论M和N矩阵可以相加的前提条件是:M和N矩阵是一样的,也就是说行数和列数的个数相同,M和N相加的结果矩阵就是一个一样大小的矩阵。

结果矩阵中每个行单链表也还是需要列号有序,它是对M和N中对应行单链表的按列号有序的合并结果。

当M和N中相应的行单链表的两个结点分别是一样的行号和列号时,如果他们的元素之和为0,就不在结果矩阵中建立结点,只有当元素的和不为0或者列号不一样时,才需要在结果矩阵中建立结点。

参考文献[1]谭浩强编著.C++课程设计.北京:清华大学社,2004[2]S.B.Lippman,joie著.潘爱民译.C++Primer(3rd Edition)中文版.北京:中国电力出版社,2002[3]H.M.Deitel,Paul James Deitel著.薛万鹏译.C++程序设计教程.北京:机械工业出版社,2000[4]Stephen R.Savis著.C++ For Dummies 4th edition,IDG Books Worldwide,Inc.,2002[5]Harvey M.Deitel .Jack W.Davidson著.邱仲潘译.C++大学教程(第二版).北京:电子工业出版社,2002[6]James P.Cohoon.Jack W.Davidson著.刘瑞挺等译.C++程序设计(第三版).北京:电子工业出版社[7]Decoder编著.C/C++程序设计.北京:中国铁道出版社,2002[8]Brian Overland著.董梁等译.C++语言命令译解(第二版).北京:机械工业出版社,2002[9] H.M.Deitel,Paul James Deitel著.薛万鹏译.C/C++程序设计大全.北京:机械工业出版社.1997[10]Al Strevens,Clayton Walnum著.林丽闽等译.标准C++宝典.北京:电子工业出版社.2001[11]Michael J.Young著.Mastering Visual C++6.0 Sybex Inc.1999[12]Leen Ammeraal著.刘瑞挺等译.C++程序设计教程(第三版).北京:zhongguo 铁道出版社,2003[13] 吕凤翥著. C++语言程序设计.北方交通大学出版社,2003[14] 袁启昌著.C++语言程序设计.清华大学出版社,2004[15] 刘振安,刘燕君,孙忱C++语言课程设计.机械工业出版社,2007[16] 杨进才,沈显君,刘蓉编.C++语言程序设计教程.清华大学出版社,2006[17] 宋振会著. C++语言编程基础教程.清华大学出版社,2005附录#include<iostream>using namespace std;template<class Type>class MatrixNode;template<class Type>class LinkMatrix;template<class Type>istream &operator>>(istream &,LinkMatrix<Type>&); template<class Type>ostream &operator<<(ostream &,LinkMatrix<Type>&); template<classType>LinkMatrix<Type>operator+(constLinkMatrix<Type>&a,constLinkMatrix<Type> &b);template<class Type>class MatrixNode{friend class LinkMatrix<Type>;friend istream&operator>>(istream&,LinkMatrix<Type>&);friend ostream&operator<<(ostream&out, LinkMatrix<Type>&);friend LinkMatrix<Type> operator +(const LinkMatrix<Type> &a,const Link Matrix<Type>&b);private:int row,col;MatrixNode<Type>*right,*down;union{Type data;MatrixNode<Type>*next;};};template<class Type>class LinkMatrix{private:MatrixNode<Type> *head;void InsertInCol(MatrixNode<Type>*p);void DeleteInCol(MatrixNode<Type>*p);public:friend istream&operator>>(istream&in,LinkMatrix<Type>&);friend ostream&operator<<(ostream&out,LinkMatrix<Type>&);MatrixNode<Type>* Head(int i);LinkMatrix<Type>&operator +=(const LinkMatrix<Type> &a);friend LinkMatrix<Type> operator +(const LinkMatrix<Type> &a,const LinkMa trix<Type>&b);};template<class Type>istream&operator>>(istream&in,LinkMatrix<Type>&a){int m,n,terms,s;MatrixNode<Type>**cp,*p,*q;cout<<"输入矩阵的行数、列数、和非零元素个数"<<endl;in>>m>>n>>terms;if(n>m)s=n;else s=m;a.head=new MatrixNode<Type>;a.head->row=m;a.head->col=n;a.head->right=a.head->down=NULL;cp=new MatrixNode<Type>*[s+1];cp[0]=a.head;int i;for(i=1;i<=s;i++){p=new MatrixNode<Type>;p->row=p->col=0;p->right=p->down=p;cp[i]=p;cp[i-1]->next=p;}cp[s]->next=a.head;for(i=1;i<=terms;i++){cout<<"输入一个非零元三元组(row,col,value)"<<endl;p=new MatrixNode<Type>;in>>p->row>>p->col>>p->data;q=cp[p->row];while((q->right!=cp[p->row]&&(q->right->col<p->col)))q=q->right;p->right=q->right;q->right=p;q=cp[p->col];while((q->down!=cp[p->row]&&(q->down->col<p->col)))q=q->down;p->down=q->down;q->down=p;}delete[]cp;return in;}template<class Type> MatrixNode<Type>* LinkMatrix<Type>::Head(int i){MatrixNode<Type>*a;a=head->next;for(int j=1;j<i;j++){a=a->next;}return a;}template<class Type>void LinkMatrix<Type>::InsertInCol(MatrixNode<Type>*p) {MatrixNode<Type>*pre,*ch=Head(p->col);pre=ch;while(pre->down!=ch&&pre->down->row<p->row)pre=pre->down;p->down=pre->down;pre->down=p;}template<class Type>void LinkMatrix<Type>::DeleteInCol(MatrixNode<Type>*p) {MatrixNode<Type>*pre,*ch=Head(p->col);pre=ch;while(pre->down!=ch&&pre->down!=p)pre=pre->down;if(pre->down==p){pre->down=p->down;delete p;}//else throw invalid_arguement("No such a Node to be deleted in Delet eInCol()");}template<class Type> //重载符合赋值运算符+=LinkMatrix<Type>&LinkMatrix<Type>::operator +=(const LinkMatrix<Type> &a) {MatrixNode<Type> *pre,*pa,*h,*ah,*p,*tmp;if(head->col !=a.head->col||head->row !=a.head->row)//非同型矩阵不可相加cout<<"The two matrice aren't isomorphic!";//throw domain_error("The two matrice aren't isomorphic!");h=head->next;ah=a.head->next; //h、ah指向当前处理行的头结点while(h !=head){ //逐一处理各行pre=h; p=h->right; //p指向被加矩阵的当前结点,pre指向其前驱pa=ah->right; //pa分别指向加矩阵的当前结点while(pa !=ah) { //处理当前行if(p !=h&&(p->col<pa->col)){ //若被加矩阵的列标更小,则比较下一个pre=p; p=p->right;}else if(p==h||p->col>pa->col){ //若加矩阵的列标更小,则插入tmp=new MatrixNode<Type>(*pa)pre->right=tmp; //在行链表中插入pa复制结点tmptmp->right=p;InsertInCol(tmp); //在列表中插入tmppre=tmp; //当前指针p的前驱变为tmppa=pa->right;}else { //列标相同,则做加法p->data +=pa->data;if(!p->data) { //和为0,则删除之(行、列都要删除)tmp=p;p=p->right;pre->right=p;//在行链表中将tmp摘下DeleteInCol(tmp); //在列链表中将tmp删除}pre=p;p=p->right;pa=pa->right;}}h=h->next; ah=ah->next; //处理下一行}return *this;}template<class Type> //重载加法运算符+LinkMatrix<Type> operator +(const LinkMatrix<Type> &a,const LinkMatrix<Typ e> &b){LinkMatrix<Type> c(a); //复制构造函数得到被加矩阵A的一个副本放在矩阵C中c+=b;return c;}template<class Type>ostream & operator<<(ostream & out ,LinkMatrix<Type>& a) {for(int i=1;i<=a.head->row;i++){MatrixNode<Type>*b=a.Head(i);b=b->right;for(int j=1;j<=a.head->col;j++){if(b->row==i&&b->col==j){cout<<b->data<<' ';b=b->right;}else{cout<<'0'<<' ';}}cout<<endl;}return out;}int main(){LinkMatrix<int>a,b,c;cin>>a;cout<<"A矩阵为:\n"<<a<<endl;cin>>b;cout<<"B矩阵为:\n"<<b<<endl;c=a+b;cout<<"A+B=\n"<<c<<endl;system("pause");return 0;}。

相关主题