《算法》第四章部分程序 part 15

时间:2023-03-09 08:48:35
《算法》第四章部分程序 part 15

▶ 书中第四章部分程序,包括在加上自己补充的代码,Kruskal 算法和 Boruvka 算法求最小生成树

● Kruskal 算法求最小生成树

 package package01;

 import edu.princeton.cs.algs4.In;
import edu.princeton.cs.algs4.StdOut;
import edu.princeton.cs.algs4.Edge;
import edu.princeton.cs.algs4.EdgeWeightedGraph;
import edu.princeton.cs.algs4.Queue;
import edu.princeton.cs.algs4.MinPQ;
import edu.princeton.cs.algs4.UF; public class class01
{
private double weight;
private Queue<Edge> mst = new Queue<Edge>(); public class01(EdgeWeightedGraph G)
{
MinPQ<Edge> pq = new MinPQ<Edge>(); // 建立最小优先队列
for (Edge e : G.edges())
pq.insert(e);
for (UF uf = new UF(G.V()); !pq.isEmpty() && mst.size() < G.V() - 1;) // 加入生成树的变得集合
{
Edge e = pq.delMin(); // 取权值最小的边
int v = e.either();
int w = e.other(v);
if (!uf.connected(v, w)) // 顶点 v 和 w 没有都在树中,说明添加边 v-w 不会构成环
{
uf.union(v, w); // 添加边,更新生成树的权值
mst.enqueue(e);
weight += e.weight();
}
}
} public Iterable<Edge> edges()
{
return mst;
} public double weight()
{
return weight;
} public static void main(String[] args)
{
In in = new In(args[0]);
EdgeWeightedGraph G = new EdgeWeightedGraph(in);
class01 mst = new class01(G);
for (Edge e : mst.edges())
StdOut.println(e);
StdOut.printf("%.5f\n", mst.weight());
}
}

● Boruvka 算法求最小生成树

 package package01;

 import edu.princeton.cs.algs4.In;
import edu.princeton.cs.algs4.StdOut;
import edu.princeton.cs.algs4.Edge;
import edu.princeton.cs.algs4.EdgeWeightedGraph;
import edu.princeton.cs.algs4.Bag;
import edu.princeton.cs.algs4.UF; public class class01
{
private double weight;
private Bag<Edge> mst = new Bag<Edge>(); public class01(EdgeWeightedGraph G)
{
UF uf = new UF(G.V());
for (int t = 1; t < G.V() && mst.size() < G.V() - 1; t = t + t) // 重复 v-1 次直到得到生成树
{
Edge[] closest = new Edge[G.V()]; // 最小生成树中连接着顶点 v 的边记作 closest[v]
for (Edge e : G.edges())
{
int v = e.either(), w = e.other(v);
int i = uf.find(v), j = uf.find(w);
if (i == j) // 顶点 v 和 w 来自同一棵树,加入边 v-w 会导致环
continue;
if (closest[i] == null || less(e, closest[i])) // v 是新顶点,加入边 v-w 会使得 v 的距离比现在小
closest[i] = e; // 值标记新距离,还没有加入边
if (closest[j] == null || less(e, closest[j])) // w 是新顶点,加入边 v-w 会使得 w 的距离比现在小
closest[j] = e;
}
for (int i = 0; i < G.V(); i++)
{
Edge e = closest[i];
if (e != null) // 存在连着顶点 v 的最小生成树的边
{
int v = e.either(), w = e.other(v); // 正式加入边 v-w
if (!uf.connected(v, w)) // 防止已经在生成书中的边被再次添加
{
mst.add(e);
weight += e.weight();
uf.union(v, w);
}
}
}
}
} public Iterable<Edge> edges()
{
return mst;
} public double weight()
{
return weight;
} private static boolean less(Edge e, Edge f) // 比较两条边的权值
{
return e.weight() < f.weight();
} public static void main(String[] args)
{
In in = new In(args[0]);
EdgeWeightedGraph G = new EdgeWeightedGraph(in);
class01 mst = new class01(G);
for (Edge e : mst.edges())
StdOut.println(e);
StdOut.printf("%.5f\n", mst.weight());
}
}