十字链表实现矩阵的加法
数据结构实验五矩阵的压缩存储与运算学习资料

数据结构实验五矩阵的压缩存储与运算第五章矩阵的压缩存储与运算【实验目的】1. 熟练掌握稀疏矩阵的两种存储结构(三元组表和十字链表)的实现;2. 掌握稀疏矩阵的加法、转置、乘法等基本运算;3. 加深对线性表的顺序存储和链式结构的理解。
第一节知识准备矩阵是由两个关系(行关系和列关系)组成的二维数组,因此对每一个关系上都可以用线性表进行处理;考虑到两个关系的先后,在存储上就有按行优先和按列优先两种存储方式,所谓按行优先,是指将矩阵的每一行看成一个元素进行存储;所谓按列优先,是指将矩阵的每一列看成一个元素进行存储;这是矩阵在计算机中用一个连续存储区域存放的一般情形,对特殊矩阵还有特殊的存储方式。
一、特殊矩阵的压缩存储1. 对称矩阵和上、下三角阵若n阶矩阵A中的元素满足= (0≤i,j≤n-1 )则称为n阶对称矩阵。
对n阶对称矩阵,我们只需要存储下三角元素就可以了。
事实上对上三角矩阵(下三角部分为零)和下三角矩阵(上三角部分为零),都可以用一维数组ma[0.. ]来存储A的下三角元素(对上三角矩阵做转置存储),称ma为矩阵A的压缩存储结构,现在我们来分析以下,A和ma之间的元素对应放置关系。
问题已经转化为:已知二维矩阵A[i,j],如图5-1,我们将A用一个一维数组ma[k]来存储,它们之间存在着如图5-2所示的一一对应关系。
任意一组下标(i,j)都可在ma中的位置k中找到元素m[k]= ;这里:k=i(i+1)/2+j (i≥j)图5-1 下三角矩阵a00 a10 a11 a20 … an-1,0 … an-1,n-1k= 0 1 2 3 …n(n-1)/2 …n(n+1)/2-1图5-2下三角矩阵的压缩存储反之,对所有的k=0,1,2,…,n(n+1)/2-1,都能确定ma[k]中的元素在矩阵A中的位置(i,j)。
这里,i=d-1,(d是使sum= > k的最小整数),j= 。
2. 三对角矩阵在三对角矩阵中,所有的非零元素集中在以主对角线为中心的带内状区域中,除了主对角线上和直接在对角线上、下方对角线上的元素之外,所有其它的元素皆为零,见图5-3。
习题二和上机答案

习题二⒉1描述以下四个概念的区别:头指针变量,头指针,头结点,首结点(第一个结点)。
解:头指针变量和头指针是指向链表中第一个结点(头结点或首结点)的指针;在首结点之前附设一个结点称为头结点;首结点是指链表中存储线性表中第一个数据元素的结点。
若单链表中附设头结点,则不管线性表是否为空,头指针均不为空,否则表示空表的链表的头指针为空。
2.2简述线性表的两种存储结构有哪些主要优缺点及各自使用的场合。
解:顺序存储是按索引直接存储数据元素,方便灵活,效率高,但插入、删除操作将引起元素移动,降低了效率;而链式存储的元素存储采用动态分配,利用率高,但须增设表示结点之间有序关系的指针域,存取数据元素不如顺序存储方便,但结点的插入和删除十分简单。
顺序存储适用于线性表中元素数量基本稳定,且很少进行插入和删除,但要求以最快的速度存取线性表中的元素的情况;而链式存储适用于频繁进行元素动态插入或删除操作的场合。
2.3 在头结点为h的单链表中,把值为b的结点s插入到值为a的结点之前,若不存在a,就把结点s插入到表尾。
Void insert(Lnode *h,int a,int b){Lnode *p,*q,*s;s=(Lnode*)malloc(sizeof(Lnode));s->data=b;p=h->next;while(p->data!=a&&p->next!=NULL){q=p;p=p->next;}if (p->data==a){q->next=s;s->next=p;}else{p->next=s;s->next=NULL;}}2.4 设计一个算法将一个带头结点的单链表A分解成两个带头结点的单链表A和B,使A中含有原链表中序号为奇数的元素,而B中含有原链表中序号为偶数的元素,并且保持元素原有的相对顺序。
Lnode *cf(Lnode *ha){Lnode *p,*q,*s,*hb;int t;p=ha->next;q=ha;t=0;hb=(Lnode*)malloc(sizeof(Lnode));s=hb;while(p->next!=NULL){if (t==0){q=p;p=p->next;t=1;}else{q->next=p->next;p->next=s->next; s->next=p; s=p;p=p->next; t=0;}}s->next=NULL;return (hb);}2.5设线性表中的数据元素是按值非递减有序排列的,试以不同的存储结构,编写一算法,将x插入到线性表的适当位置上,以保持线性表的有序性。
邻接多重表和十字链表

邻接多重表(Adjacency Multilist)是无向图的另一种链式存储结构。
虽然邻接表是无向图的一种很有效的存储结构,在邻接表中容易求得顶点和边的各种信息。
但是,在邻接表中每一条边(vi , vj)有两个结点,分别在第i个和第j个链表中,这给某些图的操作带来不便。
[例如],在某些图的应用问题中需要对边进行某种操作,如对已被搜索过的边作记号或删除一条边等,此时需要找到表示同一条边的两个结点。
因此,在进行这一类操作的无向图的问题中采用邻接多重表作存储结构更为适宜。
邻接多重表的结构和十字链表类似。
在邻接多重表中,每一条边用一个结点表示,它由如下所示的六个域组成:其中,mark为标志域,可用以标记该条边是否被搜索过;ivex和jvex为该边依附的两个顶点在图中的位置;ilink指向下一条依附于顶点ivex的边;jlink指向下一条依附于顶点jvex的边,info为指向和边相关的各种信息的指针域。
每一个顶点也用一个结点表示,它由如下所示的两个域组成:其中,data域存储和该顶点相关的信息,firstedge域指示第一条依附于该顶点的边。
[例如],图7.12所示为无向图G2的邻接多重表。
十字链表十字链表对稀疏矩阵实施某些操作(例如A=A+B),可能会引起矩阵中非零元素的个数和位置的变化,如果用顺序方式(三元组表)来存储稀疏矩阵的非零元素,那么这些变化将引起与矩阵A对应的三元组表中大量结点的移动,效率较低,而采用链接存储结构则会避免这些问题.用链接存储实现稀疏矩阵有几种方式,我们介绍其中的一种:十字链表. 在稀疏矩阵的十字链表中,矩阵的每一行都设置为由一个表头结点引导的循环链表(简称为行链表),矩阵的每一列也都设置为由一个表头结点引导的循环链表(简称为列链表).矩阵的元素结构如下:其中LEFT,UP,ROW,COL,VAL分别表示该元素的左邻非零元素、上邻非零元素、所在的行、所在的列和它的值。
下图给出一个稀疏矩阵和它的十字链表:图5.2 正交链表这里,每一行和每一列都有一个表头结点:BASEROW[i],i=1,2,…,m(m行)BASECOL[j], j=1,2,…,n(n列)它们有如下特点:-1 = COL(Loc(BASEROW[i]))< 0-1 = ROW(Loc(BASECOL[j]))< 0因为行或列都是一个循环链表,所以行表头BASEROW[i]中的LEFT指针循环地链接到该行最右边的非零元素,列表头BASECOL[j]中的UP指针循环地链接到该列最下边的非零元素.下面,我们将用一个例子来说明十字链表的使用. 在解线性方程组、求矩阵的逆以及求解线性规划等实际问题中,都需要施行一种“主步骤”操作,即如下的矩阵变换:处于主行主列的元素a被称为主元素,主元素必须是非零元素:(5.1)所示的矩阵A,如以A[1][0]为主元素,即第1行为主行,第0列为主列,经主步骤操作后,就得到如下稀疏矩阵:读者或许已经注意到,变换前主行别列上元素b若为0,变换后该列的元素不变;同样,若别行主列元素c为0,变换后该行的元素不变.对于别行别列元素,事实上,若设某个主行非零元素c所在的列是j,某个主列非零元素b所在的行是i,那么整个矩阵中,只有这些A[i][j]需要处理.(1)变换前:A[i][j]=0;变换后:在十字链表中合适的位置插入一个新结点,该结点行号为i,列号为j,值为-b*c/a;(2)变换前:d=A[i][j]≠0;变换后:考察d-b*c/a=0是否成立?若不成立,则将该结点的value值更新为d-b*c/a;若成立,则将该结点从十字链表中删除.不难给出如下的主步骤操作算法. 该算法的控制过程是:首先处理主行,然后从下向上逐个处理别行.。
稀疏矩阵压缩的存储方法是

稀疏矩阵压缩的存储方法是稀疏矩阵压缩是一种数据结构,可以有效地占用存储空间,合理地存储稀疏矩阵。
通常来说,稀疏矩阵的元素大部分为0,只有少部分非零,所以采用压缩存储方法可以大大减少存储空间的使用。
稀疏矩阵的压缩存储方法有三种:顺序表压缩、链表压缩和十字链表压缩。
下面将对这三种方法进行详细介绍。
1.顺序表压缩方法:顺序表压缩方法是使用一个一维数组来存储稀疏矩阵。
数组的第一行存储矩阵的行数、列数、非零元素的个数。
数组的后续元素按行优先顺序存储矩阵的每一个非零元素。
例如,对于一个3*3的稀疏矩阵:1 0 00 0 23 0 0它的顺序表压缩形式为:3 3 2 第一行分别为行数、列数和非零元素个数1 1 1 第1个非零元素在第1行第1列,值为12 3 2 第2个非零元素在第2行第3列,值为23 1 3 第3个非零元素在第3行第1列,值为3在这个例子中,非零元素的个数为3,而原先需要占据9个空间的矩阵,现在只需要使用7个元素的数组就可以存储。
2.链表压缩方法:链表压缩方法首先将稀疏矩阵存储在单链表中。
单链表中的每一个节点包含4个数据域:行数,列数,元素值和指针域。
其中,指针域指向下一个非零元素节点。
例如,对于一个5*5的稀疏矩阵:0 0 0 0 03 0 0 0 00 0 1 0 00 0 0 2 00 0 0 0 0它的链表表示形式如下:(1,2,3)->(2,1,3)->(3,3,1)->(4,4,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即可。
用三元组表示稀疏矩阵的乘法

该结点除了( row , col , value )以外,还要有以下两个链域:
right: down: 用于链接同一列中的下一个非零元素。
row Down
col
Value right
第十二讲
1 1 3
1 4 5
2 2 -1
3 1 3
图5.23 十字链表的结构
第十二讲
十字链表的结构类型说明如下:
typedef struct OLNode
第十二讲
用三元组表实现稀疏矩阵的乘法运算
第十二讲
两个矩阵相乘也是矩阵的一种常用的运算。设矩阵 M 是
m1×n1 矩阵, N 是 m2×n2 矩阵;若可以相乘,则必须满足矩
阵 M 的列数 n1 与矩阵 N 的行数 m2 相等,才能得到结果矩阵 Q=M×N(一个m1×n2的矩阵)。
数学中矩阵Q中的元素的计算方法如下:
矩阵不仅节约了空间,而且使得矩阵某些运算的运算时间比经
典算法还少。但是在进行矩阵加法、减法和乘法等运算时,有 时矩阵中的非零元素的位置和个数会发生很大的变化。如
A=A+B, 将矩阵B加到矩阵A上,此时若还用三元组表表示法,
势必会为了保持三元组表“以行序为主序”而大量移动元素。
第十二讲
在十字链表中,矩阵的每一个非零元素用一个结点表示,
0 1 N 2 0
2 0 4 0
0 Q 1 0
6 0 4
图5.17 Q=M×N
第十二讲
图5.18 矩阵M、N、Q的三元组表
第十二讲
经典算法中,不论 M [ i ][ k ]、 N [ k ][ j ]是否为零,
for(k=1; k<=n1; k++)
十字链表存储稀疏矩阵算法
十字链表存储稀疏矩阵实现相乘算法#include <stdio.h>#include <stdlib.h>#include <assert.h>#define OK 1#define ERROR 0typedef struct list{int row;int colum;int value;struct list *right;struct list *down;}node,*element;typedef struct link{int row_size;int colum_size;int non_zero_amount;element *rhead;element *chead;}crosslist;int init_matrix(crosslist &one){one.row_size=0;one.colum_size=0;one.non_zero_amount=0;one.rhead=NULL;one.chead=NULL;return OK;}int creat_matrix(crosslist &one){int i;element news,temp;printf("Input the row size of the matrix:");scanf("%d",&one.row_size);printf("Input the colum size of the matrix:"); scanf("%d",&one.colum_size);printf("Input the non zero amount of the matrix:");scanf("%d",&one.non_zero_amount);one.rhead=(element*)malloc(sizeof(element)*(one.row_size+1));assert(one.rhead!=NULL);one.chead=(element*)malloc(sizeof(element)*(one.colum_size+1));assert(one.chead!=NULL);for(i=1;i<=one.row_size;i++)one.rhead[i]=NULL;for(i=1;i<=one.colum_size;i++)one.chead[i]=NULL;printf("/********************************/\n");for(i=1;i<=one.non_zero_amount;i++){news=(element)malloc(sizeof(node));assert(news!=NULL);do{printf("Input the script of the row:");scanf("%d",&news->row);}while(news->row>one.row_size);do{printf("Input the script of the colum:");scanf("%d",&news->colum);}while(news->colum>one.colum_size);printf("Input the value of the node:");scanf("%d",&news->value);if(!one.rhead[news->row]){news->right=NULL;one.rhead[news->row]=news;}else{for(temp=one.rhead[news->row];temp->right!=NULL;temp=temp->right)NULL;news->right=temp->right;temp->right=news;}if(!one.chead[news->colum]){news->down=NULL;one.chead[news->colum]=news;}else{for(temp=one.chead[news->colum];temp->down!=NULL;temp=temp->down)NULL;news->down=temp->down;temp->down=news;}printf("/*******************************/\n");}return OK;}int print_matrix(crosslist &one){element temp;int count;for(count=1;count<=one.row_size;count++){if(!one.rhead[count])continue;else{for(temp=one.rhead[count];temp!=NULL;temp=temp->right){printf("\t%d\t%d\t%d\n",temp->row,temp->colum,temp->value);printf("--------------------------------\n");}}}return OK;}int multi_matrix(crosslist one,crosslist two,crosslist &three){assert(one.colum_size==two.row_size);int i,j;int value;element insert;element pone,ptwo;element prow,pcolum;three.row_size=one.row_size;three.colum_size=two.colum_size;three.non_zero_amount=0;three.rhead=(element*)malloc(sizeof(element)*(three.row_size+1)); assert(three.rhead!=NULL);three.chead=(element*)malloc(sizeof(element)*(three.colum_size+1)); assert(three.chead!=NULL);for(i=1;i<=three.row_size;i++)three.rhead[i]=NULL;for(i=1;i<=three.colum_size;i++)three.chead[i]=NULL;for(i=1;i<=one.row_size;i++){for(j=1;j<=two.colum_size;j++){pone=one.rhead[i];ptwo=two.chead[j];value=0;while(pone!=NULL&&ptwo!=NULL){if(pone->colum==ptwo->row){value+=pone->value*ptwo->value;pone=pone->right;ptwo=ptwo->down;while(pone!=NULL&&ptwo!=NULL){if(pone->colum==ptwo->row){value+=pone->value*ptwo->value;pone=pone->right;ptwo=ptwo->down;}else if(pone->colum>ptwo->row){ptwo=ptwo->down;continue;}else{pone=pone->right;continue;}}if(value==0)break;insert=(element)malloc(sizeof(node));assert(insert!=NULL);insert->row=i;insert->colum=j;insert->value=value;insert->right=NULL;insert->down=NULL;three.non_zero_amount++;if(three.rhead[i]==NULL)three.rhead[i]=prow=insert;else{prow->right=insert;prow=insert;}if(three.chead[j]==NULL)three.chead[j]=pcolum=insert;else{pcolum->down=insert;pcolum=insert;}}else if(pone->colum>ptwo->row){ptwo=ptwo->down;continue;}else{pone=pone->right;continue;}}}}return OK;}int main(void){crosslist one,two,three;char flag;printf("<Creat the first matrix>\n");creat_matrix(one);putchar('\n');printf("Print the first matrix\n");printf("Row\tColum\tValue\n");printf("-----------------------------------\n");print_matrix(one);printf("<Initialization>\n");init_matrix(two);putchar('\n');printf("<Creat the second matrix>\n");creat_matrix(two);putchar('\n');printf("Print the second matrix\n");printf("Row\tColum\tValue\n");printf("-----------------------------------\n");print_matrix(two);printf("Multiply the two matrix\n");init_matrix(three);multi_matrix(one,two,three);printf("The result is below:\n");print_matrix(three);system("pause");}。
稀疏矩阵三元组实验报告
一、设计人员相关信息
1.设计者姓名、学号和班号:12地信李晓婧12012242983
2.设计日期:2014.
3.上机环境:VC++6.0
二、程序设计相关信息
1.实验题目:实验题6.4 假设n*n的稀疏矩阵A采用三元组表示,设计一个程序实现
如下功能:(1)生成稀疏矩阵三元组;(2)输出转置矩阵三元组。
| 1 0 3 1 |
| 0 1 0 0 |
| 0 0 1 0 |
| 0 0 1 1 |
2.实验项目组成:
(1)生成稀疏矩阵三元组;(2)输出转置矩阵三元组
3.实验项目的程序结构(程序中的函数调用关系图):
4.实验项目包含的各个文件中的函数的功能描述:
CreatMat:对一个二维稀疏矩阵创建其三元组表示,以行序方式扫描二维稀疏矩阵A,将其非零的元素插入到三元组t中。
DispMat:输出三元组。
从头到尾扫描三元组t,依次输出元素值。
TranMat:矩阵转置。
对一个m*n的矩阵A m*n,其转置矩阵是一个n*m的矩阵,设为
B n*m,满足a i,j=b i,j,其中0≤i≤m-1,0≤j≤n-1。
5.算法描述或流程图:
6.实验数据和实验结果:
7.出现的问题及解决方案
主函数缺少一次输出,稀疏矩阵没有显示。
解决方案:主函数加一个输出稀疏矩阵disp(A)。
三、程序盘
提交的程序盘应包含全部的源程序清单和可执行文件。
案例教学法在数据结构稀疏矩阵十字链表存储与运算教学中的应用
2011年6月 第3期 兴义民族师范学院学报 June 201 1
Journal of Xingyi Normal University for Nationalities No.3
案例教学法在数据结构稀疏矩阵十字链表存储与 运算教学中的应用
徐聚星 (贵州财经学院, 贵州贵阳550000)
摘要:数据结构课程作为一门较难的课程开设于低年级本科生教学中,由于学生的抽象逻辑思维 有限造成了学习较为困难。通过以稀疏矩阵十字链表存储与运算为例,简单从案例准备、案例分析与讨 论以及案例分析报告撰写等环节进行阐述,分析授课过程中遇到的问题,并予以研究和解决。以起到学 生在教学中的主体地位、激发学生学习主动性和自主性的目的,实现教学改革的优化。 关键词:数据结构;稀疏矩阵;案例教学 文章编号:1 009__0673(201 1)03--0059--04 中图分类号:G623.58 文献标识码:A
The Application of Case Study Method in Teaching Data Structure Sparse Matrix O ̄hogonal List Storage and O’peration XU Ju-xing (Guizhou University for Finance and Economics,Guiyang Guizhou 550004,China) Abstract:For undergraduates in junior grade,data structure is comparatively dificuh because their logic thinking is finite. This paper takes the storage and operation of sparse matrix cross chain table for example。case preparation。case analysis and discus— sion.and case analysis report writing and SO on are been expatiated.Problems met with in teaching process are analyzed and worked out,SO as to emphasize student-centered teaching mode,stimulate students’initiative and autonomy and optimize teaching reform eventually. Key words:data structure;sparse matrix;ease teaching
稀疏矩阵的十字链表存储结构
稀疏矩阵的十字链表存储结构
稀疏矩阵是指矩阵中绝大多数元素为0,而仅有少数元素非0,这种矩阵的存在会占用大量的存储空间,而且在进行一些操作时也会变得非常低效。
为了解决这个问题,可以采用十字链表的方式对稀疏矩阵进行存储。
十字链表存储结构是一种非常高效的稀疏矩阵存储方法。
它将矩阵中所有非零元素按行列坐标分别存储到两个链表中,并且在每个节点中还包含指向该元素左右上下四个方向节点的指针,形成一个类似于十字路口的结构。
这样一来,我们就可以在O(n)的时间内轻松地遍历矩阵中所有的非零元素,而且还能够快速地定位和更新某个元素的值,大大提高了存储和处理的效率。
在十字链表存储结构中,我们通常会使用头节点来记录矩阵的大小和非零元素的总数,以及行列链表的头指针。
节点中的数据需要同时包含行列坐标和元素的值,这样才能够快速地进行查找和替换。
同时,在插入或删除一个元素时,我们需要更新该元素所在节点的邻接节点的指针,以保证整个结构的完整性和正确性。
总的来说,十字链表存储结构是一种非常高效和灵活的稀疏矩阵存储方案,可以大大减小矩阵的存储空间和处理时间,同时也可以满足各种复杂的操作需求。
在实际应用中,我们可以根据具体的问题和数据特征灵活地选择适合的数据结构和算法,来达到更好的效果和效率。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
1 / 6 十字链表实现矩阵的加法: /*-------------------------------------------------------------- -------------------用十字链表实现稀疏矩阵的加法-------------------- ------------------------编译环境:VS 2013------------------------ ---------------------------------------------------------------*/ #define _CRT_SECURE_NO_WARNINGS//用于取消VS 2013对printf、scanf等函数的警告 #include #include
#define MAXSIZE 50 typedef 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); 2 / 6
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; else s = 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)) 3 / 6
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) { 4 / 6
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->jj)//如果A中有元素的列数小于B的,将A中的所有小于B的值都插到C中 { 5 / 6
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)//判断行是否循环完