-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathmst.go
More file actions
254 lines (239 loc) · 6.86 KB
/
mst.go
File metadata and controls
254 lines (239 loc) · 6.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
// Copyright 2014 Sonia Keys
// License MIT: http://opensource.org/licenses/MIT
package graph
import (
"container/heap"
"sort"
"github.com/soniakeys/bits"
)
type dsElement struct {
from NI
rank int
}
type disjointSet struct {
set []dsElement
}
func newDisjointSet(n int) disjointSet {
set := make([]dsElement, n)
for i := range set {
set[i].from = -1
}
return disjointSet{set}
}
// return true if disjoint trees were combined.
// false if x and y were already in the same tree.
func (ds disjointSet) union(x, y NI) bool {
xr := ds.find(x)
yr := ds.find(y)
if xr == yr {
return false
}
switch xe, ye := &ds.set[xr], &ds.set[yr]; {
case xe.rank < ye.rank:
xe.from = yr
case xe.rank == ye.rank:
xe.rank++
fallthrough
default:
ye.from = xr
}
return true
}
func (ds disjointSet) find(n NI) NI {
// fast paths for n == root or from root.
// no updates need in these cases.
s := ds.set
fr := s[n].from
if fr < 0 { // n is root
return n
}
n, fr = fr, s[fr].from
if fr < 0 { // n is from root
return n
}
// otherwise updates needed.
// two iterative passes (rather than recursion or stack)
// pass 1: find root
r := fr
for {
f := s[r].from
if f < 0 {
break
}
r = f
}
// pass 2: update froms
for {
s[n].from = r
if fr == r {
return r
}
n = fr
fr = s[n].from
}
}
// Kruskal implements Kruskal's algorithm for constructing a minimum spanning
// forest on an undirected graph.
//
// The forest is returned as an undirected graph.
//
// Also returned is a total distance for the returned forest.
//
// This method is a convenience wrapper for LabeledEdgeList.Kruskal.
// If you have no need for the input graph as a LabeledUndirected, it may be
// more efficient to construct a LabeledEdgeList directly.
func (g LabeledUndirected) Kruskal(w WeightFunc) (spanningForest LabeledUndirected, dist float64) {
return g.WeightedArcsAsEdges(w).Kruskal()
}
// Kruskal implements Kruskal's algorithm for constructing a minimum spanning
// forest on an undirected graph.
//
// The algorithm allows parallel edges, thus it is acceptable to construct
// the receiver with LabeledUndirected.WeightedArcsAsEdges. It may be more
// efficient though, if you can construct the receiver WeightedEdgeList
// directly without parallel edges.
//
// The forest is returned as an undirected graph.
//
// Also returned is a total distance for the returned forest.
//
// The edge list of the receiver is sorted in place as a side effect of this
// method. See KruskalSorted for a version that relies on the edge list being
// already sorted. This method is a wrapper for KruskalSorted. If you can
// generate the input graph sorted as required for KruskalSorted, you can
// call that method directly and avoid the overhead of the sort.
func (l WeightedEdgeList) Kruskal() (g LabeledUndirected, dist float64) {
e := l.Edges
w := l.WeightFunc
sort.Slice(e, func(i, j int) bool { return w(e[i].LI) < w(e[j].LI) })
return l.KruskalSorted()
}
// KruskalSorted implements Kruskal's algorithm for constructing a minimum
// spanning tree on an undirected graph.
//
// When called, the edge list of the receiver must be already sorted by weight.
// See the Kruskal method for a version that accepts an unsorted edge list.
// As with Kruskal, parallel edges are allowed.
//
// The forest is returned as an undirected graph.
//
// Also returned is a total distance for the returned forest.
func (l WeightedEdgeList) KruskalSorted() (g LabeledUndirected, dist float64) {
ds := newDisjointSet(l.Order)
g.LabeledAdjacencyList = make(LabeledAdjacencyList, l.Order)
for _, e := range l.Edges {
if ds.union(e.N1, e.N2) {
g.AddEdge(Edge{e.N1, e.N2}, e.LI)
dist += l.WeightFunc(e.LI)
}
}
return
}
// Prim implements the Jarník-Prim-Dijkstra algorithm for constructing
// a minimum spanning tree on an undirected graph.
//
// Prim computes a minimal spanning tree on the connected component containing
// the given start node. The tree is returned in FromList f. Argument f
// cannot be a nil pointer although it can point to a zero value FromList.
//
// If the passed FromList.Paths has the len of g though, it will be reused.
// In the case of a graph with multiple connected components, this allows a
// spanning forest to be accumulated by calling Prim successively on
// representative nodes of the components. In this case if leaves for
// individual trees are of interest, pass a non-nil zero-value for the argument
// componentLeaves and it will be populated with leaves for the single tree
// spanned by the call.
//
// If argument labels is non-nil, it must have the same length as g and will
// be populated with labels corresponding to the edges of the tree.
//
// Returned are the number of nodes spanned for the single tree (which will be
// the order of the connected component) and the total spanned distance for the
// single tree.
func (g LabeledUndirected) Prim(start NI, w WeightFunc, f *FromList, labels []LI, componentLeaves *bits.Bits) (numSpanned int, dist float64) {
al := g.LabeledAdjacencyList
if len(f.Paths) != len(al) {
*f = NewFromList(len(al))
}
if f.Leaves.Num != len(al) {
f.Leaves = bits.New(len(al))
}
b := make([]prNode, len(al)) // "best"
for n := range b {
b[n].nx = NI(n)
b[n].fx = -1
}
rp := f.Paths
var frontier prHeap
rp[start] = PathEnd{From: -1, Len: 1}
numSpanned = 1
fLeaves := &f.Leaves
fLeaves.SetBit(int(start), 1)
if componentLeaves != nil {
if componentLeaves.Num != len(al) {
*componentLeaves = bits.New(len(al))
}
componentLeaves.SetBit(int(start), 1)
}
for a := start; ; {
for _, nb := range al[a] {
if rp[nb.To].Len > 0 {
continue // already in MST, no action
}
switch bp := &b[nb.To]; {
case bp.fx == -1: // new node for frontier
bp.from = fromHalf{From: a, Label: nb.Label}
bp.wt = w(nb.Label)
heap.Push(&frontier, bp)
case w(nb.Label) < bp.wt: // better arc
bp.from = fromHalf{From: a, Label: nb.Label}
bp.wt = w(nb.Label)
heap.Fix(&frontier, bp.fx)
}
}
if len(frontier) == 0 {
break // done
}
bp := heap.Pop(&frontier).(*prNode)
a = bp.nx
rp[a].Len = rp[bp.from.From].Len + 1
rp[a].From = bp.from.From
if len(labels) != 0 {
labels[a] = bp.from.Label
}
dist += bp.wt
fLeaves.SetBit(int(bp.from.From), 0)
fLeaves.SetBit(int(a), 1)
if componentLeaves != nil {
componentLeaves.SetBit(int(bp.from.From), 0)
componentLeaves.SetBit(int(a), 1)
}
numSpanned++
}
return
}
type prNode struct {
nx NI
from fromHalf
wt float64 // p.Weight(from.Label)
fx int
}
type prHeap []*prNode
func (h prHeap) Len() int { return len(h) }
func (h prHeap) Less(i, j int) bool { return h[i].wt < h[j].wt }
func (h prHeap) Swap(i, j int) {
h[i], h[j] = h[j], h[i]
h[i].fx = i
h[j].fx = j
}
func (p *prHeap) Push(x interface{}) {
nd := x.(*prNode)
nd.fx = len(*p)
*p = append(*p, nd)
}
func (p *prHeap) Pop() interface{} {
r := *p
last := len(r) - 1
*p = r[:last]
return r[last]
}