【427】Graph 实现 以及 DFS & BFS
目录:
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
浙公网安备 33010602011771号