深度优先遍历(Depth-First Search):
用深度优先搜索策略遍历一个图类似于树的前序遍历,对于一个图G=(V,E),首先将图中的每一个顶点都标记为未访问,然后选取一个源点v,将其标为已访问,再递归地用深度优先搜索方法,依次搜索该点的所有邻接点w。若w未曾访问,则以w为源点继续进行深度优先遍历,如果从v出发的所有路的顶点都已被访问过,则从v的搜索过程结束。此时如果图中还有未被访问的顶点(该图有多个连通分量或强连通分量),则再任选一个未被访问过的顶点,从这个顶点开始新的搜索,直到V中所有顶点都已被访问过为止。
用深度优先搜索方法遍历图称为图的深度优先遍历。
例如,对于这个无向图:
**深度优先搜索的访问顺序与图的邻接表存储状态有关,由于图的邻接表存储不是唯一的,因此对于同一个图,DFS的结果可能也是不同的。但是邻接矩阵就唯一了。
例如我采取不同的输入方式,就得到了不同的结果:
(第一行为点的数量,第二行为边的数量,第三行为各个顶点值,接下来的有序对为每条边对应的顶点)
(代码将在稍后给出)
由此可见,邻接表的建立方式不同(边的输入方式不同),DFS的结果也不同。
广度优先遍历(Breadth-First Search):
用广度优先搜索策略遍历一个图类似于树的层次遍历,对于一个图G=(V,E),从图中的某个源点v出发,在访问了顶点v之后,接着就尽可能横向搜索v的所有邻接点。在依次访问v的各个未被访问过的邻接点w1、w2 … wk之后,分别从这些邻接点出发依次访问与w1、w2 … wk邻接的所有未曾访问过的顶点。依此类推,直至图中所有和源点v有路径相通的顶点都已访问过为止,此时从v开始的搜索过程结束。若G是连通图,则遍历完成;否则,在G中另选一个尚未访问过的顶点作为新的源点继续上述搜索过程,直至G中所有顶点均被访问完为止。
用广度优先搜索方法遍历图称为图的广度优先遍历。
同理,BFS也会因为邻接表的建立差异而导致结果不同,如图所示:
接下来给出源码:
(其中头文件"ljb.h"是邻接表的建立过程,->代码在这里<-)
/*main.c*/
#include "ljb.h"
int visited[M]; //标志数组,为1代表已访问过,为0代表未访问过
void dfs(LinkedGraph g, int i) {
EdgeNode* p;
printf("%c ", g.adjlist[i].vertex); //访问源点
/*此时i==0*/
visited[i] = 1;
/*第0个结点的标志为1,表示第0个结点已经访问过了*/
p = g.adjlist[i].FirstEdge;
/*p为第0个结点的头指针域,指向下一个邻接表结点(由你的输入顺序决定)*/
while (p) { //从p的邻接点进行深度优先搜索
/*p不为空*/
if (!visited[p->adjvex]) {
/*p的邻接表节点存在且未被访问(标志数组为0)*/
dfs(g, p->adjvex);
/*继续以p的邻接点为源点进行深度优先遍历*/
}
p = p->next;
}
}
void DfsTraverse(LinkedGraph g) {
int i;
for (i = 0; i < g.n; i++) {
visited[i] = 0; //初始化标志数组
}
for (i = 0; i < g.n; i++) {
if (!visited[i]) { //未访问过
dfs(g, i);
}
}
printf("\n");
}
void bfs(LinkedGraph g, int i) {
int j;
EdgeNode* p;
int queue[M], front, rear; //初始化FIFO队列
front = rear = 0; //初始化空队列
printf("%c ", g.adjlist[i].vertex); //访问源点
/*此时i==0*/
visited[i] = 1;
/*第0个结点的标志为1,表示第0个结点已经访问过了*/
queue[rear++] = i; //被访问节点进队
/*第0个结点进队,此时队列中只有一个0*/
while (rear > front) { //当队列非空时,执行以下循环
j = queue[front++]; //出队
/*此时j==0,0出队*/
p = g.adjlist[j].FirstEdge;
/*p为第0个结点的头指针域,指向下一个邻接表结点(由你的输入顺序决定)*/
while (p) {
/*p不为空*/
if (visited[p->adjvex] == 0) {
/*p的邻接表节点存在且未被访问(标志数组为0)*/
printf("%c ", g.adjlist[p->adjvex].vertex);
queue[rear++] = p->adjvex;
/*p的邻接表结点的序号入队*/
visited[p->adjvex] = 1;
/*标记已被访问*/
}
p = p->next;
}
}
}
int BfsTraverse(LinkedGraph g) {
int i, count = 0;
for (i = 0; i < g.n; i++) {
visited[i] = 0; //初始化标志数组
}
for (i = 0; i < g.n; i++) {
if (!visited[i]) { //未访问过
count++; //连通分量个数加一
bfs(g, i);
}
return(count);
}
}
int main() {
LinkedGraph g;
int count;
create(&g, 0);
printf("\nDFS:\n");
DfsTraverse(g);
printf("BFS:\n");
count = BfsTraverse(g);
printf("\n该图共有%d个连通分量\n", count);
return 0;
}
接下来我们再用一个有向图举个例子:
程序运行结果: