【问题标题】:Why is the time complexity of both DFS and BFS O( V + E )为什么 DFS 和 BFS 的时间复杂度都是 O( V + E )
【发布时间】:2012-07-13 04:39:35
【问题描述】:

BFS 的基本算法:

set start vertex to visited

load it into queue

while queue not empty

   for each edge incident to vertex

        if its not visited

            load into queue

            mark vertex

所以我认为时间复杂度是:

v1 + (incident edges) + v2 + (incident edges) + .... + vn + (incident edges) 

其中v 是顶点1n

首先,我说的对吗?其次,这个O(N + E) 怎么样,以及为什么会非常好的直觉。谢谢

【问题讨论】:

    标签: algorithm time-complexity graph-theory breadth-first-search


    【解决方案1】:

    你的总和

    v1 + (incident edges) + v2 + (incident edges) + .... + vn + (incident edges)
    

    可以改写为

    (v1 + v2 + ... + vn) + [(incident_edges v1) + (incident_edges v2) + ... + (incident_edges vn)]
    

    第一组是O(N),另一组是O(E)

    【讨论】:

    • 但是每个顶点都必须从队列中提取出来,这是log(|Q|)这部分呢?
    • log(|Q|)
    • 如果在邻接列表中,每个顶点都连接到所有其他顶点,那么复杂度将等于 O(V+E)=O(V+V^2)=O(V^2 )。 E=V^2 因为最多边数 = V^2。
    • 根据你的回答,复杂度不会变成O(V+2E)吗?因为每条边都可能与另一条边有共同的边?
    • 常数项可以去掉。
    【解决方案2】:

    DFS(分析):

    • 设置/获取顶点/边标签需要 O(1) 时间
    • 每个顶点被标记两次
      • 曾经是 UNEXPLORED
      • 曾经访问过
    • 每条边被标记两次
      • 曾经是 UNEXPLORED
      • 一次作为 DISCOVERY 或 BACK
    • 对每个顶点调用一次方法incidentEdges
    • DFS 在O(n + m) 时间运行,前提是图形由邻接表结构表示
    • 回想一下Σv deg(v) = 2m

    BFS(分析):

    • 设置/获取顶点/边标签需要 O(1) 时间
    • 每个顶点被标记两次
      • 曾经是 UNEXPLORED
      • 曾经访问过
    • 每条边被标记两次
      • 曾经是 UNEXPLORED
      • 曾经作为 DISCOVERY 或 CROSS
    • 每个顶点被插入一次序列Li
    • 对每个顶点调用一次方法incidentEdges
    • BFS 在O(n + m) 时间运行,前提是图形由邻接表结构表示
    • 回想一下Σv deg(v) = 2m

    【讨论】:

    • tnx 进行编辑我是新来的,所以我仍然尝试使用编辑屏幕进行管理:)
    • 感谢您具体提到图形将由邻接表结构表示,这让我很困惑为什么 DFS 是 O(n+m),我认为它是 O(n + 2m) 因为每条边都被回溯遍历了两次。
    【解决方案3】:

    非常简化,没有太多形式:每条边都被认为是两次,每个节点只被处理一次,所以复杂度必须是边数和顶点数的常数倍。

    【讨论】:

    • 比没有进一步解释的数学符号更容易理解,尽管这就是 Google 的用途。
    • 为什么每条边都被精确地考虑了两次?
    • 每个顶点最多被访问一次,因为只有第一次到达它的距离为 null ,所以每个顶点最多被排队一次。由于我们仅在从顶点访问时检查入射在顶点上的边,所以每条边最多检查两次,对于它入射的每个顶点一次。 See Source
    【解决方案4】:

    对此的直观解释是通过简单地分析单个循环:

    1. 访问一个顶点 -> O(1)
    2. 在所有入射边上的 for 循环 -> O(e) 其中 e 是在给定顶点 v 上入射的边数。

    所以单次循环的总时间是O(1)+O(e)。现在对每个顶点求和,因为每个顶点都被访问一次。这给了

    For every V
    => 
    
        O(1)
        +
    
        O(e)
    
    => O(V) + O(E)
    

    【讨论】:

      【解决方案5】:

      时间复杂度是O(E+V)而不是O(2E+V),因为如果时间复杂度是n^2+2n+7,那么它写成O(n^2)。

      因此,O(2E+V) 写成 O(E+V)

      因为 n^2 和 n 之间的差异很重要,但 n 和 2n 之间的差异不重要。

      【讨论】:

      • @Am_I_Helpful 有人在上面用 big-oh 表示法询问 2E....这就是为什么在时间复杂度中不考虑 2。
      • @Am_I_Helpful 只是看到我的答案上面的帖子....那里名为 Kehe CAI 的用户写道“我认为每条边都被考虑了两次,每个节点都被访问过一次,所以总时间复杂度应该是 O(2E+V)。”所以我相应地回答....知道了!!!
      • 我删除了我的反对票,因为您编辑了您的答案,
      【解决方案6】:

      我认为每条边都被考虑了两次,每个节点都被访问过一次,所以总的时间复杂度应该是O(2E+V)。

      【讨论】:

      • 即使我也有同感。谁能对此给出进一步的解释?
      • 大 O 分析忽略了常数。 O(2E+V) 是 O(E+V)。
      • 是的,在大 O 分析中,通常会丢弃常数和非显性部分。
      【解决方案7】:

      简短而简单的解释:

      在最坏的情况下,您需要访问所有顶点和边,因此 最坏情况下的时间复杂度是O(V+E)

      【讨论】:

        【解决方案8】:

        在 Bfs 中,每个相邻顶点都会被插入一次队列中。这是通过查看顶点的边缘来完成的。每个访问过的顶点都被标记,因此它不能被再次访问:每个顶点只被访问一次,并且每个顶点的所有边都被检查。所以BFS的复杂度是V+E。 在 DFS 中,每个节点维护其所有相邻边的列表,然后,对于每个节点,您需要通过在线性时间内遍历其邻接列表一次来发现其所有邻居。对于有向图,所有节点的邻接表大小之和为 E(总边数)。所以,DFS的复杂度是O(V + E)。

        【讨论】:

          【解决方案9】:

          这是 O(V+E) 因为每次访问 V 的 v 必须访问 E 的每个 e 其中 |e| O(E)。所以总的时间复杂度是 O(V + E)。

          【讨论】:

            猜你喜欢
            • 2015-01-01
            • 1970-01-01
            • 2021-02-15
            • 1970-01-01
            • 1970-01-01
            • 2019-01-29
            • 2022-06-10
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多