稀疏矩阵的十字链表加法

合集下载

稀疏矩阵引用十字链表运算

稀疏矩阵引用十字链表运算

稀疏矩阵应用摘要本课程设计主要实现在三元组存储结构与十字链表存储结构下输入稀疏矩阵,并对稀疏矩阵进行转置,相加,相乘操作,最后输出运算后的结果。

在程序设计中,考虑到方法的难易程度,采用了先用三元组实现稀疏矩阵的输入,输出,及其转置,相加,相乘操作的方法,再在十字链表下实现。

程序通过调试运行,结果与预期一样,初步实现了设计目标。

关键词程序设计;稀疏矩阵;三元组;十字链表1 引言•课程设计任务本课程设计主要实现在三元组存储结构与十字链表存储结构下输入稀疏矩阵,并对稀疏矩阵进行转置,相加,相乘操作,最后输出运算后的结果。

稀疏矩阵采用三元组和十字链表表示,并在两种不同的存储结构下,求两个具有相同行列数的稀疏矩阵A和B的相加矩阵C,并输出C;求出A的转置矩阵D,输出D;求两个稀疏矩阵A和B的相乘矩阵E,并输出E。

•课程设计性质数据结构课程设计是重要地实践性教学环节。

在进行了程序设计语言课和《数据结构》课程教学的基础上,设计实现相关的数据结构经典问题,有助于加深对数据结构课程的认识。

本课程设计是数据结构中的一个关于稀疏矩阵的算法的实现,包括在三元组和十字链表下存储稀疏矩阵,并对输入的稀疏矩阵进行转置,相加,相乘等操作,最后把运算结果输出。

此课程设计要求对数组存储结构和链表存储结构非常熟悉,并能熟练使用它们。

1.3课程设计目的其目的是让我们在学习完C、数据结构等课程基础上,掌握多维数组的逻辑结构和存储结构、掌握稀疏矩阵的压缩存储及转置,相加,相乘等基本操作,并用不同的方法输出结果,进一步掌握设计、实现较大系统的完整过程,包括系统分析、编码设计、系统集成、以及调试分析,熟练掌握数据结构的选择、设计、实现以及操作方法,为进一步的应用开发打好基础。

•需求分析2.1设计函数建立稀疏矩阵及初始化值和输出稀疏矩阵的值本模块要求设计函数建立稀疏矩阵并初始化,包括在三元组结构下和十字链表结构下。

首先要定义两种不同的结构体类型,在创建稀疏矩阵时,需要设计两个不同的函数分别在三元组和十字链表下创建稀疏矩阵,在输入出现错误时,能够对错误进行判别处理,初始化稀疏矩阵都为空值,特别注意在十字链表下,对变量进行动态的地址分配。

十字链表法存储稀疏矩阵

十字链表法存储稀疏矩阵

十字链表法存储稀疏矩阵稀疏矩阵是指其中大部分元素为0的矩阵。

在实际应用中,稀疏矩阵的存储和计算都会带来一定的困扰。

为了高效地存储和处理稀疏矩阵,我们可以使用十字链表法。

一、稀疏矩阵的特点稀疏矩阵的特点是其中绝大部分元素为0,而只有少部分非零元素。

这导致稀疏矩阵的存储空间浪费很大,因此需要采取一种有效的存储方式。

二、十字链表法的原理十字链表法是一种组合了链表和线性表的数据结构,用于存储稀疏矩阵。

具体实现如下:1. 定义两个链表headRow和headCol,分别用于存储行和列的头节点;2. 每个非零元素都对应一个结点,结点包含四个属性:行号row、列号col、值value以及指向下一个非零元素的指针nextRow和nextCol;3. headRow链表中的每个节点都指向同一行中的第一个非零元素,而headCol链表中的每个节点都指向同一列中的第一个非零元素;4. 非零元素之间通过nextRow和nextCol指针连接。

通过这种方式,我们可以高效地存储稀疏矩阵,并可以方便地进行矩阵的各种操作。

三、十字链表法的优势相比于其他存储稀疏矩阵的方法,十字链表法有以下几个优势:1. 空间利用率高:相比于使用二维数组存储,十字链表法可以大大减少存储空间的浪费,因为只存储非零元素及其位置信息;2. 支持高效的插入和删除操作:十字链表法可以通过调整指针的指向来进行插入和删除操作,而不需要像其他方法那样移动元素;3. 方便进行矩阵操作:通过十字链表法,我们可以方便地进行稀疏矩阵的各种操作,如矩阵相加、矩阵相乘等。

四、十字链表法的应用十字链表法广泛地应用于各个领域,特别是在图论和网络分析中。

在这些领域中,往往需要处理大规模的稀疏矩阵,而十字链表法能够有效地解决这个问题。

以社交网络为例,社交网络中的用户和用户之间往往存在着复杂的关系。

通过将社交网络建模成稀疏矩阵,可以使用十字链表法来存储和处理这些关系。

这样可以方便地进行各种网络分析操作,如查找某个用户的好友、计算两个用户之间的距离等。

稀疏矩阵的十字链表存储

稀疏矩阵的十字链表存储

稀疏矩阵的⼗字链表存储稀疏矩阵的压缩存储有⼏种⽅式,如:三元组顺序表、⾏逻辑链接的顺序表和⼗字链表。

使⽤链表存储的好处是:便于矩阵中元素的插⼊和删除。

例如:“将矩阵B加到矩阵A上”,那么矩阵A存储的元素就会有变动。

⽐如会增加⼀些⾮零元,或者删除⼀些元素(因为b ij+a ij=0)。

下图是矩阵M和M的⼗字链表存储:⼗字链表及其结点可⽤如下结构体表⽰:typedef struct OLNode{int i, j; // ⾮零元的⾏列下标ElemType e;struct OLNode *right, *down; // 向右域和向下域} OLNode, *OLink;typedef struct{OLink *rhead, *chead; // ⾏链表和列链表的头指针数组int mu, nu, tu; // 稀疏矩阵的⾏数、列数和⾮零元个数} CrossList;在通过代码创建⼗字链表时,要特别注意right、down和rhead、chead这些指针的赋值。

现在来看“将矩阵B加到矩阵A上”这个问题。

所要做的操作:a ij +b ij,其结果⼀共会有4种情况:1. a ij(b ij = 0)(不做变化)2. b ij(a ij = 0)(在A中插⼊⼀个新结点)3. a ij +b ij ≠ 0 (改变结点a ij的值域)4. a ij +b ij = 0 (删除结点a ij)假设指针pa和pb分别指向矩阵A和B中⾏值相同的两个结点,对于上述4种情况的处理过程为:1. 若“pa == NULL”或“pa->j⼤于pb->j”,则在矩阵A中插⼊⼀个值为b ij的结点。

并且需要修改同⼀⾏前⼀结点的right指针,和同⼀列前⼀结点的down指针。

2. 若“pa->j⼩于pb-j”,则pa指针右移⼀步。

3. 若“pa->j等于pb-j”,并且“pa->e + pb->e != 0”,则修改pa->e即可。

408考稀疏矩阵十字链表

408考稀疏矩阵十字链表

408考稀疏矩阵十字链表稀疏矩阵是指大部分元素为零的矩阵。

在很多实际应用中,如图像处理、网络分析等领域,大型矩阵中的非零元素只占很小一部分。

为了节省存储空间和提高运算效率,我们可以使用稀疏矩阵来表示这些矩阵。

408考稀疏矩阵十字链表是一种常用的稀疏矩阵存储结构。

它通过将非零元素按行和列分别排列,并使用链表将它们连接在一起,从而实现对稀疏矩阵的高效存储和操作。

在408考中,稀疏矩阵十字链表是一种常用的数据结构,用于表示稀疏矩阵。

它是由徐仲恺老师于1971年提出的,是一种改进的稀疏矩阵链表存储结构。

相比于其他存储结构,稀疏矩阵十字链表具有存储空间小、插入和删除元素方便等优点。

稀疏矩阵十字链表的基本思想是将矩阵分解为行链表和列链表两部分,通过链表将非零元素连接起来。

具体来说,稀疏矩阵十字链表包含三个链表:行链表、列链表和非零元素链表。

行链表是由一组头指针组成的链表,每个头指针指向一行的第一个非零元素。

列链表是由一组头指针组成的链表,每个头指针指向一列的第一个非零元素。

非零元素链表则是将矩阵中的非零元素按照行优先的顺序连接起来。

通过这种方式,我们可以通过行链表和列链表快速找到某一行或某一列的非零元素,并可以在常数时间内插入和删除元素。

同时,由于非零元素链表是按照行优先的顺序连接的,因此可以按照矩阵的行优先顺序遍历非零元素。

使用稀疏矩阵十字链表存储稀疏矩阵可以大大减少存储空间的占用。

对于一个m×n的矩阵,如果非零元素的个数为k,那么稀疏矩阵十字链表的存储空间复杂度为O(k+max(m,n))。

相比之下,使用普通的二维数组存储矩阵需要O(m×n)的存储空间。

稀疏矩阵十字链表还可以实现矩阵的加法、减法和乘法等基本运算。

在进行运算时,我们只需要遍历非零元素链表,并根据链表中的信息进行相应的计算,而无需考虑矩阵中的零元素,从而提高了运算效率。

408考稀疏矩阵十字链表是一种高效的稀疏矩阵存储结构。

数据结构 课程设计 十字链表

数据结构 课程设计 十字链表

数据结构课程设计十字链表xx学院一、问题的分析和任务定义:该设计是采用十字链表表示稀疏矩阵,并实现矩阵的加法运算。

还要检查有关运算的条件,并对错误的条件产生报警。

根据对该程序任务的理解,对本程序分别从以下几个方面进行分析: 1.输入数据的的类型和输入的范围该程序首先输入稀疏矩阵的行数和列数,再输入一个有非零元素的行号,有非零元素的列号,再输入非零元素的值,然后输入当前行下一个元素所在的列,如果该行只有一个非零元素就直接输入-1结束当前行的一组数据,如果还有其他的非零元素的话就输入当前行下一个非零元素所在的列,就这样,直到该当前行的非零元素输入完。

然后再输入当前列下一个非零元素的所在的行,其步骤与前一步相同。

其输入值都为稀疏矩阵的数据,类型都为整型。

2.输出数据的形式这样得到一个稀疏矩阵a,以同样的方法就可以得到另一个稀疏矩阵b,最后就可以得到稀疏矩阵a和稀疏矩阵b的和矩阵.输出是以稀疏矩阵的标准形式输出的。

输出值的有两种:一种是字符,一种是整数。

输出的字符型数据是稀疏矩阵的代号,输出的整型数据为稀疏矩阵的值。

3.测试数据测试数据一:测试数据二:稀疏矩阵的行数与列数:3 3 稀疏矩阵的行数与列数:3 3 矩阵a:矩阵b:矩阵a:矩阵b: 2 0 0 0 0 2 2 0 0 0 0 00 0 6 3 0 0 0 0 0 0 0 07 0 0 2 0 5 0 0 0 7 0 0二、概要设计和数据结构的选择:1.算法(程序)中用到的所有各种数据类型的定义:定义整型数据为int m,int n,分别代表矩阵的行和列;定义十字链表类型结点OLnode *h,*p分别代表为头结点开辟空间和指向下一结点;在主函数中定义OLnode *a,*b,分别表示a,b两个稀疏矩阵。

2.各程序模块之间的层次关系:程序中用到的函数:1 OLnode *create(int m,int n); 创建以十字链表表示的一个元素全为零的稀疏矩阵。

采用十字链表表示稀疏矩阵,并实现矩阵的加法运算

采用十字链表表示稀疏矩阵,并实现矩阵的加法运算

采用十字链表表示稀疏矩阵,并实现矩阵的加法运算课程设计所抽题目:采用十字链表表示稀疏矩阵,并实现矩阵的加法运算。

要求:要检查有关运算的条件,并对错误的条件产生报警。

问题分析和建立模型:本题目主要是运用所学知识,用十字链表的方法去表示稀疏矩阵,并使之可以在两矩阵间进行相加。

而后,若有错误,则对错误进行警报。

框架搭建:1选择File|New菜单项,弹出New对话框,选择Files标签,选中C++ Source File项,在File编辑器中输入项目名称“十字链表表示稀疏矩阵实现加法”,在Location编辑框中输入项目所在目录,按下OK 按钮即可。

2在操作界面中输入,程序代码。

(1)结构体和共用体的定义#include#include#define smax 45typedef int datatype;typedef struct lnode(2)建立稀疏矩阵的函数,返回十字链表头指针int i,j;struct lnode *cptr,*rptr;union{struct lnode *next;datatype v;}uval;}link;int flag=0;建立十字链表头结点head=(link *)malloc(sizeof(link));建立头结点循环链表for(i=1;i<=s;i++)(3)插入结点函数p=(link *)malloc(sizeof(link));p->i=0;p->j=0;p->rptr=p;p->cptr=p;cp[i]=p; cp[i-1]->uval.next=p;}cp[s]->uval.next=head;for(k=1;k<=t;k++){printf("\t 第%d个元素(行号i 列号j 值v,数字间用空格分隔):",k); scanf("%d%d%d",&i,&j,&v);p=(link *)malloc(sizeof(link));p->i=i;p->j=j;p->uval.v=v;q=cp[i];while((q->rptr!=cp[i])&&(q->rptr->j<j))< p="">q=q->rptr;p->rptr=q->rptr;q->rptr=p;q=cp[j];while((q->cptr!=cp[j])&&(q->cptr->i<i))< p="">q=q->cptr;p->cptr=q->cptr;q->cptr=p;}return head;(4)输出十字链表的函数link *p,*q;p=(link *)malloc(sizeof(link));p->i=i;p->j=j;p->uval.v=v;q=cp[i];while((q->rptr!=cp[i])&&(q->rptr->j<j))< p="">q=q->rptr;p->rptr=q->rptr;q->rptr=p;q=cp[j];while((q->cptr!=cp[j])&&(q->cptr->i<i))< p="">q=q->cptr ;p->cptr=q->cptr;q->cptr=p;(5)定义两个矩阵的非零元素,及两个矩阵的行和列数。

稀疏矩阵十字链表算法

稀疏矩阵十字链表算法

稀疏矩阵十字链表算法稀疏矩阵是指矩阵中绝大多数元素为0的矩阵。

在实际应用中,很多矩阵都具有稀疏性,即元素中大部分为0,而只有少数非零元素。

对于这种类型的矩阵,为了节省内存空间并提高计算效率,可以采用稀疏矩阵的存储方式。

稀疏矩阵的一种常用存储方式是十字链表。

十字链表是一种将稀疏矩阵以链表形式存储的数据结构,它能够有效地表示稀疏矩阵的非零元素,并且能够方便地进行插入、删除和查找操作。

稀疏矩阵十字链表的基本思想是将矩阵中的每个非零元素存储为一个结点,并将这些结点以行列坐标的方式进行链接。

具体来说,稀疏矩阵十字链表由两个链表组成:行链表和列链表。

行链表是一个以行为主的链表,每个结点表示矩阵中的一行。

每个结点包含三个字段:行号、列号和值。

行链表中的结点按照行号从小到大的顺序进行排列,同一行中的结点按照列号从小到大的顺序进行排列。

列链表是一个以列为主的链表,每个结点表示矩阵中的一列。

每个结点也包含三个字段:行号、列号和值。

列链表中的结点按照列号从小到大的顺序进行排列,同一列中的结点按照行号从小到大的顺序进行排列。

通过行链表和列链表,可以方便地进行插入、删除和查找操作。

插入操作可以通过在行链表和列链表中找到对应的位置,将新结点插入到相应的位置上。

删除操作可以通过在行链表和列链表中找到对应的位置,将对应的结点删除。

查找操作可以通过在行链表和列链表中找到对应的位置,获取对应的结点。

稀疏矩阵十字链表算法的优点是能够有效地存储稀疏矩阵,并且可以方便地进行插入、删除和查找操作。

相比于其他存储方式,稀疏矩阵十字链表可以节省更多的内存空间,并且具有更高的计算效率。

总结来说,稀疏矩阵十字链表算法是一种有效地存储稀疏矩阵的方法。

通过行链表和列链表的链接,可以方便地进行插入、删除和查找操作。

稀疏矩阵十字链表算法在实际应用中具有广泛的应用,能够节省内存空间并提高计算效率。

稀疏矩阵十字链表算法

稀疏矩阵十字链表算法

稀疏矩阵十字链表算法稀疏矩阵是指矩阵中大部分元素为0的矩阵。

在实际应用中,稀疏矩阵常常出现,比如图像处理、网络分析等领域。

由于稀疏矩阵中存在大量的0元素,传统的二维数组存储方式会造成内存空间的浪费,因此需要一种高效的数据结构来表示和存储稀疏矩阵。

稀疏矩阵十字链表算法就是一种解决这个问题的方法。

稀疏矩阵十字链表算法是一种基于链表的数据结构,用于表示和存储稀疏矩阵。

它通过两个链表来分别表示行和列,同时还使用了一个数据链表来存储非零元素的值和位置信息。

这种算法的核心思想是将稀疏矩阵的非零元素存储在链表中,并记录它们在矩阵中的位置信息,从而节省了存储空间。

具体来说,稀疏矩阵十字链表算法中,我们可以使用三个结构体来表示矩阵的行、列和非零元素。

其中,行和列的结构体包含了指向非零元素的指针和矩阵的维度信息。

非零元素的结构体包含了元素的值、行列坐标以及指向下一个非零元素的指针。

使用稀疏矩阵十字链表算法存储稀疏矩阵的好处是,它不仅节省了存储空间,还可以提高对稀疏矩阵的操作效率。

比如,对于稀疏矩阵的遍历操作,我们可以通过遍历链表的方式来实现,而不需要遍历整个矩阵,从而减少了时间复杂度。

除了存储和遍历操作,稀疏矩阵十字链表算法还可以支持其他一些常见的矩阵操作,比如矩阵的相加、相乘等。

对于这些操作,我们只需要按照链表的顺序进行遍历,并根据矩阵的位置信息进行计算即可。

稀疏矩阵十字链表算法的实现过程相对简单,但需要注意一些细节。

首先,我们需要确定稀疏矩阵的维度信息,并创建相应的行和列的链表头结点。

然后,我们可以按照行优先的方式遍历整个矩阵,将非零元素插入到链表中,并更新行和列的指针。

最后,我们可以根据需要进行各种矩阵操作。

稀疏矩阵十字链表算法是一种高效的存储和表示稀疏矩阵的方法。

它通过链表来存储非零元素,并记录它们在矩阵中的位置信息,从而节省了存储空间。

同时,它还可以支持各种常见的矩阵操作。

在实际应用中,稀疏矩阵十字链表算法可以提高程序的运行效率,减少内存的占用,是一种非常实用的数据结构算法。

用十字链表和一般方法分别实现稀疏矩阵的乘法和加法资料

用十字链表和一般方法分别实现稀疏矩阵的乘法和加法资料

#include<stdio.h>#include<malloc.h>#define Size 2501# define Size1 51typedef struct{int i;int j;int e;//非零元的值}triple; //定义三元组typedef struct{triple data[Size+1];//矩阵中的元素int rops[Size1+1];// rops[i]为第i行元素中的首非零元在data[]中的序号int mu;//行数int nu;//列数int tu;//非零元数} juzhen;//定义矩阵typedef struct node// 定义十字链表元素{int i,j,e;struct node *right,*down;// 该非零元所在行表和列表的后继元素}node,*link;typedef struct // 定义十字链表对象结构体{link *rhead,*chead;//行和列的头指针int m,n,t;// 系数矩阵的行数,列数,和非零元素个数}crosslist;void createcross(crosslist &M)//建立十字链表{int i,j,e,k;node *p,*q;printf("输入行,列和非零元数,空格隔开:\n");scanf("%d %d %d",&M.m,&M.n,&M.t);M.rhead=(link *)malloc((M.m+1)*sizeof(link));//给行和列的头指针分配内存M.chead=(link *)malloc((M.n+1)*sizeof(link));for(k=1;k<=M.m;k++)//初始化行,列的头指针M.rhead[k]=NULL;for(k=1;k<=M.n;k++)M.chead[k]=NULL;printf("输入非零元的行,列和值,空格隔开:\n");for(k=1;k<=M.t;k++)//输入非零元{scanf("%d %d %d",&i,&j,&e);p=(node *)malloc(sizeof(node));p->i=i;p->j=j;p->e=e;if(M.rhead[i]==NULL||M.rhead[i]->j>j)//插入元素所在行无非零元或首非零元的列标大于插入元素的列标{p->right=M.rhead[i];M.rhead[i]=p;}else{for(q=M.rhead[i];(q->right)&&q->right->j<j;q=q->right);//空循环找到第一个列标大于或等于插入元素列标的元素p->right=q->right;q->right=p;}if(M.chead[j]==NULL||(M.chead[j]->i>i))//插入元素所在列无非零元或首非零元的行标大于插入元素的行标{p->down=M.chead[j];M.chead[j]=p;}else{for(q=M.chead[j];(q->down)&&q->down->i<i;q=q->down);//空循环找到第一个行标大于或等于插入元素行标的元素p->down=q->down;q->down=p;}}}void printcross(crosslist A)//输出十字链表{if(A.m==0)printf("十字链表为空!\n");else{printf("十字链表为:\n");int i,j;for(i=1;i<=A.m;i++){link p=A.rhead[i];for(j=1;j<=A.n;j++){if((p)&&(j==p->j)){printf("%5d",p->e);p=p->right; }elseprintf("%5d",0);}printf("\n");}}printf("\n");}crosslist addcross(){printf("十字链表加法:\n");crosslist a,b;// 创建两个十字链表对象,并初始化createcross(a);createcross(b);node *pre,*h[51],*pa,*pb,*q;//定义辅助指针,pa,pb分别为a,b当前比较的元素,pre为pa的前驱元素int i,j,k=0,m,n; //h[j]指向j列的当前插入位置if(a.m!=b.m||a.n!=b.n)printf("格式不对,不能相加!\n");else{for(i=1;i<=a.m;i++){pa=a.rhead[i];pb=b.rhead[i];pre=NULL;for(j=1;j<=a.n;j++)h[j]=NULL;while(pb){p=(node *)malloc(sizeof(node)); // 开辟新节点,存储b中取出的元素p->i=pb->i;p->j=pb->j;p->e=pb->e;if(pa==NULL||pa->j>pb->j)//当a此行已经检查完或者pb因该放在pa前面{if (pre==NULL)a. rhead[p->i]=p;elsepre->right=p;p->right=pa;pre=p;if (h[p->j]==NULL)//当前插入位置下面无非零元//因为是逐行处理,so,h[p->j],依次下移//因此每次都是指向插入的位置{a. chead [p->j]= p;p->down = NULL;}else{p->down = h[p->j]->down;h[p->j]->down = p;}h[p->j]=p;//*******h[p->j]下移指向下次插入的位置pb=pb->right;//pb指向该行下个元素}else if((pa&&pa->j<pb->j))//只要移动pa的指针****先不加||(pb==NULL&&pa){pre = pa;h[pa->j]=pa;//移动h[],使其指向下次插入的位置pa = pa->right;}else if(pa->j==pb->j){pa->e+=pb->e;if(pa->e)//不为零{pre=pa;h[pa->j]=pa;pb=pb->right;//加else//pa->e为零,删除节点{if (pre ==NULL)a.rhead [pa->i]=pa->right;else{pre->right=pa->right;}p=pa;//p指向pa,用来在下面修改列指针pa=pa->right;if (h [p->j]==NULL)a.chead [p->j]=p->down;else{h[p->j]->down=p->down;}free(p);pb=pb->right;}}}}}return a;}void multycross(crosslist &c)//十字链表乘法{node *p,*q,*u,*v,*p1,*p2;crosslist a,b;link *r;int i,j,k,e;printf("十字链表乘法:\n");createcross(a);createcross(b);if(a.n!=b.m)printf("格式错误,不能相乘!\n");else{c.m=a.m;c.n=b.n;c.t=0;c.rhead=(link *)malloc((a.m+1)*sizeof(link));//给行和列的头指针分配内存c.chead=(link *)malloc((b.n+1)*sizeof(link));for(k=1;k<=a.m;k++)//初始化行,列的头指针c.rhead[k]=NULL;for(k=1;k<=b.n;k++)c.chead[k]=NULL;r=(link *)malloc((b.n+1)*sizeof(link));for(i=1;i<=a.m;i++){u=(node *)malloc(sizeof(node));u->e=0;u->i=0;u->j=0;for(k=1;k<=b.n;k++)//初始化r[]r[k]=u;p1=p=a.rhead[i];for(j=1;j<=b.n;j++){p=p1;q=b.chead[j];v=(node *)malloc(sizeof(node));//初始化v,v为将插入c矩阵的元素v->e=0;v->i=i;v->j=j;while(p&&q){if(p->j>q->i)q=q->down;else if(p->j<q->i)p=p->right;else{v->e+=p->e*q->e;p=p->right;q=q->down;}}if(v->e)//如果不为零,则插入c矩阵中{//同建立十字链表if(c.rhead[i]==NULL||c.rhead[i]->j>j)//插入元素所在行无非零元或首非零元的列标大于插入元素的列标{v->right=c.rhead[i];c.rhead[i]=v;}else{for(p2=c.rhead[i];(p2->right)&&(p2->right->j<j);p2=p2->right);//空循环找到第一个列标大于或等于插入元素列标的元素v->right=p2->right;p2->right=v;}if(c.chead[j]==NULL||c.chead[j]->i>i)//插入元素所在列无非零元或首非零元的行标大于插入元素的行标{v->down=c.chead[j];c.chead[j]=v;}else{for(p2=c.chead[j];(p2->down)&&(p2->down->i<i);p2=p2->down);//空循环找到第一个行标大于或等于插入元素行标的元素v->down=p2->down;p2->down=v;}}}}}}void create(juzhen & M) //创建稀疏矩阵{int i,t=0;printf("输入矩阵行数和列数and非零元的个数,以空格隔开:\n");scanf("%d %d %d",&M.mu,&M.nu,&M.tu);printf("输入矩阵非零元的行,列,和数值(中间空格隔开):\n");for(i=1;i<=M.tu;i++)scanf("%d %d %d",&M.data[i].i,&M.data[i].j,&M.data[i].e); //输入三元组的元素for(i=1;i<=Size1;i++)//初始化rops【】M.rops[i]=0;for(i=1,t=1;i<=M.mu;i++)//得到各行第一个元素的序号{M.rops[i]=t;while(M.data[t].i<=i&&t<=M.tu)//遇到i行非零元,则t累加t++;}}void add(juzhen A,juzhen B,juzhen & C)//稀疏矩阵加法{int k=1,temp=0,k1=1, k2=1;//k1,k2,k分别控制A,B,C中非零元的序号变化printf("稀疏矩阵加法:\n");create(A);create(B);if(A.mu!=B.mu||A.nu!=B.nu)printf("格式不对,不能相加!\n");else{while(k1<=A.tu&&k2<=B.tu)//当A,B中的非零元都没用完{if(A.data[k1].i<B.data[k2].i)//A当前k1指向的元素的行标小于列标直接把data 【k1】的值赋给c中data【k】C.data[k++]=A.data[k1++];else if(A.data[k1].i>B.data[k2].i)//同上C.data[k++]=B.data[k2++];else//data[k1],data[k2]行标相同{if(A.data[k1].j>B.data[k2].j)//data[k1]列标大于data[k2]列标,则把data[k2]的值赋给data[k]C.data[k++]=B.data[k2++];else if(A.data[k1].j<B.data[k2].j)//同上C.data[k++]=A.data[k1++];else //行,列标都相同{temp=0;temp=A.data[k1].e+B.data[k2].e;if(temp)//相加后不为零{C.data[k].i=A.data[k1].i;C.data[k].j=A.data[k1].j;C.data[k].e=temp;k++;}k1++;k2++;}}}while(k1<=A.tu)//B中非零元已用完,A中还有非零元C.data[k++]=A.data[k1++];while(k2<=B.tu)//A中非零元已用完,B中还有非零元C.data[k++]=B.data[k2++];C.mu=A.mu;//确定C的行列数和非零元个数C.nu=A.nu;C.tu=k-1;}}void print(juzhen A)//输出稀疏矩阵{printf("\n矩阵为:\n");int i,j,k=1;if(A.mu==0)printf("矩阵为空!\n");else if(A.tu==0)//矩阵元素为空printf("零矩阵!\n");elsefor(i=1;i<=A.mu;i++)//逐行输出{for(j=1;j<=A.nu;j++){if(A.data[k].i==i&&A.data[k].j==j)//行和列分别对应相等则输出相应非零元,否则输出零printf("%5d",A.data[k++].e);elseprintf("%5d",0);}printf("\n");//该行输出结束,空行输出下一行}printf("\n");}void multy(juzhen A,juzhen B,juzhen &C)//稀疏矩阵乘法{int arow,brow,ccol,temp[51],p,q,t,tp,i;//各变量代表含义见下面printf("稀疏矩阵乘法:\n");create(A);create(B);if(A.nu!=B.mu)printf("格式错误,不能相乘!\n");else{C.mu=A.mu;//初始化c的行列及非零元个数C.nu=B.nu;C.tu=0;if(A.nu!=B.mu)printf("A,B格式不对不能相乘!\n");else //{for(arow=1;arow<=A.mu;arow++)//arow为当前A矩阵的行标{for(i=0;i<51;i++)//初始化temptemp[i]=0;if(arow<A.mu)tp=A.rops[arow+1];//tp为arow+1行的首非零元在data【】中的序号else //arow为最后一行tp=A.tu+1;for(p=A.rops[arow];p<tp;p++)//p为A中当前元素在data[]中的序号{brow=A.data[p].j;//brow为与B矩阵中的相应行对应的A中当前元素的列标if(brow<B.mu)t=B.rops[brow+1];//t为brow+1行的首非零元在B中data【】中的序号else //brow大小等于B.mut=B.tu+1;for(q=B.rops[brow];q<t;q++)//q为B中当前元素在B.data[]中的序号{ccol=B.data[q].j;//ccol:data[p]*data[q]所得结果所在的列temp[ccol]+=A.data[p].e*B.data[q].e;//temp【ccol】:相乘所得的C 矩阵中第arow行cool列元素的值}}for(ccol=1;ccol<=B.nu;ccol++)//if(temp[ccol])//temp【ccol】不为零,则把值赋到c中,c.tu加1。

稀疏矩阵的十字链表存储结构

稀疏矩阵的十字链表存储结构

稀疏矩阵的十字链表存储结构
稀疏矩阵是指矩阵中绝大多数元素为0,而仅有少数元素非0,这种矩阵的存在会占用大量的存储空间,而且在进行一些操作时也会变得非常低效。

为了解决这个问题,可以采用十字链表的方式对稀疏矩阵进行存储。

十字链表存储结构是一种非常高效的稀疏矩阵存储方法。

它将矩阵中所有非零元素按行列坐标分别存储到两个链表中,并且在每个节点中还包含指向该元素左右上下四个方向节点的指针,形成一个类似于十字路口的结构。

这样一来,我们就可以在O(n)的时间内轻松地遍历矩阵中所有的非零元素,而且还能够快速地定位和更新某个元素的值,大大提高了存储和处理的效率。

在十字链表存储结构中,我们通常会使用头节点来记录矩阵的大小和非零元素的总数,以及行列链表的头指针。

节点中的数据需要同时包含行列坐标和元素的值,这样才能够快速地进行查找和替换。

同时,在插入或删除一个元素时,我们需要更新该元素所在节点的邻接节点的指针,以保证整个结构的完整性和正确性。

总的来说,十字链表存储结构是一种非常高效和灵活的稀疏矩阵存储方案,可以大大减小矩阵的存储空间和处理时间,同时也可以满足各种复杂的操作需求。

在实际应用中,我们可以根据具体的问题和数据特征灵活地选择适合的数据结构和算法,来达到更好的效果和效率。

十字链表实现矩阵的加法

十字链表实现矩阵的加法

十字链表实现矩阵的加法:/*---------------------------------------------------------------------------------用十字链表实现稀疏矩阵的加法--------------------------------------------编译环境:VS 2013---------------------------------------------------------------------------------------*/#define_CRT_SECURE_NO_WARNINGS//用于取消VS 2013对printf、scanf等函数的警告#include<stdio.h>#include<stdlib.h>#define MAXSIZE 50typedef int ElemType;typedef struct matrixnode//结构体和共用体的定义{int i, j;struct matrixnode *right, *down;union{ElemType value;struct matrixnode *next;}tag;}manode;manode *creatcroslist(); //建立稀疏矩阵的函数,返回十字链表头指针void insert(int i, int j, int value, manode *cp[]);//插入结点函数manode *add(manode *A, manode *B); //矩阵相加void print(manode *M); //输出十字链表的函数void main(){manode *A, *B, *C;printf("正在获取稀疏矩阵A......\n");A = creatcroslist();system("cls");printf("正在获取稀疏矩阵B......\n");B = creatcroslist();system("cls");printf("稀疏矩阵A:\n");print(A);printf("稀疏矩阵B:\n");print(B);C = add(A, B);puts("稀疏矩阵A与稀疏矩阵B的和为:");print(C);}manode *creatcroslist(){manode *p, *q, *head, *cp[MAXSIZE];int i, j, k, m, n, t, s;ElemType value;printf("请输入行、列、非零元素个数(中间用逗号隔开):");scanf("%d,%d,%d", &m, &n, &t);if (m > n)s = m;elses = n;head = (manode *)malloc(sizeof(manode));//建立十字链表头结点head->i = m;head->j = n;cp[0] = head;//cp[]是临时指针数组,分别指向头结点和行、列表头结点for (i = 1; i <= s; i++)//建立头结点循环链表{p = (manode *)malloc(sizeof(manode));p->i = 0;p->j = 0;p->right = p;p->down = p;cp[i] = p;cp[i - 1]->tag.next = p;}cp[s]->tag.next = head;for (k = 1; k <= t; k++){printf("第%d个非零元素的行号、列号、元素值(中间用逗号隔开):", k);scanf("%d,%d,%d", &i, &j, &value);p = (manode *)malloc(sizeof(manode));p->i = i;p->j = j;p->tag.value = value;q = cp[i];while ((q->right != cp[i]) && (q->right->j < j))q = q->right;p->right = q->right;q->right = p;q = cp[j];while ((q->down != cp[j]) && (q->down->i < i))q = q->down;p->down = q->down;q->down = p;}return head;}void insert(int i, int j, int value, manode *cp[]){manode *p, *q;p = (manode *)malloc(sizeof(manode));p->i = i;p->j = j;p->tag.value = value;//以下是经*p结点插入第i行链表中q = cp[i];while ((q->right != cp[i]) && (q->right->j < j))q = q->right;//在第i行中找第一个列号大于j的结点*(q->right)//找不到时,*q是该行表上的尾结点p->right = q->right;q->right = p;//*p插入在*q之后//以下是将结点插入第j列链表中q = cp[j];//取第j列表头结点while ((q->down != cp[j]) && (q->down->i < i))q = q->down;//在第j行中找第一个列号大于i的结点*(q->down)//找不到时,*q是该行表上的尾结点p->down = q->down;q->down = p;//*p插入在*q之后}manode *add(manode *A, manode *B){manode *p, *q, *u, *v, *r, *cp[MAXSIZE], *C;//p,q控制十字链A的行列,u,v控制十字链B的行列int s, i;if (A->i != B->i || A->j != B->j){puts("稀疏矩阵A与稀疏矩阵B不能相加!");exit(0);}//建立C的表头环链C = (manode *)malloc(sizeof(manode));C->i = A->i; C->j = A->j;if (C->i > C->j)s = C->i; else s = C->j;cp[0] = C;for (i = 1; i <= s; i++){r = (manode *)malloc(sizeof(manode));r->i = 0; r->j = 0;r->right = r; r->down = r;cp[i] = r;cp[i - 1]->tag.next = r;}cp[s]->tag.next = C;//矩阵相加p = A->tag.next; u = B->tag.next;while (p != A && u != B){q = p->right;v = u->right;if (q == p && v != u)//矩阵A中第p行为空,矩阵B的第u行不为空while (v != u)//将B的行的都复制到和矩阵中{insert(v->i, v->j, v->tag.value, cp);v = v->right;}else if (v == u && q != p)//矩阵A中第p行不为空,矩阵B的第u行为空while (q != p){insert(q->i, q->j, q->tag.value, cp);q = q->right;}else if (q != p && v != u)//矩阵B的第u行和矩阵A的第p行都不为空{while (q != p && v != u){if(q->j<v->j)//如果A中有元素的列数小于B的,将A中的所有小于B的值都插到C中{insert(q->i, q->j, q->tag.value, cp);q = q->right;}else if (q->j>v->j)//如果B中有元素的列数小于A的,将A中的所有小于B的值都插到C中{insert(v->i, v->j, v->tag.value, cp);v = v->right;}else//A、B当前是在同一个位置,判断加的和是否为零,不为零才做加法运算{if (q->tag.value + v->tag.value != 0)insert(q->i, q->j, (q->tag.value + v->tag.value), cp);q = q->right; v = v->right;}}if (q == p && v != u)//如果B未处理完,将B中未处理的值都插入到和矩阵中while (v != u){insert(v->i, v->j, v->tag.value, cp);v = v->right;}else if (v == u && q != p)//如果A未处理完,将A中未处理的值都插入到和矩阵中while (q != p){insert(q->i, q->j, q->tag.value, cp);q = q->right;}}p = p->tag.next;u = u->tag.next;//A,B都指向下一行}return C;}void print(manode *M){manode *p, *q, *r;//p是指向行,q是指向列,r是指向某一节点的临时指针int k, t, col, row;col = M->j;//矩阵M的列数p = M->tag.next;//p指向第一个结点,不是头结点row = 1;while (row <= M->i)//判断行是否循环完{q = p->right;//p指向这一行的一个值r = p;//r指向这一行的头结点while (q != p)//判断列是否循环完{for (k = 1; k < (q->j - r->j); k++)//输出同一行上两非零数据间的零printf(" 0");printf("%4d", q->tag.value);//输出那个非零值q = q->right;//q指向这一行的下一个元素r = r->right;//r指向q前面的一个非零元素}k = r->j;//k的值是某一行的最后一个非零元的列数for (t = k; t < col; t++)//输出一行上最后一个非零元后面的零printf(" 0");printf("\n\n");p = p->tag.next;//p指向下一行row++;}}程序运行结果图:。

题目稀疏矩阵的相加

题目稀疏矩阵的相加

题目: 稀疏矩阵的相加1、问题描述稀疏矩阵是指那些多数元素为零的矩阵。

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

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

以“带行逻辑链接信息”的三元组顺序表表示稀疏矩阵,实现两个矩阵相加运算。

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

2、设计2.1.存储结构设计稀疏矩阵的行逻辑连接的顺序表存储结构表示如下:#define MAXSIZE 20 /*非零元个数最大值*/#define MAXRC 10 /*各行第一个非零元总数最大值*/typedef struct{int i,j; /*行下标,列下标*/int e; /*非零元值*/}Triple;typedef struct { /*行逻辑链接的顺序表*/Triple data[MAXSIZE+1]; /*非零元三元组表,data[0]未用*/int rpos[MAXRC+1]; /*各行第一个非零元的位置表*/int mu,nu,tu; /*阵的行数、列数和非零元个数*/ }TSMatrix;2.2.主要算法设计对2个矩阵相加的算法如下:bool AddSMatrix(TSMatrix M,TSMatrix N,TSMatrix &Q) /*求稀疏矩阵的和Q=M+N*/{int p=1,q=1,k=1;if(M.tu==0&&N.tu==0) /*为空矩阵的情况*/{cout<<"该矩阵为空矩阵"<<endl;return 0;}while(p<=M.tu) /*不为空矩阵的情况,先看M矩阵*/{if(M.data[p].i<N.data[q].i) /*M的行比N的小,Q取M的值*/{Q.data[k].i=M.data[p].i;Q.data[k].j=M.data[p].j;Q.data[k].e=M.data[p].e;k++;p++;}else if(M.data[p].i>N.data[q].i) /*M的行值比N的大取N的值*/ {Q.data[k].i=N.data[q].i;Q.data[k].j=N.data[q].j;Q.data[k].e=N.data[q].e;k++;q++;}else /*M的行值和N一样大的情况*/{if(M.data[p].j<N.data[q].j)/*M的列值比M的小取M的值*/{Q.data[k].i=M.data[p].i;Q.data[k].j=M.data[p].j;Q.data[k].e=M.data[p].e;k++;p++;}else if(M.data[p].j>N.data[q].j)/*M的列值比M的大取N的值*/ {Q.data[k].i=N.data[q].i;Q.data[k].j=N.data[q].j;Q.data[k].e=N.data[q].e;k++;q++;}else /*M和N的列值相等*/{if(M.data[p].e+N.data[q].e!=0)/*相加结果不为0才取M值*/{Q.data[k].i=M.data[q].i;Q.data[k].j=M.data[q].j;Q.data[k].e=M.data[q].e+N.data[p].e;k++;}p++;q++;}}}while(q<=N.tu) /*再看N矩阵,直接取N值*/{Q.data[k].i=N.data[q].i;Q.data[k].j=N.data[q].j;Q.data[k].e=N.data[q].e;k++;q++;}if(M.mu>N.mu) Q.mu=M.mu;/*Q的行和列的值取M,N的最大值*/else Q.mu=N.mu;if(M.nu>N.nu) Q.nu=M.nu;else Q.nu=N.nu;Q.tu=k-1;cout<<"相加成功"<<endl;return 1;}2.3.测试用例设计采用一下2个稀疏矩阵进行测试:M矩阵如下:3 0 0 50 -1 0 02 0 0 0N矩阵如下:0 21 0-2 40 03.调试报告3.1调试过程程序刚写完时有不少问题,像有些变量忘定义,符号错误等等,一些很低级的错误,主要是编程过程中不仔细造成的。

c语言稀疏矩阵应用代码实现三元组,十字链表下的稀疏矩阵的加、转、乘的实现。

c语言稀疏矩阵应用代码实现三元组,十字链表下的稀疏矩阵的加、转、乘的实现。

c语言稀疏矩阵应用代码实现三元组,十字链表下的稀疏矩阵的加、转、乘的实现。

在C语言中,实现稀疏矩阵的加法、转置和乘法涉及复杂的数据结构和算法。

其中,常用的表示稀疏矩阵的两种数据结构是三元组和十字链表。

下面我将为您提供一个简单的示例代码,用C语言实现稀疏矩阵的加法、转置和乘法操作,使用三元组表示法来表示稀疏矩阵。

首先,我们需要定义表示稀疏矩阵的三元组结构体:```c#include<stdio.h>#define MAX_SIZE100typedef struct{int row;int col;int value;}Element;typedef struct{int rows;int cols;int num_elements;Element data[MAX_SIZE];}SparseMatrix;```接下来,我们实现稀疏矩阵的加法、转置和乘法函数:```c#include<stdbool.h>//加法函数SparseMatrix addSparseMatrix(SparseMatrix matrix1,SparseMatrix matrix2){ SparseMatrix result;result.rows=matrix1.rows;result.cols=matrix1.cols;result.num_elements=0;int i=0,j=0;while(i<matrix1.num_elements&&j<matrix2.num_elements){if(matrix1.data[i].row<matrix2.data[j].row||(matrix1.data[i].row==matrix2.data[j].row&&matrix1.data[i].col<matrix2.data[j].col)){ result.data[result.num_elements++]=matrix1.data[i++];}else if(matrix1.data[i].row>matrix2.data[j].row||(matrix1.data[i].row==matrix2.data[j].row&&matrix1.data[i].col>matrix2.data[j].col)){ result.data[result.num_elements++]=matrix2.data[j++];}else{Element element;element.row=matrix1.data[i].row;element.col=matrix1.data[i].col;element.value=matrix1.data[i].value+matrix2.data[j].value;if(element.value!=0){result.data[result.num_elements++]=element;}i++;j++;}}while(i<matrix1.num_elements){result.data[result.num_elements++]=matrix1.data[i++];}while(j<matrix2.num_elements){result.data[result.num_elements++]=matrix2.data[j++];}return result;}//转置函数SparseMatrix transposeSparseMatrix(SparseMatrix matrix){ SparseMatrix result;result.rows=matrix.cols;result.cols=matrix.rows;result.num_elements=matrix.num_elements;int count[matrix.cols];int index[matrix.cols];for(int i=0;i<matrix.cols;i++){count[i]=0;}for(int i=0;i<matrix.num_elements;i++){count[matrix.data[i].col]++;}index[0]=0;for(int i=1;i<matrix.cols;i++){index[i]=index[i-1]+count[i-1];}for(int i=0;i<matrix.num_elements;i++){int j=index[matrix.data[i].col];result.data[j].row=matrix.data[i].col;result.data[j].col=matrix.data[i].row;result.data[j].value=matrix.data[i].value;index[matrix.data[i].col]++;}return result;}//乘法函数SparseMatrix multiplySparseMatrix(SparseMatrix matrix1,SparseMatrix matrix2){ SparseMatrix result;if(matrix1.cols!=matrix2.rows){result.rows=0;result.cols=0;result.num_elements=0;return result;}result.rows=matrix1.rows;result.cols=matrix2.cols;result.num_elements=0;bool visited[matrix2.cols];for(int i=0;i<matrix2.cols;i++){visited[i]=false;}for(int i=0;i<matrix1.num_elements;i++){for(int j=0;j<matrix2.num_elements;j++){if(matrix1.data[i].col==matrix2.data[j].row){Element element;element.row=matrix1.data[i].row;element.col=matrix2.data[j].col;element.value=matrix1.data[i].value*matrix2.data[j].value; result.data[result.num_elements++]=element;visited[matrix2.data[j].col]=true;}}}for(int i=0;i<matrix2.cols;i++){if(!visited[i]){for(int j=0;j<matrix1.rows;j++){Element element;element.row=j;element.col=i;element.value=0;result.data[result.num_elements++]=element;}}}return result;}```请注意,上述代码只是一个简单示例,实际应用中可能需要根据具体需求进行优化和扩展。

表示稀疏矩阵的十字链表

表示稀疏矩阵的十字链表
链表
void invert(node *head)
{ node *p,*q,*r;

p=head;
q=p->next;
3
while(q!=NULL) /*没有后继时停止*/
.
{
1
r=q->next; q->next=p;

p=q;

q=r;
}
head->next=NULL;
head=p;
}
链表
例3.2
}
链表
例3.3
给出在双链表中第i个结点(i≥0)之后插入一个元素为x的 结点的函数。
解:在前面双链表一节中,已经给出了在一个结点之前 插入一个新结点的方法,在一个结点之后插入一个新结 点的思想与前面是一样的。
链表
void insert(dnode *head,int i,x)
{
dnode *s,*p;
link(node *head1,head2)
{

node *p,*q; p=head1;
3.
while(p->next!=head1)
2
p=p->next;

q=head2; while(q->next!=head2)

q=q->next;
p->next=head2;
q->next=head1;
对于每行、每列的循环链表都有一个空表 头结点,以利于元素的插入和删除运算。 这些空表头结点的行号、列号都标成零, 以便和其它结点相区别。
整个十字链表有一个总的空表头结点,在 一般结点标以行号、列号之处,此结点是 标出矩阵的行数m和列数n。
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

目录前言 (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;}。

相关文档
最新文档