大话数据结构学习笔记 - 图的遍历之深度优先遍历和广度优先遍历
图的遍历(Traversing Graph):从图中某一顶点出发访遍图中其余顶点,且使每一个顶点仅被访问一次,这一过程就叫做图的遍历
深度优先遍历
深度优先遍历介绍
深度优先遍历(Depth First Search):也有称为深度优先搜索,简称为DFS。
思想: 从图中某个顶点v
出发,访问此顶点,然后从v
的未被访问的邻接点出发深度优先遍历图,直至图中所有和v
有路径想通的顶点都被访问到。若图中尚有顶点未被访问到,则另选图中一个未曾被访问的顶点作起始点,重复上述过程,直至图中所有顶点都被访问到为止。显然,深度优先遍历是一个 递归的过程
深度优先遍历图解
无向图的深度优先遍历
对下图左图做深度优先遍历,遍历过程如下图右图所示
- 顶点
A
出发,访问A
, 假设没有碰到重复顶点的情况下,始终向右手边走 - 访问
A
的邻接点B
,B
的邻接点C
,C
的邻接点D
,D
的邻接点E
,E
的邻接点F
- 在顶点
F
处,右手边为顶点A
,但已被访问过,故访问顶点G
- 在顶点
G
处,右手边为顶点B
,下一个为D
, 都已被访问,故访问顶点H
- 在顶点
H
处,由于邻接点G
、D
和E
都被访问,故回退到G
,同理,一直回退到D
处,访问I
因此,访问顺序为A->B->C->D->E->F->G->H->I
深度优先遍历代码
无向图的邻接矩阵
typedef int Boolean; /* Boolean 是布尔类型, 其值是 TRUE 或 FALSE */
Boolean visited[MAX]; /* 访问标志的数组 */
/* 邻接矩阵的深度优先递归算法 */
void DFS(MGraph G, int i)
{
printf("%C ", G.vexs[i]); /* 打印顶点,也可以是其他操作 */
visited[i] = TRUE;
for(int j = 0; j < G.numVertexes; j++)
{
if(G.arc[i][j] == 1 && !visited[j])
DFS(G, j); /* 对未访问的邻接顶点递归调用 */
}
}
/* 邻接矩阵的深度遍历操作 */
void DFSTraverse(MGraph G)
{
for(int i = 0; i < G.numVertexes; i++)
visited[i] = FALSE; /* 初始所有顶点状态都是未访问过状态 */
for(int i = 0; i < G.numVertexes; i++)
if(!visited[i]) /* 对未访问过的顶点调用 DFS, 若是连通图,只会执行一次 */
DFS(G, i);
}
无向图的邻接表
/* 邻接表的深度优先递归算法 */
void DFS(GraphAdjList GL, int i)
{
printf("%c ", GL.adjList[i].data);
visited[i] = TRUE;
EdgeNode *p = GL.adjList[i].firstedge;
while(p)
{
if(!visited(p->adjvex))
DFS(GL, p->adjvex);
p = p->next;
}
}
/* 邻接表的深度遍历操作 */
void DFSTraverse(GraphAdjList GL)
{
for(int i = 0; i < GL.numVertexes; i++)
visited[i] = TRUE;
for(int i = 0; i < GL.numVertexes; i++)
if(!visited[i])
DFS(GL, i);
}
广度优先遍历
广度优先遍历介绍
广度优先遍历(Breadth First Search),又称为 广度优先搜索, 简称 BFS。
思想: 从图中某个顶点v
出发,在访问了顶点v
后,依次访问顶点v
的所有未被访问过的邻接点,然后分别从这些邻接点依次访问他们的邻接点,并使得先被访问过的顶点的邻接点先于后被访问的顶点的邻接点被访问
, 直至图中所有已被访问的顶点的邻接点都被访问到。如果此时图中尚有顶点未被访问,则需要另选一个未曾被访问过的顶点作为新的起始点,重复上述过程,直至图中所有顶点都被访问到为止。广度优先遍历类似于树的层序遍历
广度优先遍历图解
对下图左图1
进行广度优先遍历, 类似于下图右图的层序遍历,图三为遍历过程
- 访问
A
- 依次访问
B
、F
,紧接着访问B
的邻接点和F
的邻接点 - 依次访问
C
、I
、G
和E
,然后依次访问他们的邻接点 - 依次访问
D
、H
因此访问顺序为A->B->F->C->I->G->E->D->H
扫描二维码关注公众号,回复:
1496894 查看本文章
广度优先遍历代码
无向图的邻接矩阵
void BFSTraverse(MGraph G)
{
SqQueue Q;
for(int i = 0; i < G.numVertexes; i++)
visited[i] = FALSE; /* 初始化辅助用的队列 */
for(int i = 0; i < G.numVertexes; i++) /* 对每一个顶点做循环 */
{
if(!visited[i]) /* 若是未访问过就处理 */
{
EnQueue(&Q, i); /* 将此队列入队 */
printf("%c ", G.vexs[i]); /* 打印顶点,也可以是其他操作 */
visited[i] = TRUE; /* 设置当前顶点访问过 */
while(!QueueEmpty(Q)) /* 若当前队列不为空 */
{
DeQueue(&Q, &i); /* 将队列中元素出队列,赋值给 i */
for(int j = 0; j < G.numVertexes; j++)
{
/* 判断其他顶点若与当前顶点存在边且未被访问过 */
if(G.arc[i][j] == 1 && !visited[j])
{
printf("%c ", G.vexs[j]); /* 打印顶点 */
visited[j] = TRUE; /* 将找到的此顶点标记为已访问 */
EnQueue(&Q, j); /* 将找到的此顶点入队 */
}
}
}
}
}
}
无向图的邻接表
/* 邻接表的广度遍历算法 */
void BFS(GraphAdjList GL)
{
SqQueue Q;
for(int i = 0; i < GL.numVertexes; i++)
visited[i] = FALSE;
InitQueue(&Q);
for(int i = 0; i < GL.numVertexes; i++)
{
if(!visited[i])
{
EnQueue(&Q, i);
visited[i] = TRUE;
printf("%c ", GL.adjList[i].data); /* 打印顶点,也可以是其他操作 */
while(!QueueEmpty(Q))
{
DeQueue(&Q, &i);
NodeEdge *p = GL.adjList[i].firstedge; /* 找到当前顶点边表链表头指针 */
while(p)
{
if(!visited[p->adjvex]) /* 若此顶点未被访问 */
{
printf("%c ", G.adjList[p->adjvex].data);
EnQueue(&Q, p->adjvex); /* 将此顶点入队 */
visited[p->adjvex] = TRUE;
}
p = p->next; /* 指针指向下一个邻接点 */
}
}
}
}
}
结语
关于有向图的遍历,后续会继续整理。