Prim和Dijkstra算法的区别?

时间:2013-01-03 17:45:29

标签: algorithm graph dijkstra minimum-spanning-tree prims-algorithm

Dijkstra和Prim的算法之间的确切区别是什么?我知道Prim会给MST,但是Dijkstra生成的树也是MST。那么确切的区别是什么?

11 个答案:

答案 0 :(得分:117)

Prim的算法为图形构建minimum spanning tree,该树是连接图中所有节点的树,并且在连接所有节点的所有树中总成本最低。但是,MST中任意两个节点之间的路径长度可能不是原始图中这两个节点之间的最短路径。例如,如果您希望物理连接图中的节点以便以最低总成本为其提供电力,则MST非常有用。两个节点之间的路径长度可能不是最佳的并不重要,因为您关心的只是它们已连接的事实。

Dijkstra的算法从某个源节点开始构造shortest path tree。最短路径树是将图中的所有节点连接回源节点的树,并且具有从源节点到图中任何其他节点的任何路径的长度最小化的属性。例如,如果您想要建立一个尽可能高效的道路网络,让每个人都能到达一些重要的重要里程碑,这是非常有用的。但是,最短路径树不能保证是最小生成树,构建这样一棵树的成本可能远远大于MST的成本。

另一个重要的差异涉及算法工作的图形类型。 Prim的算法仅适用于无向图,因为MST的概念假设图本质上是无向的。 (对于有向图,有一种称为“最小跨越树”的东西,但找到它们的算法要复杂得多)。 Dijkstra的算法在有向图上可以正常工作,因为最短的路径树确实可以被定向。另外,Dijkstra的算法does not necessarily yield the correct solution in graphs containing negative edge weights,而Prim的算法可以处理这个。

希望这有帮助!

答案 1 :(得分:73)

Dijkstra的算法不会创建MST,它会找到最短的路径。

考虑此图

       5     5
  s *-----*-----* t
     \         /
       -------
         9

最短路径是9,而MST是10的不同“路径”。

答案 2 :(得分:51)

Prim和Dijkstra算法几乎相同,除了"放松功能"。

在Prim:

MST-PRIM (G, w, r) {

        for each key ∈ G.V

            u.key = ∞
            u.parent = NIL

        r.key = 0
        Q = G.V
        while (Q ≠ ø)

            u = Extract-Min(Q)
            for each v ∈ G.Adj[u]

                if (v ∈ Q) and w(u,v) < v.key

                    v.parent = u
                    v.key = w(u,v)    <== relax function, Pay attention here

}

在Dijkstra:

Dijkstra (G, w, r) {

        for each key ∈ G.V

            u.key = ∞
            u.parent = NIL

        r.key = 0
        Q = G.V
        while (Q ≠ ø)

            u = Extract-Min(Q)
            for each v ∈ G.Adj[u]

                if (v ∈ Q) and w(u,v) < v.key

                    v.parent = u
                    v.key = w(u,v) + u.key  <== relax function, Pay attention here

}

唯一的区别是代码的最后一行,即relax函数。 搜索最小生成树的Prim只关心覆盖所有顶点的总边缘的最小值。 所以它看起来像:v.key = w(u,v) Dijkstra,它搜索最小路径长度,因此它关心边缘积累。 所以它看起来像:v.key = w(u,v)+ u.key

答案 3 :(得分:14)

  

Dijkstra找到了它的开始节点之间的最短路径   和其他所有节点。因此,作为回报,您从起始节点获得最小距离树,即您可以尽可能有效地到达每个其他节点。

     

Prims算法可以获得给定图形的MST,即连接所有节点的树,而所有成本的总和是最小的。

用一个现实的例子来简化故事:

  1. Dijkstra希望通过节省旅行时间和燃料来了解到每个目的地点的最短路径。
  2. Prim想知道如何有效地部署火车轨道系统,即节省材料成本。

答案 4 :(得分:8)

直接来自Dijkstra's Algorithm's维基百科文章:

  

Dijkstra算法的基础过程类似于Prim算法中使用的贪婪过程。 Prim的目的是找到连接图中所有节点的最小生成树; Dijkstra只关心两个节点。 Prim不会评估起始节点的路径总重量,只评估单个路径。

答案 5 :(得分:3)

基本算法之间的关键区别在于它们的边缘选择标准不同。通常,它们都使用优先级队列来选择下一个节点,但是具有不同的标准来选择当前处理节点的相邻节点:Prim的算法要求下一个相邻节点也必须保留在队列中,而Dijkstra的算法不会:

def dijkstra(g, s):
    q <- make_priority_queue(VERTEX.distance)
    for each vertex v in g.vertex:
        v.distance <- infinite
        v.predecessor ~> nil
        q.add(v)
    s.distance <- 0
    while not q.is_empty:
        u <- q.extract_min()
        for each adjacent vertex v of u:
            ...

def prim(g, s):
    q <- make_priority_queue(VERTEX.distance)
    for each vertex v in g.vertex:
        v.distance <- infinite
        v.predecessor ~> nil
        q.add(v)
    s.distance <- 0
    while not q.is_empty:
        u <- q.extract_min()
        for each adjacent vertex v of u:
            if v in q and weight(u, v) < v.distance:// <-------selection--------
            ...

vertex.distance 的计算是第二个不同点。

答案 6 :(得分:1)

第一个区别是Dijkstra的算法解决了与Kruskal和Prim不同的问题。 Dijkstra解决了最短路径问题(来自指定节点),而Kruskal和Prim找到了最小成本生成树。以下是我在此页面上编写的描述的修改形式:图算法。

对于任何图形,生成树是一组边缘,足以在每对顶点之间提供恰好一条路径。这种限制意味着所选边缘不会形成电路。

最低成本生成树是具有尽可能小的总权重(其中权重代表成本或距离)的生成树。可能有不止一棵这样的树,但Prim和Kruskal都保证会找到其中一棵。

对于指定的顶点(比方说X),最短路径树是生成树,这样从X到任何其他顶点的路径尽可能短(即,具有最小可能的权重)。

Prim和Dijkstra&#34;成长&#34;从起始顶点出来的树。换句话说,他们有一个&#34; local&#34;焦点;在每一步,我们只考虑与先前选择的顶点相邻的那些边,选择满足我们需求的最便宜的选项。与此同时,Kruskal是一个全球性的&#34;算法,意味着从整个图中(贪婪地)选择每个边。 (实际上,Dijkstra可能会被视为具有一些全球性,如下所述。)

要查找最低成本生成树:

Kruskal(全局方法):在每个步骤中,选择任何不违反创建生成树目标的最便宜的可用边缘。 Prim(本地方法):选择一个起始顶点。在每个连续步骤中,选择附加到任何先前选择的顶点的最便宜的可用边缘,这不会违反创建生成树的目标。 要查找最短路径生成树:

Dijkstra:在每一步中,选择附加到任何先前选择的顶点(局部方面)的边,这使得距离起始顶点(全局方面)的总距离尽可能小,并且不违反创建的目标生成树。

最低成本树和最短路径树很容易混淆,正如解决它们的Prim和Dijkstra算法一样。这两种算法都能长出来#34;从起始顶点开始,在每一步选择一条边,该边连接树中的顶点Y和不是顶点的顶点。然而,当Prim选择最便宜的边缘时,Dijkstra选择边缘,从而产生从X到Z的最短路径。

一个简单的例子有助于理解这些算法与它们产生的树之间的区别。在下图中,从顶点A开始,Prim和Dijkstra都选择边AB,然后添加边BD。这里是两个算法发散的地方:Prim通过添加边缘DC来完成树,而Dijkstra添加AC或BC,因为路径AC和ABC(两者的总距离为30)比路径ABDC(总距离31)短。

答案 7 :(得分:1)

Dijkstras算法仅用于查找最短路径。

最小生成树(Prim&#39;或Kruskal算法)中,您获得最小边值的最小值。

例如: - 考虑一种情况,你不想创建一个巨大的网络,你将需要大量的电线,所以这些计算线可以使用最小生成树(Prim& #39; s或Kruskal的算法 (即,它会为您提供最少数量的线路,以最低的成本创建巨大的有线网络连接)。

&#34; Dijkstras算法&#34; 将用于获取两个节点之间的最短路径,同时将任何节点相互连接。

答案 8 :(得分:1)

这对我来说很重要:考虑算法接下来采用哪个顶点:

Prim 的算法接下来取最接近树的顶点,即最接近树上任意位置的某个顶点

Dijkstra 的算法接下来取最接近源的顶点。

来源:R. Sedgewick 关于 Dijkstra 算法的讲座,算法,第二部分:https://coursera.org/share/a551af98e24292b6445c82a2a5f16b18

答案 9 :(得分:0)

@templatetypedef涵盖了MST和最短路径之间的差异。我通过演示两者都可以使用相同的通用算​​法来实现another So answer中的算法差异,这种算法又需要一个参数作为输入:function f(u,v)。 Prim和Dijkstra算法之间的区别就在于你使用的f(u,v)

答案 10 :(得分:0)

在代码级别,另一个区别是API。

使用源顶点 s 初始化Prim,即Prim.new(s); s 可以是任何顶点,无论 s ,最终结果(最小生成树(MST)的边缘)都是相同的。为了获得MST边缘,我们调用方法edges()

使用源顶点 s 初始化Dijkstra,即Dijkstra.new(s),您希望获得到所有其他顶点的最短路径/距离。最终结果,是从 s 到所有其他顶点的最短路径/距离;根据 s 而有所不同。为了获得从 s 到任何顶点 v 的最短路径/距离,我们分别调用方法distanceTo(v)pathTo(v)