当前位置:   article > 正文

【C语言|DFS+BFS】无向图的邻接表遍历非递归算法-用栈实现深度优先(DFS)以及用队列实现广度优先(BFS)遍历(文件读写操作)_无向图的非递归深度优先遍历算法

无向图的非递归深度优先遍历算法

目录

实验课题:​

实验代码(C):

实验思路:

实验代码解释:

申明相关变量:

初始化数据 

主函数部分:

算法核心

实验代码(全):

 实验效果:


实验课题:

现有一组无向图,要求用DFS和BFS遍历图,依次输出相关值。

实验代码(C):

实验思路:

采用读取text文件,第一阶段依次读取文件中的顶点表数量和边表的数量,第二阶段读取各个顶点的名称,第三阶段读取各边表的两个下标位置。(注意:若是构建有向图的,可以在赋予边表时候只赋给一边,本案例是按照无向图双边赋值)。

实验代码解释:

申明相关变量:

申明变量(链表、节点、队列)

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. //#include<malloc.h>
  4. #define _CRT_SECURE_NO_WARNINGS
  5. #define MaxVertices 100
  6. #define MaxVertNum 100
  7. #define MAX 10
  8. typedef int VertextType;//顶点类型应由用户定义
  9. //typedef int EdgeType;//边上的权值类型应由用户定义
  10. /*边表结点*/
  11. typedef struct EdgeNode {//边表结点 边表
  12. int adjvex;//邻接点域,存储该顶点对应的下标
  13. //EdgeType weight;//用于存储权值,对于非网图可以不需要
  14. struct EdgeNode* next;//链域,指向下一个邻接点
  15. }EdgeNode;
  16. typedef struct VertextNode {//顶点表结点 顶点表
  17. VertextType data;//顶点域,存储顶点信息
  18. EdgeNode* firstedge;//边表头指针
  19. }VertexNode;
  20. typedef VertexNode AdjList[MaxVertices];//顶点表数组
  21. typedef struct {
  22. //VertexNode adjList[MaxVertices];
  23. AdjList adjList;//存放所有顶点表的数组-> VertexNode adjList[MaxVertices]
  24. int numVertexes, numEdges;//图中当前顶点数和边数
  25. }GraphAdjList;
  26. typedef GraphAdjList* GraphAdj;
  27. typedef struct LoopQueue{ //定义循环队列结构体
  28. int data[MAX];
  29. int front;
  30. int rear; //注意每次队尾标记指向最后一个元素的下一个位置
  31. }Queue, *LQueue;
  32. void InitQueue(LQueue &Q){ //初始化队列
  33. Q->front = Q->rear = 0;
  34. }
  35. bool QueueisFull(LQueue &Q){ //判断队列是否满了
  36. if((Q->rear + 1) % MAX == Q->front){
  37. return true; //已满
  38. }
  39. else{
  40. return false;
  41. }
  42. }
  43. bool QueueisEmpty(LQueue &Q){//判断队列是否为空
  44. if(Q->front == Q->rear){
  45. return true;
  46. }
  47. return false;
  48. }
  49. void EnQueue(LQueue &Q, int i){ //入队列
  50. if(!QueueisFull(Q)){
  51. Q->data[Q->rear] = i;
  52. Q->rear = (Q->rear + 1) % MAX; //队尾指针后移
  53. }
  54. }
  55. void DeQueue(LQueue &Q, int *k){ //出队列
  56. if(!QueueisEmpty(Q)){
  57. *k = Q->data[Q->front];
  58. Q->front = (Q->front + 1) % MAX;
  59. }
  60. }

初始化数据 

  1. int InitGraph(GraphAdj G) {
  2. int i, j;
  3. EdgeNode* s;//新的边结点
  4. FILE* fp = NULL;
  5. fp = fopen("D://Project//shuJuJieGou//DFS//GraphAdjList2.txt", "rb");
  6. if (fp == NULL) {
  7. printf("ERROR");
  8. return -1;
  9. }
  10. fscanf(fp, "%d %d", &G->numVertexes, &G->numEdges);//顶点数,边数
  11. /*******************创建顶点表**************************/
  12. for (i = 0; i < G->numVertexes; i++) {
  13. fscanf(fp, "%d", &G->adjList[i].data);
  14. G->adjList[i].firstedge = NULL;//注意将边表置空
  15. }
  16. /******************创建边表****************************/
  17. for (int k = 0; k < G->numEdges; k++) {
  18. fscanf(fp, "%d %d", &i, &j);//"输入边(Vi,Vj)上的顶点序号
  19. //对于直接相连的进行编入(即对输入“0 1”时,在0对应的边表中编入1)
  20. s = (EdgeNode*)malloc(sizeof(EdgeNode));
  21. s->adjvex = j;//边表赋值
  22. s->next = G->adjList[i].firstedge;
  23. G->adjList[i].firstedge = s;
  24. //对于间接相连的进行编入(即对输入“0 1”时,在1对应的边表中编入0)
  25. s = (EdgeNode*)malloc(sizeof(EdgeNode));
  26. s->adjvex = i;
  27. s->next = G->adjList[j].firstedge;
  28. G->adjList[j].firstedge = s;
  29. }
  30. fclose(fp);
  31. }
  32. void DisplayGraph(GraphAdjList* G) {
  33. int i;
  34. FILE *fp;
  35. /**文档输出 ***/
  36. fp = fopen("D://Project//shuJuJieGou//DFS//GraphAdjList_result.txt", "w");
  37. if (fp == NULL) {
  38. printf("ERROR");
  39. // return -1;
  40. }
  41. fprintf(fp, "Enter contents to store in file : \n");
  42. EdgeNode* p;
  43. for (int i = 0; i < G->numVertexes; i++) {
  44. p = G->adjList[i].firstedge;
  45. printf("%d->", i);
  46. fprintf(fp, "%d->", i);
  47. while (1) {
  48. if (p == NULL) {
  49. printf("^");
  50. fprintf(fp, "^");
  51. break;
  52. }
  53. printf("%d->", p->adjvex);//输出边表的下标,但这里可以表示原有的 数
  54. fprintf(fp, "%d->", p->adjvex);
  55. p = p->next;
  56. }
  57. printf("\n");
  58. fprintf(fp, "\n");
  59. }
  60. fclose(fp);//???
  61. }

主函数部分:

  1. int main() {
  2. int index, flage = 1;
  3. GraphAdjList* G = (GraphAdjList*)malloc(sizeof(GraphAdjList));
  4. InitGraph(G);
  5. printf("现有无向图的链表存储:\n");
  6. DisplayGraph(G);
  7. while (flage) {
  8. printf("现有无向图的DFS(按1):\n");
  9. printf("现有无向图的BFS(按2):\n");
  10. printf("退出遍历(按3):\n");
  11. //DFSTraverse(G);
  12. scanf("%d", &index);
  13. switch (index) {
  14. case 1:
  15. DFS(G, 0);
  16. break;
  17. case 2:
  18. BFS(G,0);
  19. break;
  20. case 3:
  21. flage = 0;
  22. break;
  23. }
  24. }
  25. return 0;
  26. }

算法核心:

DFS部分。运用。将head后面依次放入栈中,并选取栈头的visit为1置为新的head,遍历其后面的依次放入栈中,直到栈为空结束。

  1. void DFS(GraphAdjList* G, int v0) { //图,下标位置
  2. int stack[MaxVertNum];
  3. EdgeNode* p;
  4. int visited[MaxVertNum] = { 0 }, top = -1, v;
  5. printf("此图的DFS遍历:\n");
  6. //p = G->adjList[v0].firstedge;
  7. stack[++top] = v0;//top=0,存储第一个数v0(下标)
  8. FILE *fp; /**文档输出 ***/
  9. fp = fopen("D://Project//shuJuJieGou//DFS//GraphAdjList_result_DFS.txt", "w");
  10. if (fp == NULL) {
  11. printf("ERROR");
  12. // return -1;
  13. }
  14. fprintf(fp, "此图的DFS遍历:\n");
  15. while (top != -1)//判断栈有无有空
  16. {
  17. v = stack[top--];//出栈 v(数值data/下标)
  18. if (!visited[v]) {//v 未被访问
  19. printf("%d ", G->adjList[v].data);
  20. fprintf(fp, "%d ", G->adjList[v].data);
  21. visited[v] = 1;
  22. }
  23. p = G->adjList[v].firstedge;//边结点指针
  24. while (p) {
  25. if (!visited[p->adjvex]) {//p边结点的下标有无访问到
  26. stack[++top] = p->adjvex;
  27. }
  28. p = p->next;
  29. }
  30. }
  31. fclose(fp);
  32. printf("\n");
  33. }

BFS部分。运用队列。将head后面依次放入队列中,并选取队头的取出,其visit为1置为新的head,遍历其后面的依次放入队列中,直到队列为空结束。

  1. void BFS(GraphAdjList* G,int i){
  2. int visited[MaxVertNum] = { 0 };
  3. //int i = 0;
  4. Queue *Q =(LQueue)malloc(sizeof(Queue));
  5. for(int i = 0; i < G->numVertexes; i++){
  6. visited[i] = 0;
  7. }
  8. FILE *fp; /**文档输出 ***/
  9. fp = fopen("D://Project//shuJuJieGou//DFS//GraphAdjList_result_BFS.txt", "w");
  10. if (fp == NULL) {
  11. printf("ERROR");
  12. // return -1;
  13. }
  14. fprintf(fp, "此图的BFS遍历:\n");
  15. InitQueue(Q); //初始化队列
  16. visited[i] = 1;//从0下标开始
  17. printf("%d ", G->adjList[i].data);
  18. fprintf(fp,"%d ", G->adjList[i].data);
  19. EnQueue(Q, i);//入队?
  20. while(!QueueisEmpty(Q)){//根据队列遍历全部顶点坐标
  21. DeQueue(Q, &i); //这里不断的修改i的值,队头元素出队,改变i值?
  22. EdgeNode *e = G->adjList[i].firstedge; //i顶点的邻接链表的第一个结点
  23. while(e){//e存在时,将e的所有邻接点加入队列,也就是遍历i的所有邻接点
  24. if(!visited[e->adjvex]){ // adjvex是e所表示的结点下标
  25. visited[e->adjvex] = 1;
  26. printf("%d ", G->adjList[e->adjvex].data);//输出顶点下标的数值
  27. fprintf(fp,"%d ", G->adjList[e->adjvex].data);//输出顶点下标的数值
  28. EnQueue(Q, e->adjvex); //将该结点入队
  29. }
  30. e = e->next; //遍历i的下一个邻接点
  31. }
  32. }
  33. printf("\n");
  34. fclose(fp);
  35. }

实验代码(全):

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. //#include<malloc.h>
  4. #define _CRT_SECURE_NO_WARNINGS
  5. #define MaxVertices 100
  6. #define MaxVertNum 100
  7. #define MAX 10
  8. typedef int VertextType;//顶点类型应由用户定义
  9. //typedef int EdgeType;//边上的权值类型应由用户定义
  10. /*边表结点*/
  11. typedef struct EdgeNode {//边表结点 边表
  12. int adjvex;//邻接点域,存储该顶点对应的下标
  13. //EdgeType weight;//用于存储权值,对于非网图可以不需要
  14. struct EdgeNode* next;//链域,指向下一个邻接点
  15. }EdgeNode;
  16. typedef struct VertextNode {//顶点表结点 顶点表
  17. VertextType data;//顶点域,存储顶点信息
  18. EdgeNode* firstedge;//边表头指针
  19. }VertexNode;
  20. typedef VertexNode AdjList[MaxVertices];//顶点表数组
  21. typedef struct {
  22. //VertexNode adjList[MaxVertices];
  23. AdjList adjList;//存放所有顶点表的数组-> VertexNode adjList[MaxVertices]
  24. int numVertexes, numEdges;//图中当前顶点数和边数
  25. }GraphAdjList;
  26. typedef GraphAdjList* GraphAdj;
  27. int InitGraph(GraphAdj G) {
  28. int i, j;
  29. EdgeNode* s;//新的边结点
  30. FILE* fp = NULL;
  31. fp = fopen("D://Project//shuJuJieGou//DFS//GraphAdjList2.txt", "rb");
  32. if (fp == NULL) {
  33. printf("ERROR");
  34. return -1;
  35. }
  36. fscanf(fp, "%d %d", &G->numVertexes, &G->numEdges);//顶点数,边数
  37. /*******************创建顶点表**************************/
  38. for (i = 0; i < G->numVertexes; i++) {
  39. fscanf(fp, "%d", &G->adjList[i].data);
  40. G->adjList[i].firstedge = NULL;//注意将边表置空
  41. }
  42. /******************创建边表****************************/
  43. for (int k = 0; k < G->numEdges; k++) {
  44. fscanf(fp, "%d %d", &i, &j);//"输入边(Vi,Vj)上的顶点序号
  45. //对于直接相连的进行编入(即对输入“0 1”时,在0对应的边表中编入1)
  46. s = (EdgeNode*)malloc(sizeof(EdgeNode));
  47. s->adjvex = j;//边表赋值
  48. s->next = G->adjList[i].firstedge;
  49. G->adjList[i].firstedge = s;
  50. //对于间接相连的进行编入(即对输入“0 1”时,在1对应的边表中编入0)
  51. s = (EdgeNode*)malloc(sizeof(EdgeNode));
  52. s->adjvex = i;
  53. s->next = G->adjList[j].firstedge;
  54. G->adjList[j].firstedge = s;
  55. }
  56. fclose(fp);
  57. }
  58. void DisplayGraph(GraphAdjList* G) {
  59. int i;
  60. FILE *fp;
  61. /**文档输出 ***/
  62. fp = fopen("D://Project//shuJuJieGou//DFS//GraphAdjList_result.txt", "w");
  63. if (fp == NULL) {
  64. printf("ERROR");
  65. // return -1;
  66. }
  67. fprintf(fp, "Enter contents to store in file : \n");
  68. EdgeNode* p;
  69. for (int i = 0; i < G->numVertexes; i++) {
  70. p = G->adjList[i].firstedge;
  71. printf("%d->", i);
  72. fprintf(fp, "%d->", i);
  73. while (1) {
  74. if (p == NULL) {
  75. printf("^");
  76. fprintf(fp, "^");
  77. break;
  78. }
  79. printf("%d->", p->adjvex);//输出边表的下标,但这里可以表示原有的 数
  80. fprintf(fp, "%d->", p->adjvex);
  81. p = p->next;
  82. }
  83. printf("\n");
  84. fprintf(fp, "\n");
  85. }
  86. fclose(fp);//???
  87. }
  88. void DFS(GraphAdjList* G, int v0); //图,下标位置
  89. void BFS(GraphAdjList* G,int v0);
  90. int main() {
  91. int index, flage = 1;
  92. GraphAdjList* G = (GraphAdjList*)malloc(sizeof(GraphAdjList));
  93. InitGraph(G);
  94. printf("现有无向图的链表存储:\n");
  95. DisplayGraph(G);
  96. while (flage) {
  97. printf("现有无向图的DFS(按1):\n");
  98. printf("现有无向图的BFS(按2):\n");
  99. printf("退出遍历(按3):\n");
  100. //DFSTraverse(G);
  101. scanf("%d", &index);
  102. switch (index) {
  103. case 1:
  104. DFS(G, 0);
  105. break;
  106. case 2:
  107. BFS(G,0);
  108. break;
  109. case 3:
  110. flage = 0;
  111. break;
  112. }
  113. }
  114. return 0;
  115. }
  116. /********************DFS*************************************/
  117. void DFS(GraphAdjList* G, int v0) { //图,下标位置
  118. int stack[MaxVertNum];
  119. EdgeNode* p;
  120. int visited[MaxVertNum] = { 0 }, top = -1, v;
  121. printf("此图的DFS遍历:\n");
  122. //p = G->adjList[v0].firstedge;
  123. stack[++top] = v0;//top=0,存储第一个数v0(下标)
  124. FILE *fp; /**文档输出 ***/
  125. fp = fopen("D://Project//shuJuJieGou//DFS//GraphAdjList_result_DFS.txt", "w");
  126. if (fp == NULL) {
  127. printf("ERROR");
  128. // return -1;
  129. }
  130. fprintf(fp, "此图的DFS遍历:\n");
  131. while (top != -1)//判断栈有无有空
  132. {
  133. v = stack[top--];//出栈 v(数值data/下标)
  134. if (!visited[v]) {//v 未被访问
  135. printf("%d ", G->adjList[v].data);
  136. fprintf(fp, "%d ", G->adjList[v].data);
  137. visited[v] = 1;
  138. }
  139. p = G->adjList[v].firstedge;//边结点指针
  140. while (p) {
  141. if (!visited[p->adjvex]) {//p边结点的下标有无访问到
  142. stack[++top] = p->adjvex;
  143. }
  144. p = p->next;
  145. }
  146. }
  147. fclose(fp);
  148. printf("\n");
  149. }
  150. /********************BFS*************************************/
  151. typedef struct LoopQueue{ //定义循环队列结构体
  152. int data[MAX];
  153. int front;
  154. int rear; //注意每次队尾标记指向最后一个元素的下一个位置
  155. }Queue, *LQueue;
  156. void InitQueue(LQueue &Q){ //初始化队列
  157. Q->front = Q->rear = 0;
  158. }
  159. bool QueueisFull(LQueue &Q){ //判断队列是否满了
  160. if((Q->rear + 1) % MAX == Q->front){
  161. return true; //已满
  162. }
  163. else{
  164. return false;
  165. }
  166. }
  167. bool QueueisEmpty(LQueue &Q){//判断队列是否为空
  168. if(Q->front == Q->rear){
  169. return true;
  170. }
  171. return false;
  172. }
  173. void EnQueue(LQueue &Q, int i){ //入队列
  174. if(!QueueisFull(Q)){
  175. Q->data[Q->rear] = i;
  176. Q->rear = (Q->rear + 1) % MAX; //队尾指针后移
  177. }
  178. }
  179. void DeQueue(LQueue &Q, int *k){ //出队列
  180. if(!QueueisEmpty(Q)){
  181. *k = Q->data[Q->front];
  182. Q->front = (Q->front + 1) % MAX;
  183. }
  184. }
  185. void BFS(GraphAdjList* G,int i){
  186. int visited[MaxVertNum] = { 0 };
  187. //int i = 0;
  188. Queue *Q =(LQueue)malloc(sizeof(Queue));
  189. for(int i = 0; i < G->numVertexes; i++){
  190. visited[i] = 0;
  191. }
  192. FILE *fp; /**文档输出 ***/
  193. fp = fopen("D://Project//shuJuJieGou//DFS//GraphAdjList_result_BFS.txt", "w");
  194. if (fp == NULL) {
  195. printf("ERROR");
  196. // return -1;
  197. }
  198. fprintf(fp, "此图的BFS遍历:\n");
  199. InitQueue(Q); //初始化队列
  200. visited[i] = 1;//从0下标开始
  201. printf("%d ", G->adjList[i].data);
  202. fprintf(fp,"%d ", G->adjList[i].data);
  203. EnQueue(Q, i);//入队?
  204. while(!QueueisEmpty(Q)){//根据队列遍历全部顶点坐标
  205. DeQueue(Q, &i); //这里不断的修改i的值,队头元素出队,改变i值?
  206. EdgeNode *e = G->adjList[i].firstedge; //i顶点的邻接链表的第一个结点
  207. while(e){//e存在时,将e的所有邻接点加入队列,也就是遍历i的所有邻接点
  208. if(!visited[e->adjvex]){ // adjvex是e所表示的结点下标
  209. visited[e->adjvex] = 1;
  210. printf("%d ", G->adjList[e->adjvex].data);//输出顶点下标的数值
  211. fprintf(fp,"%d ", G->adjList[e->adjvex].data);//输出顶点下标的数值
  212. EnQueue(Q, e->adjvex); //将该结点入队
  213. }
  214. e = e->next; //遍历i的下一个邻接点
  215. }
  216. }
  217. printf("\n");
  218. fclose(fp);
  219. }

 实验效果:

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/445358
推荐阅读
相关标签
  

闽ICP备14008679号