图的深度优先搜索类似于树的深度优先搜索。不同的是,图中可能包括循环,即我们有可能重复访问节点。为了避免访问已经访问过的节点,我们要使用一个布尔变量的数组。
例如,在下图中,我们从节点2开始访问。当访问到节点0,我们寻找它的所有紧接节点。节点2也属于节点0的邻接节点。如果我们没有标记访问的节点,那么节点2 将会被重复访问,这样的话整个算法过程就不会停下来了。下图的深度优先搜索是2,0,1,3
这种搜索算法所遵循的搜索策略是尽可能“深”地搜索一个图。它的基本思想如下:首先访问图中某一起始顶点v,然后由v出发,访问与v邻接且未被访问的任一顶点w1,再访问与w1邻接且未被访问的任一顶点w2,......重复上述过程。当不能再继续向下访问时,一次退回到最近被访问的顶点,若它还有邻接顶点未被访问过,则从该点开始继续上述搜索过程,直到图中所有顶点均被访问过为止。
举个例子:
上图一幅无向图。我们从A点开始遍历,并假设左边的节点先被访问到。那么访问顺序是A,搜索A所有可访问的邻接节点并选择B,然后访问B,搜索B所有可访问的邻接节点并选择D,然后访问D,搜索D的所有可访问的邻接节点。由于D只有一个邻接节点B,而B已经被访问过。所以回退到D的上级B(注意,不是访问B,仅仅是回到上级)。然后再搜索B的所有可访问的邻接节点,AD已经被访问过,所以访问F。这个过程一直持续直到访问过所有的节点。
选择可访问邻接节点的时候,可以使用我们自己定义的顺序。比如访问A的邻接节点的时候,可以先访问B,也可以先访问E。可根据需求灵活调整。
下述代码是深度优先搜索的C++版本,有递归和迭代版本。图的实现使用邻接链表表示。STL的list被用来存储邻接节点。
#include<list> #include<iostream> using namespace std; class Graph { private: int V; list<int>* adj; void DfsUtil(int v, bool visited[]); public: Graph(int n); //No of vertices ~Graph(); //Pointer to an array containing adjacency lists void addEdge(int v, int w); //function to add an edge to graph void Dfs(int s); //Dfs traversal of the vertices reachable from v void DfsIter(int s); }; Graph::Graph(int v) { V = v; adj = new list<int>[V]; } Graph::~Graph() { delete []adj; adj = NULL; } void Graph::addEdge(int v, int w) { adj[v].push_back(w); //Add w to v's list } void Graph::Dfs(int s) { bool* visited = new bool[V]; for (int i = 0; i < V; i++) visited[V] = false; DfsUtil(s, visited); } void Graph::DfsUtil(int v, bool visited[]) { //Mark the current node as the visited and print it visited[v] = true; cout<<v<<" "; //Recur for all vertices adjacent to this vertex list<int>::iterator i; for (i = adj[v].begin(); i != adj[v].end(); i++) if (!visited[*i]) DfsUtil(*i, visited); } void Graph::DfsIter(int v) { bool* visited = new bool[V]; for (int i = 0; i < V; i++) visited[i] = false; list<int> stack; stack.push_back(v); list<int>::iterator i; while (!stack.empty()) { v = stack.back(); cout<<v<<" "; stack.pop_back(); visited[v] = true; for(i = adj[v].begin(); i != adj[v].end(); i++) if (!visited[*i]) stack.push_back(*i); } delete []visited; } int main() { // Create a graph given in the above diagram Graph g(4); g.addEdge(0, 1); g.addEdge(0, 2); g.addEdge(1, 2); g.addEdge(2, 0); g.addEdge(2, 3); g.addEdge(3, 3); cout << "Following is Depth First Traversal (starting from vertex 2) \n"; g.DfsIter(2); return 0; }
输出:
Following is Depth First Traversal (starting from vertex 2) 2 0 1 3
参考资料:
1. http://www.geeksforgeeks.org/depth-first-traversal-for-a-graph/