图的遍历
从图中某一个顶点出发访遍图中其余顶点,且使每一个顶点仅被访问一次,这一过程叫做图的遍历。
- 深度优先搜索
- 广度优先搜索
深度优先搜索(DFS):
图的深度优先搜索类似于二叉树的先序遍历。
在深度优先搜索中,对于最新发现的顶点,如果它还有以此为起点而未探测到的边,就沿此边继续探测下去。当顶点 v
的所有边都已被探寻过后,搜索将回溯到发现顶点 v
有起始点的那些边。这一过程一直进行到已发现从源顶点可达的所有顶点为止。实际上深度优先搜索最初的探究也是为了解决迷宫问题。
深度优先搜索的思想:
- 首先访问出发点v,并将其标记成已访问过;
- 然后选取与v邻接的未被访问的任意一个顶点w,并访问它;
- 再选取与w邻接的未被访问的任意一个顶点并访问;
- 重复进行;
- 当一个顶点所有的邻接顶点都被访问过,则依次退回最近被访问过的顶点;
- 若该顶点还有其他邻接顶点未被访问,则从这些未被访问的顶点中取一个并重复上述过程;
- 直至图中所有的顶点都被访问过为止;
无向图的深度优先遍历:
- 首先访问出发点A,并将其标记为已访问。
- 访问(A的邻接顶点)C.
由图可知A的邻接顶点有C.D.F。 - 访问(C的邻接顶点)B.
- 访问(C的邻接顶点)D.
- 访问(A的邻接顶点)F.
前面已经访问了A,并且访问完了A的邻接点C的所有邻接点(包括递归的邻接点在内);因此,此时返回到访问A的另一个邻接点F。
由图可知F的邻接顶点是A和G,A已访问。
- 访问(F的邻接顶点)G.
G的邻接顶点为F和E,F已访问。 - 访问(G的邻接顶点)E.
因此访问顺序是:A -> C -> B -> D -> F -> G -> E
有向图的深度优先遍历:
- 访问A。
- 访问(A的出边顶点)B
- 访问(B的出边顶点)C
在访问了B之后,接下来应该访问的是B的出边顶点,即顶点C,E,F。 - 访问(B的出边顶点)E
接下来访问C的出边的另一个顶点,即顶点E。 - 访问(E的出边顶点)D
接下来访问E的出边的另一个顶点,即顶点B,D。顶点B已访问,因此访问顶点D。 - 访问(B的出边顶点)F
- 访问(F的出边顶点)G
因此访问顺序是:A -> B -> C -> E -> D -> F -> G
算法执行过程:任取一个顶点,访问,然后检查这个顶点的所有邻接顶点,递归访问其中未被访问过的顶点。
图的遍历结果取决于图的存储结构。
图的邻接矩阵是唯一的,但对于邻接表来说,如果边的输入次序不同,邻接表也不同,
- 因此对于同一个图,基于邻接矩阵的遍历所得的DFS序列和BFS序列是唯一的;
- 基于邻接表的遍历所得到的DFS序列和BFS序列是不唯一的 。
深度优先的算法分析
在遍历过程中,一个顶点至多调用一次DFS函数,如果一旦某个顶点标志为已访问,就不再从它出发进行搜索
⑴ 利用邻接矩阵作为图的存储结构时, 查找每个顶点的
邻接点所需要时间为O(n²),其中为n顶点数。
⑵ 利用邻接表作为图的存储结构时, 找邻接点所需要的时间为O(e);因此,总的时间复杂度为O(n+e)
算法过程:
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) // 本代码从v=0开始遍历
if(!visited[v])
DFS(G,v); // 对未访问的结点调用DFS
}
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
}
广度优先搜索遍历(BFS)
图的广度优先搜索遍历类似于树的层次遍历。
层序遍历
概念:先遍历第一层,再遍历第二层,…
特点:思想简单,实现复杂
访问过程:
-
首先A入列。
访问A,A已访问,A出列 -
(A的邻接顶点)B、F入列
访问B,B已访问,B出列 -
(B的邻接顶点)C、I、G入列
访问F,F已访问,F出列 -
(F的邻接顶点)E入列
访问C,C已访问,C出列 -
(C的邻接顶点)D入列
访问I,I已访问,I出列
访问G,G已访问,G出列
访问E,E已访问,E出列 -
(E的邻接顶点)H入列
访问H,H已访问,H出列
void BFSTraverse(Graph G,Status(*Visit)(int v))
{// 使用访问标志数组visited和辅助队列Q
for(v=0;v<G.vexnum;++v)
visited[v]=FALSE;// 访问标志数组初始化
InitQueue(Q); // 置空的辅助队列Q
for(v=0;v<G.wexnum;++v)//从0号顶点开始遍历
if(!visited[v])
{
visited[v]=TRUE;
Visit(v);
EnQueue(Q,v);
while(!QueueEmpty(Q))
{
DeQueue(Q,u); // 队头元素出队并置为u
for(w=FirstAdjVex(G,v);
w>=0;w=NextAdjVex(G,u,w))
if(!visited[w]) // w为v的尚未访问的邻接顶点
{
visited[w]=TRUE;
Visit(w);
EnQueue(Q,w);
}
}
}
}
好啦,下次等我做了习题再来更新。留给赞吧~