数据结构与算法-图的邻接表
实验报告
课程:数据结构与算法实验日期:
实验名称:图的邻接表
一、实验目的
掌握图的邻接表的创建和遍历
二、实验内容
必做部分
1、给出图的邻接表存储结构的类型定义。
2、设计并实现以邻接表的方式构造一个无向网的算法。
Status CreateUDN(ALGraph &G)
3、设计并实现无向网的输出算法,要求能显示顶点以及顶点之间的邻接关系(方式自定)
4、基于邻接表方式实现:
a) int FirstAdjVex(ALGraph G,int v) //返回v的第一个邻接点的下标,若不存在,则返回-1
b) int NextAdjVex(ALGraph G,int v,int w) // 返回v相对于w的下一个邻接点,若不存在,则返回-1
5、基于邻接表存储结构实现图的深度优先搜索算法。
void DFSTraverse(ALGraph G)
6、在主函数中调用上述操作函数。要求给出至少两组测试数据。
选做部分
基于邻接表存储结构实现图的广度优先搜索算法。
三、实验步骤
必做部分
1、给出图的邻接表存储结构的类型定义。
2、设计并实现以邻接表的方式构造一个无向网的算法。
Status CreateUDN(ALGraph &G)
3、设计并实现无向网的输出算法,要求能显示顶点以及顶点之间的邻接关系(方式自定)
4、基于邻接表方式实现:
a) int FirstAdjVex(ALGraph G,int v) //返回v的第一个邻接点的下标,若不存在,则返回-1
b) int NextAdjVex(ALGraph G,int v,int w) // 返回v相对于w的下一个邻接点,若不存在,则返回-1
5、基于邻接表存储结构实现图的深度优先搜索算法。
void DFSTraverse(ALGraph G)
6、在主函数中调用上述操作函数。要求给出至少两组测试数据。
选做部分
基于邻接表存储结构实现图的广度优先搜索算法。
四、实验结果
五、实验总结
1、邻接表是图的一种链式存储结构,在邻接表中,对图的每个定点建立一个单链表,
第i个单链表中的节点表示依附于定点Vi的边。
2、邻接表的类型定义包含了三个结构体,定义了顶点个数,弧数,顶点数组,权值指
向下一条弧的指针等,在用时需要分清楚,写对。
3、邻接表构造无向网,其在编程序时,类似于单链表的指针操作
4、深度优先遍历:类似于树的先根遍历,是树先根遍历的推广。
5、广度优先遍历:类似于树的按层次遍历的过程,其中结合了循环队列的使用
邻接表存储结构建立无向图
//算法功能:采用邻接表存储结构建立无向图 #include
邻接表存储表示
邻接表存储表示 Status Build_AdjList(ALGraph &G)//输入有向图的顶点数,边数,顶点信息和边的信息建立邻接表 { InitALGraph(G); scanf("%d",&v); if(v<0) return ERROR; G.vexnum=v; scanf("%d",&a); if(a<0) return ERROR; G.arcnum=a; for(m=0;m 邻接表表示的图的基本操作的实现 //采用邻接表完成无权无向及有向图的"建立、输出、深度遍历、广度遍历"操作 #include typedef struct Headnode//头结点结构 { ElemType vertex;//顶点域vertex,存放顶点vi的信息 struct Tablenode *firstEdge;//vi的邻接表的头指针 }HeadNode; typedef struct Mgraph { struct Headnode vector[MAX_VERTEX_NUM]; //顶点向量 int vexnum; //图中当前顶点数 } MGraph; //队列初始化 Status InitLinkQueue(LinkQueue *Q) { QNode *p; p=(QNode*)malloc(sizeof(QNode));//开辟头结点空间 if(p!=NULL) { p->next=NULL; Q->front=Q->rear=p; return OK; } else return ERROR; } //链式队列的入队操作,在已知队列的队尾插入一个元素e,修改队尾指针rear。 Status InsertLinkQueue(LinkQueue *Q,ElemType e) { QNode *p; 浙江大学城市学院实验报告 课程名称数据结构基础 实验项目名称实验十三图的基本操作—邻接表存储结构 学生姓名专业班级学号 实验成绩指导老师(签名)日期2015-1-15 一.实验目的和要求 1、掌握图的存储结构:邻接表。 2、学会对图的存储结构进行基本操作。 二.实验内容 1、图的邻接表的定义及实现:建立头文件AdjLink.h,在该文件中定义图的邻接表存储结构,并编写图的初始化、建立图、输出图、输出图的每个顶点的度等基本操作实现函数。同时在主函数文件test5_2.cpp中调用这些函数进行验证。 2、选做:编写图的深度优先遍历函数与广度优先遍历函数,要求把这两个函数添加到头文件AdjLink.h中,并在主函数文件test5_2.cpp中添加相应语句进行测试。 3、填写实验报告,实验报告文件取名为report13.doc。 4、上传实验报告文件report13.doc及源程序文件test5_2.cpp、AdjLink.h到Ftp服务器上自己的文件夹下。 三. 函数的功能说明及算法思路 (包括每个函数的功能说明,及一些重要函数的算法实现思路) 邻接表表示法的C语言描述: typedef struct Node { int adjvex; // 邻接点的位置 WeightType weight; //权值域,根据需要设立 struct Node *next; // 指向下一条边(弧) } edgenode; // 边结点 typedef edgenode *adjlist[ MaxVertexNum ];//定义图的邻接表结构类型(没包含顶点信息) typedef struct{ vexlist vexs; //顶点数据元素 《图的邻接表存储结构实验报告》1.需解决的的问题 利用邻接表存储结果,设计一种图。 2.数据结构的定义 typedef struct node {//边表结点 int adj;//边表结点数据域 struct node *next; }node; typedef struct vnode {//顶点表结点 char name[20]; node *fnext; }vnode,AList[M]; typedef struct{ AList List;//邻接表 int v,e;//顶点树和边数 }*Graph; 3.程序的结构图 4.函数的功能 1)建立无向邻接表 Graph Create1( )//建立无向邻接表{ Graph G; int i,j,k; node *s; G=malloc(M*sizeof(vnode)); printf("输入图的顶点数和边数:"); scanf("%d%d",&G->v,&G->e);//读入顶点数和边数for(i=0;i 图的邻接表存储方式——数组实现初探 焦作市外国语中学岳卫华在图论中,图的存储结构最常用的就是就是邻接表和邻接矩阵。一旦顶点的个数超过5000,邻接矩阵就会“爆掉”空间,那么就只能用邻接表来存储。比如noip09的第三题,如果想过掉全部数据,就必须用邻接表来存储。 但是,在平时的教学中,发现用动态的链表来实现邻接表实现时,跟踪调试很困难,一些学生于是就觉得邻接表的存储方式很困难。经过查找资料,发现,其实完全可以用静态的数组来实现邻接表。本文就是对这种方式进行探讨。 我们知道,邻接表是用一个一维数组来存储顶点,并由顶点来扩展和其相邻的边。具体表示如下图: 其相应的类型定义如下: type point=^node; node=record v:integer; //另一个顶点 next:point; //下一条边 end; var a:array[1..maxv]of point; 而用数组实现邻接表,则需要定义两个数组:一个是顶点数组,一个 是边集数组。 顶点编号结点相临边的总数s第一条邻接边next 此边的另一邻接点边权值下一个邻接边 对于上图来说,具体的邻接表就是: 由上图我们可以知道,和编号为1的顶点相邻的有3条边,第一条边在边集数组里的编号是5,而和编号为5同一个顶点的下条边的编号为3,再往下的边的编号是1,那么和顶点1相邻的3条边的编号分别就是5,3,1。同理和顶点3相邻的3条边的编号分别是11,8,4。如果理解数组表示邻接表的原理,那么实现就很容易了。 类型定义如下: 见图的代码和动态邻接表类似: 下面提供一道例题 邀请卡分发deliver.pas/c/cpp 【题目描述】 实现图的邻接矩阵和邻接表存储 1.需求分析 对于下图所示的有向图G,编写一个程序完成如下功能: 1.建立G的邻接矩阵并输出之 2.由G的邻接矩阵产生邻接表并输出之 3.再由2的邻接表产生对应的邻接矩阵并输出之 2.系统设计 1.图的抽象数据类型定义: ADT Graph{ 数据对象V:V是具有相同特性的数据元素的集合,称为顶点集 数据关系R: R={VR} VR={ 一旦Visit()失败,则操作失败 BFSTraverse(G,Visit()) 初始条件:图G存在,Visit是顶点的应用函数 操作结果:对图进行广度优先遍历,在遍历过程中对每个顶点调用函数Visit一次且仅一次。一旦Visit()失败,则操作失败 }ADT Graph 2.主程序的流程: 调用CreateMG函数创建邻接矩阵M; 调用PrintMatrix函数输出邻接矩阵M 调用CreateMGtoDN函数,由邻接矩阵M创建邻接表G 调用PrintDN函数输出邻接表G 调用CreateDNtoMG函数,由邻接表M创建邻接矩阵N 调用PrintMatrix函数输出邻接矩阵N 3.函数关系调用图: 3.调试分析 (1)在MGraph的定义中有枚举类型 typedef enum{DG,DN,UDG,UDN}GraphKind;//{有向图,有向网,无向图,无向网} 赋值语句G.kind(int)=M.kind(GraphKind);是正确的,而反过来M.kind=G.kind则是错误的,要加上那个强制转换M.kind=GraphKind(G.kind);枚举类型enum{DG,DN,UDG,UDN} 会自动赋值DG=0;DN=1,UDG=2,UDN=3;可以自动从GraphKind类型转换到int型,但不会自动从int型转换到GraphKind类型 ===实习报告一“邻接表表示的带权有向图(网)”演示程序=== (一)、程序的功能和特点 1. 程序功能:建立有向图的带权邻接表,能够对建立的邻接表进行添加顶点,添加边和删除顶点,删除边的操作,并能显示输出邻接表。 2. 程序特点:采用java面向对象语言,对边,顶点和邻接表用类进行封装。采用链式存储结构。 (二八程序的算法设计 算法一:“插入一个顶点”算法: 1. 【逻辑结构与存储结构设计】 逻辑结构:线性结构。存储结构:顺序存储与链式存储结合。 邻接表(Adjacency List)是图的一种顺序存储与链式存储结合的存储方法。。邻接表表示法类似于树的孩子链表表示法。就是对于图G中的每个顶点vi,将所有邻接于vi的顶点vj链成一个单链表,这个单链表就称为顶点vi的邻接表,再将所有点的邻接表表头放到数组中,就构成了图的邻接表。如下图就是一个临界表的存储图。 vertex firstedge adjvex n ext 序号vertex firstedge 图的邻接表表示在邻接表表示中有两种结点 结构,如图所示。 邻接矩阵表示的结点结构 顶点域边指针 流程示意图:顶点数据组成的数组 顶点数组表的顺序存储: V0 V1— V2— O 2.【基本操作设计】 文字说明: (1) .首先判断顶点表是否满。 (2) .若满则插入失败,放回false 。 (3) .顶点表若不满,创建新顶点,将新顶点加入顶点表 (4) .插入顶点成功,返回true 。 添加顶点前状态 添加顶点v2后 网图的边表结构 //插入一个顶点 public boolea n In sertVertex ( char vertex ){ if (NumVertices ==MaxVertices ) return false ; // 顶点表满 Vertex t= n ewVertex(); t. data =vertex; t. adj =null ; NodeTable[ NumVertices ]=t; NumVertices++; //注明:企图以下赋值不合Java 语法 〃NodeTable[NumVertices].data=vertex; 〃NodeTable[NumVertices].adj=null; return true ; } 算法二:“插入一条边”算法: 1. 【逻辑结构与存储结构设计】 逻辑结构:线性结构。 存储结构:链式存储结构 网图的边表结构如图所示。 邻接点域 4.【高级语言代码】 图的邻接矩阵和邻接表相互转换 图的邻接矩阵存储方法具有如下几个特征:1)无向图的邻接矩阵一定是一个对称矩阵。 2)对于无向图的邻接矩阵的第i 行非零元素的个数正好是第i 个顶点的度()i v TD 。3)对于有向图,邻接矩阵的第i 行非零元素的个数正好是第i 个顶点的出度()i v OD (或入度 ()i v ID ) 。4)用邻接矩阵方法存储图,很容易确定图中任意两个顶点之间是否有边相连;但是,要确定图中有多少条边,则必须按行、按列对每个元素进行检测,所发费得时间代价大。 邻接表是图的一种顺序存储与链式存储相结合的存储方法。若无向图中有n 个顶点、e 条边,则它的邻接表需n 个头结点和2e 个表结点。显然,在边稀疏的情况下,用邻接表表示图比邻接矩阵存储空间。在无向图的邻接表中,顶点i v 的度恰好是第i 个链表中的结点数,而在有向图中,第i 个链表中结点个数是顶点i v 的出度。 在建立邻接表或邻逆接表时,若输入的顶点信息即为顶点的编号,则建立临接表的时间复杂度是)(e n O +;否则,需要通过查找才能得到顶点在图中位置,则时间复杂度为)*(e n O 。在邻接表上容易找到任意一顶点的第一个邻接点和下一个邻接点,但要判断任意两个顶点之间是否有边或弧,则需要搜索第i 个或第j 个链表,因此,不及邻接矩阵方便。 邻接矩阵和邻接表相互转换程序代码如下: #include /* 头文件:graph1.h:邻接表,中的遍历,生成树,关键路径 */ int menu_netselect1() { /* 邻接表菜单选择系统 */ char s[8]; int c; clrscr(); /* 清屏 */ printf("\n"); printf("\n"); printf(" ************************************ \n"); printf(" * * \n"); printf(" * 邻接表结构操作窗口 * \n"); printf(" * * \n"); printf(" * 无向网:a1.txt; ..... i1.txt; * \n"); printf(" * 有向网:a2.txt; ..... i2.txt; * \n"); printf(" * 无环网:a3.txt; ..... i3.txt; * \n"); printf(" * * \n"); printf(" ************************************ \n"); printf("\n"); printf(" 01:建立邻接表(无向网)\n"); printf(" 02:建立邻接表(有向网)\n"); printf(" 03:输出邻接表结构\n"); printf(" 04:深度遍(连通-非连通)\n"); printf(" 05:广度遍(连通-非连通)\n"); printf(" 06:邻接表 DFS 树\n"); printf(" 07:邻接表 BFS 树\n"); printf(" 08:深度遍历建生成树(无向 网)\n"); printf(" 09:拓扑排序(有向无环网)\n"); printf(" 10:关键路径(有向无环网)\n"); printf(" 11:销毁当前邻接表\n"); printf(" 12:返回主窗口\n"); do { printf("\n"); printf(" 输入你的选择号:1---12: "); gets(s); c=atoi(s); }while(c<0||c>12); return(c); } int LocateVex1(ALGraph G,VertexType u) 运行结果是: 请输入节点数和弧数:3 3 第1 个节点信息:5 第2 个节点信息:6 第3 个节点信息:7 第1 条弧的弧尾和弧头的位置:1 2 第2 条弧的弧尾和弧头的位置:2 3 第3 条弧的弧尾和弧头的位置:1 3 图的邻接表表示为: [1,5]-->[3,7]-->[2,6]-->^ [2,6]-->[3,7]-->[1,5]-->^ [3,7]-->[1,5]-->[2,6]-->^ 交换后是:: 图的邻接矩阵表示为: 0 1 1 1 0 1 1 1 0 请按任意键继续. . . 代码是: #include struct arcnode *nextarc; }; struct vexnode { int data; struct arcnode *firstarc; }; struct graph { int vexnum,arcnum; vexnode vexpex[100]; }; struct graph *creatgraph() { int i,s,d; struct graph *g; struct arcnode *p,*q; g = (struct graph *)malloc(sizeof(struct graph)); printf("请输入节点数和弧数:"); scanf("%d%d", &g->vexnum, &g->arcnum); for(i=1; i<=g->vexnum; i++) { printf("第%d 个节点信息:",i); scanf("%d", &g->vexpex[i].data); g->vexpex[i].firstarc = NULL; } for(i=1; i<=g->arcnum; i++) { p = (struct arcnode *)malloc(sizeof(struct arcnode)); q = (struct arcnode *)malloc(sizeof(struct arcnode)); printf("第%d 条弧的弧尾和弧头的位置:",i); scanf("%d%d",&s,&d); p->adjvex = d; p->info = g->vexpex[d].data; p->nextarc = g->vexpex[s].firstarc; g->vexpex[s].firstarc = p; q->adjvex = s; q->info = g->vexpex[s].data; q->nextarc = g->vexpex[d].firstarc; g->vexpex[d].firstarc = q; 标头.h #include #include 实验六图的邻接表存储及遍历 一、实验学时 2学时 二、背景知识 1.图的邻接表存储结构 在图的邻接表中,图中每个顶点都建立一个单链表,第i个单链表中的结点数为顶点i的出度。(逆邻接表中,第i个单链表中的结点数为顶点i的入度) 邻接表的数据结构描述为: struct node { int vertex; struct node *nextnode; }; typedef struct node *graph; struct node head[vertexnum]; 2.图的遍历 深度优先遍历(DFS)法: 算法步骤: 1)初始化: (1)置所有顶点“未访问”标志; (2)打印起始顶点; (3)置起始顶点“已访问”标志; (4)起始顶点进栈。 2)当栈非空时重复做: (1)取栈顶点; (2)如栈顶顶点存在未被访问过的邻接顶点,则选择第一个顶点做: ①打印该顶点; ②置顶点为“已访问”标志; ③该顶点进栈; 否则,当前栈顶顶点退栈。 3)结束。 广度优先遍历(BFS)法: 算法步骤: 1) 初始化: (1)置所有顶点“未访问”标志; (2)打印起始顶点; (3)置起始顶点“已访问”标志; (4)起始顶点入队。 2)当队列非空时重复做: (1)取队首顶点; (2)对与队首顶点邻接的所有未被访问的顶点依次做: ①打印该顶点; ②置顶点为“已访问”标志; ③该顶点入队; 否则,当前队首顶点出队。 3) 结束。 三、目的要求 1.掌握图的基本存储方法; 2.掌握有关图的操作算法并用高级语言实现; 3.熟练掌握图的两种搜索路径的遍历方法。 四、实验内容 1.编写程序实现下图的邻接表表示及其基础上的深度和广度优先遍历。 五、程序实例 图的邻接表表示法的C语言描述: #include 分别以邻接矩阵和邻接表作为图的存储结构,给出连通图的深度优先 遍历的递归算法 算法思想: (1)访问出发点vi,并将其标记为已访问过。 (2)遍历vi的的每一个邻接点vj,若vi未曾访问过,则以vi为新的出发点继续进行深度优先遍历。 算法实现: Boolean visited[max]; // 访问标志数 void DFS(Graph G, int v) { // 算法7.5从第v个顶点出发递归地深度优先遍历图G int w; visited[v] = TRUE; printf("%d ",v); // 访问第v个顶点for (w=FirstAdjVex(G, v); w>=0; w=NextAdjVex(G, v, w)) if (!visited[w]) // 对v的尚未访问的邻接顶点w递归调用DFS DFS(G, w); } /*****************************************************/ /*以邻接矩阵作为存储结构*/ DFS1(MGraph G,int i) {int j; visited[i]=1; printf("%c",G.vexs[i]); for(j=1;j<=G.vexnum;j++) if(!visited[j]&&G.arcs[i][j]==1) DFS1(G,j); } /*以邻接表作为存储结构*/ DFS2(ALGraph G,int i) {int j; ArcPtr p; visited[i]=1; printf("%c",G.vertices[i].data); for(p=G.vertices[i].firstarc;p!=NULL;p=p->nextarc) {j=p->adjvex; if(!visited[j]) DFS2(j); } } ata && i < ; i++) ; if(i >= return -1; return i; } ata); irstarc = NULL; getchar(); } char v1, v2; for(int k = 0; k < ; k++) { printf("输入第 %d 条边依附的顶点v1: ", k+1); scanf("%c", &v1); getchar(); printf("输入第 %d 条边依附的顶点v2: ", k+1); scanf("%c", &v2); getchar(); int i = LocateVex(G, v1); int j = LocateVex(G, v2); irstarc; [i].firstarc =s; t->adjvex = i; irstarc; [j].firstarc =t; } return OK; } Status PrintAdjList(ALGraph &G) { ArcNode *p; printf("%4s%6s%12s\n", "编号", "顶点", "相邻边编号"); for(int i = 0; i < ; i++) { printf("%4d%6c", i, [i].data); for(p = [i].firstarc; p; p = p->nextarc) printf("%4d", p->adjvex); printf("\n"); } return OK; } int main() { ALGraph G; CreateUDN(G); rintAdjList(G); return 0; } 福建江夏学院 《数据结构与关系数据库(本科)》实验报告姓名班级学号实验日期 课程名称数据结构与关系数据库(本科)指导教师成绩 实验名称:深度优先遍历以邻接表存储的图 一、实验目的 1、掌握以邻接表存储的图的深度优先遍历算法; 二、实验环境 1、硬件环境:微机 2、软件环境:Windows XP,VC6.0 三、实验内容、步骤及结果 1、实验内容: 基于图的深度优先遍历编写一个算法,判别以邻接表方式存储的有向图中是否存在由顶点vi到顶点vj的路径(i≠j)。 2、代码: #include 课程设计题目九:图的广度优先遍历 基本要求: 采用邻接表存储结构实现图的广度优先遍历。 (2)对任意给定的图(顶点数和边数自定),建立它的邻接表并输出;(3)实现图的广度优先遍历*/ #include 图的邻接表表示法 图的邻接表表示法类似于树的孩子链表表示法。对于图G中的每个顶点v i,该方法把所有邻接于v i的顶点v j链成一个带头结点的单链表,这个单链表就称为顶点v i的邻接表(Adjacency List)。 1.邻接表的结点结构 (1 : ① 邻接点域adjvex 存放与vi相邻接的顶点v j的序号j。 ② 链域next 将邻接表的所有表结点链在一起。 注意:若要表示边上的信息(如权值),则在表结点中还应增加一个数据域。 顶点v i邻接表的头结点包含两个域: ① 顶点域vertex 存放顶点v i的信息 ② 指针域firstedge v i的邻接表的头指针。 注意: ① 为了便于随机访问任一顶点的邻接表,将所有头结点顺序存储在一个向量中就构成了图的邻接表表示。 ② 有时希望增加对图的顶点数及边数等属性的描述,可将邻接表和这些属性放在一起来描述图的存储结构。 2.无向图的邻接表 对于无向图,v i的邻接表中每个表结点都对应于与v i相关联的一条边。因此,将邻接表的表头向量称为顶点表。将无向图的邻接表称为边表。 【例】对于无向图G5,其邻接表表示如下面所示,其中顶点v0的边表上三个表结点中的顶点序号分别为1、2和3,它们分别表示关联于v0的三条边(v0,v1),(v0,v2)和(v0,v3)。 注意:n个顶点e条边的无向图的邻接表表示中有n个顶点表结点和2e个边表结点。 3.有向图的邻接表 对于有向图,v i的邻接表中每个表结点都对应于以v i为始点射出的一条边。因此,将有向图的邻接表称为出边表。 【例】有向图G6的邻接表表示如下面(a)图所示,其中顶点v1的邻接表上两个表结点中的顶点序号分别为0和4,它们分别表示从v1射出的两条边(简称为v1的出边):邻接表表示的图的基本操作的实现
实验十三 图的基本操作—邻接表存储结构
图的邻接表存储结构实验报告
图的邻接表存储方式.
实现图的邻接矩阵和邻接表存储
邻接表表示的带权有向图(网)
图的邻接矩阵和邻接表相互转换
邻接表结构函数(GRAPH1.H)。。
经典代码之图 邻接表转换成邻接矩阵
图的基本操作(邻接表)
实现图的邻接矩阵和邻接表存储
实验六 图的邻接表存储及遍历
分别以邻接矩阵和邻接表作为图的存储结构
邻接表存储结构建立无向图
2-深度优先遍历以邻接表存储的图-实验报告
采用邻接表存储结构实现图的广度优先遍历。
图的邻接表表示法