图的存储结构与操作--C语言实现
图(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语言实现相关推荐
- 20.0、C语言数据结构——图的存储结构
20.0.C语言数据结构--图的存储结构 图的存储结构相比较线性表与树来说就复杂很多了: 1. 我们回顾下,对于线性表来说,是一对一的关系,所以用数组或者链表均可简单存放:树结构是一对多的关系,所以我 ...
- 数据结构之图的存储结构一及其实现
图的存储结构 由于图的结构比较复杂,任意两个顶点之间都可能存在联系,因此无法以数据元素在存储区中的物理位置来表示元素之间的关系,即图没有顺序映像的存储结构,但可以借助数组的数据类型表示元素之间的关系. ...
- 数据结构——图:极大小连通子图、图的存储结构、图的遍历
图的基本概念: 极大连通子图就是连通分量. 极大连通子图与连通分量在无向图(undirected graph)这个前提下是等同的概念. 极小连通子图: 减去任何一条边就不再连通. 不管树还是二叉树:n ...
- 数据结构——图(存储结构)
数据结构--图 图的定义和基本术语 图的类型定义 图的存储结构 数组(邻接矩阵表示法) 网(即有权图)的邻接矩阵表示法 邻接表 邻接表表示法(链式) 图的邻接表存储表示 采用邻接表表示法创建无向网 邻 ...
- 【数据结构——图和图的存储结构】
目录 一.图的定义和基本术语(Graph) (一)图的定义 (二)图的基本术语 一.图的存储结构 (一)邻接矩阵(Adjacency Matrix) 1.无向图的邻接矩阵 2.有向图的邻接矩阵 3.网 ...
- 图——图的存储结构(邻接矩阵和邻接表法)
图的五种存储结构: 1.图的邻接矩阵表示法 图是由顶点和边或弧两部分组成.图的邻接矩阵(Adjacency Matrix)存储方式是用两个数组表示图,一个一维数组存储图中的顶点信息,一个二维数组(邻接 ...
- 图——基本的图算法(一)图的存储结构
图--基本的图算法(一)图的存储结构 1. 图的存储结构概述 对于图G=(V, E)来说,可以有两种标准的表示方法,一个是邻接矩阵,另一个是邻接链表,这两种方法都可以表示有向图和无向图.除此之外,图的 ...
- 数据结构之图的存储结构:邻接多重表
图的存储结构:邻接多重表 产生条件: 邻接多重表的定义: 邻接多重表的代码定义: 删除: 性能分析: 十字链表与邻接多重表的对比 产生条件: 当用邻接矩阵法存储时:空间复杂度为O(|V|^2),太大 ...
- 数据结构之图的存储结构:十字链表法
图的存储结构:十字链表法 思维导图: 产生条件: 十字链表法的定义: 十字链表法的代码定义: 性能分析: 思维导图: 产生条件: 当用邻接矩阵存储时:空间复杂度为O(|v|^2),太大 当用邻接表法存 ...
最新文章
- 【新产品发布】《EVC8021 RS-232RS-485/422 隔离接口转换器》
- MFC EDIT控件的使用记录
- Lodash常用用法总结
- P3911 最小公倍数之和 (atcoder C - LCMs)(反演)
- iptables 开放远程_JavaWeb项目的部署以及远程调试
- LinuxQt工作笔记-查看程序工作目录
- android r 编译找不到头文件_嵌入式开发之交叉编译程序万能命令_以freetype为例...
- 让你更好的使用jQuery插件
- spss方差分析_SPSS统计案例:考虑交互作用的双因素方差分析
- python转换word到html,Python实现批量将word转html并将html内容发布至网站的方法
- JPEG图像压缩和解压缩操作
- EXCEL VBA 使用正则表达式清洗替换数据
- oracle中更改用户名,Oracle 更改用户名
- 操作系统-存储器管理实验
- 教你用html+js制作一个自己的点名系统,实例代码分享
- SDNU-1183.纪念品分组
- 移动互联网时代的新特点
- 生产制造|销售管理实时在线,业务效率直线提升
- win7上安装MySQL没提示密码_win7下安装mysql后修改密码
- json数据导出到excel中
热门文章
- android app 历史版本,怎么找到App的所有历史版本,以及每次改版的变更点呢?
- php怎么写获取手机剪切板到搜索栏,如何根据指定的剪切板获取html?
- python爬虫beautifulsoup实例-Python爬虫学习(二)使用Beautiful Soup库
- python简单代码hello-小白学 Python(1):开篇
- python画折线图详解-Python数据可视化(一) 绘制折线图和散点图
- python四大软件-传智播客解析Python之移动端页面适配四大方式
- python科学计算基础教程pdf下载-Python科学计算基础教程_PDF电子书
- python编程入门指南怎么样-学习python网络编程怎么入门
- 初学者python编辑器-分享|Mu 入门:一个面向初学者的 Python 编辑器
- 学python工资高吗-Python工资一般是多少 看完吓你一跳