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


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

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

  • 相关阅读:
    linux创建用户与删除用户及问题解决(ubuntu)
    Build tool
    Version Control&Git
    IntelliJ IDEA激活
    KDJ 指标
    MACD 分析理解
    MACD 指标
    BOLL 指标
    IaaS,PaaS,SaaS 的区别
    Kubernetes 第十七章 调度器 污点和容忍 以及高级调度方式
  • 原文地址:https://www.cnblogs.com/vincently/p/4769617.html
Copyright © 2020-2023  润新知