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

时间:2014-10-24 12:24:19

标签: algorithm graph big-o time-complexity dijkstra

根据我的理解,我使用下面给出的邻接列表计算了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)
  5. 但是Dijkstra算法的时间复杂度是O(ElogV)。为什么呢?

6 个答案:

答案 0 :(得分:60)

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

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

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

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

让我们将您的E重命名为N。因此,一项分析显示O(ElogV),另一项分析显示O(VNlogV)。两者都是正确的,事实上E = O(VN)。区别在于ElogV是一个更严格的估计。

答案 1 :(得分:1)

以我理解的方式添加更详细的解释,以防万一:

  • 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))

答案 2 :(得分:0)

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

由于使用Dijkstra的算法,您拥有O(n)删除分钟 s和O(m) decrease_key s,每个花费O(logn),总运行时间使用二进制堆将是O(log(n)(m + n))。完全有可能使用Fibonacci堆将 decrease_key 的成本摊销到O(1),从而导致总运行时间为O(nlogn + m),但实际上,由于常数FH的因子惩罚很大,在随机图上, decrease_key s的数量远低于其各自的上限(在O(n * log(m / n)的范围内更大)在其中m = O(n))的稀疏图上效果更好。因此,请始终注意一个事实,即总运行时间取决于您的数据结构和输入类。

答案 3 :(得分:0)

在密集(或完整)图中,function stringReverse(string) { return string .split("") .reverse() .join(""); } function login() { var username = document.getElementById("username").value; var password = document.getElementById("password").value; var reverseInput = stringReverse(username); if (password === reverseInput) { alert("Authorized"); } else { alert("Unauthorized"); } }

使用链接数据和二进制堆并不总是最好的。

在这种情况下,我更喜欢仅使用矩阵数据并逐行保存最小长度。

只需<form> <label>Username: </label> <input id="username" type="text" placeholder="Username" /> <label>Password: </label> <input id="password" type="text" placeholder="Password" /> <button type="button" onclick="login()">Login</button> </form>时间。

如果是E logV > V^2

或者,每个顶点的最大边缘小于某个常数V^2

然后使用二进制堆。

答案 4 :(得分:0)

让我们尝试分析CLRS本书中给出的算法。

enter image description here

对于第7行中的每个循环:对于任何顶点,如果说'u',则循环运行的次数等于'u'的相邻顶点的数目。 节点的相邻顶点数始终小于或等于图中的边总数。

如果我们取V(由于第4行中的while循环)和E(由于第7行中的每个循环)并将其复杂度计算为V E log(V),则等价于假设每个顶点上都有E边入射,但是实际上每个顶点上最多有或少于E边入射。 (单个顶点情况下最多E个相邻顶点发生在内部顶点为星图的情况下)

答案 5 :(得分:0)

V:顶点数, E:总边数 假设图是稠密的 复杂度为 O(V*logV) + O( (1+2+...+V)*logV)

1+2+....+(V-1) = (v)*(v+1)/2 ~ V^2 ~ E 因为图是稠密的 所以复杂度是 O(ElogV)。

总和 1+2+...+ V 指的是:对于 G.adj[u] 中但不在 S 中的每个顶点 v 如果你在提取顶点之前考虑 Q 有 V 个顶点,那么它有 V-1 然后是 V-2 ...然后1。

enter image description here