diff --git a/algs4/edge.py b/algs4/edge.py index 05451f0..d3a0863 100644 --- a/algs4/edge.py +++ b/algs4/edge.py @@ -7,13 +7,11 @@ def __init__(self, v, w, weight): def __str__(self): return "%d-%s %.5f" % (self.v, self.w, self.weight) - def __cmp__(self, other): - if self.weihgt < other.weight: - return -1 - elif self.weight > other.weight: - return 1 - else: - return 0 + def __lt__(self, other): + return self.weight < other.weight + + def __gt__(self, other): + return self.weight > other.weight def either(self): return self.v diff --git a/algs4/index_min_pq.py b/algs4/index_min_pq.py index a6559a8..6f8fa4c 100644 --- a/algs4/index_min_pq.py +++ b/algs4/index_min_pq.py @@ -30,6 +30,12 @@ def delete(self, i): self.qp[i] = -1 return item + def decrease_key(self, i, key): + if self.keys[i] <= key: + raise Exception("calling decrease key with invalid value") + self.keys[i] = key + self.swim(self.qp[i]) + def greater(self, i, j): return self.keys[self.pq[i]] > self.keys[self.pq[j]] @@ -43,7 +49,6 @@ def del_min(self): self.sink(0) self.qp[m] = -1 - self.keys[m] = None return m def is_empty(self, ): diff --git a/algs4/lazy_prim_mst.py b/algs4/lazy_prim_mst.py new file mode 100644 index 0000000..8db1368 --- /dev/null +++ b/algs4/lazy_prim_mst.py @@ -0,0 +1,86 @@ +""" + * Execution: python lazy_prim_mst.py filename.txt + * Data files: https://algs4.cs.princeton.edu/43mst/tinyEWG.txt + * https://algs4.cs.princeton.edu/43mst/mediumEWG.txt + * https://algs4.cs.princeton.edu/43mst/largeEWG.txt + * + * Compute a minimum spanning forest using a lazy version of Prim's + * algorithm. + * + * % python lazy_prim_mst.py tinyEWG.txt + * 0-7 0.16000 + * 1-7 0.19000 + * 0-2 0.26000 + * 2-3 0.17000 + * 5-7 0.28000 + * 4-5 0.35000 + * 6-2 0.40000 + * 1.81000 + * + * % python lazy_prim_mst.py mediumEWG.txt + * 0-225 0.02383 + * 49-225 0.03314 + * 44-49 0.02107 + * 44-204 0.01774 + * 49-97 0.03121 + * 202-204 0.04207 + * 176-202 0.04299 + * 176-191 0.02089 + * 68-176 0.04396 + * 58-68 0.04795 + * 10.46351 + * + * % python lazy_prim_mst.py largeEWG.txt + * ... + * 647.66307 + * +""" + +from algs4.edge_weighted_graph import EdgeWeightedGraph +from algs4.min_pq import MinPQ +from algs4.queue import Queue + + +class LazyPrimMST: + def __init__(self, g): + self.marked = [False for _ in range(g.V)] + self.pq = MinPQ() + self.mst = Queue() + self.weight = 0 + + for v in range(g.V): + if not self.marked[v]: + self.prim(g, v) + + def prim(self, g, v): + self.visit(g, v) + while not self.pq.is_empty(): + e = self.pq.del_min() + v = e.either() + w = e.other(v) + if self.marked[v] and self.marked[w]: + continue + self.mst.enqueue(e) + self.weight += e.weight + if not self.marked[v]: + self.visit(g, v) + if not self.marked[w]: + self.visit(g, w) + + def visit(self, g, v): + self.marked[v] = True + for e in g.adj[v]: + if not self.marked[e.other(v)]: + self.pq.insert(e) + + def edges(self): + return self.mst + + +if __name__ == "__main__": + import sys + g = EdgeWeightedGraph(file=open(sys.argv[1])) + mst = LazyPrimMST(g) + for e in mst.edges(): + print(e) + print("%.5f" % mst.weight) diff --git a/algs4/multiway.py b/algs4/multiway.py index 73244d6..c9d2bc7 100644 --- a/algs4/multiway.py +++ b/algs4/multiway.py @@ -1,3 +1,26 @@ +""" +* Compilation: python multiway.py +* Data files: https://algs4.cs.princeton.edu/24pq/m1.txt +* https://algs4.cs.princeton.edu/24pq/m2.txt +* https://algs4.cs.princeton.edu/24pq/m3.txt +* +* Merges together the sorted input stream given as command-line arguments +* into a single sorted output stream on standard output. +* +* % more m1.txt +* A B C F G I I Z +* +* % more m2.txt +* B D H P Q Q +* +* % more m3.txt +* A B E F J N +* +* % python multiway.py m1.txt m2.txt m3.txt +* A A B B B C D E F F G H I I J N P Q Q Z +* +""" + from algs4.index_min_pq import IndexMinPQ @@ -18,6 +41,7 @@ def merge(cls, streams): pq.insert(i, streams[i][0]) streams[i] = streams[i][1:] + if __name__ == "__main__": import sys streams = [] diff --git a/algs4/prim_mst.py b/algs4/prim_mst.py new file mode 100644 index 0000000..78ce107 --- /dev/null +++ b/algs4/prim_mst.py @@ -0,0 +1,89 @@ +""" + * Execution: python prim_mst.py filename.txt + * Data files: https://algs4.cs.princeton.edu/43mst/tinyEWG.txt + * https://algs4.cs.princeton.edu/43mst/mediumEWG.txt + * https://algs4.cs.princeton.edu/43mst/largeEWG.txt + * + * Compute a minimum spanning forest using a lazy version of Prim's + * algorithm. + * + * % python prim_mst.py tinyEWG.txt + * 0-7 0.16000 + * 1-7 0.19000 + * 0-2 0.26000 + * 2-3 0.17000 + * 5-7 0.28000 + * 4-5 0.35000 + * 6-2 0.40000 + * 1.81000 + * + * % python prim_mst.py mediumEWG.txt + * 0-225 0.02383 + * 49-225 0.03314 + * 44-49 0.02107 + * 44-204 0.01774 + * 49-97 0.03121 + * 202-204 0.04207 + * 176-202 0.04299 + * 176-191 0.02089 + * 68-176 0.04396 + * 58-68 0.04795 + * 10.46351 + * + * % python prim_mst.py largeEWG.txt + * ... + * 647.66307 + * +""" + +from algs4.edge_weighted_graph import EdgeWeightedGraph +from algs4.index_min_pq import IndexMinPQ +from algs4.queue import Queue + + +class PrimMST: + def __init__(self, g): + self.edgeTo = [None for _ in range(g.V)] + self.distTo = [float("inf") for _ in range(g.V)] + self.marked = [False for _ in range(g.V)] + self.pq = IndexMinPQ(g.V) + + for v in range(g.V): + if not self.marked[v]: + self.prim(g, v) + + def prim(self, g, s): + self.distTo[s] = 0 + self.pq.insert(s, self.distTo[s]) + while not self.pq.is_empty(): + v = self.pq.del_min() + self.visit(g, v) + + def visit(self, g, v): + self.marked[v] = True + for e in g.adj[v]: + w = e.other(v) + if self.marked[w]: + continue + if e.weight < self.distTo[w]: + self.distTo[w] = e.weight + self.edgeTo[w] = e + if self.pq.contains(w): + self.pq.decrease_key(w, self.distTo[w]) + else: + self.pq.insert(w, self.distTo[w]) + + def edges(self): + return [e for e in self.edgeTo if e != None] + + def weight(self): + return sum([e.weight for e in self.edges()]) + + +if __name__ == "__main__": + import sys + g = EdgeWeightedGraph(file=open(sys.argv[1])) + mst = PrimMST(g) + for e in mst.edges(): + print(e) + print("%.5f" % mst.weight())