forked from realpacific/algorithms
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPrimMinSpanningTreeAlgorithm.kt
93 lines (78 loc) · 2.61 KB
/
PrimMinSpanningTreeAlgorithm.kt
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
package algorithmsinanutshell
import utils.assertArraysSame
import java.util.*
import kotlin.test.assertEquals
/**
* Prim Algorithm starts from min cost edge and then selects the next small cost edge
* while maintaining the connection with first edge.
*
* This can be modeled using [PriorityQueue] sorted using [Edge] w.r.t its weight
*/
class PrimMinSpanningTreeAlgorithm(val graph: Graph) {
private val selected = mutableSetOf<Vertex>()
private val mst = Stack<Edge>()
private val pq = PriorityQueue<Edge> { o1, o2 -> o1!!.weight!! - o2!!.weight!! }
private var isExecuted = false
private lateinit var minEdge: Graph.Edge
init {
graph.getAllNodes().forEach { startVertex ->
startVertex.edges.forEach {
if (!::minEdge.isInitialized) {
minEdge = it
} else if (minEdge.weight!! > it.weight!!) {
minEdge = it
}
}
}
}
fun execute(): PrimMinSpanningTreeAlgorithm {
runAlgorithm()
mst.forEach(::println)
isExecuted = true
return this
}
fun result(): List<Edge> {
require(isExecuted)
return mst.toList()
}
fun minCost(): Int {
require(isExecuted)
return mst.sumBy { it.weight!! }
}
private fun runAlgorithm() {
// Add the starting vertex to selected
selected.add(minEdge.startVertex)
// Put its edge on priority queue
minEdge.startVertex.edges.forEach(pq::offer)
while (pq.isNotEmpty()) {
// Since items in priority queue are sorted using edge's weight, lowest cost edge is always at the top
val edge = pq.poll()
if (selected.contains(edge.endVertex)) {
continue
} else {
mst.add(edge)
selected.add(edge.endVertex)
// Add end vertex's edges to priority queue
// This will put it as candidate to be included in mst
edge.endVertex.edges.forEach(pq::offer)
}
}
}
}
fun main() {
val graph = Graph(Relation.WEIGHTED_UNDIRECTED)
val v1 = graph.add(1)
val v2 = graph.add(2)
val v3 = graph.add(3)
val v4 = graph.add(4)
val v5 = graph.add(5)
v1.connectWith(v2, 3)
v2.connectWith(v3, 6)
v3.connectWith(v4, 5)
v4.connectWith(v1, 10)
v5.connectWith(v2, 9)
v5.connectWith(v4, 8)
val mst = PrimMinSpanningTreeAlgorithm(graph).execute()
assertEquals(22, mst.minCost())
assertArraysSame(arrayOf(3, 6, 5, 8), mst.result().map { it.weight }.toTypedArray())
}