Skip to content

Commit 8bd9a4b

Browse files
committed
add mst
1 parent 0ff4e1d commit 8bd9a4b

File tree

7 files changed

+200
-18
lines changed

7 files changed

+200
-18
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ To test each algorithm(data structure), instead of running the file directly, yo
7070
* MST
7171
* [EdgeWeightedGraph](edge_weighted_graph.go)
7272
* [LazyPrimMST](lazy_prim_mst.go)
73+
* [PrimMST](prim_mst.go)
7374

7475
* 5 STRING
7576

cmd/multiway/main.go

+19-3
Original file line numberDiff line numberDiff line change
@@ -31,20 +31,36 @@ import (
3131
"github.com/shellfly/algo/stdin"
3232
)
3333

34+
type StringPQItem string
35+
36+
func (s StringPQItem) CompareTo(other interface{}) int {
37+
ss := other.(StringPQItem)
38+
if s < ss {
39+
return -1
40+
} else if s > ss {
41+
return 1
42+
} else {
43+
return 0
44+
}
45+
}
46+
func (s StringPQItem) String() string {
47+
return string(s)
48+
}
49+
3450
func merge(streams []*stdin.In) {
3551
n := len(streams)
3652
pq := algo.NewIndexMinPQ(n)
3753
for i := 0; i < n; i++ {
3854
if !streams[i].IsEmpty() {
3955
str := streams[i].ReadString()
40-
pq.Insert(i, str)
56+
pq.Insert(i, StringPQItem(str))
4157
}
4258
}
4359
for !pq.IsEmpty() {
44-
fmt.Print(pq.Min() + " ")
60+
fmt.Print(pq.Min(), " ")
4561
i := pq.DelMin()
4662
if !streams[i].IsEmpty() {
47-
pq.Insert(i, streams[i].ReadString())
63+
pq.Insert(i, StringPQItem(streams[i].ReadString()))
4864
}
4965
}
5066
}

cmd/prim-mst/main.go

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/******************************************************************************
2+
* Execution: go run cmd/prim-mst/main.go filename.txt
3+
* Data files: https://algs4.cs.princeton.edu/43mst/tinyEWG.txt
4+
* https://algs4.cs.princeton.edu/43mst/mediumEWG.txt
5+
* https://algs4.cs.princeton.edu/43mst/largeEWG.txt
6+
*
7+
* Compute a minimum spanning forest using Prim's algorithm.
8+
*
9+
* % go run cmd/prim-mst/main.go tinyEWG.txt
10+
* 1-7 0.19000
11+
* 0-2 0.26000
12+
* 2-3 0.17000
13+
* 4-5 0.35000
14+
* 5-7 0.28000
15+
* 6-2 0.40000
16+
* 0-7 0.16000
17+
* 1.81000
18+
*
19+
* % go run cmd/prim-mst/main.go mediumEWG.txt
20+
* 1-72 0.06506
21+
* 2-86 0.05980
22+
* 3-67 0.09725
23+
* 4-55 0.06425
24+
* 5-102 0.03834
25+
* 6-129 0.05363
26+
* 7-157 0.00516
27+
* ...
28+
* 10.46351
29+
*
30+
* % go run cmd/prim-mst/main.go largeEWG.txt
31+
* ...
32+
* 647.66307
33+
*
34+
******************************************************************************/
35+
36+
package main
37+
38+
import (
39+
"fmt"
40+
"os"
41+
42+
"github.com/shellfly/algo"
43+
"github.com/shellfly/algo/stdin"
44+
)
45+
46+
func main() {
47+
g := algo.NewEdgeWeightedGraph(stdin.NewIn(os.Args[1]))
48+
mst := algo.NewLazyPrimMST(g)
49+
for _, e := range mst.Edges() {
50+
fmt.Println(e)
51+
}
52+
fmt.Printf("%.5f\n", mst.Weight())
53+
}

index_min_pq.go

+22-7
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ type IndexMinPQ struct {
88
n int // number of elements on PQ
99
pq []int // binary heap using 1-based indexing
1010
qp []int // inverse of pq - qp[pq[i]] = pq[qp[i]] = i
11-
keys []string // keys[i] = priority of i
11+
keys []PQItem // keys[i] = priority of i
1212
}
1313

1414
// NewIndexMinPQ ...
@@ -18,12 +18,13 @@ func NewIndexMinPQ(maxN int) *IndexMinPQ {
1818
for i := 0; i < len(qp); i++ {
1919
qp[i] = -1
2020
}
21-
keys := make([]string, maxN)
21+
keys := make([]PQItem, maxN)
2222
return &IndexMinPQ{maxN, 0, pq, qp, keys}
2323
}
2424

2525
func (mq IndexMinPQ) less(i, j int) bool {
26-
return mq.keys[mq.pq[i]] < mq.keys[mq.pq[j]]
26+
cmp := mq.keys[mq.pq[i]].CompareTo(mq.keys[mq.pq[j]])
27+
return cmp < 0
2728
}
2829

2930
func (mq *IndexMinPQ) exch(i, j int) {
@@ -59,7 +60,7 @@ func (mq IndexMinPQ) validateIndex(index int) {
5960
}
6061

6162
// Insert ...
62-
func (mq *IndexMinPQ) Insert(i int, key string) {
63+
func (mq *IndexMinPQ) Insert(i int, key PQItem) {
6364
mq.validateIndex(i)
6465
if mq.Contains(i) {
6566
panic("Index is alreay in the priority queue")
@@ -73,7 +74,7 @@ func (mq *IndexMinPQ) Insert(i int, key string) {
7374
}
7475

7576
// ChangeKey ...
76-
func (mq *IndexMinPQ) ChangeKey(i int, key string) {
77+
func (mq *IndexMinPQ) ChangeKey(i int, key PQItem) {
7778
mq.validateIndex(i)
7879
if mq.Contains(i) {
7980
panic("Index is alreay in the priority queue")
@@ -102,12 +103,26 @@ func (mq *IndexMinPQ) Delete(i int) {
102103
mq.n--
103104
mq.swim(index)
104105
mq.sink(index)
105-
mq.keys[i] = ""
106+
mq.keys[i] = nil
106107
mq.qp[i] = -1
107108
}
108109

110+
// DecreaseKey ...
111+
func (mq *IndexMinPQ) DecreaseKey(i int, key PQItem) {
112+
mq.validateIndex(i)
113+
if !mq.Contains(i) {
114+
panic("index not in the queue")
115+
}
116+
cmp := mq.keys[i].CompareTo(key)
117+
if cmp <= 0 {
118+
panic("Calling DecreaseKey with wrong value")
119+
}
120+
mq.keys[i] = key
121+
mq.swim(mq.qp[i])
122+
}
123+
109124
// Min ...
110-
func (mq *IndexMinPQ) Min() string {
125+
func (mq *IndexMinPQ) Min() PQItem {
111126
return mq.keys[mq.MinIndex()]
112127
}
113128

max_pq.go

+6-5
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,19 @@ package algo
33
// MaxPQ is a priority queue
44
type MaxPQ struct {
55
n int
6-
pq []Transaction
6+
pq []PQItem
77
}
88

99
// NewMaxPQ ...
1010
func NewMaxPQ(n int) *MaxPQ {
1111
// index 0 is not used in PQ
12-
pq := make([]Transaction, n+1)
12+
pq := make([]PQItem, n+1)
1313
return &MaxPQ{pq: pq}
1414
}
1515

1616
func (mq MaxPQ) less(i, j int) bool {
17-
return mq.pq[i].Amount < mq.pq[j].Amount
17+
cmp := mq.pq[i].CompareTo(mq.pq[j])
18+
return cmp < 0
1819
}
1920

2021
func (mq *MaxPQ) exch(i, j int) {
@@ -43,14 +44,14 @@ func (mq *MaxPQ) sink(k int) {
4344
}
4445

4546
// Insert ...
46-
func (mq *MaxPQ) Insert(t Transaction) {
47+
func (mq *MaxPQ) Insert(t PQItem) {
4748
mq.pq = append(mq.pq, t)
4849
mq.n++
4950
mq.swim(mq.n)
5051
}
5152

5253
// DelMax ...
53-
func (mq *MaxPQ) DelMax() Transaction {
54+
func (mq *MaxPQ) DelMax() PQItem {
5455
m := mq.pq[1]
5556
mq.exch(1, mq.n)
5657
mq.n--

min_pq.go

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package algo
22

3+
import "fmt"
4+
35
// PQItem is an interface of the item in PQ
46
type PQItem interface {
7+
fmt.Stringer
58
CompareTo(interface{}) int
69
}
710

@@ -23,7 +26,6 @@ func NewMinPQN(n int) *MinPQ {
2326
return &MinPQ{pq: pq}
2427
}
2528

26-
2729
func (mq *MinPQ) resize(capacity int) {
2830
pq := make([]PQItem, capacity)
2931
copy(pq, mq.pq)
@@ -62,8 +64,8 @@ func (mq *MinPQ) sink(k int) {
6264

6365
// Insert ...
6466
func (mq *MinPQ) Insert(t PQItem) {
65-
if (mq.n == len(mq.pq) - 1){
66-
mq.resize(2 * len(mq.pq))
67+
if mq.n == len(mq.pq)-1 {
68+
mq.resize(2 * len(mq.pq))
6769
}
6870

6971
mq.n++

prim_mst.go

+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package algo
2+
3+
import "fmt"
4+
5+
type FloatPQItem float32
6+
7+
func (f FloatPQItem) CompareTo(other interface{}) int {
8+
ff := other.(FloatPQItem)
9+
if f < ff {
10+
return -1
11+
} else if f > ff {
12+
return 1
13+
} else {
14+
return 0
15+
}
16+
}
17+
func (f FloatPQItem) String() string {
18+
return fmt.Sprintf("%.5f", f)
19+
}
20+
21+
// PrimMST ...
22+
type PrimMST struct {
23+
edgeTo []*Edge
24+
distTo []float32
25+
marked []bool
26+
pq *IndexMinPQ
27+
}
28+
29+
// NewPrimMST ...
30+
func NewPrimMST(g *EdgeWeightedGraph) *PrimMST {
31+
edgeTo := make([]*Edge, g.V())
32+
distTo := make([]float32, g.V())
33+
marked := make([]bool, g.V())
34+
pq := NewIndexMinPQ(g.V())
35+
l := &PrimMST{edgeTo, distTo, marked, pq}
36+
for v := 0; v < g.V(); v++ {
37+
l.distTo[v] = 999.0 // fake infinity
38+
}
39+
for v := 0; v < g.V(); v++ {
40+
if !l.marked[v] {
41+
l.prim(g, v)
42+
}
43+
}
44+
45+
return l
46+
}
47+
48+
func (l *PrimMST) prim(g *EdgeWeightedGraph, s int) {
49+
l.distTo[s] = 0.0
50+
l.pq.Insert(s, FloatPQItem(l.distTo[s]))
51+
52+
for !l.pq.IsEmpty() {
53+
v := l.pq.DelMin()
54+
l.visit(g, v)
55+
}
56+
}
57+
func (l *PrimMST) visit(g *EdgeWeightedGraph, v int) {
58+
l.marked[v] = true
59+
for _, e := range g.Adj(v) {
60+
w := e.Other(v)
61+
if l.marked[w] {
62+
continue
63+
}
64+
if e.Weight() < l.distTo[w] {
65+
l.distTo[w] = e.Weight()
66+
l.edgeTo[w] = e
67+
if !l.pq.Contains(w) {
68+
l.pq.DecreaseKey(w, FloatPQItem(l.distTo[w]))
69+
} else {
70+
l.pq.Insert(w, FloatPQItem(l.distTo[w]))
71+
}
72+
}
73+
}
74+
}
75+
76+
// Weight ...
77+
func (l *PrimMST) Weight() float32 {
78+
var weight float32
79+
for _, e := range l.Edges() {
80+
weight += e.Weight()
81+
}
82+
return weight
83+
}
84+
85+
// Edges ...
86+
func (l *PrimMST) Edges() (edges []*Edge) {
87+
for v := 0; v < len(l.edgeTo); v++ {
88+
e := l.edgeTo[v]
89+
if e != nil {
90+
edges = append(edges, e)
91+
}
92+
}
93+
return
94+
}

0 commit comments

Comments
 (0)