目录:

  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

【427】Graph 实现 以及 DFS & BFS的更多相关文章

  1. DFS/BFS+思维 HDOJ 5325 Crazy Bobo

    题目传送门 /* 题意:给一个树,节点上有权值,问最多能找出多少个点满足在树上是连通的并且按照权值排序后相邻的点 在树上的路径权值都小于这两个点 DFS/BFS+思维:按照权值的大小,从小的到大的连有 ...

  2. 【DFS/BFS】NYOJ-58-最少步数(迷宫最短路径问题)

    [题目链接:NYOJ-58] 经典的搜索问题,想必这题用广搜的会比较多,所以我首先使的也是广搜,但其实深搜同样也是可以的. 不考虑剪枝的话,两种方法实践消耗相同,但是深搜相比广搜内存低一点. 我想,因 ...

  3. ID(dfs+bfs)-hdu-4127-Flood-it!

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4127 题目意思: 给n*n的方格,每个格子有一种颜色(0~5),每次可以选择一种颜色,使得和左上角相 ...

  4. [LeetCode] 130. Surrounded Regions_Medium tag: DFS/BFS

    Given a 2D board containing 'X' and 'O' (the letter O), capture all regions surrounded by 'X'. A reg ...

  5. HDU 4771 (DFS+BFS)

    Problem Description Harry Potter has some precious. For example, his invisible robe, his wand and hi ...

  6. DFS/BFS视频讲解

    视频链接:https://www.bilibili.com/video/av12019553?share_medium=android&share_source=qq&bbid=XZ7 ...

  7. POJ 3083 -- Children of the Candy Corn(DFS+BFS)TLE

    POJ 3083 -- Children of the Candy Corn(DFS+BFS) 题意: 给定一个迷宫,S是起点,E是终点,#是墙不可走,.可以走 1)先输出左转优先时,从S到E的步数 ...

  8. [LeetCode]695. 岛屿的最大面积(DFS/BFS)、200. 岛屿数量(DFS/BFS待做/并差集待做)

    695. 岛屿的最大面积 题目 给定一个包含了一些 0 和 1的非空二维数组 grid , 一个 岛屿 是由四个方向 (水平或垂直) 的 1 (代表土地) 构成的组合.你可以假设二维矩阵的四个边缘都被 ...

  9. POJ2308连连看dfs+bfs+优化

    DFS+BFS+MAP+剪枝 题意:       就是给你一个10*10的连连看状态,然后问你最后能不能全部消没? 思路:      首先要明确这是一个搜索题目,还有就是关键的一点就是连连看这个游戏是 ...

随机推荐

  1. machine learning (6)---how to choose features, polynomial regression

    how to choose features, polynomial regression:通过定义更适合我们的feature,选择更好的模型,使我们的曲线与数据更好的拟合(而不仅仅是一条直线) 可以 ...

  2. matlab的diff()函数

    diff():求差分 一阶差分 X = [1 1 2 3 5 8 13 21]; Y = diff(X) 结果: Y = 0 1 1 2 3 5 8 X = [1 1 1; 5 5 5; 25 25 ...

  3. Õ() Big-O-notation

    Õ只是大\(O\)表示法的变种,忽略了对数因子: \[f(n) \in \tilde O(h(n))\] \[=> \exists k : f(n) \in O \!\left( h(n)\lo ...

  4. [CodeForces - 906D] Power Tower——扩展欧拉定理

    题意 给你 $n$ 个 $w_i$ 和一个数 $p$,$q$个询问,每次询问一个区间 $[l,r] $,求 $w_l ^{w_{l+1}^{{\vdots}^{w_r}}} \ \% p$ 分析 由扩 ...

  5. 国赛 strange_int

    参考文章地址https://www.52pojie.cn/thread-936377-1-1.html https://qrzbing.cn/2019/04/27/CISCN2019-strange- ...

  6. 入门node.js

    我们现在要做一个简单的h5应用:包含登录.注册.修改密码.个人中心主页面.个人中心内页修改名称.个人中心修改手机号码. 第一步:工具安装,我选择了能够辅助我们快速开发的light开发工具 1. lig ...

  7. gosched

    Go语言runtime.Gosched()函数浅析 这个函数的作用是让当前goroutine让出CPU,好让其它的goroutine获得执行的机会.同时,当前的goroutine也会在未来的某个时间点 ...

  8. Tensorflow细节-P202-数据集的高层操作

    本节是对上节的补充 import tempfile import tensorflow as tf # 输入数据使用本章第一节(1. TFRecord样例程序.ipynb)生成的训练和测试数据. tr ...

  9. linux服务器初始化(防火墙、内核优化、时间同步、打开文件数)

    #!/bin/bash read -p 'enter the network segment for visiting the server:' ips # 关闭firewalld和selinux s ...

  10. 鼠标常用样式(cursor)

    <body> <div>常用的鼠标样式(cursor):pointer,move,defalt,text(火狐不支持hand)</div> </body> ...