图的遍历
通常有两条遍历图的路径:深度优先搜索和广度优先搜索。它们对无向图和有向图都适用。
为了避免同一顶点被访问多次,在遍历过程中,必须记下每个已访问过的顶点。为此,我们可以设一个辅助数组 visited[0…n-1],它的初始值置为“假”或者0,一旦访问了顶点 vi,便置 visited[i] 为“真”或者为被访问时的次序号
用到的基本操作P:
- FirstAdjVex(G,v);
初始条件:图G存在,v是G中的某个顶点
操作结果:返回v的第一个邻接顶点。若顶点在G中没有邻接顶点,则返回“空” - NextAdjVex(G,v,w);
初始条件:图G存在,v是G中某个顶点,w是v的邻接顶点
操作结果:返回v的(相对于w的)下一个邻接顶点。若w是v的最后一个邻接顶点,则返回“空”
深度优先搜索
深度优先搜索(Depth_ First Search)遍历类似于树的先序遍历过程。
- 从图中某顶点 v 出发,访问顶点v
- 依次从 v 的未访问的邻接点出发,继续对图进行深度优先搜索
例:求图G以V0为起点的深度优先序列
V0,V1,V3,V7,V4,V2,V5,V6
由于没有规定访问邻接点的顺序,访问结果不唯一
DFS算法
Boolean visited[MAX]; //访问标志数组
Status (*VisitFunc)(int v); //函数变量
void DFSTraverse(Graph G, Status (*Visit)(int v)) {
/*对图G做深度优先遍历*/
VisitFunc = Visit; //使用劝酒按量VisitFunc,使DFS不必设函数指针参数
for (v = 0; v < G.vexnum; v++)
visited[v] = FALSE; //访问标志数组初始化
for (v = 0; v < G.vexnum; v++)
if (!visited[v])
DFS(G, v);
}
void DFS(Graph G, int v) {
/*从第v个顶点出发递归地深度优先遍历图G*/
visited[v] = TRUE;
VisitFunc(v); //访问第v个顶点
for (w = FirstAdjVex(G, v); w >= 0; w = NextAdjVex(G, v, w))
if (!visited[w])
DFS(G, w); //对v的尚未访问的邻接顶点w递归调用DFS
}
广度优先搜索
广度优先搜索(Broadth_ First Search)遍历类似于树的按层次遍历的过程。
- 从图中某未访问过的顶点 vi 出发,访问顶点 vi
- 访问 vi 的所有未被访问过的邻接点w1,w2,…,wk
- 依次从这些邻接点出发,访问它们的所有未访问过的邻接点,直到图中所有的顶点都被访问
例:求图G以V0为起点的广度优先序列
V0,V1,V2,V3,V4,V5,V6,V7
由于没有规定访问邻接点的顺序,访问结果不唯一
BFS算法
void BFSTraverse(Graph G, Status (*Visit)(int v)) {
/*按广度优先非递归遍历图G,使用辅助队列Q和访问标志数组visited*/
for (v = 0; v < G.vexnum; v++)
visited[v] = FALSE; //访问标志数组初始化
InitQueue(Q); //置空的辅助队列Q
for (v = 0; v < G.vexnum; v++) {
if (!visited[v]) { //v尚未访问
visited[v] = TRUE;
Visit(v);
EnQueue(Q, v); //v入队列
while (!QueueEmpty(Q)) {
DeQueue(Q, u); //队头元素出队并置为u
for (w = FirstAdjVex(G, u); w >= 0; w = NextAdjVex(G, u, w)) {
if (!visited[w]) { //w为u的未访问的邻接顶点
visited[w] = TRUE;
Visit(w);
EnQueue(Q, w);
} //if
} //for
} //while
} //if
} //for
} //BFSTraverse