图(graph)是一种比树结构还要复杂的数据结构,它的术语,存储方式,遍历方式,用途都比较广,所以如果想要一次性完成所有的代码,那代码会非常长。所以,我将分两次来完成图的代码。这一次,我会完成图的五种存储结构的创建(邻接矩阵存储,邻接表存储,十字链表存储,邻接多重表存储,边集数组存储),两种遍历方式(深度优先遍历,广度优先遍历)。与树结构一样,图结构的遍历也需要借助队列来协助实现。

  1 #include<stdio.h>
  2 #include<malloc.h>
  3 typedef char VertexType;        //顶点类型
  4 typedef int EdgeType;            //权值类型
  5 #define MAXVEX 100                //最大顶点数
  6 #define INFINITY 65535            //无限大
  7 #define TURE 1
  8 #define FALSE 0
  9 typedef int Boolean;
 10 Boolean visited[MAXVEX];            //记录访问过的结点数组
 11
 12 #define MAXSIZE 100                            //队列最大空间
 13 typedef int QElemType;                        //队列中元素类型
 14 typedef int Status;                            //返回值类型
 15 #define OK 1                                //操作成功
 16 #define ERROR 0                                //操作失败
 17
 18 typedef struct                                //队列结点结构
 19 {
 20     QElemType date[MAXSIZE];                //结点元素
 21     int front;                                //队头
 22     int rear;                                //队尾
 23 }SqQueue;
 24
 25 /*队列的初始化*/
 26 Status InitQue(SqQueue *Q)
 27 {
 28     Q->front = 0;                            //队头指向0
 29     Q->rear = 0;                            //队尾指向0
 30     return OK;
 31 }
 32
 33 /*队列的入队操作*/
 34 Status EnQueue(SqQueue *Q, QElemType e)
 35 {
 36     if((Q->rear + 1) % MAXSIZE == Q->front)                //判断队列是否已满
 37         return ERROR;
 38     Q->date[Q->rear] = e;                                //队尾赋值为e
 39     Q->rear = (Q->rear + 1) % MAXSIZE;                    //队尾后移
 40     return OK;
 41 }
 42
 43 /*队列的出队操作*/
 44 Status DeQueue(SqQueue *Q, QElemType *e)
 45 {
 46     if(Q->front == Q->rear)                                //判断队列是否为空
 47         return ERROR;
 48     *e = Q->date[Q->front];                                //将队头元素取出
 49     Q->front = (Q->front + 1) % MAXSIZE;                //队头后移
 50     return OK;
 51 }
 52
 53 /*获取队列的长度*/
 54 int LengthQue(SqQueue Q)
 55 {
 56     return (Q.rear - Q.front + MAXSIZE) % MAXSIZE;
 57 }
 58
 59 //邻接矩阵结构体
 60 typedef struct
 61 {
 62     VertexType adList[MAXVEX];            //声明顶点数组
 63     EdgeType arc[MAXVEX][MAXVEX];        //声明权值数组
 64     int numVerexes,numEdges;            //顶点数,边数
 65 }Graph;
 66
 67 //邻接表结构体
 68 typedef struct EdgeNode                //边表结构体
 69 {
 70     int adjSub;                        //存储边表的下标
 71 //    EdgeType weight;                //权重
 72     struct EdgeNode *next;            //指向下一个相邻顶点的指针
 73 }EdgeNode;
 74
 75 typedef struct VertexNode            //顶点结构体
 76 {
 77     VertexType date;                //顶点内容
 78     EdgeNode *firstEdge;            //指向顶点第一个邻接点
 79 }GraphList[MAXVEX];
 80
 81 typedef struct                        //邻接表结构体
 82 {
 83     GraphList graphList;            //顶点数组
 84     int numVerexes, numEdges;        //顶点数,边数
 85 }AjaGraph;
 86
 87 //十字链表结构体
 88 typedef struct Orthogonal            //边表结构体
 89 {
 90     int tailVex;                    //当前顶点下标
 91     int headVex;                    //弧尾顶点下标
 92     struct Orthogonal *tailLink;    //指向入度弧的弧尾
 93     struct Orthogonal *headLink;    //指向出度弧的弧头
 94 }Orthogonal;
 95
 96 typedef struct                        //顶点结构体
 97 {
 98     VertexType date;                //顶点内容
 99     Orthogonal *firstin;            //指向第一个弧头为自己的点
100     Orthogonal *firstout;            //指向第一个弧尾为自己的点
101 }Orthogonal_Node[MAXVEX];
102
103 typedef struct
104 {
105     Orthogonal_Node orth_Node;        //声明结点数组
106     int numVertexes,numEdges;        //顶点数量,边数量
107 }OrthGraph;                            //十字链表图结构
108
109 //边集数组结构体
110 typedef struct                        //边结构体
111 {
112     int iVex;                        //顶点位置
113     int jVex;                        //顶点位置
114     EdgeType weight;                //权重
115 }EdgeArray[MAXVEX];
116
117 typedef struct                        //图结构体
118 {
119     VertexType VexterList[MAXVEX];    //顶点数组
120     EdgeArray EdgeList;                //边数组
121     int numVexteres, numEdges;        //顶点数量,边数量
122 }EdgeListArray;                        //边集数组图结构
123
124 //邻接多重表
125 typedef struct EdgeList_multiple            //边表结点
126 {
127     int iVex;                                    //当前顶点下标
128     int jVex;                                    //终点下表
129     struct EdgeList_multiple *iLink;                    //指向与顶点i有相同起点的结点
130     struct EdgeList_multiple *jLink;                    //指向与顶点j有相同终点的结点
131 }EdgeList_multiple;
132
133 typedef struct
134 {
135     VertexType date;                        //顶点数据
136     EdgeList_multiple *firstEdge;            //指向顶点的第一个邻接点
137 }Vexs;
138
139 typedef struct
140 {
141     Vexs vexs[MAXVEX];                                //建立顶点数组
142     int numVexes;                            //顶点数量
143     int numEdges;                            //边的数量
144 }MultipleGraph;
145
146 //邻接多重表创建图结构
147 int CreatGraphMultiple(MultipleGraph *G)
148 {
149     int i,j,k;
150     printf("请输入顶点数i与边的数量j:");
151     scanf("%d,%d",&G->numVexes,&G->numEdges);
152     EdgeList_multiple *em;
153     getchar();
154     for(i = 0; i < G->numVexes; i++)
155     {
156         printf("请输入第%d个顶点:",i);
157         scanf("%c", &G->vexs[i].date);
158         getchar();
159     }
160     for(k = 0; k < G->numEdges; k++)
161     {
162         printf("请输入边的起点i与终点j的下标:");
163         scanf("%d,%d",&i,&j);
164         em = (EdgeList_multiple *)malloc(sizeof(EdgeList_multiple));        //创建新结点空间
165         em->iVex = i;
166         em->jVex = j;
167         em->iLink = G->vexs[i].firstEdge;
168         G->vexs[i].firstEdge = em;
169         em->jLink = G->vexs[j].firstEdge;
170         G->vexs[j].firstEdge = em;
171     }
172     return 1;
173 }
174
175 //邻接矩阵创建图结构
176 int CreatGraph(Graph *G)
177 {
178     int i,j,k,w;
179     printf("请输入结点数i,边数j:");
180     scanf("%d,%d",&G->numVerexes,&G->numEdges);        //写入顶点数和边数
181     for(i = 0; i < G->numVerexes; i++)                    //初始化顶点数组
182     {
183         printf("请输入第%d个顶点:",i);
184         scanf("%c",&G->adList[i]);
185         getchar();
186     }
187     for(i = 0; i < G->numVerexes; i++)                    //初始化权值矩阵
188         for(j = 0; j < G->numVerexes; j++)
189             G->arc[i][j] = INFINITY;
190     for(k = 0; k<G->numEdges; k++)                        //写入权值
191     {
192         printf("请输入需要添加权值的下标i和下标j,及其权值w:");
193         scanf("%d,%d,%d", &i, &j, &w);
194         G->arc[i][j] = w;
195         G->arc[j][i] = G->arc[i][j];                    //无向图的对称性
196     }
197     return 1;
198 }
199
200 //邻接表创建图结构
201 int CreatAjaGraph(AjaGraph *G)
202 {
203     int i, j, k;
204     char a;
205     EdgeNode *e;                                //声明边表新结点
206     printf("请输入顶点i和边数j:");
207     scanf("%d, %d", &G->numVerexes, &G->numEdges);        //写入顶点数与边数
208     getchar();
209     for(i = 0; i < G->numVerexes; i++)                    //初始化顶点数组
210     {
211         printf("请输入第%d个结点:",i);
212         scanf("%c",&G->graphList[i].date);
213         getchar();
214         printf("%c\n", a);
215         G->graphList[i].firstEdge = NULL;                //顶点数组的指针域指向空
216     }
217     for(k = 0; k < G->numEdges; k++)                    //构建边表
218     {
219         printf("请输入邻接点Vi与Vj的下标:");
220         scanf("%d,%d", &i, &j);
221         e = (EdgeNode *)malloc(sizeof(EdgeNode));        //创建新结点空间
222         e->adjSub = j;                                    //新结点的数据域为j
223         e->next = G->graphList[i].firstEdge;            //新结点指针域指向顶点指针域
224         G->graphList[i].firstEdge = e;                    //顶点指针域指向新结点
225
226         e = (EdgeNode *)malloc(sizeof(EdgeNode));        //因为是无向图
227         e->adjSub = i;                                    //同时为i操作
228         e->next = G->graphList[j].firstEdge;
229         G->graphList[j].firstEdge = e;
230     }
231
232     return 1;
233 }
234
235 //十字链表结构创建图结构
236 int CreatOrthGraph(OrthGraph *G)
237 {
238     int i,j,k;
239     Orthogonal *e;
240     printf("请输入顶点数量i和边数量j:");
241     scanf("%d,%d", &G->numVertexes, &G->numEdges);        //写入顶点数和边数
242     for(i = 0; i < G->numVertexes; i++)                    //对顶点数组初始化
243     {
244         printf("请输入第%d个结点:",i);
245         scanf("%c",&G->orth_Node[i].date);                    //输入顶点内容
246         getchar();
247         G->orth_Node[i].firstin = NULL;                    //将入边表指向空
248         G->orth_Node[i].firstout = NULL;                //将出边表指向空
249     }
250     for(k = 0; k < G->numEdges; k++)                    //构建边表
251     {
252         printf("请输入起点i与终点j的下标:");
253         scanf("%d,%d", &i, &j);
254         e = (Orthogonal *)malloc(sizeof(Orthogonal));    //创建新结点空间
255         e->tailVex = i;                                    //当前结点等于i
256         e->headVex = j;                                    //弧尾等于j
257         e->tailLink = G->orth_Node[i].firstout;            //入度指针等于顶点入度指针
258         G->orth_Node[i].firstout = e;                    //顶点位置i的firstout指向e
259         e->headLink = G->orth_Node[j].firstin;            //出度指针等于顶点出度指针
260         G->orth_Node[j].firstin = e;                    //顶点位置j的firstout指向e
261     }
262     return 1;
263 }
264
265 //边集数组创建图结构
266 int CreatGraph(EdgeListArray *G)
267 {
268     int i, j, w;
269     printf("请输入顶点数量i与边的数量j:");
270     scanf("%d,%d", &G->numVexteres, &G->numEdges);        //写入顶点数量与边数量
271     for(i = 0; i < G->numVexteres; i++)                    //构建顶点数组
272     {
273         printf("请输入第%d个结点:",i);
274         scanf("%c",&G->VexterList[i]);
275     }
276     for(i = 0; i < G->numEdges; i++)                    //构建边数组
277     {
278         printf("请输入顶点i与顶点j及其权重w:");
279         scanf("%d,%d", &i, &j, &w);
280         G->EdgeList[i].iVex = i;                        //这里的i只是边数组的下标,与顶点数组无关
281         G->EdgeList[i].jVex = j;
282         G->EdgeList[i].weight = w;
283     }
284     return 1;
285 }
286
287 //遍历邻接矩阵结构
288 void PrintfGraph(Graph G)
289 {
290     int i,j;
291     for(i = 0; i < G.numVerexes; i++)
292         for(j = 0; j < G.numVerexes; j++)
293             if(G.arc[i][j] != INFINITY && i < j)
294                 printf("顶点:    %d    ,    %d,     权重:    %d\n", i, j, G.arc[i][j]);
295 }
296
297 //邻接表深度优先遍历
298 void PrintDeepthAjaGraph(AjaGraph G, int i)            //递归函数
299 {
300     visited[i] = TURE;                                //将此顶点记为访问过
301     printf("%c\n", G.graphList[i].date);            //打印当前顶点
302     EdgeNode *ag;                                    //创建顶点指针
303     ag = G.graphList[i].firstEdge;                    //将此指针赋值为当前顶点的边表第一个结点
304     while(ag)                                        //只要ag不为空
305     {
306         if(!visited[ag->adjSub])                    //如果当前边表第一个结点不为空
307             PrintDeepthAjaGraph(G, ag->adjSub);        //递归
308         ag = ag->next;                                //否则ag赋值为ag的下一临结点
309     }
310 }
311
312 void Depth_first(AjaGraph G)                //深度优先遍历函数
313 {
314     int j;
315     for(j = 0; j < G.numVerexes; j++)        //初始化记录数组
316         visited[j] = FALSE;
317     for(j = 0; j < G.numVerexes; j++)        //遍历顶点数组中的每一个顶点
318     {
319 //        printf("当前结点是:%d, 其是否遍历过 %d\n", j, visited[j]);
320         if(!visited[j])                        //如果当前结点没被访问过
321             PrintDeepthAjaGraph(G, j);        //调用递归函数
322     }
323 }
324
325 //邻接表广度优先搜索
326 void BFs(AjaGraph G)
327 {
328     int j;
329     SqQueue Q;            //创建队Q
330     InitQue(&Q);        //初始化队列
331     for(j = 0; j < G.numVerexes; j++)            //初始化记录数组
332         visited[j] = FALSE;
333     EdgeNode *ag;                                //创建边表指针
334     visited[0] = TURE;                            //将第一个顶点记为访问过
335     printf("%c\n", G.graphList[0].date);        //打印第一个顶点
336     EnQueue(&Q, 0);                                //将第一个顶点入队
337     while(Q.front != Q.rear)                    //只要队列不为空
338     {
339         DeQueue(&Q, &j);                        //将当前顶点出队
340         ag = G.graphList[j].firstEdge;            //ag赋值为当前结点的第一个边表结点
341         while(ag && !visited[ag->adjSub])        //ag不为空且ag未被访问过
342         {
343             visited[ag->adjSub] = TURE;            //将ag记为访问过
344             printf("%c\n", G.graphList[ag->adjSub].date);    //打印ag
345             EnQueue(&Q, ag->adjSub);            //将ag入队
346             ag = ag->next;                        //ag赋值为ag的下一邻接表结点
347         }
348     }
349 }
350
351 void main()
352 {
353     Graph G1;
354     AjaGraph G2;
355     OrthGraph G3;
356     MultipleGraph G4;
357     EdgeListArray G5;
358     while(true)
359     {
360         int flag = 0;
361         printf("请选择对图的操作:\n");
362         printf("1.邻接矩阵存储创建\n");
363         printf("2.邻接表存储创建\n");
364         printf("3.十字链表存储创建\n");
365         printf("4.邻接多重表创建\n");
366         printf("5.边集数组创建\n");
367         printf("6.遍历邻接矩阵图结构\n");
368         printf("7.邻接表深度优先遍历\n");
369         printf("8.遍历线索化二叉树\n");
370         printf("9.退出\n");
371         int a;
372         scanf("%d", &a);
373         switch(a)
374         {
375             case 1:
376                 flag = 0;
377                 flag = CreatGraph(&G1);
378                 if(flag)
379                     printf("创建成功\n");
380                 else
381                     printf("创建失败\n");
382                 break;
383             case 2:
384                 flag = 0;
385                 flag = CreatAjaGraph(&G2);
386                 if(flag)
387                     printf("创建成功\n");
388                 else
389                     printf("创建失败\n");
390                 break;
391             case 3:
392                 flag = 0;
393                 flag = CreatOrthGraph(&G3);
394                 if(flag)
395                     printf("创建成功\n");
396                 else
397                     printf("创建失败\n");
398                 break;
399             case 4:
400                 flag = 0;
401                 flag = CreatGraphMultiple(&G4);
402                 if(flag)
403                     printf("创建成功\n");
404                 else
405                     printf("创建失败\n");
406                 break;
407             case 5:
408                 flag = 0;
409                 CreatGraph(&G5);
410                 if(flag)
411                     printf("创建成功\n");
412                 else
413                     printf("创建失败\n");
414                 break;
415             case 6:
416                 PrintfGraph(G1);
417                 break;
418             case 7:
419                 Depth_first(G2);
420                 break;
421             case 8:
422                 BFs(G2);
423                 break;
424             case 9:
425                 return;
426             default:
427                 printf("选择错误\n");
428                 break;
429         }
430     }
431 }

转载于:https://www.cnblogs.com/yurui/p/10362128.html

图的存储结构与操作--C语言实现相关推荐

  1. 20.0、C语言数据结构——图的存储结构

    20.0.C语言数据结构--图的存储结构 图的存储结构相比较线性表与树来说就复杂很多了: 1. 我们回顾下,对于线性表来说,是一对一的关系,所以用数组或者链表均可简单存放:树结构是一对多的关系,所以我 ...

  2. 数据结构之图的存储结构一及其实现

    图的存储结构 由于图的结构比较复杂,任意两个顶点之间都可能存在联系,因此无法以数据元素在存储区中的物理位置来表示元素之间的关系,即图没有顺序映像的存储结构,但可以借助数组的数据类型表示元素之间的关系. ...

  3. 数据结构——图:极大小连通子图、图的存储结构、图的遍历

    图的基本概念: 极大连通子图就是连通分量. 极大连通子图与连通分量在无向图(undirected graph)这个前提下是等同的概念. 极小连通子图: 减去任何一条边就不再连通. 不管树还是二叉树:n ...

  4. 数据结构——图(存储结构)

    数据结构--图 图的定义和基本术语 图的类型定义 图的存储结构 数组(邻接矩阵表示法) 网(即有权图)的邻接矩阵表示法 邻接表 邻接表表示法(链式) 图的邻接表存储表示 采用邻接表表示法创建无向网 邻 ...

  5. 【数据结构——图和图的存储结构】

    目录 一.图的定义和基本术语(Graph) (一)图的定义 (二)图的基本术语 一.图的存储结构 (一)邻接矩阵(Adjacency Matrix) 1.无向图的邻接矩阵 2.有向图的邻接矩阵 3.网 ...

  6. 图——图的存储结构(邻接矩阵和邻接表法)

    图的五种存储结构: 1.图的邻接矩阵表示法 图是由顶点和边或弧两部分组成.图的邻接矩阵(Adjacency Matrix)存储方式是用两个数组表示图,一个一维数组存储图中的顶点信息,一个二维数组(邻接 ...

  7. 图——基本的图算法(一)图的存储结构

    图--基本的图算法(一)图的存储结构 1. 图的存储结构概述 对于图G=(V, E)来说,可以有两种标准的表示方法,一个是邻接矩阵,另一个是邻接链表,这两种方法都可以表示有向图和无向图.除此之外,图的 ...

  8. 数据结构之图的存储结构:邻接多重表

    图的存储结构:邻接多重表 产生条件: 邻接多重表的定义: 邻接多重表的代码定义: 删除: 性能分析: 十字链表与邻接多重表的对比 产生条件: 当用邻接矩阵法存储时:空间复杂度为O(|V|^2),太大 ...

  9. 数据结构之图的存储结构:十字链表法

    图的存储结构:十字链表法 思维导图: 产生条件: 十字链表法的定义: 十字链表法的代码定义: 性能分析: 思维导图: 产生条件: 当用邻接矩阵存储时:空间复杂度为O(|v|^2),太大 当用邻接表法存 ...

最新文章

  1. 【新产品发布】《EVC8021 RS-232RS-485/422 隔离接口转换器》
  2. MFC EDIT控件的使用记录
  3. Lodash常用用法总结
  4. P3911 最小公倍数之和 (atcoder C - LCMs)(反演)
  5. iptables 开放远程_JavaWeb项目的部署以及远程调试
  6. LinuxQt工作笔记-查看程序工作目录
  7. android r 编译找不到头文件_嵌入式开发之交叉编译程序万能命令_以freetype为例...
  8. 让你更好的使用jQuery插件
  9. spss方差分析_SPSS统计案例:考虑交互作用的双因素方差分析
  10. python转换word到html,Python实现批量将word转html并将html内容发布至网站的方法
  11. JPEG图像压缩和解压缩操作
  12. EXCEL VBA 使用正则表达式清洗替换数据
  13. oracle中更改用户名,Oracle 更改用户名
  14. 操作系统-存储器管理实验
  15. 教你用html+js制作一个自己的点名系统,实例代码分享
  16. SDNU-1183.纪念品分组
  17. 移动互联网时代的新特点
  18. 生产制造|销售管理实时在线,业务效率直线提升
  19. win7上安装MySQL没提示密码_win7下安装mysql后修改密码
  20. json数据导出到excel中

热门文章

  1. android app 历史版本,怎么找到App的所有历史版本,以及每次改版的变更点呢?
  2. php怎么写获取手机剪切板到搜索栏,如何根据指定的剪切板获取html?
  3. python爬虫beautifulsoup实例-Python爬虫学习(二)使用Beautiful Soup库
  4. python简单代码hello-小白学 Python(1):开篇
  5. python画折线图详解-Python数据可视化(一) 绘制折线图和散点图
  6. python四大软件-传智播客解析Python之移动端页面适配四大方式
  7. python科学计算基础教程pdf下载-Python科学计算基础教程_PDF电子书
  8. python编程入门指南怎么样-学习python网络编程怎么入门
  9. 初学者python编辑器-分享|Mu 入门:一个面向初学者的 Python 编辑器
  10. 学python工资高吗-Python工资一般是多少 看完吓你一跳