删去非已知的边:
当然,在实际编程中,有可能并不会执行这两个操作,我们只要在将最小生成树的相关信息保存在pathTable中即可,本例中算法结束后pathTable应为如下(与Dijkstra算法使用的pathTable略有不同:没有distance域):
当然,我们也可以使用和Dijkstra算法时一样的pathTable,即加上distance域,不过在计算最小生成树时,一个顶点的distance域应该是其与preV邻接的边的权重:
在我们走一遍Prim算法时,我们发现v4.preV既可以设为v3,也可以设为v1,这就已经说明了一点:一个图的最小生成树并不一定是唯一的。不过还要注意的是:一个图即便有多个最小生成树,它们的总权重也应该是一样的。
如果你回顾一遍Prim算法和Dijkstra算法,就会发现,Prim算法与Dijkstra算法的区别可以说就两个:
1.Prim算法的“起点”是任选的,Dijkstra算法是给定的(毕竟要找的是单源最短路径)
2.Prim算法在将一个未知顶点设为已知时,其distance设为其与已知顶点的最小邻接边的weight,而Dijkstra算法则是设为已知顶点.distance+weight
换句话说,Prim算法就是稍稍修改了一下的Dijkstra算法。如果你仔细观察我们用Prim算法生成的树,你会发现从v3出发到任意顶点的路径恰好是v3到该顶点的最短路径:
接下来本应讨论Kruskal算法,但是我忽然发现我之前忘了写一篇关于树的集合与不相交集的博文(⊙ˍ⊙)。如果要讨论Kruskal算法,这两个预备知识是必不可少的,而如果这两个知识也要讲解的话,博文就太长了Orz。所以我只简单说说Kruskal的思路。
在Prim算法中,我们是以已知顶点(即已在最小生成树中的顶点)为基础,不断地将未知顶点拉进树中。而Kruskal算法则是另一种思路:以当前最小的边为基础,不断地将未知顶点拉进树中(这个过程可能产生多棵树)。
以下图为例,我们走一遍Kruskal算法:
首先,我们需要将边按权重从小到大排序,才能找“当前最小边”:
先是处理当前最小边[v0,v1],其所连接的两个顶点均未知,所以我们将它们均设为已知,并连起来:
然后处理下一个当前最小边[v1,v3],其所连接的v3未知,将v3设为已知,连起来: