本博文是是博主在学习数据结构图的这一章知识时做的一些总结,代码运行环境:visual studio2017 纯C语言 ,当然掌握了方法,你也可以试着用其它的语言来实现同样的功能。

下面的程序主要实现了对有向图,有向网,无向图,无向网,无向图的深度优先遍历,广度优先遍历,有向无环图的拓扑排序功能等。

主要代码实现如下:

  1. #pragma once
  2. #include<stdio.h>
  3. #include"stdlib.h"
  4. #define ElemType char
  5. #define MAXQSIZE 50
  6. #define INFINITY INT_MAX
  7. #define MAX_VERTEX_NUM 20
  8. typedef enum { DG, DN, UDG, UDN } GraphKind;
  9. typedef struct ArcCell {
  10. int adj; //顶点关系类型 对于无权图 用0或1表示
  11. //char *info; //弧相关信息的指针
  12. }ArcCell, AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
  13. typedef struct {
  14. char vers[MAX_VERTEX_NUM]; //用一个字符数组存储顶点向量
  15. AdjMatrix arcs; //邻接矩阵
  16. int vexnum, arcnum; //图的当前顶点数和弧数
  17. GraphKind kind; //图的种类标志
  18. int in[MAX_VERTEX_NUM]; //存放所有节点的入度
  19. }MGraph;
  20. //图G中顶点v的第一个邻接点,不存在时返回 -1
  21. int FirstAdjVex(MGraph&G, int v)
  22. {
  23.  
  24. int i;
  25. for (i = ; i < G.vexnum; i++)
  26. {
  27. if (G.arcs[v][i].adj)
  28. {
  29. return i;
  30. }
  31. }
  32. return -;
  33. }
  34. //图G中顶点v在w之后的下一个邻接点,不存在时返回 -1
  35. int NextAdjVex(MGraph G, int v, int w)
  36. {
  37.  
  38. int i;
  39. for (i = w + ; i < G.vexnum; i++)
  40. {
  41. if (G.arcs[v][i].adj)
  42. {
  43. return i;
  44. }
  45. }
  46. return -;
  47.  
  48. }
  49. //深度优先遍历图
  50. bool visited[MAX_VERTEX_NUM];
  51. void DFS(MGraph G, int v)
  52. {
  53. visited[v] = true;
  54. printf("%c", G.vers[v]);
  55. int j;
  56. for (j = ; j <= G.vexnum; j++) {
  57. if (visited[j] == && G.arcs[v][j].adj == )
  58. {
  59. DFS(G, j);//v每循环一次值都会变 上一轮的j值赋给了v
  60. }
  61. }
  62. }
  63.  
  64. //广度优先遍历
  65. int BFSTraverse(MGraph G, int s)
  66. {
  67. //清空访问标志
  68. for (int i = ; i <MAX_VERTEX_NUM; i++)
  69. visited[i] = false;
  70. //定义队列,用于保存当前节点的邻接顶点
  71. int Q[MAX_VERTEX_NUM];
  72. int front = ;
  73. int rear = ;
  74. int i, j;
  75. printf("%c", G.vers[s]);
  76. visited[s] = ;
  77. Q[rear++] = s;
  78. //遍历队列
  79. while (front < rear)
  80. {
  81. i = Q[front++];
  82. for (j = ; j <= G.vexnum; j++)
  83. {
  84. if (visited[j] == false && G.arcs[i][j].adj == )
  85. {
  86. printf("%c", G.vers[j]);
  87. visited[j] = true;
  88. Q[rear++] = j;
  89. }
  90.  
  91. }
  92. }
  93. return ;
  94. }
  95.  
  96. //定位顶点
  97. int LocateVex(MGraph &G, char v)
  98. {
  99. int i;
  100. for (i = ; i<G.vexnum; i++)
  101. {
  102. if (v == G.vers[i])
  103. {
  104. return i;
  105. }
  106. }
  107. return -;
  108.  
  109. }
  110.  
  111. //创建有向图
  112. int CreateDG(MGraph &G) {
  113. int i, j, k;
  114. char v1, v2;
  115. printf("请输入顶点数:");
  116. scanf("%d", &G.vexnum);
  117. printf("\n请输入弧数:");
  118. scanf("%d", &G.arcnum);
  119. printf("请输入%d个顶点:(每个顶点之间用空格隔开)", G.vexnum);
  120. fflush(stdin);
  121. getchar(); //吃掉空格
  122. for (i = ; i < G.vexnum; i++)
  123. {
  124. scanf("%c", &G.vers[i]);
  125. getchar(); //吃掉空格 注意数组vers[i]的初始大小为20
  126. }
  127. //打印输出各个顶点
  128. for (i = ; i < G.vexnum; i++)
  129. {
  130. printf("%c", G.vers[i]);
  131.  
  132. }
  133. printf("\n");
  134. for (i = ; i < G.vexnum; i++)
  135. {
  136. for (j = ; j < G.vexnum; j++)
  137. {
  138. G.arcs[i][j].adj = INFINITY;
  139.  
  140. }
  141. }
  142. //入度初始化
  143. for (int i = ; i < G.vexnum; i++)
  144. {
  145. G.in[i] = ;
  146. }
  147. for (k = ; k < G.arcnum; k++)
  148. {
  149. printf("\nplease input <v1 v2>:");
  150. fflush(stdin);
  151. scanf("%c %c", &v1, &v2); //v1 v2 之间用空格隔开
  152. fflush(stdin);//清除残余后,后面再读入时不会出错
  153. i = LocateVex(G, v1);
  154. j = LocateVex(G, v2);
  155. G.arcs[i][j].adj = ;
  156. G.in[j]++;
  157. getchar();
  158. }
  159. return ;
  160. }
  161.  
  162. //创建有向网
  163. int CreateDN(MGraph &G) {
  164. int i, j, k, w;
  165. char v1, v2;
  166. printf("请输入顶点数:");
  167. scanf("%d", &G.vexnum);
  168. printf("\n请输入弧的数目:");
  169. scanf("%d", &G.arcnum);
  170. printf("请输入%d个顶点:(每个顶点之间用空格隔开)", G.vexnum);
  171. fflush(stdin);
  172. getchar(); //吃掉空格
  173. for (i = ; i < G.vexnum; i++)
  174. {
  175. scanf("%c", &G.vers[i]);
  176. getchar(); //吃掉空格 注意数组vers[i]的初始大小为20
  177. }
  178. //打印输出各个顶点
  179. for (i = ; i < G.vexnum; i++)
  180. {
  181. printf("%c", G.vers[i]);
  182.  
  183. }
  184. printf("\n");
  185. //初始化邻接矩阵
  186. for (i = ; i < G.vexnum; i++)
  187. {
  188. for (j = ; j < G.vexnum; j++)
  189. {
  190. G.arcs[i][j].adj = INFINITY;
  191.  
  192. }
  193. }
  194. for (k = ; k < G.arcnum; k++)
  195. {
  196. printf("\n please input <v1 v2 w>:");
  197. fflush(stdin);
  198. scanf("%c %c %d", &v1, &v2, &w); //v1 v2 w之间用空格隔开
  199. fflush(stdin);//清除残余后,后面再读入时不会出错
  200. i = LocateVex(G, v1);
  201. j = LocateVex(G, v2);
  202. G.arcs[i][j].adj = w;
  203.  
  204. getchar(); //吃掉空格
  205. }
  206. return ;
  207. }
  208.  
  209. //创建无向图
  210. int CreateUDG(MGraph &G)
  211. {
  212. int i, j, k;
  213. char v1, v2;
  214. printf("请输入顶点数:");
  215. scanf("%d", &G.vexnum);
  216. printf("\n请输入边数:");
  217. scanf("%d", &G.arcnum);
  218. printf("请输入%d个顶点:(每个顶点之间用空格隔开)", G.vexnum);
  219. fflush(stdin);
  220. getchar(); //吃掉空格
  221. for (i = ; i < G.vexnum; i++)
  222. {
  223. scanf("%c", &G.vers[i]);
  224. getchar(); //吃掉空格 注意数组vers[i]的初始大小为20
  225. }
  226. //打印输出各个顶点
  227. for (i = ; i < G.vexnum; i++)
  228. {
  229. printf("%c", G.vers[i]);
  230.  
  231. }
  232. printf("\n");
  233. for (i = ; i < G.vexnum; i++)
  234. {
  235. for (j = ; j < G.vexnum; j++)
  236. {
  237. G.arcs[i][j].adj = INFINITY;
  238. }
  239. }
  240. for (k = ; k < G.arcnum; k++)
  241. {
  242. printf("\nplease input <v1 v2>:");
  243. fflush(stdin);
  244. scanf("%c %c", &v1, &v2); //v1 v2 之间用空格隔开
  245. fflush(stdin);//清除残余后,后面再读入时不会出错
  246. i = LocateVex(G, v1);
  247. j = LocateVex(G, v2);
  248. G.arcs[i][j].adj = ;
  249. G.arcs[j][i].adj = ;
  250. getchar();
  251. }
  252. return ;
  253. }
  254.  
  255. //创建无向网
  256. int CreateUDN(MGraph &G)
  257. {
  258. int i, j, k, w;
  259. char v1, v2;
  260. printf("请输入顶点数:");
  261. scanf("%d", &G.vexnum);
  262. printf("\n请输入边的数目:");
  263. scanf("%d", &G.arcnum);
  264. printf("请输入%d个顶点:(每个顶点之间用空格隔开)", G.vexnum);
  265. fflush(stdin);
  266. getchar(); //吃掉空格
  267. for (i = ; i < G.vexnum; i++)
  268. {
  269. scanf("%c", &G.vers[i]);
  270. getchar(); //吃掉空格 注意数组vers[i]的初始大小为20
  271. }
  272. //打印输出各个顶点
  273. for (i = ; i < G.vexnum; i++)
  274. {
  275. printf("%c", G.vers[i]);
  276.  
  277. }
  278. printf("\n");
  279. //初始化邻接矩阵
  280. for (i = ; i < G.vexnum; i++)
  281. {
  282. for (j = ; j < G.vexnum; j++)
  283. {
  284. G.arcs[i][j].adj = INFINITY;
  285. }
  286. }
  287. for (k = ; k < G.arcnum; k++)
  288. {
  289. printf("\n please input <v1 v2 w>:");
  290. fflush(stdin);
  291. scanf("%c %c %d", &v1, &v2, &w); //v1 v2 w之间用空格隔开
  292. fflush(stdin);//清除残余后,后面再读入时不会出错
  293. i = LocateVex(G, v1);
  294. j = LocateVex(G, v2);
  295. G.arcs[i][j].adj = w;
  296. G.arcs[j][i].adj = w;
  297. getchar(); //吃掉空格
  298. }
  299. return ;
  300. }
  301. //栈类型
  302. typedef int SElemType;
  303. #define STACK_INIT_SIZE1 10 //存储空间初始分配量
  304. #define STACKINCREMENT1 2 //存储空间分配增量
  305.  
  306. //栈的顺序存储结构表示
  307. typedef struct SqStack1
  308. {
  309. SElemType *base; //基地址
  310. SElemType *top; //栈顶指针
  311. int stacksize1; //当前已经分配的存储空间
  312. }SqStack1;
  313.  
  314. //构造一个空栈
  315. int InitStack1(SqStack1&S)
  316. {
  317. //为栈底分分配一个指定大小的存储空间
  318. S.base = (SElemType *)malloc(STACK_INIT_SIZE1 * sizeof(SElemType));
  319. if (!S.base)
  320. exit();
  321. S.top = S.base; //栈底与栈顶指针相同
  322. S.stacksize1 = STACK_INIT_SIZE1;
  323. return ;
  324. }
  325.  
  326. //若栈S为空栈(栈底指针和栈顶指针相同), 则返回1,否则返回0
  327. int StackEmpty1(SqStack1&S)
  328. {
  329. if (S.top == S.base)
  330. return ;
  331. else
  332. return ;
  333. }
  334.  
  335. //插入元素e为新的栈顶元素
  336. int Push(SqStack1 *S, SElemType e)
  337. {
  338. if ((*S).top - (*S).base >= (*S).stacksize1)
  339. {
  340. (*S).base = (SElemType *)realloc((*S).base, ((*S).stacksize1 + STACKINCREMENT1) * sizeof(SElemType));
  341. if (!(*S).base)
  342. exit();
  343. (*S).top = (*S).base + (*S).stacksize1;
  344. (*S).stacksize1 += STACKINCREMENT1;
  345. }
  346. *((*S).top)++ = e;
  347. return ;
  348. }
  349.  
  350. //若栈不为空,则删除S栈顶元素用e返回其值,并返回1,否则返回0
  351. int Pop(SqStack1 *S, SElemType *e)
  352. {
  353. if ((*S).top == (*S).base)
  354. {
  355. return ;
  356. }
  357. *e = *--(*S).top;
  358. return ;
  359. }
  360. //有向图的拓扑排序
  361. void TopologicalSort(MGraph G)
  362. {
  363. int i, j,k;
  364. int count = ;
  365. SqStack1 S;
  366. InitStack1(S);
  367. for (i = ; i<G.vexnum; i++)
  368. {
  369. if (G.in[i] == )
  370. {
  371. Push(&S, i);
  372. }
  373. }
  374. while (!StackEmpty1(S))
  375. {
  376. Pop(&S, &k);
  377. printf("%c->", G.vers[k]);
  378. count++;
  379. for (i = ; i < G.vexnum; i++)
  380. {
  381. if (G.arcs[k][i].adj == )
  382. {
  383. G.in[i]--;
  384. if (G.in[i] == )
  385. {
  386. Push(&S, i);
  387. }
  388. }
  389. }
  390. }
  391. //如果计算得到的拓扑排序的节点数目小于总的,说明不是连通图
  392. if (count < G.vexnum)
  393. {
  394. printf("此图是有环路的\n");
  395. }
  396. else
  397. {
  398. printf("此图是没有环路的\n");
  399. }
  400.  
  401. }

C语言数据结构之图的基本操作的更多相关文章

  1. 【数据结构】图的基本操作——图的构造(邻接矩阵,邻接表),遍历(DFS,BFS)

    邻接矩阵实现如下: /* 主题:用邻接矩阵实现 DFS(递归) 与 BFS(非递归) 作者:Laugh 语言:C++ ***************************************** ...

  2. C++数据结构之图

    图的实现是一件很麻烦的事情,很多同学可能在学数据结构时只是理解了图的基本操作和遍历原理,但并没有动手实践过.在此,我说说我的实现过程. 首先,在草稿纸上画一个图表,这里是有向图,无向图也一样,如下: ...

  3. 数据结构之--图(Graphics)

    1.1:图的定义和术语   图是一种比线性表和树更为复杂的数据结构.在线性表中,数据元素之间仅有线性关系,每个元素仅有一个直接前驱和一个直接后继:在树形结构中,数据元素之间有着明显的层次关系,并且每一 ...

  4. 利用python+graphviz绘制数据结构关系图和指定目录下头文件包含关系图

    作为一名linux系统下的C语言开发,日常工作中经常遇到两个问题: 一是分析代码过程中,各种数据结构互相关联,只通过代码很难理清系统中所有结构体的整体架构,影响代码消化的效率; 二是多层头文件嵌套包含 ...

  5. python数据结构之图的实现

    python数据结构之图的实现,官方有一篇文章介绍,http://www.python.org/doc/essays/graphs.html 下面简要的介绍下: 比如有这么一张图: A -> B ...

  6. hdu 1233:还是畅通工程(数据结构,图,最小生成树,普里姆(Prim)算法)

    还是畅通工程 Time Limit : 4000/2000ms (Java/Other)   Memory Limit : 65536/32768K (Java/Other) Total Submis ...

  7. python数据结构之图的实现方法

    python数据结构之图的实现方法 本文实例讲述了python数据结构之图的实现方法.分享给大家供大家参考.具体如下: 下面简要的介绍下: 比如有这么一张图:     A -> B     A ...

  8. python数据结构之图深度优先和广度优先实例详解

    本文实例讲述了python数据结构之图深度优先和广度优先用法.分享给大家供大家参考.具体如下: 首先有一个概念:回溯 回溯法(探索与回溯法)是一种选优搜索法,按选优条件向前搜索,以达到目标.但当探索到 ...

  9. 数据结构(C语言)关于树、二叉树、图的基本操作。

    1) 编写算法函数int equal(tree t1, tree t2),判断两棵给定的树是否等价: int equal(tree t1,tree t2) { int k; if(t1==NULL&a ...

随机推荐

  1. 线程并发线程安全介绍及java.util.concurrent包下类介绍

    线程Thread,在Java开发中多线程是必不可少的,但是真正能用好的并不多! 首先开启一个线程三种方式 ①new Thread(Runnable).start() ②thread.start(); ...

  2. Jdeveloper下Svn的使用

    Jdeveloper下Svn的使用 官方pdf:jdeveloper使用svn 官方网地址:http://www.oracle.com/technetwork/cn/java/subversion-0 ...

  3. php识别二维码

    php-zbarcode 是 PHP 读取条形码的扩展模块,目前仅支持 php5.x

  4. WEB开发常见错误-php无法操作数据库

    Ubuntu 安装phpmyadmin 和配置   ubuntu 安装 phpmyadmin  两种 : 1: apt-get 安装  然后使用 已有的虚拟主机目录建立软连接  sudo  apt-g ...

  5. 如何在Github上删除项目及某个文件

    在Github上删除项目 在GitHub仓库中找到已经建立好的某个仓库,本篇文章以我的myBookCodes仓库为例,在建立的myBookCodes仓库中首先找到settings选项,如图所示: 将页 ...

  6. CentOS 6.6 MySQL 8.0详细安装步骤

    1.备份服务器上MySQL数据库 [root@localhost ] # mysqldump -h localhost -u root -proot --databases Surpass --rou ...

  7. [转]How to Clean the Global Assembly Cache

    本文转自:https://www.techwalla.com/articles/how-to-clean-the-global-assembly-cache The Global Assembly C ...

  8. 洛谷 P1967 货车运输(克鲁斯卡尔重构树)

    题目描述 AAA国有nn n座城市,编号从 11 1到n nn,城市之间有 mmm 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 qqq 辆货车在运输货物, 司机们想知道每辆车在不超过车 ...

  9. Linux文件扩展思考随笔

    Linux文件时间 ============================================================ ls -l 文件名 仅看到的是最后被修改的时间 Linux ...

  10. NativeScript的开发体会

    上个月开始,国内的主流技术网站开始在推荐NativeScrpit,"js+xml写跨终端app"."原生体验挡不住",很多网站都拿这个当做宣传NativeScr ...