Depth First Search (DFS) | Iterative & Recursive Implementation

来源:互联网 发布:网络营运商 编辑:程序博客网 时间:2024/05/21 19:34

深度优先搜索(DFS)|迭代和递归实现

深度优先搜索(DFS)是一种用于遍历或搜索树或图形数据结构的算法。一个从根开始(在图形的情况下选择一些任意节点作为根),并且在回溯之前尽可能沿着每个分支进行探索。

下图显示了在DFS中发现节点的顺序

这里写图片描述

深度首先在树中搜索

树是一个无向图,其中任何两个顶点通过一个路径连接。换句话说,任何非循环连接图是一棵树。对于树,我们有以下遍历方法 -

preorder:访问其子节点前的每个节点。

postorder:访问每个节点后的孩子。

inorder(仅适用于二叉树):访问左子树,节点,右子树。

深度在图中首先搜索

深度优先搜索是一种遍历图形的方式,这与树的预订遍历密切相关。以下是预订遍历的递归执行:

procedure preorder(treeNode v){    visit(v);    for each child u of v    preorder(u);}

为了将其转换为图形遍历算法,我们基本上将“child”替换为“neighbor”。但是为了防止无限循环,我们跟踪顶点已经被发现,而不再访问它们。

procedure dfs(vertex v){    visit(v);    for each neighbor u of v    if u is undiscovered    call dfs(u);}

C ++实现 -

    include <bits/stdc++.h>    using namespace std;    //图中的顶点数    #define N 13    //数据结构存储图形边    struct Edge {        int src, dest;    };    //类来表示一个图形对象    class Graph    {        public:       //表示相邻列表的向量数组        vector<int> adjList[N];         //构造函数        Graph(vector<Edge> edges)        {             //将边缘添加到无向图            for (int i = 0; i < edges.size(); i++)            {                int src = edges[i].src;                int dest = edges[i].dest;                adjList[src].push_back(dest);                adjList[dest].push_back(src);            }        }    };    //执行DFS遍历的功能    int DFS(Graph const &graph, int v, vector<bool> &discovered)    {        //将当前节点标记为已发现        discovered[v] = true;        //打印当前节点        cout << v << " ";            //为每个边缘做(v - > u)        for (int u : graph.adjList[v])        {             //u没有发现            if (!discovered[u])                DFS(graph, u, discovered);        }    }    // 主功能    int main()    {        //如上图所示的图形边沿向量        vector<Edge> edges = {             {1, 2}, {1, 7}, {1, 8}, {2, 3}, {2, 6}, {3, 4},             {3, 5}, {8, 9}, {8, 12}, {9, 10}, {9, 11}         };        //从给定的边缘创建图形        Graph graph(edges);      //存储顶点是否被发现        vector<bool> discovered(N);           //将DFS从所有未发现的节点遍历到    //覆盖图形的所有未连接的组件        for (int i = 1; i < N; i++)            if (discovered[i] == false)                DFS(graph, i, discovered);        return 0;    }
输出:
1 2 3 4 5 6 7 8 9 10 11 12

DFS遍历的时间复杂度为O(n + m),其中n为顶点数,e为图中边缘数。请注意,O(m)可能在O(1)和O(n2)之间变化,具体取决于图形的密度。

DFS的应用 -

在图中查找连接的组件
DAG中的拓扑排序(定向非循环图)
查找2-(边缘或顶点)连接的组件。
查找3-(边缘或顶点)连接的组件。
找到一个图表的桥梁。
查找强连接的组件。
解决谜题只有一个解决方案,如迷宫。
在图表中找到双连通性等等。
非递归执行DFS

DFS的非递归实现类似于BFS的非递归实现,但与两种方式不同:

它使用堆栈而不是队列
只有在弹出顶点之后,DFS才能标记发现。
它使用反向迭代器而不是迭代器来产生与递归DFS相同的结果。

C ++实现 -

    #include <bits/stdc++.h>    using namespace std;    //图中的顶点数    #define N 13    //数据结构存储图形边    struct Edge {        int src, dest;    };    //类来表示一个图形对象    class Graph    {    public:          //表示相邻列表的向量数组        vector<int> adjList[N];          //构造函数        Graph(vector<Edge> edges)        {             //将边缘添加到无向图            for (int i = 0; i < edges.size(); i++)            {                int src = edges[i].src;                int dest = edges[i].dest;                adjList[src].push_back(dest);                adjList[dest].push_back(src);            }        }    };    //从顶点v开始,在图g上执行迭代DFS       int iterativeDFS(Graph const &graph, int v)    {         //存储顶点是否被发现        vector<bool> discovered(N);        //创建一个用于执行迭代DFS的堆栈        stack<int> stack;         //将源节点推入堆栈        stack.push(v);        //运行到堆栈不是空的        while (!stack.empty())        {            //从堆栈中弹出一个顶点            v = stack.top();            stack.pop();        //如果顶点已经被发现了,        // 忽略它            if (discovered[v])                continue;             //如果弹出的顶点v        //尚未发现。我们打印并处理        //其未发现的相邻节点进入堆栈            discovered[v] = true;            cout << v << " ";        //为每个边缘做(v - > u)        //我们使用反向迭代器(为什么?)            for (auto it = graph.adjList[v].rbegin();                 it != graph.adjList[v].rend(); ++it)            {                int u = *it;                if (!discovered[u])                    stack.push(u);            }        }    }    // 主功能    int main()    {        //如上图所示的图形边沿向量        vector<Edge> edges = {              {1, 2}, {1, 7}, {1, 8}, {2, 3}, {2, 6}, {3, 4},             {3, 5}, {8, 9}, {8, 12}, {9, 10}, {9, 11}            // , {6, 9} //介绍循环        };        //从给定的边缘创建图形        Graph graph(edges);        //从顶点1执行迭代DFS遍历        iterativeDFS(graph, 1);        return 0;    }
输出:
1 2 3 4 5 6 7 8 9 10 11 12
原创粉丝点击