数据结构 课程设计 十字链表
十字链表的画法
⼗字链表的画法
⼗字链表的画法
基本概念
⼗字链表(Orthogonal List)是有向图的另⼀种链式存储结构。
该结构可以看成是将有向图的邻接表和逆邻接表结合起来得到的。
⼊弧和出弧:⼊弧表⽰图中发出箭头的顶点,出弧表⽰箭头指向的顶点。
弧头和弧尾:弧尾表⽰图中发出箭头的顶点,弧头表⽰箭头指向的顶点。
同弧头和同弧尾:同弧头,弧头相同弧尾不同;同弧尾,弧头不同互为相同。
我研究得出画⼗字链表的⽅法
还是以课上⽼师给出的有向图为例
第⼀步,列出图的所有顶点,并进⾏编号。
画五⾏含三个⽅格的横格,每⼀排最左边那格分别填写各顶点,⼊弧和出弧的暂时不管。
第⼆步,画出各⾏对应的顶点表⽰出弧的所有关系——即右半部分的那些含四个⽅格的横格。
画的时候为了⽅便之后的连线,建议可以将弧尾相同的画在同⼀⾏,将弧头相同的画同⼀列。
填写弧尾与弧头,同弧头和同弧尾先暂时不管。
第三步,连线。
1. 将表⽰顶点的三格图中⼊弧指向对应列所有的四格⽅格。
例如a的编号为0,则a的⼊弧指向第⼀列弧头为0的四格⽅格。
2. 四格⽅格中,同弧头指向本列,同弧尾指向本⾏。
3. 若出弧或同弧尾右边没有⽅格,则为空。
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 }。
稀疏矩阵十字链表算法
稀疏矩阵十字链表算法稀疏矩阵是指矩阵中绝大多数元素为0的矩阵。
在实际应用中,很多矩阵都具有稀疏性,即元素中大部分为0,而只有少数非零元素。
对于这种类型的矩阵,为了节省内存空间并提高计算效率,可以采用稀疏矩阵的存储方式。
稀疏矩阵的一种常用存储方式是十字链表。
十字链表是一种将稀疏矩阵以链表形式存储的数据结构,它能够有效地表示稀疏矩阵的非零元素,并且能够方便地进行插入、删除和查找操作。
稀疏矩阵十字链表的基本思想是将矩阵中的每个非零元素存储为一个结点,并将这些结点以行列坐标的方式进行链接。
具体来说,稀疏矩阵十字链表由两个链表组成:行链表和列链表。
行链表是一个以行为主的链表,每个结点表示矩阵中的一行。
每个结点包含三个字段:行号、列号和值。
行链表中的结点按照行号从小到大的顺序进行排列,同一行中的结点按照列号从小到大的顺序进行排列。
列链表是一个以列为主的链表,每个结点表示矩阵中的一列。
每个结点也包含三个字段:行号、列号和值。
列链表中的结点按照列号从小到大的顺序进行排列,同一列中的结点按照行号从小到大的顺序进行排列。
通过行链表和列链表,可以方便地进行插入、删除和查找操作。
插入操作可以通过在行链表和列链表中找到对应的位置,将新结点插入到相应的位置上。
删除操作可以通过在行链表和列链表中找到对应的位置,将对应的结点删除。
查找操作可以通过在行链表和列链表中找到对应的位置,获取对应的结点。
稀疏矩阵十字链表算法的优点是能够有效地存储稀疏矩阵,并且可以方便地进行插入、删除和查找操作。
相比于其他存储方式,稀疏矩阵十字链表可以节省更多的内存空间,并且具有更高的计算效率。
总结来说,稀疏矩阵十字链表算法是一种有效地存储稀疏矩阵的方法。
通过行链表和列链表的链接,可以方便地进行插入、删除和查找操作。
稀疏矩阵十字链表算法在实际应用中具有广泛的应用,能够节省内存空间并提高计算效率。
稀疏矩阵十字链表算法
稀疏矩阵十字链表算法稀疏矩阵是指矩阵中大部分元素为0的矩阵。
在实际应用中,稀疏矩阵常常出现,比如图像处理、网络分析等领域。
由于稀疏矩阵中存在大量的0元素,传统的二维数组存储方式会造成内存空间的浪费,因此需要一种高效的数据结构来表示和存储稀疏矩阵。
稀疏矩阵十字链表算法就是一种解决这个问题的方法。
稀疏矩阵十字链表算法是一种基于链表的数据结构,用于表示和存储稀疏矩阵。
它通过两个链表来分别表示行和列,同时还使用了一个数据链表来存储非零元素的值和位置信息。
这种算法的核心思想是将稀疏矩阵的非零元素存储在链表中,并记录它们在矩阵中的位置信息,从而节省了存储空间。
具体来说,稀疏矩阵十字链表算法中,我们可以使用三个结构体来表示矩阵的行、列和非零元素。
其中,行和列的结构体包含了指向非零元素的指针和矩阵的维度信息。
非零元素的结构体包含了元素的值、行列坐标以及指向下一个非零元素的指针。
使用稀疏矩阵十字链表算法存储稀疏矩阵的好处是,它不仅节省了存储空间,还可以提高对稀疏矩阵的操作效率。
比如,对于稀疏矩阵的遍历操作,我们可以通过遍历链表的方式来实现,而不需要遍历整个矩阵,从而减少了时间复杂度。
除了存储和遍历操作,稀疏矩阵十字链表算法还可以支持其他一些常见的矩阵操作,比如矩阵的相加、相乘等。
对于这些操作,我们只需要按照链表的顺序进行遍历,并根据矩阵的位置信息进行计算即可。
稀疏矩阵十字链表算法的实现过程相对简单,但需要注意一些细节。
首先,我们需要确定稀疏矩阵的维度信息,并创建相应的行和列的链表头结点。
然后,我们可以按照行优先的方式遍历整个矩阵,将非零元素插入到链表中,并更新行和列的指针。
最后,我们可以根据需要进行各种矩阵操作。
稀疏矩阵十字链表算法是一种高效的存储和表示稀疏矩阵的方法。
它通过链表来存储非零元素,并记录它们在矩阵中的位置信息,从而节省了存储空间。
同时,它还可以支持各种常见的矩阵操作。
在实际应用中,稀疏矩阵十字链表算法可以提高程序的运行效率,减少内存的占用,是一种非常实用的数据结构算法。
《数据结构》课程标准
《数据结构》课程标准一、课程定位《数据结构》是大数据技术与应用专业的一门专业基础课程,本课程所涵盖的知识和技能是作为大数据技术与应用专业学生其他专业课程的核心基础课程之一。
通过本课程的学习,使学生能够获得学习后续专业课程所需的编程算法、数据结构方面的基础知识。
通过本课程及其实践环节教学,使学生能够培养良好的编程习惯,锻炼计算机软件算法思想,并培养学生分析问题和解决问题的能力。
为以后进行实际的软件开发工作打下良好的专业知识和职业技能基础。
二、课程目标通过本课程的学习,培养和提高计算机软件技术专业学生的职业核心能力和素质。
使学生能够具备良好的职业素养,具备团队协作、与人沟通等多方面的能力;使学生具有较强的编程专业基础知识和技能,并具备进行自我拓展的能力。
让学生能够具备深厚的专业基础,为今后的长足发展提供厚实而强大的动力。
1、知识目标本课程涵盖了以下知识目标:(1)掌握算法设计的基本度量方法;(2)掌握线性表、栈、队列、数组和二叉树抽象数据类型的实现及其基本的操作实现;(3)理解图抽象数据类型的实现及其基本的操作特点;(4)掌握常见查找算法和排序算法的特点和实现方法。
2、能力目标(1)能查阅英文版的相关技术手册;(2)能正确地实现常用的抽象数据类型,并能实现常见的基本操作;(3)能针对现实问题选择正确的数据结构,并能在所选择的数据结构基础上编写相应算法以解决该问题;(4)能够对所编写的算法进行简单的度量和评估。
3、素质目标(1)具有良好的心理素质,顽强的意志力,勇于克服困难;(2)具有较强的身心素质,适应艰苦工作需要;(3)具有较扎实的业务基础,并能不断进行创新和自我超越。
三、课程设计1、设计思想教学内容框架按照知识和技能递进的关系,本课程的内容框架设计如下图所示:教学内容框架示意图本课程教学内容按照线性表、栈、队列、数组、树及二叉树和图等基本数据结构的顺序来实施教学,最后将前面的基本数据结构应用于查询算法和排序算法的设计和实现。
基于十字链表的矩阵运算
数 据 结 构课 程 设 计 报 告日期: 年 月 日122009 30 学 号班 级卫熙 姓 名指 导 教 师 王 平2007级信息与计算科学 20070744044 题目:基于正交链表的矩阵运算说明本组成员名单:卫熙谢武杰孙洋洋王帅吴波组长:卫熙本人承担的课程设计的工作情况:程序的算法设计以及部分功能实现,后期程序调试、测试,主函数的设计。
目录1 任务概述 (3)1.1 问题描述 (3)1.2 编程的基本要求 (3)1.3 程序的主要功能 (3)1.4 编程语言及选择的操作平台 (3)2 概要设计 (4)2.1 数据结构 (4)2.2 总体结构 (4)3 详细设计 (5)3.1 数据结构中的函数 (6)3.2 主函数及其他函数 (7)4 调试分析 (9)4.1调试过程 (9)4.2测试结果 (9)4.2改进设想 (14)5 用户手册 (15)6 总结 (17)参考文献 (18)附件源程序代码清单 (19)1 任务概述1.1 问题描述应用三元组和正交链表存储稀疏矩阵,并实现稀疏矩阵的转置、加法和乘法运算。
1.2 编程的基本要求1)应用三元组和正交链表的数据结构。
2)矩阵运算由正交链表类的成员函数实现,矩阵的输入输出由类的友元重载函数实现。
3)主函数用于实现菜单和调用。
1.3 程序的主要功能1. 按《数据结构课程设计》报告格式所给出的框架撰写。
2. 具体内容应尽量包含文字叙述、图表(表格,框图,流程图,UML图等)和程序代码。
3. 每个同学要提交电子文档和一份打印稿。
1.4 编程语言及选择的操作平台编程语言选用C++程序设计语言。
程序开发平台选用Mcrosoft Visual Studio 6.0的Microsoft Visual C++ 6.0开发环境。
程序运行在DOS界面。
2 概要设计2.1 数据结构稀疏矩阵类(matrix)稀疏矩阵的节点类(node)2.2总体结构说明:表达式i!=0 True,向下执行,False 结束退出3 详细设计3.1 数据结构中的函数(其中函数的实现请参看源代码部分)1) 矩阵结点(matrix)中的函数:Private:friend istream&operator>>(istream&,matrix&);friend ostream&operator<<(ostream&,matrix&);//int Row,Col,Terms,temp; //矩阵的总行数,总列数,和非零元素个数和临时变量;//node*headnode; //稀疏矩阵的总表头public:matrix(int m,int n); //重载构造函数matrix(); //对矩阵进行构造matrix(matrix& T); //拷贝构造函数~matrix(){makeEmpty();} //析构函数void Init(int m,int n); //初始化函数,又来初始化无参构造函数构造的矩阵void makeEmpty(); //清空矩阵void Insert(int m,int n,float p); //插入矩阵元素void Delete(int m,int n); //删除特定行列元素node *Locate(int i); //定位附加头结点matrix transpose(); //矩阵的转置运算matrix Add( matrix b); //两个矩阵相加matrix Mul(matrix b); //两个矩阵相乘matrix &operator=(matrix &T); //重载赋值号2)节点类(node)的函数:node():head(TRUE){ right=down=this;} //建立附加头结点node(element *t){// 建立非零元素结点triple.col=t->col; triple.row=t->row; triple.item=t->item; right=down=this; head=FALSE;}3.2 主函数及其他函数#include"matrix.h"#include<conio.h>void main(){int i;matrix B,B1,B2,C;while(i!=0){cout<<" ----------------基于正交链表的稀疏矩阵的运算-----------------"<<endl<<endl;cout<<" 1.转置 2.加法 3.乘法0.退出程序"<<endl<<endl;cout<<"请选择:";cin>>i; cout<<endl;switch(i){case 0: break;case 1: cout<<" -------稀疏矩阵的转置------\n"<<endl;cout<<"请输入矩阵:"<<endl<<endl;cin>>B;system("cls");cout<<"原矩阵为:"<<endl;cout<<B<<endl;cout<<"转置后为"<<endl;cout<<B.transpose()<<endl; break;case 2: cout<<" --------稀疏矩阵的加法-------\n"<<endl;cout<<"请输入矩阵1:"<<endl<<endl;cin>>B1;cout<<"请输入矩阵2:"<<endl<<endl;cin>>B2;system("cls");cout<<"矩阵1为:"<<endl;cout<<B1<<endl;cout<<"矩阵2为:"<<endl;cout<<B2<<endl;cout<<"两个矩阵之和为:"<<endl;cout<<B1.Add(B2)<<endl;break;case 3: cout<<" --------稀疏矩阵的乘法-------\n"<<endl;cout<<"注意:输入的矩阵必须满足矩阵相乘的条件,并且按顺序输入(即1和2的顺序)\n"<<endl;cout<<"请输入矩阵1:"<<endl;cin>>B1;cout<<"请输入矩阵2:"<<endl;cin>>B2;system("cls");cout<<"矩阵1为:"<<endl;cout<<B1<<endl;cout<<"矩阵2为:"<<endl;cout<<B2<<endl;cout<<"两个矩阵之积为:"<<endl;cout<<B1.Mul(B2)<<endl;break;default:break;}if(i!=0){cout<<"按任意继续......"<<endl; getch();system("cls");}}}//YEAH!!!!终于于31日9:19调试成功了!!!4.1 调试过程再调试过程中,出现最多的问题是控制循环的终止条件,由于指针用的比较多,导致有时用指针做循环终止条件时没有考虑到其值的改变。
邻接表十字链表
(续) for(i=0;i<G->vexnum;i++) printf("%4d",i); printf("\n"); for(i=0;i<G->vexnum;i++) { printf("%6d",i); for(j=0;j<G->vexnum;j++) printf("%4d",G->edges[i][j]);
A B A B
C
D
C
D
图7.6 G2的两棵生成树
例7.1 有n个顶点的连通图最多有多少条边? 最少应多少条边? 解:有n个顶点的连通图最多有n(n-1)/2条 边,也就是一个无向完全图;最少有n-1条 边。
7.2 图的存储结构
图的存储结构除存储图中各个顶点本身 的信息外,同时还要存储顶点之间的所 有关系。图的常用存储结构有邻接矩阵、 邻接表、十字链表。
7.2.1
邻接矩阵
设G=(V,E)是具有n(n>0)个顶点的图,顶 点的顺序依次为(v0,v1,…,vn-1),则 G的邻接矩阵A是n阶方阵,其定义如下: (1) 如果G是无向图,则:
1, 若(vi , v j ) E (G ) A[i ][ j ] 0, 其它
(2) 如果G是有向图,则:
邻接表的头结点和表结点的结构如下:
data
firstarc
adjvex
nextarc
info
头结点
表结点
如图7.8(a)和(b)所示分别为图G1和图G2的 邻接表。
0 1 2 3
A B C D /\ 3 0 /\ /\ 2 1 /\
十字链表法
十字链表法十字链表(又称叉链表)是一种利用数据链表技术实现图表表示的数据结构。
一般来说,它由两个基本结构:一个表示节点的字表和一个表示节点之间联系的叉链表组成,利用叉链表的特点,可以把一个复杂的图/网表结构以一种更简单的方式表示出来,并且可以应用在不同的任务上。
十字链表的结构非常类似。
它有一个头节点,每个节点都包含两个指针:一个指向表头,一个指向该节点的父节点,以及一个指向该节点的子节点。
字表则用于保存该节点的相关数据,其中包括该节点的事件,以及与之关联的其它数据。
###字链表在数据处理中的应用十字链表法可以应用在多种情况中,用于快速查找、修改,以及处理复杂的数据结构。
它比其它常见的数据存取方法更加有效率,因为它可以非常快速地找到数据的父节点和子节点。
例如,在图结构存储中,当我们需要查找一个特定的节点时,我们可以使用十字链表法快速找到,因为它的优势是它可以基于每个节点的父子关系查找所有相关的节点和数据。
另外,十字链表法也可以用于实现事件驱动系统,当用户改变某个图表中的内容时,系统可以根据这些内容的变化,快速地更新数据结构中的关系。
例如,当用户添加一个节点时,系统就可以立即将其添加到十字链表中,以此达到实时更新的目的。
此外,还可以利用十字链表来实现复杂的搜索引擎,允许用户快速搜索数据库中的指定内容。
一个典型的例子是满足多个条件的数据,十字链表可以极大地减少搜索的范围。
###字链表的优势首先,十字链表可以更有效地存储图形网络结构和复杂数据结构,它可以把这些复杂的结构转换成更简单的表示形式,从而使得可以更快地查找和处理这些数据。
其次,十字链表的插入和删除操作也较快,它可以把节点从一个位置转移到另一个位置,而不会增加其它操作的次数。
最后,十字链表法的另一个特点是可以很容易地实现多处理器的数据处理,这意味着它可以被用来在同一时间处理多个数据流。
###论虽然十字链表法在某些情况下并不直观,但它却可以帮助我们快速查找和处理复杂的数据结构。
《数据结构》课程标准
《数据结构》课程标准一、概述(一) 课程的性质本课程为计算机专业技术人员提供必要的专业基础知识和技能训练,同时也是计算机应用相关学科所必须掌握的课程。
通过本课程的学习,使学生熟练掌握计算机程序设计中常见的各种数据的逻辑结构、存储结构及相应的运算,初步掌握算法的时间分析和空间分析的技术,并能根据计算机加工的数据特性运用数据结构的知识和技巧设计出更好的算法和程序,并进一步培养基本的良好的程序设计能力。
(二)课程基本理念以培养学生如何合理地组织数据、有效地存储和处理数据,正确地设计算法以及对算法进行的分析和评价的能力,学会数据的组织方法和实现方法,并进一步培养基本的良好的程序设计能力。
(三)课程设计思路本课程标准从计算机软件技术及应用技术专业的视角出发,以满足本专业就业岗位所必须具备的计算机软件技术基础知识为基础,教学内容设计通过岗位工作目标与任务分析,分解完成工作任务所必备的知识和能力,采用并列和流程相结合的教学结构,构建教学内容的任务和达到工作任务要求而组建的各项目,以及教学要求和参考教学课时数。
通过实践操作、案例分析,培养学生的综合职业能力,基本达到程序员级职业技能鉴定标准。
本课程建议课时为64学时,理论课时为20,实训课时为44,在具体教学过程中可进行进行调整。
二、课程目标(一)总目标本课程以培养学生的数据抽象能力和复杂程序设计的能力为总目标。
通过本课程的学习,学生可以学会分析研究计算机加工的数据结构的特性,以便为应用涉及的数据选择适当的逻辑结构、存储结构及其相应的运算,并初步掌握算法的时间分析和空间分析的技术;另一方面,本课程的学习过程也是复杂程序设计的训练过程,要求学生编写的程序结构清楚和正确易读,符合软件工程的规范。
(二)具体目标掌握各种主要数据结构的特点、计算机内的表示方法,以及处理数据的算法实现。
使学生学会分析研究计算机加工的数据结构的特性,以便为应用涉及的数据选择适当的逻辑结构、存储结构及相应的算法,并初步了解对算法的时间分析和空间分析技术。
《数据结构与算法》课件 第3章 链表
练习
1、链表中逻辑上相邻的元素在物理上()相邻。 2、已知带头结点的单链表L,指针p指向链表中的一个节点, 指针q指向链表外的节点,在指针p的后面插入q的语句序 列( ) 3、设某非空单链表,要删除指针p所指的结点的直接后继结 点,则需要执行下述语句序列: p=q->next; ( );free(p); 4、线性表的存储有顺序存储和( )存储两种。 5、线性表中哪些元素只有一个直接前驱和一个直接后继? A 首元素 b 尾元素 c 中间的元素 d 所有的元素 6、线性表的各元素之间是()关系 A 层次 b 网状 c 有序 d 集合 7、在单链表中一个结点有()个指针,在双向链表中的一 个结点有()指针
2、求长度 L 21 18 p k p
30
p
75
p
42
p
56 ∧
p p
6 5 4 3 2 1 0
int list_length(LinkList L) {int n=0; LinkList p=L->next; while(p!=NULL) { n++;p=p->next;} return n; }
exit(0);}
s=(SNode *) malloc(sizeof(SNode)); sdata=x; snext=prenext; prenext=s; }
5、删除算法的实现
void LinkListDelete(LinkList L,int i)
……..
ai-1
ai
ai+1
……..
P
相互之间的关系是靠其中的后继地址来表示的
动态链表:根据实际需要临时分配
结构描述如下: typedef struct SNode{ ElemType data; struct SNode *next; //指向结构体类型指针 }*LinkList;
表示稀疏矩阵的十字链表
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。
I第九讲(十字链表及基本操作)
(b)每行 列设一个表头结点(结构同元素结点), 每行/列设一个表头结点 结构同元素结点), 每行 列设一个表头结点( 为链构成循环链表, 以down/right为链构成循环链表,即第 列头结点的 为链构成循环链表 即第i列头结点的 down指向该列上第 个非 元素,第i 行头结点的 指向该列上第1个非 元素, 指向该列上第 个非0元素 right指向该行第 个非 元素.第i列/行上最后一个 指向该行第1个非 元素. 列 行上最后一个 指向该行第 个非0元素 结点的down/right指向该列 行的头结点.若某列 行 指向该列/行的头结点 若某列/行 结点的 指向该列 行的头结点. 中无非0元素 则令它的头结点down/right域指向自 元素, 中无非 元素,则令它的头结点 域指向自 己. (c)设一个总头结点(结构同元素结点),令总 设一个总头结点( ),令总 设一个总头结点 结构同元素结点), 头结点和各个列/行头结点用 字段 按列/行序构 头结点和各个列 行头结点用val字段,按列 行序构 行头结点用 字段, 成一个循环单链表. 成一个循环单链表.
row元素在稀疏矩阵中的行号col元素在稀疏矩阵中的列号val元素值down指向同列中下一个非0元素结点right指向同行中下一个非0元素结点rowcolvaldownrightb每行列设一个表头结点结构同元素结点以downri上第1个非0元素第i行头结点的right指向该行第1个非0元素
(d)可令总头结点的 可令总头结点的row,col与val 分别表示矩阵的 , 与 可令总头结点的 最大行号,列号与非0元素个数 元素个数, 最大行号,列号与非 元素个数,而down/right指向 指向 行的头结点. 第1列/行的头结点.该总头结点可作为整个十字链表 列 行的头结点 的代表. 的代表. (e)由于行与列的头结点分别使用 由于行与列的头结点分别使用right域与 域与down域 由于行与列的头结点分别使用 域与 域 (不同时使用 ,故第i列与第 行头结点可合用同一个 不同时使用),故第 列与第i 不同时使用 列与第 头结点(对所有可能的i),以节省存储空间. ),以节省存储空间 头结点(对所有可能的i),以节省存储空间. (f)有时,为了快速访问行 列头结点,设置一个一维 有时, 列头结点, 有时 为了快速访问行/列头结点 数组headNodes[] ,使headNodes[i]指向 行/列的 数组 指向i行 列的 指向 头结点.但这并不是必须的,因为各行/列的头结点 头结点.但这并不是必须的,因为各行 列的头结点 已形成了一个循环单链表, 已形成了一个循环单链表,故若已知十字链表总头 结点,即可搜索到任一头结点. 结点,即可搜索到任一头结点.
数据结构课程设计分类题目 (1)
(1)确定在序列中比正整数x大的数有几个(相同的数只计算一次,如序列{20,20,17,16,15,15,11,10,8,7,7,5,4}中比10大的数有5个);
13、设有一个由正整数组成的无序单链表,编写完成下列功能的算法:
(1)找出最小值结点,且打印该数值;
(2)若该数值是奇数,则将其与直接后继结点的数值交换;
(3)若该数值是偶数,则将其直接后继结点删除。
14、在一个递增有序的线性表中,有数值相同的元素存在。若存储方式为单链表,设计算法去掉数值相同的元素,使表中不再有重复的元素。例如:(7,10,10,21,30,42,42,42,51,70)将变作(7,10,21,30,42,51,70)。
printf(sum);}
树和二叉树
1、二叉树用二叉链表存储,写一个算法将二叉树中的叶子结点按从右至左的顺序建立一个单链表。
2、知二叉树用二叉链表存储,写出求二叉树宽度的算法。所谓宽度是指在二叉树的各层上,具有结点数最多的那一层上的结点总数。
3、叉树用二叉链表存储,写一个算法交换各结点的左右子树。
4、二叉树用二叉链表存储,若结点的左孩子的数据域的值大于右孩子数据域的值,则交换其左右子树。
19、试设计一个算法打印出由根结点出发到达叶结点的所有路径。
20、试写出算法,求任意二叉树中第一条最长的路径长度,并输出此路径上各结点的值。
21、给定一组项及其权值,假定项都存放于二叉树的树叶结点,则具有最小带权外部路径长度的树称为huffman 树。编写构造huffman 树 的算法。
22、已知一中序线索二叉树,写一算法完成对它的中序扫描。
十字链表和九宫格算法
十字链表和九宫格算法
十字链表是一种数据结构,它可以根据二维地图,将其分成x轴和y轴两个链表。
如果是三维地图,则还需要维护多一个z轴的链表。
将对象的坐标值按照大小相应的排列在相应的坐标轴上面。
十字链表的节点需要四个指针,分布为x轴的前后指针,y轴的前后指针。
而九宫格算法是一种空间划分算法,它将二维空间划分为九个等大的格子,每个格子代表一个区域。
对于每个格子,算法将计算出该格子内所有点的平均值,并将该格子内的点都替换为该平均值。
九宫格算法可以应用于图像处理、计算机视觉等领域,用于实现图像压缩、目标检测、图像分割等功能。
综上,十字链表和九宫格算法是两种不同的算法,应用的场景和解决的问题也不同。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 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在数据的输入过程中因为没有注意测试数据的范围,结果导致处理数据超出范围,出现错误。