显然,图分为两种:无向图和有向图。
无向图示例:
如图,任意两个相连的结点是可以互相通达的。例如,V1与V2相连,那么从V1可以到达V2,从V2也可以到达V1(所有路径都是双向的).
有向图示例:
对于任意两个相连的结点U、V,若存在存在从U到V的路径,即不存在从V到U的路径(所有路径都是单向的)。
在利用邻接矩阵描述图的情况下,我接下来阐释如何利用深度优先搜索进行两种图的遍历。
无向图的深度优先遍历
无向图–>表格
对于如上的无向图,我们可以用如下的表格进行描述。
最左列的黑色数字表示出发点,最上行的黑色数字表示终止点,红色1表示有路径。
表格–>数组(类似于邻接矩阵)
如果用二维数组map[7][7]描述该表格,设定出发点为一维坐标,终止点为二维坐标,那map[ i ][ j ](1<=i<=6,1<=j<=6)为
0表示没有路径,1表示有路径。
map[ 1 ][ 2 ]==1 <=>结点1 可通向结点2 ,
map[ 2 ][ 1 ]==1 <=>结点2 可通向结点1.
实例分析
假设从结点1出发遍历整个如上的无向图,
1、 搜索结点1的每条路径(有多少出度)。如上图,结点1有3条路径(出度)(1—2、1—3、1—3)。
2、沿结点 1的3条路径逐一深入搜索,直到不能继续前进为止(在搜索的过程中要将探访过的所有结点一一标记,防止重复搜索)。所谓不能继续前进有两种情况:
(1). 当前结点已访问过
(2). 当前结点已无未被访问过的路径
3、先讨论1—2路径。结点2的两条路径中,2—1路径已经访问过,所以只需访问2—5路径。
(红色区域意为已经访问过,绿色三角形为当前搜索进度)
结点5的三条路径中5—2已访问过,所以接下来分别访问5—3、5—6。
(1)5—3路径。结点3的3条路径中3—5、3—1已访问过,所以接下来分别访问3—4、3—6路径。
①3—4路径。结点4的三条路径中4–1、4—3已经访问过,所以只能探访4—6路径。
结点6的所有路径都访问过,已无法前进。
②3—6路径。结点6已访问过,无法前进。
(2)、5–6路径中的结点6已访问过,无法前进。
4、1—3路径中结点3已访问过,无法前进。
5、1—4路径中结点4已访问过,无法前进。
搜索结束……
思路概括
- 任选一个结点作为出发点,以此结点为中心,逐一探访该结点 的所有路径(路径1、路径2、……、路径n)。途中每到达新的结点,则又以此新结点为中心,逐一探访该结点 的所有路径(路径1‘、路径2’、……、路径n’)。(是不是该用递归呢……)
- 每到一个结点就检查该结点是否被访问过以及是否有未被访问的路径。两者之中只要一个为是,则停止对本条路径的搜索。
代码示例
#include <stdio.h>
#include <stdlib.h>
int n,m;//n代表路径数量,m为结点数量
int map[100][100];
int visit[100];//visit用于标记结点
int DFS(int number)//number结点编号
{
int i;
if(visit[number])//该结点已被访问过
{
return 0;//结束搜索
}
printf("%d ",number);//打印结点
visit[number]=1;//标记结点
for(i=1;i<=m;i++)//探访当前结点的所有可能的相邻路径
{
if(map[number][i])//若有通向其它结点的路径
{
DFS(i);//沿路径深入搜索
}
}
return 0;
}
int main()
{
int start;//出发点
int i,start_point,end_point;//start_point路径起始点,end_point路径终止点
printf("Please input the number of paths and number of nodes\n");
scanf("%d%d",&n,&m);//输入路径数量和结点数量
printf("Please input the start_point and end_point\n");
for(i=1;i<=n;i++)
{
scanf("%d%d",&start_point,&end_point);
//因为是无向图,所以路径是对称的
map[start_point][end_point]=1;
map[end_point][start_point]=1;
}
printf("Please input the start\n");
scanf("%d",&start);
if(start>n||n==0)
{
return 0;
}
else
{
DFS(start);
}
return 0;
}
有向图的深度优先遍历
有向图的深度优先遍历思路与无向图基本相同,唯一不同的是,因为有向图的路径是非对称的(即对于任意两个相连的结点U、V,若存在存在从U到V的路径,即不存在从V到U的路径),所以在构造邻接矩阵时,部分元素不需要被赋1.
for(i=1;i<=n;i++)
{
scanf("%d%d",&start_point,&end_point);
//因为是有向图,所以路径是非对称的
map[start_point][end_point]=1;
}