图的遍历:从图中的某一顶点出发,访问图中其余顶点,并且使得图中每个顶点都被访问一次,所为访问其实就是对顶点做相关的自定义操作,比如打印数值,更改数据信息等。图的遍历有两种方式: (1) 图的深度优先搜索,简称DFS; (2)图的广度优先搜索, 简称BFS。 图的遍历其实和树的遍历是一样的 DFS对应于树的先根回溯遍历,而BFS则是对应了树的广度按层遍历。但是树和图不一样的地方在于,树不会存在环,而图可能遍历到后面又回到了已经遍历过的地方,所以在图的遍历时,需要额外开辟一个空间用来标记是否下一个遍历的顶点已经遍历过,若遍历过则不再选取进行重复遍历。
DFS深度优先遍历:深度优先遍历和树的先根顺序遍历一样,初始时假设所有的顶点都没有被遍历过,选取其中一个作为起点V,同事初始化一个标记数组 mark[vertex_num]全部为false, 然后依次深度优先访问顶点V未被访问过的邻接顶点V',并且标记mark[V'] = true; 重复上述过程,直到所有与V相通的顶点都被访问完毕。若此时还有顶点未被访问到,则另选取图中一个未被访问过的顶点,重复上述过程,直到图中所有顶点都被访问过为止。如下所示:
由图可知: DFS 遍历时先遍历V1 然后V2 V4 ...... 则DFS遍历序列为:V1 V2 V4 V8 V5 V3 V6 V7
邻接矩阵实现DFS遍历:
#define VertexNum 100
int mark[VertexNum];
int map[VertexNum][VertexNum];
void DFS(int cur_ver)
{
mark[cur_ver] = 1; // 标记当前遍历的顶点
for(int next_ver = 0 ; next_ver < VertexNum; next_ver++)
{
// 寻找下一个与当前顶点邻接的还没有被标记过的顶点
if (map[cur_ver][next_ver] == 1 && !mark[next_ver])
DFS(next_ver);
}
}
void DFSTraverse()
{
memset(map, 0x00, sizeof(map)); // 初始化标记数组mark
for (int i = 0; i < VertexNum; i++)
{
if (mark[i] == 0) // 依次遍历顶点,顶点起点为V0
DFS(i); // 调用DFS进行遍历标记,若为连通图此处仅仅调用一次
}
}
邻接表实现DFS遍历:
typedef int EdgeType;
typedef int VertexType;
#define MAXVEERTEX 100
typedef struct edge // 边表结点
{
int ver_index; // 邻接顶点域 说明邻接顶点在数组中的下标
edge* next; // 下一个邻接顶点域
}EdgeNode;
typedef struct vertex // 顶点表结构
{
VertexType ver_noee; // 顶点信息
EdgeNode* first_vertex; // 顶点链表
}VertexNode, AdjList[MAXVEERTEX];
typedef struct graph
{
AdjList list;
int ver_num, edge_num;
}Graph;
bool mark[MAXVEERTEX];
void DFS(Graph* g, int cur_ver)
{
mark[cur_ver] = true; // 获取到当前顶点,并且标记
// 找到当前顶点的下一个邻接顶点进行DFS
EdgeNode* next = g->list[cur_ver].first_vertex;
while(next)
{
if (!mark[next->ver_index])
DFS(g, next->ver_index);
next = next->next;
}
}
void DFSTraverse(Graph* g)
{
// 初始化标记数组
for (int i = 0; i < g->ver_num; i++)
mark[i] = false;
// 对各个顶点进行DFS遍历
for (int i = 0; i < g->ver_num; i++)
{
if (!mark[i])
DFS(g, i);
}
}