了解Dijkstra算法的时间复杂度计算

Mee*_*ary 48 algorithm big-o graph dijkstra time-complexity

根据我的理解,我使用下面给出的邻接表将Dijkstra算法的时间复杂度计算为big-O表示法.它没有像它应该的那样出来,这让我逐步理解它.

  1. 每个顶点可以连接到(V-1)个顶点,因此每个顶点的相邻边的数量是V-1.让我们说E代表连接到每个顶点的V-1边.
  2. 在最小堆中查找和更新每个相邻顶点的权重是O(log(V))+ O(1)或O(log(V)).
  3. 因此,从上面的步骤1和步骤2,更新顶点的所有相邻顶点的时间复杂度是E*(logV).或E*logV.
  4. 因此,所有V顶点的时间复杂度是V*(E*logV),即O(VElogV).

但是Dijkstra算法的时间复杂度是O(ElogV).为什么?

Sha*_*baz 64

Dijkstra的最短路径算法是O(ElogV):

  • V 是顶点的数量
  • E 是边的总数

你的分析是正确的,但你的符号有不同的含义!你说算法在O(VElogV)哪里:

  • V 是顶点的数量
  • E 是附加到单个节点的最大边数.

让我们重命名你EN.一个分析说O(ElogV),另一个分析说O(VNlogV).两者都是正确的,事实上E = O(VN).不同的是,这ElogV是一个更严格的估计.

  • 我想指出这个时间复杂度,`O(E log V)`,假设给定的图是连通的。例如,在具有很多孤立顶点的稀疏图的情况下,它将不成立。这就是为什么 Dijkstra 二叉堆实现的最坏情况是“O(V log V + E log V)”。当我们不能假设 `E >= V` 时,它不能简化为 `O(E log V)` (5认同)
  • @MeenaChaudhary,更确切地说是`maxAdjacentEdgesOfAVertex*totalVertices> = totalEdges`,这就是更严格的约束.更严格的约束意味着更接近事实的估计.例如,如果一个算法执行"n + 10"运算,你可以说它是"O(n ^ 2)",这是真的,或者"O(nlogn)"也是如此.但它也是"O(n)",它比其他两个更紧密.可能的最严格的界限称为"Θ",因此在上面的例子中,"n + 1 =Θ(n)".(`Θ`的定义是上限和下限) (4认同)
  • 谢谢,得到你的观点,adjacentEdges*totalVertices = totalEdges(E).但是你能否对一个更严格的约束/估计真正意味着什么有所了解. (3认同)
  • @SeldomNeedy,是的,这是基数2中的`log`.虽然只要涉及`O`表示法,但它没有区别,因为`log [10](V)= log [10](2)*log [2](V)`,所以差异只是一个常数,它不会改变算法的时间顺序. (2认同)
  • @SeldomNeedy,哦,对于计算机算法,您很少需要以 2 以外的任何基数记录 `log`,因此基数 2 是隐含的。(看看我在那里做了什么?) (2认同)

Sam*_*Sam 11

添加更详细的解释,以防万一:

  • O(对于使用最小堆的每个顶点:对于每个边线性:将顶点推到该边指向的最小堆)
  • V = 顶点数
  • O(V * (从最小堆弹出顶点+在边缘中找到未访问的顶点*将它们推到最小堆))
  • E = 每个顶点上的边数
  • O(V * (从最小堆弹出顶点+ E *将未访问的顶点推送到最小堆))。请注意,在我们“访问”它之前,我们可以在此处多次推送同一个节点。
  • O(V * (log(堆大小) + E * log(堆大小)))
  • O(V * ((E + 1) * log(堆大小)))
  • O(V * (E * log(堆大小)))
  • E = V 因为每个顶点都可以引用所有其他顶点
  • O(V * (V * log(堆大小)))
  • O(V^2 * log(堆大小))
  • 堆大小是V^2因为我们每次想要更新距离时都会推送到它,并且每个顶点最多可以进行 V 次比较。例如,对于最后一个顶点,第一个顶点有距离10,第二个有9,第三个有8,等等,所以,我们每次都推送更新
  • O(V^2 * log(V^2))
  • O(V^2 * 2 * log(V))
  • O(V^2 * log(V))
  • V^2也是边的总数,所以如果我们让E = V^2(如官方命名),我们将得到O(E * log(V))

  • @MrA,如果你有顶点 A、B、C,那么 A 可以连接到 B 和 C。B 可以连接到 A 和 C。C 可以连接到 A 和 B。所以任何顶点都可以连接到 V - 1 个顶点(除了它本身),所以每个顶点上可以有 V - 1 条边,基本上等于 V。所以,E = V (2认同)

tim*_*ody 7

令 n 为顶点数,m 为边数。

由于使用 Dijkstra 算法您有 O(n) delete-min s 和 O(m) reduction_key s,每个成本 O(logn),使用二元堆的总运行时间将为 O(log(n)(m + n)) . 完全有可能使用斐波那契堆将降低密钥的成本摊销到 O(1) 导致总运行时间为 O(nlogn+m) 但实际上这通常不会这样做,因为 FH 的常数因子惩罚非常大并且在随机图上,decrease_key的数量远低于其各自的上限(更多在 O(n*log(m/n) 的范围内,这在 m = O(n) 的稀疏图上更好)。因此,请始终注意总运行时间取决于您的数据结构和输入类这一事实。