【数据结构】图的深度优先搜索

  图的深度优先搜索类似于树的深度优先搜索。不同的是,图中可能包括循环,即我们有可能重复访问节点。为了避免访问已经访问过的节点,我们要使用一个布尔变量的数组。

  例如,在下图中,我们从节点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/

posted @ 2015-08-29 19:58  vincently  阅读(1968)  评论(0编辑  收藏  举报