目录:

  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 (4)---feature scaling

    feature scaling:缩小或扩大feature的值,使所有的feature处于类似的范围,这样进行gradient descnet时更快趋向最小值.因为不同的feature的范围相差很大时, ...

  2. python会缓存小的整数和短小的字符

    经过测试,python会缓存的小整数的范围是 [-5, 256] # True a = 1 b = 1 print(a is b) # True a = "good" b = &q ...

  3. ubuntu下subversion1.7的安装

    环境: ubuntu11.10 subversion1.7 1.用synaptic安装的svn都是1.6版,根本于现在的主流svn服务器无法通信.需要升级为1.7. 1.1 apt-add-repos ...

  4. Hive 数据类型与文件格式

    一.基本数据类型 1.基本数据类型 Tinyint  1byte有符号整数  比如20 Smalint 2byte有符号整数 比如20 Int          4byte有符号整数 比如20 Big ...

  5. Kubernetes 学习17 dashboard认证及分级授权

    一.概述 1.我们前面介绍了kubernetes的两个东西,认证和授权 2.在kubernetes中我们对API server的一次访问大概会包含哪些信息?简单来讲它是restfule风格接口,也就是 ...

  6. 使用echarts生成海友网企业全国分布地图

    不分类别的效果 不同分类的分布效果图 从海友网获取各个企业名单保存进mysql cmfishhelper.py 从下列网址得到各个企业名片的网址保存进表cmfish cds = get_cds() h ...

  7. Logstash 安装配置使用

    一.Windows下安装运行 官网下载,下载与elasticSearch同一个版本,zip格式.Logstash占用内存较大,我在使用的时候cpu一般都是冲到90% 1.CMD直接运行 创建一个基本的 ...

  8. Processing 中自定义旋转的实现

    一.首先是关键概念在 Processing 中希望处理圆周上的点需要 旋转公式:x = 旋转中心 + 旋转半径 x cos(旋转角度);y = 旋转中心 + 旋转半径 x sin(旋转角度): 用这一 ...

  9. HIVE 乱码以及 HUE SQL 语句兼容性的记录(遇到应该会一直更新)

    最近在 HUE 里面查询有中文字段相关的东西被报错警告... (1366, Incorrect string value: \\xE4\\xBA\\xAC\\xE4\\xB8\\x9C... for ...

  10. beego 前后端分离登录验证

    conf>app.conf 文件添加一下参数 copyrequestbody=true sessionon =true routers>router.go 文件添加初始化路由 func i ...