Java 为什么Dikstra算法在O(V+;E log V)而不是O(V^2)中运行?

Java 为什么Dikstra算法在O(V+;E log V)而不是O(V^2)中运行?,java,algorithm,graph,Java,Algorithm,Graph,其中,V是顶点数,E是边数,在最坏的情况下,所有节点都是连接的,在每个节点上,您可以查看所有其他节点。那么这不就是O(V^2)?我查了一下,发现它实际上是O(V+E log V),但没有解释。您只考虑完全连通图的情况。big-O表示法适用于给定某些输入参数的最坏情况,并且由于给定的复杂性使用V和E,这意味着完全连通图是不相关的。对于一般的图,Dijkstra的算法将在O(V+ElogV)或更快的时间内完成;对于全连通图,当E大约为(V^2)/2时,它将在O(V^2)中完成,这确实比O(V+((V

其中,
V
是顶点数,E是边数,在最坏的情况下,所有节点都是连接的,在每个节点上,您可以查看所有其他节点。那么这不就是O(V^2)?我查了一下,发现它实际上是
O(V+E log V)
,但没有解释。

您只考虑完全连通图的情况。big-O表示法适用于给定某些输入参数的最坏情况,并且由于给定的复杂性使用V和E,这意味着完全连通图是不相关的。对于一般的图,Dijkstra的算法将在O(V+ElogV)或更快的时间内完成;对于全连通图,当E大约为(V^2)/2时,它将在O(V^2)中完成,这确实比O(V+((V^2)/2)logV快。

不,Dijkstra的最佳实现是使用斐波那契堆作为优先级队列,根据。请记住,在一个稠密图中,
|E |
O(| v |^2)
O(| E |+| v |*log | v |)
等于
O(| v | ^2)
,这是算法的最坏情况,但在所有这些情况下,它都不会在
O(| v | E | E | log | log | log

中运行,而忽略队列的成本分析。不过,你并不是完全错了

它需要O(| E |)减少关键点操作,因为您访问的几乎每一条边都可能会这样做,而O(| V |)删除最小操作则需要O(| V |)减少关键点操作,因为您必须这样做才能将顶点从队列中取出

如果使用Fibonacci堆作为优先级队列,那么reduce key需要固定的时间,而delete min需要O(log | V |)时间,所以得到O(| E |+| V | log | V |)。仅就| V |而言,| E |被O(| V | 2)所取代,因为它可能会达到那么高的水平,而这在给出O(|V | 2)的总复杂性的| V | log | V |项中占主导地位

因此,如果您只想给出| V |的界,那么您是正确的,但是最好分别给出| V |和| E |的界,因为它传递了更多信息。它告诉您,对于稀疏图,它比O(| V | 2)快,这可能很重要

请注意,您查找的O(V+E log V)是针对使用不同类型优先级队列(如二进制堆)而不是斐波那契堆的实现。这在实践中很常见