Coursera Algorithm, Part2 Week2: Minimum Spanning Trees & Shortest Paths

来源:互联网 发布:fc2最新域名2016 编辑:程序博客网 时间:2024/05/22 02:02

这周的课程学得真是纠结,因为有考试的原因,lecture的前几部分学得还是挺顺利的,后面就给耽搁了。最蛋疼的是一到每个week新的lecture发布,coursera官网就和翔一样慢。最后还有课程作业,就不吐槽了,不知道花了多长时间,目前作业部分还有很多的问题。但确实也是学到很多,也让基础更扎实了。


这一周研究图的边都是带权重,之前的针对节点的邻接表和无向图、有向图的数据结构已经不够用了,所以需要建立新的数据结构,该数据结构是用来描述边的性质的。

1.1 带权重的边

需要描述一条边的起点、终点和权重,注意:一定是边作为中心,可以通过边描述边的性质(起点、终点和权重)。

public class Edge implements Comparable<Edge> {private final int v, w;private final double weight;// constructorpublic Edge(int v, int w, double weight) {this.v = v;this.w = w;this.weight = weight;}// either endpointpublic int either() {return v;}// other endpointpublic int other(int vertex) {if (vertex == v) return w;return v;}// compare edges by weightpublic int compareTo(Edge that) {if (this.weight < that.weight) return -1;else if (this.weight > that.weight) return 1;else return 0;}}

1.2 Kruskal's algorithm

考虑所有的边按权重非降排序;然后按所排顺序将每条边加入到树中除非添加的这条边后会构成环,那么就选择下一条边,直到边总数为V-1。

用优先队列/最小堆存放所有的边,逐个删除优先队列根节点得到最小权重边,并维护优先队列;路径压缩/并查集判定是否构成环(一条边的两个节点若在同一并查集中则会构成环)。

public class KruskalMST {private Queue<Edge> mst = new Queue<Edge>();public KruskalMST(EdgeWeightedGraph G) {MinPQ<Edge> pq = new MinPQ<Edge>();// build priority queuefor (Edge e : G.edges())pq.insert(e);UF uf = new UF(G.V());while(!pq.isEmpty() && mst.size()<G.V()-1) {// greedily add edges to MSTEdge e = pq.delMin();int v = e.either(), w = e.other(v);// edge v-w does not create cycleif (!uf.connected(v, w)) {uf.union(v, w);  // merge setsmst.enqueue(e);  // add edge to MST}}}public Iterable<Edge> edges() {return mst;}}

1.3 Prim's algorithm

Prim算法与Kruskal算法类似,都是贪心的思想选取一条最小权重边,不过Kruskal是在整个带权有向图中选取这样的边,并维护当前的树;而Prim算法则是在与当前树相连接的各个节点的边中选取权重最小的,一旦选取了某个节点距当前树的最小边,就标记该节点并把边加入队列。此处的优先队列维护的是当前边的权重,根节点是与当前树相连的边的最小权重。

课程中给出了两种实现的Prim算法,抱歉我只看懂了第一种,另一种和单源点最短路径相关。

public class LazyPrimMST {private boolean[] marked;  // MST verticesprivate Queue<Edge> mst;   // MST edgesprivate MinPQ<Edge> pq;    // PQ of edgespublic LazyPrimMST(WeightedGraph G) {pq = new MinPQ<Edge>();mst = new Queue<Edge>();marked = new boolean[G.V()];visit(G, 0);           // assume G is connectedwhile (!pq.isEmpty() && mst.size()<G.V()-1) {// repeatedly delete the min weight edge e = v-w from PQEdge e = pq.delMin();int v = e.either(), w = e.other(v);// ignore if both endpoints in Tif (marked[v] && marked[w]) continue;mst.enqueue(e);if (!marked[v]) visit(G, v);  // add v or w to treeif (!marked[w]) visit(G, w);}}private void visit(WeightedGraph G, int v) {marked[v] = true;  // add v to tree// for each edge e = v-w, add to PQ if w not already in Tfor (Edge e : G.adj(v))if (!marked[e.other(v)])pq.insert(e);}public Iterable<Edge> mst() {return mst;}}


2.1 Dijkstra's algorithm

与Prim算法类似的维护优先队列找到到单源点的最短路径,对于每个新加入的节点,relax由该节点发出的每一条边,实现每个节点的到单源点的最小值。

public class DijkstraSP {private DirectedEdge[] edgeTo;private double[] distTo;private IndexMinPQ<Double> pq;public DijkstraSP(EdgeWeightedDigraph G, int s) {edgeTo = new DirectedEdge[G.V()];distTo = new double[G.V()];pq = new IndexMinPQ<Double>(G.V());for (int v = 0; v < G.V(); v++)distTo[v] = Double.POSITIVE_INFINITY;distTo[s] = 0.0;pq.insert(s, 0.0);// relax vertices in order of distance from swhile (!pq.isEmpty()) {int v = pq.delMin();for (DirectedEdge e : G.adj(v))relax(e);}}private void relax(DirectedEdge e) {int v = e.from(), w = e.to();if (distTo[w] > distTo[v]+e.weight()) {distTo[w] = distTo[v]+e.weight();edge[w] = e;// update PQif (pq.contains(w)) pq.decreaseKey(w, distTo[w]);else pq.insert(w, distTo[w]);}}}


2.2 DAG的SP

与Dijkstra算法不同的是,DAG求解SP不需要维护优先队列,节点访问顺序是DAG拓扑排序的结果,以此relax每条边得到结果。

public class AcyclicSP {private DirectedEdge[] edgeTo;private double[] distTo;public AcyclicSP(EdgeWeightedDigraph G, int s) {edgeTo = new DirectedEdge[G.V()];distTo = new double[G.V()];for (int v = 0; v < G.V(); v++)distTo[v] = Double.POSITIVE_INFINITY;distTo[s] = 0.0;// topological orderTopological topological = new Topological(G);for (int v : topological.order()) for (DirectedEdge e : G.adj(v)) relax(e);}}


最后谈谈作业吧,自己虽然独立完成了,但是花了好长的时间,而且作业的结果也是惨不忍睹,等自己修改好了再上传吧。

0 0