alex_bn_lee

导航

【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\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 

// 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 

// 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  

#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 

// 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 

#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 

#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 

#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 

#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 进行查找
  • 从起始顶点不停的向下递归,直到两个顶点重合位置
#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

 

posted on 2019-07-25 08:38  McDelfino  阅读(452)  评论(0编辑  收藏  举报