深度优先遍历(Depth_First_Search),也有称为深度优先搜索,简称为DFS。

图7-5-2
反应快的同学一定会感觉到,深度优先遍历其实就是一个递归的过程,
如果再敏感一些,会发现其实转换成如图7-5-2的右图后,就像是一棵树的前序遍历,
没错,它就是。它从图中某个顶点v出发,访问此顶点,然后从v的未被访问的邻接点出发深度优先遍历图,直至图中所有和v有路径相通的顶点都被访问到。
事实上,我们这里讲到的是连通图,对于非连通图,只需要对它的连通分量分别进行深度优先遍历,即在先前一个顶点进行一次深度优先遍历后,若图中尚有顶点未被访问,则另选图中一个未曾被访问的顶点作起始点,重复上述过程,直至图中所有顶点都被访问到为止。
//如果我们用的是邻接矩阵的方式,则代码如下:/* Boolean是布尔类型,其值是TRUE或FALSE */typedef int Boolean;/* 访问标志的数组 */Boolean visited[MAX];/* 邻接矩阵的深度优先递归算法 */void DFS(MGraph G, int i){int j;visited[i] = TRUE;/* 打印顶点,也可以其他操作 */printf("%c ", G.vexs[i]);for (j = 0; j < G.numVertexes; j++)if (G.arc[i][j] == 1 && !visited[j])/* 对为访问的邻接顶点递归调用 */DFS(G, j);}/* 邻接矩阵的深度遍历操作 */void DFSTraverse(MGraph G){int i;for (i = 0; i < G.numVertexes; i++)/* 初始所有顶点状态都是未访问过状态 */visited[i] = FALSE;for (i = 0; i < G.numVertexes; i++)/* 对未访问过的顶点调用DFS,若是连通图,只会执行一次 */if (!visited[i])DFS(G, i);}
//如果图结构是邻接表结构,其DFSTraverse函数的代码是几乎相同的,只是在递归函数中因为将数组换成了链表而有不同,代码如下。/* 邻接表的深度优先递归算法 */void DFS(GraphAdjList GL, int i){EdgeNode *p;visited[i] = TRUE;/* 打印顶点,也可以其他操作 */printf("%c ", GL->adjList[i].data);p = GL->adjList[i].firstedge;while (p){if (!visited[p->adjvex])/* 对为访问的邻接顶点递归调用 */DFS(GL, p->adjvex);p = p->next;}}/* 邻接表的深度遍历操作 */void DFSTraverse(GraphAdjList GL){int i;for (i = 0; i < GL->numVertexes; i++)/* 初始所有顶点状态都是未访问过状态 */visited[i] = FALSE;for (i = 0; i < GL->numVertexes; i++)/* 对未访问过的顶点调用DFS,若是连通图,只会执行一次 */if (!visited[i])DFS(GL, i);}
对比两个不同存储结构的深度优先遍历算法,
- 对于n个顶点e条边的图来说,邻接矩阵由于是二维数组,要查找每个顶点的邻接点需要访问矩阵中的所有元素,因此都需要O(n2)的时间。
- 而邻接表做存储结构时,找邻接点所需的时间取决于顶点和边的数量,所以是O(n+e)。
显然对于点多边少的稀疏图来说,邻接表结构使得算法在时间效率上大大提高。
对于有向图而言,由于它只是对通道存在可行或不可行,算法上没有变化,是完全可以通用的。这里就不再详述了。
