所谓最小生成树,就是用最少的边连接所有的顶点。对于给定的一组顶点,可能又很多种最小生成树,但是最小生成树边E的数量总是比顶点V的数量小1,即E=V-1。
普里姆算法
假设N=(V,{E})是连通网,TE是N上最小生成树中边的集合,算法从 U = u 0 ( u 0 ∈ V ) U={u_0}(u_0∈V) U=u0(u0∈V),TE={}开始。重复执行下述操作:在所有u∈U,v∈V-U的边(u,v)∈E中找到一条代价最小的边( u 0 , v 0 u_0,v_0 u0,v0)并入集合TE,同时 v 0 v_0 v0并入U,直至U = V为止。此时TE中必有n-1条边,则T =(V,{TE})为N的最小生成树。此算法更适用于稠密图。
算法要点如下:
所谓连通图可以为有权图(网)也可以为无权图(把权值均看成1)。
建议用优先级队列来实现这个反复选择最小的路径,而不是链表或数组,这是解决最小生成树的有效方式。在正式的程序中,优先级队列可能基于堆来实现(堆其实是个很简单的数据结构),这会加快在较大的优先级队列中的操作。但是在本例中,我们使用数组实现优先级队列,仅仅为了说明算法。
任意从一个顶点(一般取第一个顶点)开始,把它放入树的集合中,然后重复做下面的事情:
- 找到从最新的顶点到其他顶点的所有边,这些顶点不能在树的集合中,把这些边放入优先级队列中。
- 找出权值最小的边,把它和它所达到的顶点放入树的集合中。
重复这些步骤,直到所有的顶点都在树的集合中,这时工作完成。
Java代码实现
边界路径类,主要记录了边的始末顶点,以及边的权值
class Edge{
public int srcVert;//边起始顶点的索引
public int destVert;//边终止顶点的索引
public int weight;//权重
public Edge(int sv, int dv, int w) {
srcVert = sv;
destVert = dv;
weight = w;
}
}
优先级队列
class PriorityQueue{
private final int SIZE = 20;
public Edge[] queArray;
private