【427】Graph 实现 以及 DFS & BFS
目录:
1. Graph 实现
1.1 二维数组实现
GraphAM.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | // GraphAM.c: an adjacency matrix implementation #include <stdio.h> #include <stdlib.h> #include "Graph.h" struct graphRep { int nV; // #vertices int nE; // #edges int **edges; // matrix of Booleans ... THIS IS THE ADJACENCY MATRIX }; Graph newGraph( int numVertices) { Graph g = NULL; if (numVertices < 0) { fprintf (stderr, "newgraph: invalid number of vertices\n" ); } else { g = malloc ( sizeof ( struct graphRep)); if (g == NULL) { fprintf (stderr, "newGraph: out of memory\n" ); exit (1); } g->edges = malloc (numVertices * sizeof ( int *)); if (g->edges == NULL) { fprintf (stderr, "newGraph: out of memory\n" ); exit (1); } int v; for (v = 0; v < numVertices; v++) { g->edges[v] = malloc (numVertices * sizeof ( int )); if (g->edges[v] == NULL) { fprintf (stderr, "newGraph: out of memory\n" ); exit (1); } for ( int j = 0; j < numVertices; j++) { g->edges[v][j] = 0; } } g->nV = numVertices; g->nE = 0; } return g; } Graph freeGraph(Graph g) { if (g != NULL) { int i; for (i = 0; i < g->nV; i++) { free (g->edges[i]); // free the mallocs for each row ... } free (g->edges); // now the malloc for the edges array ... free (g); // now the malloc for the graph rep } return g; } void showGraph(Graph g) { // print a graph if (g == NULL) { printf ( "NULL graph\n" ); } else { printf ( "V=%d, E=%d\n" , g->nV, g->nE); int i; for (i = 0; i < g->nV; i++) { int nshown = 0; int j; for (j = 0; j < g->nV; j++) { if (g->edges[i][j] != 0) { printf ( "%d-%d " , i, j); nshown++; } } if (nshown > 0) { printf ( "\n" ); } } } return ; } static int validV(Graph g, Vertex v) { // checks if v is in graph return (v >= 0 && v < g->nV); } Edge newE(Vertex v, Vertex w) { // create an edge from v to w Edge e = {v, w}; return e; } void showE(Edge e) { // print an edge printf ( "%d-%d" , e.v, e.w); return ; } int isEdge(Graph g, Edge e) { // return 1 if edge found, otherwise 0 int found = 0; if (g != NULL && validV(g, e.v) && validV(g, e.w)) { found = (g->edges[e.v][e.w] == 1); } return found; } void insertE(Graph g, Edge e) { // insert an edge into a graph if (g == NULL) { fprintf (stderr, "insertE: graph not initialised\n" ); } else { if (!validV(g, e.v) || !validV(g, e.w)) { fprintf (stderr, "insertE: invalid vertices %d-%d\n" , e.v, e.w); } else { if (isEdge(g, e) == 0) { // increment nE only if it is new g->nE++; } g->edges[e.v][e.w] = 1; g->edges[e.w][e.v] = 1; } } return ; } void removeE(Graph g, Edge e) { // remove an edge from a graph if (g == NULL) { fprintf (stderr, "removeE: graph not initialised\n" ); } else { if (!validV(g, e.v) || !validV(g, e.w)) { fprintf (stderr, "removeE: invalid vertices\n" ); } else { if (isEdge(g, e) == 1) { // is edge there? g->edges[e.v][e.w] = 0; g->edges[e.w][e.v] = 0; g->nE--; } } } return ; } |
1.2 Linked List 实现
GraphAL.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | // GraphAL.c: an adjacency list implementation #include <stdio.h> #include <stdlib.h> #include "Graph.h" typedef struct node *list; struct node { Vertex name; list next; }; struct graphRep { int nV; // #vertices int nE; // #edges list *edges; // array of linked lists ... THIS IS THE ADJACENCY LIST }; Graph newGraph( int numVertices) { Graph g = NULL; if (numVertices < 0) { fprintf (stderr, "newgraph: invalid number of vertices\n" ); } else { g = malloc ( sizeof ( struct graphRep)); if (g == NULL) { fprintf (stderr, "newGraph: out of memory\n" ); exit (1); } g->edges = malloc (numVertices * sizeof ( int *)); if (g->edges == NULL) { fprintf (stderr, "newGraph: out of memory\n" ); exit (1); } int v; for (v = 0; v < numVertices; v++) { g->edges[v] = NULL; } g->nV = numVertices; g->nE = 0; } return g; } Graph freeGraph(Graph g) { if (g != NULL) { int i; for (i = 0; i < g->nV; i++) { List node = g->edges[i]; // maybe NULL, maybe points to first node while (node != NULL) { List tmp = node; // save the node node = node->next; // move onto the next node free (tmp); // free the saved node } } free (g->edges); // now the malloc for the edges array ... free (g); // now the malloc for the graph rep } return g; } void showGraph(Graph g) { // print a graph if (g == NULL) { printf ( "NULL graph\n" ); } else { printf ( "V=%d, E=%d\n" , g->nV, g->nE); int i; for (i = 0; i < g->nV; i++) { int nshown = 0; list listV = g->edges[i]; while (listV != NULL) { //printf("g->edges[%d]=%p\n",i , listV); printf ( "%d-%d " , i, listV->name); nshown++; listV = listV->next; } if (nshown > 0) { printf ( "\n" ); } } } return ; } static int validV(Graph g, Vertex v) { // checks if v is in graph return (v >= 0 && v < g->nV); } Edge newE(Vertex v, Vertex w) { Edge e = {v, w}; return e; } void showE(Edge e) { // print an edge printf ( "%d-%d" , e.v, e.w); return ; } int isEdge(Graph g, Edge e) { // return 1 if edge found, otherwise 0 // a linear search for edge 'e': return 1 if edge found, 0 otherwise int found = 0; if (g != NULL && validV(g, e.v) && validV(g, e.w)) { list curr; for (curr = g->edges[e.v]; curr != NULL && !found; curr = curr->next) { if (curr->name == e.w) { found = 1; } } } return found; } void insertE(Graph g, Edge e){ if (g == NULL) { fprintf (stderr, "insertE: graph not initialised\n" ); } else { if (!validV(g, e.v) || !validV(g, e.w)) { fprintf (stderr, "insertE: invalid vertices %d-%d\n" , e.v, e.w); } else { if (isEdge(g, e) == 0) { list newnodev = malloc ( sizeof ( struct node)); list newnodew = malloc ( sizeof ( struct node)); if (newnodev == NULL || newnodew == NULL) { fprintf (stderr, "Out of memory\n" ); exit (1); } newnodev->name = e.w; // put in the data newnodev->next = g->edges[e.v]; // link to the existing list attached to e.v g->edges[e.v] = newnodev; // link e.v to new node newnodew->name = e.v; newnodew->next = g->edges[e.w]; g->edges[e.w] = newnodew; g->nE++; } } } return ; } void removeE(Graph g, Edge e) { int success = 0; List n = g->edges[v]; // n is the start node List p = NULL; // p is previous node to n while (n != NULL && !success){ // linear search for w if (n->name == w) { List nn = n->next; // we've found w, we want to skip over it if (p == NULL) { // if w is first node, p will be NULL g->edges[v] = nn; } else { p->next = nn; } free (n); success = 1; } p = n; n = n->next; } return success; } |
2. DFS:Deep First Search,深度优先搜索
2.1 通过 stack 来实现(后进先出)
- 首先 push 进去一个 vertex(任意一个顶点,一般选择 0)
- 以下为 while 循环内容,条件为栈不为空
- 然后 pop 出来,并记录 v 值
- 判断 v 是否访问过
- 从大到小遍历所有与 v 相连的 w
- 并将所有的 w 依次 push 入栈
- 执行完之后,进行下一轮的循环
- 首先 pop 出来的是上一轮最后入栈的 w
- 然后继续遍历次 w 的所有邻接点
- 不停的便利下去,直到遍历到头了
- 然后再不停的 pop,遇到访问的顶点直接就 pass 了
- 遇到没有访问的顶点就继续遍历
- 往复循环
- 直到最后所有的点都 pop 了,stack 为空的时候停止
- 此代码每次会将所有的邻接点压入栈,然后在出栈的时候会判断是否访问过,没有访问过就压入所有邻接点,否则跳过了。。。不过都会打印当前的 quack
dfsquack.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | // dfsquack.c: traverse a graph using DFS and a stack implementation #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include "Graph.h" #include "Quack.h" void dfs(Graph, Vertex, int ); #define WHITESPACE 100 int readNumV( void ) { // returns the number of vertices numV or -1 int numV; char w[WHITESPACE]; scanf ( "%[ \t\n]s" , w); // skip leading whitespace if (( getchar () != '#' ) || ( scanf ( "%d" , &numV) != 1)) { fprintf (stderr, "missing number (of vertices)\n" ); return -1; } return numV; } int readGraph( int numV, Graph g) { // reads number-number pairs until EOF int success = true ; // returns true if no error int v1, v2; while ( scanf ( "%d %d" , &v1, &v2) != EOF && success) { if (v1 < 0 || v1 >= numV || v2 < 0 || v2 >= numV) { fprintf (stderr, "unable to read edge\n" ); success = false ; } else { insertE(g, newE(v1, v2)); } } return success; } void dfs(Graph g, Vertex v, int numV) { int *mallocArray( int numV) { int *v = malloc (numV * sizeof ( int )); if (v == NULL) { fprintf (stderr, "Out of memory\n" ); exit (1); } int i; for (i=0; i<numV; i++) { v[i] = UNVISITED; } return v; } void showArray( int *v, int numV) { int i; printf ( "Visited: {" ); for (i=0; i<numV; i++) { printf ( "%d" , v[i]); if (i <= numV-2) { printf ( ", " ); } } printf ( "}\n" ); return ; } int *visited = mallocArray(numV); Quack s = createQuack(); push(v, s); showQuack(s); int order = 0; while (!isEmptyQuack(s)) { v = pop(s); if (visited[v] == UNVISITED) { showArray(visited, numV); //printf("visited[%d]=%d\n", v, order); visited[v] = order++; Vertex w; for (w=numV-1; w>=0; w--) { if (isEdge(g, newE(v,w))) { // if (isEdge(g, newE(v,w)) && visited[w] == UNVISITED) push (w, s); } } } showQuack(s); } showArray(visited, numV); free (visited); return ; } int main ( void ) { int numV; if ((numV = readNumV()) >= 0) { Graph g = newGraph(numV); if (readGraph(numV, g)) { showGraph(g); dfs(g, 0, numV); } g = freeGraph(g); g = NULL; } else { return EXIT_FAILURE; } return EXIT_SUCCESS; } // clear && gcc dfsquack.c GraphAM.c Quack.c && ./a.out < input_path.txt |
2.2 通过 recursion 来实现
- 不断的递归遍历
- 直到所有的点都已经访问过停止
dfsR.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include "Graph.h" #include "Quack.h" #define UNVISITED -1 #define WHITESPACE 100 void dfsR(Graph g, Vertex v, int numV, int *order, int *visited); int readNumV( void ) { // returns the number of vertices numV or -1 int numV; char w[WHITESPACE]; scanf ( "%[ \t\n]s" , w); // skip leading whitespace if (( getchar () != '#' ) || ( scanf ( "%d" , &numV) != 1)) { fprintf (stderr, "missing number (of vertices)\n" ); return -1; } return numV; } int readGraph( int numV, Graph g) { // reads number-number pairs until EOF int success = true ; // returns true if no error int v1, v2; while ( scanf ( "%d %d" , &v1, &v2) != EOF && success) { if (v1 < 0 || v1 >= numV || v2 < 0 || v2 >= numV) { fprintf (stderr, "unable to read edge\n" ); success = false ; } else { insertE(g, newE(v1, v2)); } } return success; } void dfs(Graph g, Vertex v, int numV) { int *mallocArray( int numV) { int *array = malloc (numV * sizeof ( int )); // l if (array == NULL) { // o fprintf (stderr, "Out of memory\n" ); // c exit (1); // a } // l int i; // f for (i=0; i<numV; i++) { // u array[i] = UNVISITED; // n } // c return array; // t } void showArray( int *array, int numV) { int i; // l printf ( "Visited: {" ); // o for (i=0; i<numV; i++) { // c printf ( "%d" , array[i]); // a if (i <= numV-2) { // l printf ( ", " ); // f } // u } // n printf ( "}\n" ); // c return ; // t } int *visited = mallocArray(numV); int order = 0; dfsR(g, v, numV, &order, visited); showArray(visited, numV); free (visited); return ; } void dfsR(Graph g, Vertex v, int numV, int *order, int *visited) { visited[v] = *order; *order = *order+1; Vertex w; for (w=0; w < numV; w++) { if (isEdge(g, newE(v,w)) && visited[w]==UNVISITED) { dfsR(g, w, numV, order, visited); } } return ; } int main ( void ) { int numV; if ((numV = readNumV()) >= 0) { Graph g = newGraph(numV); if (readGraph(numV, g)) { showGraph(g); dfs(g, 0, numV); } g = freeGraph(g); g = NULL; } else { return EXIT_FAILURE; } return EXIT_SUCCESS; } // clear && gcc dfsR.c GraphAM.c Quack.c && ./a.out < input_R.txt |
3. BFS:Breadth First Search,广度优先搜索
通过 queue 来实现(先进先出)
- 算法与 DFS 一致,只是将 stack 换成了 queue
- 将邻接点都 push 进去后,再 pop
- 由于是 queue,因此会依次先将邻接点进行 pop
- 然后再 pop 邻接点的所有邻接点
- 相当于树的分层遍历
- 效果与DFS类似,只是 stack 变成 queue
bfsquack.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | // bfsquack.c: traverse a graph using bfs and a stack implementation #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include "Graph.h" #include "Quack.h" void bfs(Graph, Vertex, int ); #define WHITESPACE 100 int readNumV( void ) { // returns the number of vertices numV or -1 int numV; char w[WHITESPACE]; scanf ( "%[ \t\n]s" , w); // skip leading whitespace if (( getchar () != '#' ) || ( scanf ( "%d" , &numV) != 1)) { fprintf (stderr, "missing number (of vertices)\n" ); return -1; } return numV; } int readGraph( int numV, Graph g) { // reads number-number pairs until EOF int success = true ; // returns true if no error int v1, v2; while ( scanf ( "%d %d" , &v1, &v2) != EOF && success) { if (v1 < 0 || v1 >= numV || v2 < 0 || v2 >= numV) { fprintf (stderr, "unable to read edge\n" ); success = false ; } else { insertE(g, newE(v1, v2)); } } return success; } void bfs(Graph g, Vertex v, int numV) { int *mallocArray( int numV) { int *v = malloc (numV * sizeof ( int )); if (v == NULL) { fprintf (stderr, "Out of memory\n" ); exit (1); } int i; for (i=0; i<numV; i++) { v[i] = UNVISITED; } return v; } void showArray( int *v, int numV) { int i; printf ( "Visited: {" ); for (i=0; i<numV; i++) { printf ( "%d" , v[i]); if (i <= numV-2) { printf ( ", " ); } } printf ( "}\n" ); return ; } int *visited = mallocArray(numV); Quack s = createQuack(); qush(v, s); showQuack(s); int order = 0; while (!isEmptyQuack(s)) { v = pop(s); if (visited[v] == UNVISITED) { showArray(visited, numV); //printf("visited[%d]=%d\n", v, order); visited[v] = order++; Vertex w; for (w=0; w<=numV-1; w++) { if (isEdge(g, newE(v,w))) { qush (w, s); } } } showQuack(s); } showArray(visited, numV); free (visited); return ; } int main ( void ) { int numV; if ((numV = readNumV()) >= 0) { Graph g = newGraph(numV); if (readGraph(numV, g)) { showGraph(g); bfs(g, 0, numV); } g = freeGraph(g); g = NULL; } else { return EXIT_FAILURE; } return EXIT_SUCCESS; } // clear && gcc bfsquack.c GraphAM.c Quack.c && ./a.out < input_path.txt // clear && gcc dfs_path_searching.c GraphAM.c Quack.c && ./a.out < input_path.txt |
4. 其他应用
4.1 非连通图遍历 - DFS recursion 实现
- 通过遍历 visited 来判断是否遍历完全
- 遇到没便利的点,就从此为起点继续遍历
- 先假设已经全部遍历,然后对 visited 数组进行遍历,如果存在未访问的,则比较 finished=0,从此顶点继续执行DFS
- 以此类推,直到全部访问为止
dfsR_multi.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include "Graph.h" #include "Quack.h" #define UNVISITED -1 #define WHITESPACE 100 void dfsR(Graph g, Vertex v, int numV, int *order, int *visited); int readNumV( void ) { // returns the number of vertices numV or -1 int numV; char w[WHITESPACE]; scanf ( "%[ \t\n]s" , w); // skip leading whitespace if (( getchar () != '#' ) || ( scanf ( "%d" , &numV) != 1)) { fprintf (stderr, "missing number (of vertices)\n" ); return -1; } return numV; } int readGraph( int numV, Graph g) { // reads number-number pairs until EOF int success = true ; // returns true if no error int v1, v2; while ( scanf ( "%d %d" , &v1, &v2) != EOF && success) { if (v1 < 0 || v1 >= numV || v2 < 0 || v2 >= numV) { fprintf (stderr, "unable to read edge\n" ); success = false ; } else { insertE(g, newE(v1, v2)); } } return success; } void dfsDisc(Graph g, Vertex v, int numV) { int *mallocArray( int numV) { int *array = malloc (numV * sizeof ( int )); // l if (array == NULL) { // o fprintf (stderr, "Out of memory\n" ); // c exit (1); // a } // l int i; // f for (i=0; i<numV; i++) { // u array[i] = UNVISITED; // n } // c return array; // t } void showArray( int *array, int numV) { int i; // l printf ( "Visited: {" ); // o for (i=0; i<numV; i++) { // c printf ( "%d" , array[i]); // a if (i <= numV-2) { // l printf ( ", " ); // f } // u } // n printf ( "}\n" ); // c return ; // t } int *visited = mallocArray(numV); int order = 0; Vertex newv = v; // this is the starting vertex int finished = 0; while (!finished) { // as long as there are vertices dfsR(g, newv, numV, &order, visited); Vertex w; finished = 1; // assume all vertices visited for (w = 0; w < numV && finished; w++) { // look for a new vertex if (visited[w] == UNVISITED) { finished = 0; // found an unvisited vertex newv = w; } } } showArray(visited, numV); free (visited); return ; } void dfsR(Graph g, Vertex v, int numV, int *order, int *visited) { visited[v] = *order; *order = *order+1; Vertex w; for (w=0; w < numV; w++) { if (isEdge(g, newE(v,w)) && visited[w]==UNVISITED) { dfsR(g, w, numV, order, visited); } } return ; } int main ( void ) { int numV; if ((numV = readNumV()) >= 0) { Graph g = newGraph(numV); if (readGraph(numV, g)) { showGraph(g); dfsDisc(g, 0, numV); } g = freeGraph(g); g = NULL; } else { return EXIT_FAILURE; } return EXIT_SUCCESS; } // clear && gcc dfsR_multi.c GraphAM.c Quack.c && ./a.out < input_multi.txt |
4.2 最短路径查找 - BFS queue 实现
- BFS 在遍历的过程中就是按层扫描
- 因此第一次扫描到 goal vertex 的时候就是最短的路径
- 类似 tree 的形式
- 因此每个 vertex 都有唯一的 parent
- 通过回溯 parent 可以将最短路径的顶点输出
- 每个点都有唯一的parent,因此每读入一个点就获取其parent的值
- 最后到达goal的时候,通过回溯parent可以将路径获取
bfs_path_searching.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 | #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include "Graph.h" #include "Quack.h" #define UNVISITED -1 #define WHITESPACE 100 int readNumV( void ) { // returns the number of vertices numV or -1 int numV; char w[WHITESPACE]; scanf ( "%[ \t\n]s" , w); // skip leading whitespace if (( getchar () != '#' ) || ( scanf ( "%d" , &numV) != 1)) { fprintf (stderr, "missing number (of vertices)\n" ); return -1; } return numV; } int readGraph( int numV, Graph g) { // reads number-number pairs until EOF int success = true ; // returns true if no error int v1, v2; while ( scanf ( "%d %d" , &v1, &v2) != EOF && success) { if (v1 < 0 || v1 >= numV || v2 < 0 || v2 >= numV) { fprintf (stderr, "unable to read edge\n" ); success = false ; } else { insertE(g, newE(v1, v2)); } } return success; } void searchPath(Graph g, Vertex start, Vertex goal, int numV) { int *mallocArray( int numV) { int *array = malloc (numV * sizeof ( int )); // l if (array == NULL) { // o fprintf (stderr, "Out of memory\n" ); // c exit (1); // a } // l int i; // f for (i=0; i<numV; i++) { // u array[i] = UNVISITED; // n } // c return array; // t } void showArray( int *array, int numV) { int i; // l printf ( "Visited: {" ); // o for (i=0; i<numV; i++) { // c printf ( "%d" , array[i]); // a if (i <= numV-2) { // l printf ( ", " ); // f } // u } // n printf ( "}\n" ); // c return ; // t } void printPath( int parent[], int numV, Vertex v) { printf ( "%d" , v); if (0<=v && v<numV) { Vertex p = parent[v]; while (p != UNVISITED) { printf ( "<--%d" , p); p = parent[p]; } } else { fprintf (stderr, "printPath: illegal vertex in parent[]\n" ); } } int *visited = mallocArray(numV); int *parent = mallocArray(numV); // need extra array to store parents Quack q = createQuack(); qush(start, q); int order = 0; visited[start] = order++; int found = 0; while (!isEmptyQuack(q) && !found) { Vertex x = pop(q); Vertex y; for (y = 0; y<numV && !found; y++) { if (isEdge(g, newE(x,y))) { // for adjacent vertex y ... if (visited[y]==UNVISITED) { // ... if y is unvisited ... qush(y, q); // ... queue y visited[y] = order++; // y is now visited parent[y] = x; // y's parent is x if (y == goal) { // if y is the goal ... found = 1; // ... SUCCESS! now get out } } } } } if (found) { printf ( "SHORTEST path from %d to %d is " , start, goal); printPath(parent, numV, goal); putchar ( '\n' ); } else { printf ( "no path found\n" ); } free (visited); free (parent); makeEmptyQuack(q); return ; } int main ( void ) { int numV; if ((numV = readNumV()) >= 0) { Graph g = newGraph(numV); if (readGraph(numV, g)) { searchPath(g, 2, 3, numV); } } else { return EXIT_FAILURE; } return EXIT_SUCCESS; } // clear && gcc bfs_path_searching.c GraphAM.c Quack.c && ./a.out < input_bow.txt // clear && gcc bfs_path_searching.c GraphAM.c Quack.c && ./a.out < input_propsbows.txt // clear && gcc bfs_path_searching.c GraphAM.c Quack.c && ./a.out < input_multi.txt // no path found // clear && gcc bfs_path_searching.c GraphAM.c Quack.c && ./a.out < input_path.txt |
4.3 查找循环路径 - DFS recursion 实现
- 循环遍历直到 visited 被访问过为止
- (v, w),就是按照 edge 的方式进行查找,但是不能找到过来的顶点,即fromv
- 除此之外,如果遇到了访问的顶点就是发现了循环
dfs_cycle.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include "Graph.h" #include "Quack.h" #define UNVISITED -1 #define WHITESPACE 100 void dfsR(Graph g, Vertex v, int numV, int *order, int *visited); int hasCycle(Graph g, int numV, Vertex fromv, Vertex v, int *order, int *visited); int readNumV( void ) { // returns the number of vertices numV or -1 int numV; char w[WHITESPACE]; scanf ( "%[ \t\n]s" , w); // skip leading whitespace if (( getchar () != '#' ) || ( scanf ( "%d" , &numV) != 1)) { fprintf (stderr, "missing number (of vertices)\n" ); return -1; } return numV; } int readGraph( int numV, Graph g) { // reads number-number pairs until EOF int success = true ; // returns true if no error int v1, v2; while ( scanf ( "%d %d" , &v1, &v2) != EOF && success) { if (v1 < 0 || v1 >= numV || v2 < 0 || v2 >= numV) { fprintf (stderr, "unable to read edge\n" ); success = false ; } else { insertE(g, newE(v1, v2)); } } return success; } void dfs(Graph g, Vertex v, int numV) { int *mallocArray( int numV) { int *array = malloc (numV * sizeof ( int )); // l if (array == NULL) { // o fprintf (stderr, "Out of memory\n" ); // c exit (1); // a } // l int i; // f for (i=0; i<numV; i++) { // u array[i] = UNVISITED; // n } // c return array; // t } void showArray( int *array, int numV) { int i; // l printf ( "Visited: {" ); // o for (i=0; i<numV; i++) { // c printf ( "%d" , array[i]); // a if (i <= numV-2) { // l printf ( ", " ); // f } // u } // n printf ( "}\n" ); // c return ; // t } int *visited = mallocArray(numV); int order = 0; dfsR(g, v, numV, &order, visited); showArray(visited, numV); free (visited); return ; } void dfsR(Graph g, Vertex v, int numV, int *order, int *visited) { visited[v] = *order; *order = *order+1; Vertex w; for (w=0; w < numV; w++) { if (isEdge(g, newE(v,w)) && visited[w]==UNVISITED) { dfsR(g, w, numV, order, visited); } } return ; } void searchForCycle(Graph g, int v, int numV) { int *mallocArray( int numV) { int *array = malloc (numV * sizeof ( int )); // l if (array == NULL) { // o fprintf (stderr, "Out of memory\n" ); // c exit (1); // a } // l int i; // f for (i=0; i<numV; i++) { // u array[i] = UNVISITED; // n } // c return array; // t } void showArray( int *array, int numV) { int i; // l printf ( "Visited: {" ); // o for (i=0; i<numV; i++) { // c printf ( "%d" , array[i]); // a if (i <= numV-2) { // l printf ( ", " ); // f } // u } // n printf ( "}\n" ); // c return ; // t } int *visited = mallocArray(numV); int order = 0; if (hasCycle(g, numV, v, v, &order, visited)) { printf ( "found a cycle\n" ); } else { printf ( "no cycle found\n" ); } showArray(visited, numV); free (visited); return ; } int hasCycle(Graph g, int numV, Vertex fromv, Vertex v, int *order, int *visited) { int retval = 0; visited[v] = *order; *order = *order+1; Vertex w; for (w=0; w<numV && !retval; w++) { if (isEdge(g, newE(v,w))) { if (visited[w]==UNVISITED) { printf ( "traverse edge %d-%d\n" , v, w); retval = hasCycle(g, numV, v, w, order, visited); } else { if (w != fromv) { // exclude the vertex we've just come from printf ( "traverse edge %d-%d\n" , v, w); retval = 1; } } } } return retval; } int main ( void ) { int numV; if ((numV = readNumV()) >= 0) { Graph g = newGraph(numV); if (readGraph(numV, g)) { searchForCycle(g, 0, numV); } } else { return EXIT_FAILURE; } return EXIT_SUCCESS; } // clear && gcc dfs_cycle.c GraphAM.c Quack.c && ./a.out < input_no_cycle.txt // clear && gcc dfs_cycle.c GraphAM.c Quack.c && ./a.out < input_cycle.txt |
4.4 Depth-First Search: Eulerian cycles
An Eulerian path is a path that includes every edge exactly once
A path may include many visits to the same vertex.
An Eulerian cycle is an Eulerian path that starts and ends on the same vertex
- 沿着一条道儿一直走,走过的路就删掉
- 因此不能走回头路
- 面对几条路的时候,选择最大顶点的(可以任意定规则)
- 如果能回到初始点,就是 cycle 了
- 访问过的路线都给删除掉,然后一条道走到黑,如果能够回到原点则为找到循环
dfs_EulerCycle.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include "Graph.h" #include "Quack.h" #define UNVISITED -1 #define WHITESPACE 100 void dfsR(Graph g, Vertex v, int numV, int *order, int *visited); Vertex getAdjacent(Graph g, int numV, Vertex v); int readNumV( void ) { // returns the number of vertices numV or -1 int numV; char w[WHITESPACE]; scanf ( "%[ \t\n]s" , w); // skip leading whitespace if (( getchar () != '#' ) || ( scanf ( "%d" , &numV) != 1)) { fprintf (stderr, "missing number (of vertices)\n" ); return -1; } return numV; } int readGraph( int numV, Graph g) { // reads number-number pairs until EOF int success = true ; // returns true if no error int v1, v2; while ( scanf ( "%d %d" , &v1, &v2) != EOF && success) { if (v1 < 0 || v1 >= numV || v2 < 0 || v2 >= numV) { fprintf (stderr, "unable to read edge\n" ); success = false ; } else { insertE(g, newE(v1, v2)); } } return success; } void dfs(Graph g, Vertex v, int numV) { int *mallocArray( int numV) { int *array = malloc (numV * sizeof ( int )); // l if (array == NULL) { // o fprintf (stderr, "Out of memory\n" ); // c exit (1); // a } // l int i; // f for (i=0; i<numV; i++) { // u array[i] = UNVISITED; // n } // c return array; // t } void showArray( int *array, int numV) { int i; // l printf ( "Visited: {" ); // o for (i=0; i<numV; i++) { // c printf ( "%d" , array[i]); // a if (i <= numV-2) { // l printf ( ", " ); // f } // u } // n printf ( "}\n" ); // c return ; // t } int *visited = mallocArray(numV); int order = 0; dfsR(g, v, numV, &order, visited); showArray(visited, numV); free (visited); return ; } void dfsR(Graph g, Vertex v, int numV, int *order, int *visited) { visited[v] = *order; *order = *order+1; Vertex w; for (w=0; w < numV; w++) { if (isEdge(g, newE(v,w)) && visited[w]==UNVISITED) { dfsR(g, w, numV, order, visited); } } return ; } void findEulerCycle(Graph g, int numV, Vertex startv) { Quack s = createQuack(); printf ( "Eulerian cycle: \n" ); push(startv, s); printf ( "push %d\n" , startv); while (!isEmptyQuack(s)) { Vertex v = pop(s); // v is the top of stack vertex and ... push(v, s); // ... the stack has not changed Vertex w; if ((w = getAdjacent(g, numV, v)) >= 0) { push(w, s); // push a neighbour of v onto stack printf ( "push %d and remove %d-%d\n" , w, v, w); removeE(g, newE(v, w)); // remove edge to neighbour } else { w = pop(s); printf ( "pop ------------------------ %d\n" , w); } } putchar ( '\n' ); } Vertex getAdjacent(Graph g, int numV, Vertex v) { // returns the Largest Adjacent Vertex if it exists, else -1 Vertex w; Vertex lav = -1; // the adjacent vertex for (w=numV-1; w>=0 && lav==-1; w--) { Edge e = newE(v, w); if (isEdge(g, e)) { lav = w; } } return lav; } int main ( void ) { int numV; if ((numV = readNumV()) >= 0) { Graph g = newGraph(numV); if (readGraph(numV, g)) { findEulerCycle(g, numV, 0); } } else { return EXIT_FAILURE; } return EXIT_SUCCESS; } // clear && gcc dfs_EulerCycle.c GraphAM.c Quack.c && ./a.out < input_box.txt // clear && gcc dfs_EulerCycle.c GraphAM.c Quack.c && ./a.out < input_bow.txt // clear && gcc dfs_EulerCycle.c GraphAM.c Quack.c && ./a.out < input_propbows.txt |
4.5 路径查找
- 通过 dfs 进行查找
- 从起始顶点不停的向下递归,直到两个顶点重合位置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include "Graph.h" #include "Quack.h" #define UNVISITED -1 #define WHITESPACE 100 void dfsR(Graph g, Vertex v, int numV, int *order, int *visited); int isPath(Graph g, Vertex v, Vertex goalv, int numV, int *order, int *visited); int readNumV( void ) { // returns the number of vertices numV or -1 int numV; char w[WHITESPACE]; scanf ( "%[ \t\n]s" , w); // skip leading whitespace if (( getchar () != '#' ) || ( scanf ( "%d" , &numV) != 1)) { fprintf (stderr, "missing number (of vertices)\n" ); return -1; } return numV; } int readGraph( int numV, Graph g) { // reads number-number pairs until EOF int success = true ; // returns true if no error int v1, v2; while ( scanf ( "%d %d" , &v1, &v2) != EOF && success) { if (v1 < 0 || v1 >= numV || v2 < 0 || v2 >= numV) { fprintf (stderr, "unable to read edge\n" ); success = false ; } else { insertE(g, newE(v1, v2)); } } return success; } void searchForPath(Graph g, int v, int goalv, int numV) { int *mallocArray( int numV) { int *array = malloc (numV * sizeof ( int )); // l if (array == NULL) { // o fprintf (stderr, "Out of memory\n" ); // c exit (1); // a } // l int i; // f for (i=0; i<numV; i++) { // u array[i] = UNVISITED; // n } // c return array; // t } void showArray( int *array, int numV) { int i; // l printf ( "Visited: {" ); // o for (i=0; i<numV; i++) { // c printf ( "%d" , array[i]); // a if (i <= numV-2) { // l printf ( ", " ); // f } // u } // n printf ( "}\n" ); // c return ; // t } int *visited = mallocArray(numV); int order = 0; if (isPath(g, v, goalv, numV, &order, visited)) { printf ( "found a path\n" ); } else { printf ( "no path found\n" ); } showArray(visited, numV); free (visited); return ; } int isPath(Graph g, Vertex v, Vertex goalv, int numV, int *order, int *visited) { int found = 0; visited[v] = *order; *order = *order+1; if (v == goalv) { found = 1; } else { Vertex w; for (w=0; w < numV && !found; w++) { if (isEdge(g, newE(v,w))) { if (visited[w] == UNVISITED) { found = isPath(g, w, goalv, numV, order, visited); printf ( "path %d-%d\n" , w, v); } } } } return found; } int main ( void ) { int numV; if ((numV = readNumV()) >= 0) { Graph g = newGraph(numV); if (readGraph(numV, g)) { searchForPath(g, 0, 6, numV); } } else { return EXIT_FAILURE; } return EXIT_SUCCESS; } // clear && gcc dfs_path_searching.c GraphAM.c Quack.c && ./a.out < input_bow.txt // clear && gcc dfs_path_searching.c GraphAM.c Quack.c && ./a.out < input_propsbows.txt // clear && gcc dfs_path_searching.c GraphAM.c Quack.c && ./a.out < input_multi.txt // no path found // clear && gcc dfs_path_searching.c GraphAM.c Quack.c && ./a.out < input_path.txt |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)
2012-07-25 【063】◀▶ Android (I) - 控件和布局
2012-07-25 【062】Android 开发入门学习