天天看点

《DSAA》 9.5.2 Kruskal 算法

如何用最少的电线给一所房子安装电路?本质上就是如何从一个无向图中找出一颗最小生成树。一个无向图中的最小生成树由该图的那些连接所有顶点的边构成的树,且其总价值最小。

有两个解决此问题的算法:Prim 和 Kruskal,这里只讨论后者,因为它比较简明有趣。

和一般处理图的算法不同,Kruskal 实际上是在处理森林,即树的集合,开始时每个顶点是一颗单节点树,添加一条边则意味着将两颗树合并成一棵树,添加边的顺序是从小到大,当边数比总顶点数小1时算法终止,这时就只有一颗树了,这颗树就是最小生成树。

但还有一个关键的问题是在添加边之前要对其进行检验,看看它是否会同已有的边构成回路,如是必须放弃这条边,否则将导致算法失败。检验的方法是使用一个不相交集合,当两个顶点在当前森林中连通时,它们必属于同一集合,所以当要添加边的两个顶点属于同一集合时,则放弃这条边。

btw,不相交集合在《DSAA》前面的章节讲过,它主要有两个方法:Union() 和 Find(),前者用于合并两个不相交集合,后者返回给定元素所在的集合,这里不赘述。

也是根据原书的伪代码做了实现,大致思路如下:

1)将全部的边装入一个二叉堆,按照权值从小到大排序

2)从堆中取出最小的边,如果其两个顶点不属于同一集合,则边数加1,合并这两个集合。否则什么也不做

3)重复第二步直到边数比总顶点数小1

下面是对原书中示例的求解,运行结果如下:

《DSAA》 9.5.2 Kruskal 算法

继续阅读