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

合集下载

十字链表的画法

十字链表的画法

⼗字链表的画法
⼗字链表的画法
基本概念
⼗字链表(Orthogonal List)是有向图的另⼀种链式存储结构。

该结构可以看成是将有向图的邻接表和逆邻接表结合起来得到的。

⼊弧和出弧:⼊弧表⽰图中发出箭头的顶点,出弧表⽰箭头指向的顶点。

弧头和弧尾:弧尾表⽰图中发出箭头的顶点,弧头表⽰箭头指向的顶点。

同弧头和同弧尾:同弧头,弧头相同弧尾不同;同弧尾,弧头不同互为相同。

我研究得出画⼗字链表的⽅法
还是以课上⽼师给出的有向图为例
第⼀步,列出图的所有顶点,并进⾏编号。

画五⾏含三个⽅格的横格,每⼀排最左边那格分别填写各顶点,⼊弧和出弧的暂时不管。

第⼆步,画出各⾏对应的顶点表⽰出弧的所有关系——即右半部分的那些含四个⽅格的横格。

画的时候为了⽅便之后的连线,建议可以将弧尾相同的画在同⼀⾏,将弧头相同的画同⼀列。

填写弧尾与弧头,同弧头和同弧尾先暂时不管。

第三步,连线。

1. 将表⽰顶点的三格图中⼊弧指向对应列所有的四格⽅格。

例如a的编号为0,则a的⼊弧指向第⼀列弧头为0的四格⽅格。

2. 四格⽅格中,同弧头指向本列,同弧尾指向本⾏。

3. 若出弧或同弧尾右边没有⽅格,则为空。

c++实现:十字链表转置

c++实现:十字链表转置

数据结构实验报告实验题目:基于十字链表的稀疏矩阵转置实验内容及要求:编写程序,从字符文件读入三个正整数m, n, t以及t个三元组(i, j, e)建立稀疏矩阵的十字链表存储结构。

其中,m、n分别表示矩阵行数和列数;i, j为非零元素行号和列号。

编写算法,实现矩阵转置,输出转置后的三元组到另一字符文件中,检查你的转置结果是否正确。

要求转置时不得新建元素结点(但允许新建行头/列头结点数组以及删除行头/列头结点数组,转置前后,总头结点不允许改变)。

实验目的:掌握稀疏矩阵的十字链表存储结构。

数据结构设计简要描述:建立十字链表存储从文件中读取的三元组,进行转置后,再存入新建的空十字链表中输出。

算法设计简要描述:创建空十字链表,以插入结点的方式依次将从文件中读取的三元组存储于十字链表中;转置以行为主序,检测到三元组则断开原十字链表行、列结点,将此三元组插入新十字链表中,依次循环,直到原十字链表变空,进行空间销毁。

输入/输出设计简要描述:从Mytext1.txt文件中读入三个正整数m, n, t以及t个三元组(i, j, e),输出在屏幕上,进行转置后,输出转置后三元组在屏幕上,并且保存在文件Mytext2.txt中。

编程语言说明:使用Visual C++编程;主要代码采用C++语言实现。

主要函数说明:init(int m,int n) //创建空十字链表insert(OLink h,int i,int j,int e) //向十字链表插入结点Delete(OLink h) //销毁十字链表Trans(OLink h) //转置TransInsert(OLink hh,OLink p) //转置过程中在各行各列插入结点程序测试简要报告:(1)测试实例1程序输入:Mytext1.txt文件数据程序输出:Mytext2.txt文件存储、转置前和转置后数据(2)测试实例1程序输入:Mytext1.txt文件数据程序输出:Mytext2.txt文件存储、转置前和转置后数据(3)测试实例1程序输入:Mytext1.txt文件数据程序输出:Mytext2.txt文件存储、转置前和转置后数据源程序代码:#include "stdafx.h" #include <iostream> #include <iomanip> #include <fstream> using namespace std;//定义十字链表结构体typedef struct node{ int i,j;int e;struct node *right,*down;}OLNode,*OLink;//创建空十字链表OLink init(int m,int n){OLink h,row,col;int i,j;h=new OLNode;h->i =m; h->j =n;h->right =NULL; h->down =NULL;row=h->down =new OLNode[m];if(!h->down )return NULL;for(i=0;i<m;i++){row[i].i =i;row[i].right =&row[i];}col=h->right =new OLNode[n];if(!h->right )return NULL;for(j=0;j<n;j++){col[j].j =j;col[j].down =&col[j];}return h;}//销毁十字链表void Delete(OLink h){int m,n,k;OLink pr1,pr2,p1,p2;m=h->i ;n=h->j ;for(k=0;k<m;k++){pr1=&h->down[k] ;p1=pr1->right ;while(p1!=&h->down[k]){pr2=&h->right[p1->j];while(p2!=p1){pr2=p2;p2=p2->down;}pr1->right =p1->right ;pr2->down =p1->down ;delete p1;p1=pr1->right ;}}delete [] h->down ;delete [] h->right ;delete h;}//向十字链表插入结点void insert(OLink h,int i,int j,int e){ int m,n;m=h->i ;n=h->j ;if(i<0||i>=m||j>=n) return;OLink s,pr,p;s=new OLNode;if(!s) return;s->i =i;s->j =j;s->e =e;//连接横向循环链表pr=&h->down[i];p=pr->right;while(p!=&h->down[i]&&j>p->j){pr=p;p=p->right;}pr->right=s;s->right=p;//连接纵向循环链表pr=&h->right[j];p=pr->down;pr=p;p=p->down;}pr->down=s;s->down =p;return;}//转置过程中在各行各列插入结点void TransInsert(OLink hh,OLink p){OLink pr,pp;//横向链表插入pr=&hh->down[p->i];pp=pr->right ;while(pp!=&hh->down[p->i]&&p->j >pp->j){ pr=pp;pp=pp->right;}pr->right=p;p->right =pp;//纵向链表插入pr=&hh->right[p->j];pp=pr->down ;while(pp!=&hh->right[p->j]&&p->i >pp->i){ pr=pp;pp=pp->down;}pr->down=p;p->down=pp;}//转置OLink Trans(OLink h){int m,n,k,a;OLink hh,pr1,p1,pr2,p2;m=h->j ;n=h->i ;hh->i=m;hh->j=n;//进行转置放置for(k=0;k<n;k++){pr1=&h->down[k] ;p1=pr1->right ;while(p1!=&h->down[k]){pr2=&h->right[p1->j];p2=pr2->down;while(p2!=p1){pr2=p2;p2=p2->down;}pr1->right =p1->right ;pr2->down =p1->down ;a=p1->i ;p1->i=p1->j ;p1->j=a;TransInsert(hh,p1);p1=pr1->right ;}}//销毁原有的行、列头结点delete [] h->down ;delete [] h->right ;delete h;h=hh;return h;}//主函数调用void main(){int m,n,t,i,j,e,k;OLink h,pr,p;ifstream in("Mytext1.txt");ofstream out("Mytext2.txt");in>>m>>n>>t;cout<<"Mytext1.txt中的三元组:"<<endl;for(k=0;k<t;k++){in>>i>>j>>e;insert(h,i,j,e);cout<<i<<""<<j<<""<<e<<""<<endl;}cout<<endl<<"Mytext1.txt中三元组转置后(存放于Mytext2.txt):"<<endl;h=Trans(h);//按行顺序输出十字链表for(k=0;k<h->i;k++){pr=&h->down[k];p=pr->right ;while(p!=&h->down[k]){cout<<p->i<<""<<p->j<<""<<p->e<<""<<endl;out<<p->i<<""<<p->j<<""<<p->e<<""<<endl;pr=p;p=p->right ;}}//关闭文件、销毁申请空间in.close();out.close();Delete(h);cout<<endl;}。

数据结构课程设计稀疏矩阵

数据结构课程设计稀疏矩阵

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

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

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

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

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

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

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

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

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

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

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

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

十字链表法存储稀疏矩阵

十字链表法存储稀疏矩阵

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

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

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

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

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

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

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

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

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

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

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

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

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

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

数据结构十字链表

数据结构十字链表

数据结构十字链表数据结构是计算机科学中非常重要的一个概念,它指的是各种不同的数据元素之间的关系,以及这些关系的操作和处理方式。

而在数据结构中,十字链表是一种常用的数据结构之一。

它是用于表示稀疏矩阵的一种链表存储结构,通过它可以高效地存储和操作稀疏矩阵。

本文将详细介绍十字链表的概念、特点以及应用。

一、十字链表的定义和特点十字链表是一种多重链表,它由两个链表组成:行链表和列链表。

行链表按照行的顺序连接各个非零元素,列链表按照列的顺序连接各个非零元素。

每个非零元素节点除了包含自身的数值外,还包含了它在行链表和列链表中的前后指针。

这样,通过行链表和列链表的组织,我们可以快速地找到某个元素的上一个元素和下一个元素。

相比于其他存储稀疏矩阵的方法,十字链表具有以下几个特点:1. 空间利用率高:十字链表只存储非零元素,对于稀疏矩阵而言,节省了大量的存储空间。

而且,十字链表的存储结构相对简单,不会浪费额外的空间。

2. 查找效率高:通过行链表和列链表的组织,我们可以快速地找到某个元素的上一个元素和下一个元素,从而提高了查找的效率。

而且,十字链表还可以支持按行或按列的遍历,方便进行各种操作。

3. 插入和删除效率高:十字链表的插入和删除操作只需要修改相应节点的指针,不需要移动其他节点,因此效率较高。

4. 支持稀疏矩阵的各种操作:十字链表不仅仅可以用于存储稀疏矩阵,还可以支持各种基本操作,如矩阵相加、相乘、转置等。

这是因为十字链表可以方便地找到某个元素的上一个元素和下一个元素,从而实现对稀疏矩阵的灵活操作。

二、十字链表的应用十字链表作为一种存储稀疏矩阵的数据结构,被广泛应用于各种领域。

下面列举了一些常见的应用场景:1. 图的存储:图是一种非常常见的数据结构,而且在很多实际问题中都需要使用图进行建模和分析。

十字链表可以用于存储和操作图的邻接矩阵,从而实现图的各种操作,如遍历、查找、删除等。

2. 网络拓扑分析:在计算机网络中,网络拓扑分析是一项重要的任务。

图——数据结构逆邻接表与十字链表

图——数据结构逆邻接表与十字链表

图——数据结构逆邻接表与⼗字链表前⾔:如果你已经学习了邻接表的存储思想,那么逆邻接表也⾮常好理解,我们的重点是⼗字链表 ⾸先我们来继续介绍逆邻接表,逆邻接表和邻接表是⼀样的,只不过在邻接表上,⼀个顶点后⾯连接的⼀串节点都是以顶点为弧尾的弧头节点,我们建⽴邻接表的时候就先查找⼀条边的起点,然后往这个起点上连接新的顶点,那么逆邻接表就是反过来,逆邻接表中⼀个顶点后⾯的⼀串节点都是以顶点为弧头的弧尾节点,我们建⽴逆邻接表的时候,先查找⼀条边的终点,然后往这个重点上连接包含起点信息的节点; 逆邻接表就介绍到这⾥,下⾯我们介绍⼗字链表,⾸先我们抛出这样⼀句话,⼗字链表是正邻接表和逆邻接表的合体,然后我们再介绍这样⼀个观念,我们在逆邻接表或者邻接表中所提到的节点,其实可以理解为弧节点,弧节点可以包含弧头顶点在图中的位置(我们在正邻接表中遇到的),也可以包含弧尾顶点在图中的位置(逆邻接表);下⾯我们给出具体的例⼦帮助⼤家理解 现在思考下当我们要建⽴⼗字链表时会发⽣些什么:⾸先我们建⽴好顶点数组,和在邻接表中的⼀样,然后呢,我们开始添加 e01 这个边,或者说弧现在我们要⽤弧节点的思路去理解他,如何添加这个弧,这个弧包含了哪些信息?弧包含了tail,代表弧尾表⽰的顶点在图中的位置,也就是这个弧是由谁发射出来的,head呢,表⽰这个弧指向了谁,同样储存的是顶点在顶点数组中的索引;后⾯这两项是地址,是什么类型的地址呢,这个地址指向的空间要放什么东西呢,放的仍然是弧节点,但是这两个地址所放的不是同⼀个弧节点,这个tlink,指向的是下⼀个弧节点,tlink指向的这个弧节点的弧尾和tlink所在的弧的弧尾是相同的,按照这样的想法,我们很容易想到沿着tlink⼀路⾛下去,我们就可以遍历由同⼀个顶点发射的所有弧,相当于是⼀个正邻接表,同理沿着hlink我们会遍历指向同⼀个顶点的所有弧,⽽⼀个弧节点既有hlink,⼜有tlink,所以正邻接表和逆邻接表是交叉的,这就叫做⼗字链表, 那么如何来具体的建⽴⼀个⼗字链表呢,回顾上⼀节我们提到的,先建⽴顶点数组,然后按照⽤户输⼊的边去建⽴弧节点,然后给弧节点填充相应的信息,再把弧节点链接到已有的⼗字链表上,链接的时候⼜需要分情况,我这个弧节点是不是处于邻接表的第⼀个或者是逆邻接表的第⼀个,如果是的话,需要操作顶点的firstin或者firstout,如果不是的话需要操作”最后⼀个“弧节点,那么这⾥和上⼀节的操作⼀样,我们仍然需要去标记⼀下”最后⼀个弧节点“,只不过这⾥不仅要标记正邻接表的最后⼀个弧节点,还需要标记逆邻接表中处于最后⼀个的弧节点, 如此如此这番这番,思路就跃然纸上了(具体化了),下⾯我们给出具体代码,并针对上⼀节中,判定是否⼀个顶点没有弧节点相连(⼗字链表中其实是没有正邻接表‘也就是弧尾’或逆邻接表‘也就是弧头’相连,或者两个都没有)的判定进⾏了更正;1//验证图的⼗字链表存储2 #include <stdio.h>3 #include <windows.h>4#define vexNum 1056 typedef struct ArcNode7 {8//索引9int tailVex;10int headVex;1112//地址,按照tlink,可以⼀路遍历完正邻接表13struct ArcNode *tlink;14struct ArcNode *hlink;1516//info代表弧的权重17int info;1819 } ArcNode;2021 typedef struct VexNode22 {23char data;24 ArcNode *last1End; //正邻接表的最后⼀个弧节点25 ArcNode *last2End; //逆邻接表的最后⼀个弧节点26 ArcNode *second1; //正、第⼀个弧节点27 ArcNode *second2; //逆、第⼀个弧节点28 } VexNode;2930 typedef struct graph31 {32int vexN;33int edgeN;34 VexNode adjList[vexNum];35 } graph;3637//寻找顶点在图中的位置38int locatVex(char vex, graph g)39 {40int i = 0;41for (i; i < g.vexN; i++)42 {43if (vex == g.adjList[i].data)44 {45return i;46 }47 }48return -1;49 }50void creatOLGraph(graph *g)51 {52 printf("请输⼊节点数和边数:\n");53 scanf("%d %d", &g->vexN, &g->edgeN);54 getchar();55 printf("请输⼊节点数组,不带空格\n");56int i = 0;57for (i; i < g->vexN; i++)58 {59 scanf("%c", &g->adjList[i].data);60 g->adjList[i].second1 = NULL;61 g->adjList[i].second2 = NULL;62 g->adjList[i].last1End = NULL;63 g->adjList[i].last2End = NULL;64 }65 getchar();66 printf("请输⼊边:\n");6768int v1, v2;69char vv1, vv2;70for (i = 0; i < g->edgeN; i++)71 {72 scanf("%c %c", &vv1, &vv2);73 getchar();74 v1 = locatVex(vv1, *g);75 v2 = locatVex(vv2, *g);76 ArcNode *p;77 p = (ArcNode *)malloc(sizeof(ArcNode));7879//同⼀个弧节点,先对正邻接表操作,再对逆邻接表操作8081//弧节点的弧尾是v182 p->tailVex = v1;83if (g->adjList[v1].last1End == NULL)84 {85//顶点的第⼀个弧节点是p,该顶点正邻接表的最后⼀个弧节点也是p86 g->adjList[v1].second1 = p;87 g->adjList[v1].last1End = p;88 }89else90 {91//向正邻接表中添加⼀个元素,92 g->adjList[v1].last1End->tlink = p;93 g->adjList[v1].last1End = p;94 }9596 p->headVex = v2;97if (g->adjList[v2].last2End == NULL)98 {99 g->adjList[v2].second2 = p;100 g->adjList[v2].last2End = p;101 }102else103 {104 g->adjList[v2].last1End->hlink = p;105 g->adjList[v2].last1End = p;106 }107 }108 }109110int main()111 {112 graph g;113 creatOLGraph(&g);114//验证⼗字链表的存储115int i = 0;116for (i; i < g.vexN; i++)117 {118 ArcNode *show;119//之前我们做判断,是判断“最后⼀个节点”是否为顶点,现在我们更改了初始化条件,把之前的初始化为顶点地址改成了初始化为NULL这就避免了类型不兼容的警告120if (g.adjList[i].last2End != NULL)121 {122 printf("发往%c的弧,弧尾是 ", g.adjList[i].data);123 show = g.adjList[i].second2;124while (show != g.adjList[i].last2End)125 {126 printf("%c、", g.adjList[show->tailVex].data);127 show = show->hlink;128 }129 printf("%c\n", g.adjList[show->tailVex].data);130 }131132if (g.adjList[i].last1End != NULL)133 {134 printf("由%c发出的弧的弧头是 ", g.adjList[i].data);135 show = g.adjList[i].second1;136while (show != g.adjList[i].last1End)137 {138 printf("%c、", g.adjList[show->headVex].data);139 show = show->tlink;140 }141 printf("%c\n", g.adjList[show->headVex].data);142 }143 }144 system("pause");145return0;146 }参考:《新编数据结构案例教程(C/C++)版》薛晓亚主编。

稀疏矩阵的十字链表存储的思路

稀疏矩阵的十字链表存储的思路

稀疏矩阵的十字链表存储的思路
稀疏矩阵是一种大多数元素都为0的矩阵,而十字链表是一种常
见的数据结构,用于存储稀疏矩阵。

十字链表提供了一种有效的方法,可以对矩阵进行高效的访问和操作。

十字链表的存储方式是将矩阵分成两个链表:行链表和列链表。

行链表和列链表中的每个节点都存储了一个非零元素和该元素的行编
号和列编号。

同时,每个节点也包含了指向下一个相同行或相同列的
节点的指针。

在十字链表中,每个节点都可以快速找到它所处的行和列以及与
它相邻的元素。

这使得我们可以在矩阵中进行诸如插入、删除、修改
及查找等操作。

在操作过程中,我们可以通过指针操作找到相邻的非
零元素,从而充分利用稀疏矩阵的特殊性质。

对于一个稀疏矩阵,我们需要将每一个非零元素存储到十字链表中。

首先,我们需要创建一个新的节点,并为它分配内存空间。

然后,我们需要将该节点插入到正确的位置,即行链表和列链表中。

插入操作的基本思路是,我们首先遍历行链表,找到该元素所在
的行号。

然后在该行号的节点中,按照列号的大小插入该新节点。

同时,我们需要在列链表中找到该元素所在的列号,并在该列号的节点
中插入新节点。

除了插入操作外,十字链表还支持删除操作、修改操作和查找操作。

这些操作都可以通过指针操作实现。

总的来说,十字链表是一种高效的数据结构,可以有效地存储稀
疏矩阵。

通过使用十字链表,我们可以对矩阵进行各种操作,而不必
费力遍历整个矩阵。

在实现稀疏矩阵算法时,我们常常会使用十字链
表这种数据结构。

(原创)数据结构之十字链表总结

(原创)数据结构之十字链表总结

(原创)数据结构之⼗字链表总结7-1 稀疏矩阵(30 分)如果⼀个矩阵中,0元素占据了矩阵的⼤部分,那么这个矩阵称为“稀疏矩阵”。

对于稀疏矩阵,传统的⼆维数组存储⽅式,会使⽤⼤量的内存来存储0,从⽽浪费⼤量内存。

为此,可以⽤三元组的⽅式来存放⼀个稀疏矩阵。

对于⼀个给定的稀疏矩阵,设第r⾏、第c列值为v,且v不等于0,则这个值可以表⽰为 <r,v,c>。

这个表⽰⽅法就称为三元组。

那么,对于⼀个包含N个⾮零元素的稀疏矩阵,就可以⽤⼀个由N个三元组组成的表来存储了。

如:{<1, 1, 9>, <2, 3, 5>, <10, 20, 3>}就表⽰这样⼀个矩阵A:A[1,1]=9,A[2,3]=5,A[10,20]=3。

其余元素为0。

要求查找某个⾮零数据是否在稀疏矩阵中,如果存在则输出其所在的⾏列号,不存在则输出ERROR。

输⼊格式:共有N+2⾏输⼊:第⼀⾏是三个整数m, n, N(N<=500),分别表⽰稀疏矩阵的⾏数、列数和矩阵中⾮零元素的个数,数据之间⽤空格间隔; 随后N⾏,输⼊稀疏矩阵的⾮零元素所在的⾏、列号和⾮零元素的值;最后⼀⾏输⼊要查询的⾮0数据k。

输出格式:如果存在则输出其⾏列号,不存在则输出ERROR。

输⼊样例:在这⾥给出⼀组输⼊。

例如:10 29 32 18 -107 1 988 10 22输出样例:在这⾥给出相应的输出。

例如:8 10解题思路:实际上这道题⽤三元组写轻松解决,但是这⾥想讲的是⼗字链表;⼗字链表的图⼤致如下:那么如何去实现呢;看以下代码:因为下⾯都有注释,这⾥便不赘述了。

1 #include<iostream>2 #include<stdio.h>3using namespace std;45struct OLNod{6int i ; //该⾮零元的⾏下标;7int j ; //该⾮零元的列下标;8int value ; //该⾮零元的数值;9struct OLNod *right ,*down ;//该⾮零元所在的⾏表和列表的后继链域;10 };11struct CrossL{12 OLNod **rhead, **sead;13//⼗字链表的⾏头指针和列头指针;定义为指向指针的指针;14int row; //稀疏矩阵的⾏数;15int col; //稀疏矩阵的列数;16int num; //稀疏矩阵的⾮零个数;17 };1819int InitSMatrix(CrossL *M) //初始化M(CrossL)类型的变量必须初始化;20 {21 (*M).rhead = (*M).sead = NULL;22 (*M).row = (*M).col = (*M).num = 0;23return1;24 }2526int DestroysMatrix(CrossL *M) //销毁稀疏矩阵M;27 {28int i ;29 OLNod *p,*q;30for( i = 1 ; i <= (*M).row;i++)31 {32 p = *((*M).rhead+i); //p指针不断向右移;33while(p!=NULL)34 {35 q = p ;36 p = p ->right;37delete q; //删除q;38 }39 }40delete((*M).rhead); //释放⾏指针空间;41delete((*M).sead); //释放列指针空间;42 (*M).rhead = (*M).sead = NULL; //并将⾏、列头指针置为空;43 (*M).num = (*M).row = (*M).col = 0; //将⾮零元素,⾏数和列数置为0; 44return1;45 }46int CreatSMatrix(CrossL *M)47 {48int i , j , m , n , t;49int value;50 OLNod *p,*q;51if((*M).rhead!=NULL)52 DestroysMatrix(M);53 cin>>m>>n>>t; //输⼊稀疏矩阵的⾏数、列数和⾮零元个数;54 (*M).row = m;55 (*M).col = n ;56 (*M).num = t;57//初始化⾏链表头;58 (*M).rhead = new OLNod*[m+1];//为⾏头指针申请⼀个空间;59if(!(*M).rhead) //如果申请不成功,则退出程序;60 exit(0);61//初始化列链表头;62 (*M).sead = new OLNod*[n+1];//为列表头申请⼀个空间;63if(!(*M).sead) //如果申请不成功,则退出程序;64 exit(0);65for(int k = 1 ; k <= m ; k++)66 {67 (*M).rhead[k] = NULL;//初始化⾏头指针向量;各⾏链表为空链表;68 }69for(int k = 1 ; k <= n ;k++)70 {71 (*M).sead[k] = NULL;//初始化列头指针向量;各列链表为空链表;72 }73for(int k = 0 ; k < t ;k++) //输⼊⾮零元素的信息;74 {75 cin>>i>>j>>value;//输⼊⾮零元的⾏、列、数值;76 p = new OLNod();//为p指针申请⼀个空间;77if(!p) //e如果申请不成功;78 exit(0); //退出程序;79 p->i = i;80 p->j = j;81 p->value = value;82if((*M).rhead[i]==NULL) //如果⾏头指针指向的为空;83 {84//p插在该⾏的第⼀个结点处;85 p->right = (*M).rhead[i];86 (*M).rhead[i] = p;87 }else//如果不指向空88 {89for(q = (*M).rhead[i];q->right; q = q->right);90 p->right = q->right;91 q->right = p;9293 }94if((*M).sead[j]==NULL)//如果列头指针指向的为空;95 {96//p插在该⾏的第⼀个结点处;97 p->down = (*M).sead[j];98 (*M).sead[j] = p;99 }else//如果不指向空100 {101for(q = (*M).sead[j];q->down;q = q->down);102 p->down = q->down;103 q->down = p;104 }105 }106return1;107 }108int PrintSMatrix(CrossL *M)109 {110int flag = 0;111int val ;//要查找的元素的值;112 cin>>val; //输⼊要查找的s值;113 OLNod *p;114for(int i = 1 ; i <= (*M).row ;i++)115 {116for(p = (*M).rhead[i];p;p = p->right) //从⾏头指针开始找,不断向右找117 {118if(p->value==val) //如果能找到119 {120 cout<<p->i<<""<<p->j; //输出⾏下标和列下标121 flag = 1; //标记找到该元素;122 }123 }124 }125126127if(flag==0) //如果找不到128 {129 cout<<"ERROR\n";130 }131132 }133int main()134 {135 CrossL A; //定义⼀个⼗字链表;136 InitSMatrix(&A); //初始化;137 CreatSMatrix(&A); //创建;138 PrintSMatrix(&A); //输出;139 DestroysMatrix(&A); //销毁;140return0;141 }。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

数据结构课程设计十字链表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); 创建以十字链表表示的一个元素全为零的稀疏矩阵。

2 int insert(OLnode *a ,int row,int col,int val); 创建稀疏矩阵结点插入函数。

3 OLnode *shuru(); 创建稀疏矩阵的输入函数。

4 void shuchu(OLnode *a); 创建稀疏矩阵的输出函数。

5 OLnode*add(OLnode *a,OLnode *b);创建对两个相同行列数矩阵进行加法运算函数。

6 void main();创建该程序的主函数。

3.程序中数据结构的选择:如下定义:typedef struct lnode //十字链表结点类型{int row,col;int val;struct lnode *rptr ,*cptr ;}OLnode;其中row,col和val域分别用来存储非零元素的行号、列号和元素值rptr域用来存储指向同一行下一个结点的指针,cptr域用来指向同一列下一个结点的指针,如果不存在下一个结点,则相应的指针域为空。

14.流程图:根据利用十字链表表示稀疏矩阵,并实现矩阵的加法运算的算法,可以设计如下流程图:该流程图体现了本实验问题的算法设计思想:首先,定义十字链表结点的类型并利用十字链表建立相应的稀疏矩阵,然后再将建立好的两个相同行列数的稀疏矩阵进行求和运算并输出最终结果。

定义十字链表结点类型建立十字链表表示稀疏矩阵稀疏矩阵a 稀疏矩阵b稀疏矩阵a,b求和输出结果结束图1. 程序流程图三、详细设计和编码:1.建立一个十字链表表示的稀疏矩阵,定义为m行n列,并为头结点开辟空间,同时定义该稀疏矩阵不会多于100列,每个行链表是一个环,使全部行链表头结点构成环;再定义该稀疏矩阵不会多于100行,每个列链表是一个环,使全部列链表头结点构成环OLnode *create(int m,int n) //m行n列{ OLnode *h,*p;int k;h=(OLnode *)malloc(sizeof(OLnode)); //为头结点开辟空间 h->row=m;h->col=n;h->val=0; //行,数和非零元素元素值 h->rptr=(OLnode*)malloc(sizeof(OLnode)*n);h->cptr=(OLnode *)malloc(sizeof(OLnode)*m);for(p=h->cptr,k=0;k<m;k++,p++){p->col=100; //定义该稀疏矩阵不会多于100列 p->rptr=p; //每个行链表是一个环p->cptr=k<m-1?p+1:h->cptr ; //使全部行链表头结点构成环 }for(p=h->rptr ,k=0;k<n;k++,p++){2p->row=100; //该稀疏矩阵不会多于100行p->cptr=p; //每个列链表是一个环 p->rptr=k<n-1?p+1:h->rptr; //使全部列链表头结点构成环}return h;}2.在十字链表中插入一个结点,对于不合理的行列号返回错误。

然后分别对行和列进行插入int insert(OLnode *a ,int row,int col,int val){OLnode *p,*q,*r,*u,*v; /* 在十字链表中插入一个结点*/if(row>=a->row||col>=a->col) return -2; /* 不合理的行列号 */r=(OLnode *)malloc(sizeof(OLnode));r->row=row;r->col=col;r->val=val;p=a->cptr +row;q=p->rptr ;while(q->col<col){p=q;q=q->rptr ;}if(q->col==col) return -1; //该行已有col行元素u=a->rptr +col;v=u->cptr ;while(v->row<row){u=v;v=v->cptr ;}if(v->row==row) return -1; //该列已有row行元素p->rptr=r; r->rptr=q; //插入到行链中 u->cptr=r; r->cptr=v; //插入到列链中 a->val=val;return 0; //插入成功}3.向十字链表输入数据OLnode *shuru() /*向十字链表输入数据*/{OLnode *h;int i,j,m,n;int v;printf("请输入稀疏矩阵的行数和列数:");scanf("%d%d",&m,&n);h=create(m,n);printf("请输入第一个非零元素的行号:");scanf("%d",&i);while(i>=0){ printf("请输入第一个非零元素的列号:");scanf("%d",&j);while(j>=0){ printf("请输入非零元素的值:");scanf("%d",&v);insert(h,i,j,v);printf("请输入当前行下一个非零元素的列号:(-1表示当前行一组数据结束):");scanf("%d",&j);}printf("请输入下一行有非零元素的行号(-1表示输入结束):");scanf("%d",&i);}return h;3}4.将得到的稀疏矩阵进行输出 void shuchu(OLnode *a){int row,col,i,j;OLnode *p;row=a->row;col=a->col;for (i=0;i<row;i++){ p=a->cptr +i;p=p->rptr ;for(j=0;j<col;j++){ if(p->row==i&&p->col==j) {printf("%d ",p->val);p=p->rptr ;} elseprintf("0 ");}printf("\n");}}5.将两个稀疏矩阵相加OLnode *add(OLnode *a,OLnode *b) //加法运算{OLnode *r,*p,*q,*u,*v;r=create(a->row,a->col);p=a->cptr;u=b->cptr ;do{ q=p->rptr;v=u->rptr ;while(q!=p||v!=u) //两矩阵中有一个一行为结束循环if(q->col==v->col) //有相同列的元素{if(q->val+v->val!=0) //和非零插入{insert(r,q->row,q->col,q->val+v->val);q=q->rptr ;v=v->rptr ;}}else if(q->col<v->col) //插入的a元素{insert(r,q->row,q->col,q->val);q=q->rptr ;}else //插入b的元素{insert(r,v->row,v->col,v->val);v=v->rptr ;}p=p->cptr ;u=u->cptr ;}while(p!=a->cptr );return r;}四、上机调试:1.语法错误:1.1在对稀疏矩阵进行十字链式存储时,开始对十字链表的结构不是很熟悉,结果在创建一个头结点后对于后继结点的指向问题上出现语法错误,不能正确指向下一个要输入值的结点,后来经查找相关书籍后找到解决方法。

41.2在打印输入的稀疏矩阵过程中,开始出现了无法正确打印出完整矩阵的错误,后来经检查,发现是主函数中一些子函数的调用顺序发生错误,后来改正即得到正确结果。

2.调试错误:2.1在数据的输入过程中因为标点符号的输入错误或遗漏,输入产生一些非语法的错误。

2.2在数据的输入过程中因为没有注意测试数据的范围,结果导致处理数据超出范围,出现错误。

相关文档
最新文档