zoukankan      html  css  js  c++  java
  • 【427】Graph 实现 以及 DFS & BFS

    目录:

    1. Graph 实现
    2. DFS:深度优先搜索
    3. BFS:广度优先搜索(queue)
    4. 其他应用

    1. Graph 实现

    1.1 二维数组实现

     GraphAM.c 

    // 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
    ");
        }
        else {
            g = malloc(sizeof(struct graphRep));
            if (g == NULL) {
                fprintf(stderr, "newGraph: out of memory
    ");
                exit(1);
            }
            g->edges = malloc(numVertices * sizeof(int *)); 
            if (g->edges == NULL) {
                fprintf(stderr, "newGraph: out of memory
    ");
                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
    ");
                    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
    ");
        }
        else {
            printf("V=%d, E=%d
    ", 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("
    ");
                }
            }
        }
        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
    ");
       }
       else {
           if (!validV(g, e.v) || !validV(g, e.w)) {
              fprintf(stderr, "insertE: invalid vertices %d-%d
    ", 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
    ");
        }
        else {
            if (!validV(g, e.v) || !validV(g, e.w)) {
                fprintf(stderr, "removeE: invalid vertices
    ");
            }
            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 

    // 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
    ");
      }
      else {
         g = malloc(sizeof(struct graphRep));
         if (g == NULL) {
            fprintf(stderr, "newGraph: out of memory
    ");
            exit(1);
         }
         g->edges = malloc(numVertices * sizeof(int *)); 
         if (g->edges == NULL) {
            fprintf(stderr, "newGraph: out of memory
    ");
            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
    ");
        }
        else {
            printf("V=%d, E=%d
    ", 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
    ",i , listV);
                   printf("%d-%d ", i, listV->name);
                   nshown++;
                   listV = listV->next;
                }
                if (nshown > 0) {
                    printf("
    ");
                }
            }
        }
        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
    ");
      }
      else {
         if (!validV(g, e.v) || !validV(g, e.w)) {
            fprintf(stderr, "insertE: invalid vertices %d-%d
    ", 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
    ");
                  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 

    // 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("%[ 	
    ]s", w);  // skip leading whitespace
       if ((getchar() != '#') ||
           (scanf("%d", &numV) != 1)) {
           fprintf(stderr, "missing number (of vertices)
    ");
           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
    ");
              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
    ");
             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("}
    ");
          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
    ", 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  

    #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("%[ 	
    ]s", w);  // skip leading whitespace
       if ((getchar() != '#') ||
           (scanf("%d", &numV) != 1)) {
           fprintf(stderr, "missing number (of vertices)
    ");
           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
    ");
              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
    ");  // 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("}
    ");                          // 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 

    // 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("%[ 	
    ]s", w);  // skip leading whitespace
       if ((getchar() != '#') ||
           (scanf("%d", &numV) != 1)) {
           fprintf(stderr, "missing number (of vertices)
    ");
           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
    ");
              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
    ");
             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("}
    ");
          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
    ", 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 

    #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("%[ 	
    ]s", w);  // skip leading whitespace
       if ((getchar() != '#') ||
           (scanf("%d", &numV) != 1)) {
           fprintf(stderr, "missing number (of vertices)
    ");
           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
    ");
              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
    ");  // 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("}
    ");                          // 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 

    #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("%[ 	
    ]s", w);  // skip leading whitespace
       if ((getchar() != '#') ||
           (scanf("%d", &numV) != 1)) {
           fprintf(stderr, "missing number (of vertices)
    ");
           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
    ");
              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
    ");  // 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("}
    ");                          // 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[]
    ");
    	   }
    	}
    
       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('
    ');
       }
       else {
          printf("no path found
    ");
       }
       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 

    #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("%[ 	
    ]s", w);  // skip leading whitespace
       if ((getchar() != '#') ||
           (scanf("%d", &numV) != 1)) {
           fprintf(stderr, "missing number (of vertices)
    ");
           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
    ");
              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
    ");  // 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("}
    ");                          // 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
    ");  // 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("}
    ");                          // c
          return;                                 // t
       }
       int *visited = mallocArray(numV);
       int order = 0;
    
       if (hasCycle(g, numV, v, v, &order, visited)) {
          printf("found a cycle
    ");
       }
       else {
          printf("no cycle found
    ");
       }
       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
    ", 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
    ", 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 

    #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("%[ 	
    ]s", w);  // skip leading whitespace
       if ((getchar() != '#') ||
           (scanf("%d", &numV) != 1)) {
           fprintf(stderr, "missing number (of vertices)
    ");
           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
    ");
              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
    ");  // 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("}
    ");                          // 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: 
    ");
    
       push(startv, s);
       printf("push %d
    ", 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
    ", w, v, w);
             removeE(g, newE(v, w)); // remove edge to neighbour
          }
          else {
             w = pop(s);
             printf("pop ------------------------ %d
    ", w);
          }
       }
       putchar('
    ');
    }
    
    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 进行查找
    • 从起始顶点不停的向下递归,直到两个顶点重合位置
    #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("%[ 	
    ]s", w);  // skip leading whitespace
       if ((getchar() != '#') ||
           (scanf("%d", &numV) != 1)) {
           fprintf(stderr, "missing number (of vertices)
    ");
           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
    ");
              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
    ");  // 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("}
    ");                          // c
          return;                                 // t
       }
       int *visited = mallocArray(numV);
       int order = 0;
    
       if (isPath(g, v, goalv, numV, &order, visited)) {
          printf("found a path
    ");
       }
       else {
          printf("no path found
    ");
       }
       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
    ", 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
    
  • 相关阅读:
    散列函数之单散列算法
    NET 使用 RabbitMQ
    leetCode
    Swift 1
    C#并发集合
    多进程与多线程1
    开发编译器
    APUE1
    微服务架构
    ExceptionHandlerMiddleware中间件如何呈现“定制化错误页面”
  • 原文地址:https://www.cnblogs.com/alex-bn-lee/p/11242024.html
Copyright © 2011-2022 走看看