add MinimumSpanningTree
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
- add Prim's mst - add Kruskal's mst - edit weight interface - add exercise directed cycle
This commit is contained in:
parent
cb60157dd1
commit
33710b1391
88
doc/exercises/directed_cycle.md
Normal file
88
doc/exercises/directed_cycle.md
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
---
|
||||||
|
author: Raffaele Mignone
|
||||||
|
title: Caratterizzazione della complessità di un algoritmo per la ricerca di cicli orientati in un grafo
|
||||||
|
keywords:
|
||||||
|
- Complessità
|
||||||
|
- Grafo
|
||||||
|
- Ciclo
|
||||||
|
subject: Caratterizzazione della complessità
|
||||||
|
papersize: a4
|
||||||
|
lang: it-IT
|
||||||
|
---
|
||||||
|
|
||||||
|
# Ricerca di cicli orientati
|
||||||
|
|
||||||
|
## Traccia
|
||||||
|
|
||||||
|
Scrivere un programma per la ricerca di directed cycles in un grafo orientato.
|
||||||
|
|
||||||
|
## Soluzione
|
||||||
|
|
||||||
|
Il problema può essere risolto prendendo come base la ricerca in profondità classica.
|
||||||
|
Ad essa deve essere aggiunto un modo per tenere memoria dei nodi presenti sul percorso che si sta esplorando.
|
||||||
|
Ciò può essere fatto tramite l'uso di un array così come si è fatto per tenere traccia dei nodi visitati[^vertex-info].
|
||||||
|
|
||||||
|
[^vertex-info]: Nel caso specifico si è utilizzata una data class che conserva le informazioni `isVisited`, `isOnPath` e `previously`.
|
||||||
|
|
||||||
|
```{#lst:cycle .kotlin caption="Versione modificata della ricerca in profondità"}
|
||||||
|
private fun dfs(graph: UndirectedGraph, vertex: Int) {
|
||||||
|
graphInfo[vertex].isVisited = true
|
||||||
|
graphInfo[vertex].isOnPath = true
|
||||||
|
|
||||||
|
graph.adjacentVertex(vertex)
|
||||||
|
.forEach {
|
||||||
|
when {
|
||||||
|
hasCycle() -> return@forEach
|
||||||
|
!graphInfo[it].isVisited -> exploreChild(graph, vertex, it)
|
||||||
|
graphInfo[it].isOnStack -> cycle = makeCycle(vertex, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
graphInfo[vertex].isOnPath = false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Quando tra i vertici adiacenti a quello che si sta esplorando si trova un nodo già presente sul percorso vuol dire che è stato trovato un ciclo.
|
||||||
|
La costruzione del ciclo viene mostrata nel @lst:makeCycle
|
||||||
|
|
||||||
|
```{#lst:makeCycle .kotlin caption="Memorizzazione dei vertici che danno origine ad un ciclo"}
|
||||||
|
private fun makeCycle(
|
||||||
|
start: Int,
|
||||||
|
end: Int
|
||||||
|
): MutableCollection<Int> {
|
||||||
|
val cycle = Stack<Int>()
|
||||||
|
|
||||||
|
var currentVertex = start
|
||||||
|
|
||||||
|
while (currentVertex != end) {
|
||||||
|
cycle.add(currentVertex)
|
||||||
|
currentVertex = graphInfo[currentVertex].previously
|
||||||
|
}
|
||||||
|
|
||||||
|
cycle.add(end)
|
||||||
|
cycle.add(start)
|
||||||
|
|
||||||
|
return cycle
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Infine la funzione `exploreChild` (@lst:exploreChild) semplicemente si occupa di settare il predecessore e di eseguire la ricerca in profondità sul nuovo vertice.
|
||||||
|
|
||||||
|
```{#lst:exploreChild .kotlin caption="Funzione per eseguire la ricerca in profondità su un vertice adiacente"}
|
||||||
|
private fun exploreChild(
|
||||||
|
graph: UndirectedGraph,
|
||||||
|
parent: Int,
|
||||||
|
child: Int
|
||||||
|
) {
|
||||||
|
graphInfo[child].previously = parent
|
||||||
|
dfs(graph, child)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Complessità
|
||||||
|
|
||||||
|
L'algoritmo per l'individuazione dei grafi mostrato precedentemente è sostanzialmente una versione modificata della ricerca in profondità e nel caso peggiore deve visitare tutti i nodi percorrendo tutti gli archi, per cui ha una complessità pari a $E + V$.
|
||||||
|
|
||||||
|
## Source code
|
||||||
|
|
||||||
|
- [DirectedCycle](https://git.norangeb.it/norangebit-unisannio-computer-science/lm-tecniche-di-programmazione/src/branch/master/src/main/kotlin/it/norangeb/algorithms/graph/operations/DirectedCycle.kt)
|
@ -43,6 +43,7 @@ interface WeightUndirectedGraph {
|
|||||||
fun edgeNumber(): Int
|
fun edgeNumber(): Int
|
||||||
fun addEdge(edge: EdgeI)
|
fun addEdge(edge: EdgeI)
|
||||||
fun adjacentVertex(vertex: Int): Collection<EdgeI>
|
fun adjacentVertex(vertex: Int): Collection<EdgeI>
|
||||||
|
fun edges(): Collection<EdgeI>
|
||||||
}
|
}
|
||||||
|
|
||||||
interface WeightDirectedGraph : WeightUndirectedGraph {
|
interface WeightDirectedGraph : WeightUndirectedGraph {
|
||||||
|
@ -52,4 +52,15 @@ class WeightDiGraph(
|
|||||||
|
|
||||||
return reverse
|
return reverse
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun edges(): Collection<EdgeI> {
|
||||||
|
val edges = mutableListOf<EdgeI>()
|
||||||
|
|
||||||
|
(0 until data.vertexNumber())
|
||||||
|
.forEach {
|
||||||
|
edges.addAll(adjacentVertex(it))
|
||||||
|
}
|
||||||
|
|
||||||
|
return edges
|
||||||
|
}
|
||||||
}
|
}
|
@ -42,4 +42,15 @@ class WeightGraph(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun adjacentVertex(vertex: Int): Collection<EdgeI> = data.adjacent(vertex)
|
override fun adjacentVertex(vertex: Int): Collection<EdgeI> = data.adjacent(vertex)
|
||||||
|
|
||||||
|
override fun edges(): Collection<EdgeI> {
|
||||||
|
val edges = mutableListOf<EdgeI>()
|
||||||
|
|
||||||
|
(0 until data.vertexNumber())
|
||||||
|
.forEach {
|
||||||
|
edges.addAll(adjacentVertex(it))
|
||||||
|
}
|
||||||
|
|
||||||
|
return edges
|
||||||
|
}
|
||||||
}
|
}
|
@ -35,8 +35,15 @@ data class Edge(val from: Int, val to: Int, val weight: Double) : EdgeI {
|
|||||||
else -> from
|
else -> from
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun compareTo(other: EdgeI): Int =
|
override fun compareTo(other: EdgeI): Int {
|
||||||
this.weight.compareTo(other.weight())
|
var result = weight().compareTo(other.weight())
|
||||||
|
if (result == 0)
|
||||||
|
result = either().compareTo(other.either())
|
||||||
|
if (result == 0)
|
||||||
|
result = other(either()).compareTo(other.other(other.either()))
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
override fun reversed(): EdgeI = Edge(to, from, weight)
|
override fun reversed(): EdgeI = Edge(to, from, weight)
|
||||||
}
|
}
|
@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 norangebit
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package it.norangeb.algorithms.graph.operations
|
||||||
|
|
||||||
|
import it.norangeb.algorithms.datastructures.queue.priority.BinaryHeap
|
||||||
|
import it.norangeb.algorithms.datastructures.queue.priority.PriorityQueue
|
||||||
|
import it.norangeb.algorithms.datastructures.unionfind.QuickFind
|
||||||
|
import it.norangeb.algorithms.datastructures.unionfind.UnionFind
|
||||||
|
import it.norangeb.algorithms.graph.WeightUndirectedGraph
|
||||||
|
import it.norangeb.algorithms.graph.data.EdgeI
|
||||||
|
|
||||||
|
class Kruskal(graph: WeightUndirectedGraph) : MinimumSpanningTree {
|
||||||
|
val mst = mutableListOf<EdgeI>()
|
||||||
|
|
||||||
|
init {
|
||||||
|
val minQueue = BinaryHeap.createMinPriorityQueue<EdgeI>()
|
||||||
|
val unionFindGraph = QuickFind(graph.vertexNumber())
|
||||||
|
|
||||||
|
graph.edges().forEach { minQueue.insert(it) }
|
||||||
|
|
||||||
|
while (!minQueue.isEmpty() && mst.size < graph.vertexNumber() - 1)
|
||||||
|
tryEdge(minQueue, unionFindGraph)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun tryEdge(heap: PriorityQueue<EdgeI>, unionFindGraph: UnionFind) {
|
||||||
|
heap.pop().map {
|
||||||
|
val from = it.either()
|
||||||
|
val to = it.other(from)
|
||||||
|
|
||||||
|
if (!unionFindGraph.connected(from, to)) {
|
||||||
|
unionFindGraph.union(from, to)
|
||||||
|
mst.add(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun edges(): Collection<EdgeI> = mst
|
||||||
|
|
||||||
|
override fun weight(): Double = mst.map { it.weight() }.sum()
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 norangebit
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package it.norangeb.algorithms.graph.operations
|
||||||
|
|
||||||
|
import it.norangeb.algorithms.graph.data.EdgeI
|
||||||
|
|
||||||
|
interface MinimumSpanningTree {
|
||||||
|
fun edges(): Collection<EdgeI>
|
||||||
|
fun weight(): Double
|
||||||
|
}
|
@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 norangebit
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package it.norangeb.algorithms.graph.operations
|
||||||
|
|
||||||
|
import it.norangeb.algorithms.datastructures.queue.priority.BinaryHeap
|
||||||
|
import it.norangeb.algorithms.datastructures.queue.priority.PriorityQueue
|
||||||
|
import it.norangeb.algorithms.graph.WeightUndirectedGraph
|
||||||
|
import it.norangeb.algorithms.graph.data.EdgeI
|
||||||
|
|
||||||
|
class Prim(graph: WeightUndirectedGraph) : MinimumSpanningTree {
|
||||||
|
private val mst = mutableListOf<EdgeI>()
|
||||||
|
private val visited = Array(graph.vertexNumber()) { false }
|
||||||
|
|
||||||
|
init {
|
||||||
|
val queue = BinaryHeap.createMinPriorityQueue<EdgeI>()
|
||||||
|
|
||||||
|
visitAdjacent(graph, 0, queue)
|
||||||
|
|
||||||
|
while (!queue.isEmpty() && mst.size < graph.vertexNumber() - 1)
|
||||||
|
tryEdge(graph, queue)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun tryEdge(graph: WeightUndirectedGraph, heap: PriorityQueue<EdgeI>) {
|
||||||
|
heap.pop().map {
|
||||||
|
val from = it.either()
|
||||||
|
val to = it.other(from)
|
||||||
|
|
||||||
|
if (visited[from] && visited[to])
|
||||||
|
return@map
|
||||||
|
if (!visited[from])
|
||||||
|
visitAdjacent(graph, from, heap)
|
||||||
|
if (!visited[to])
|
||||||
|
visitAdjacent(graph, to, heap)
|
||||||
|
|
||||||
|
mst.add(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun visitAdjacent(
|
||||||
|
graph: WeightUndirectedGraph,
|
||||||
|
vertex: Int,
|
||||||
|
heap: PriorityQueue<EdgeI>
|
||||||
|
) {
|
||||||
|
visited[vertex] = true
|
||||||
|
|
||||||
|
graph.adjacentVertex(vertex)
|
||||||
|
.forEach {
|
||||||
|
if (!visited[it.other(vertex)])
|
||||||
|
heap.insert(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun edges(): Collection<EdgeI> = mst
|
||||||
|
|
||||||
|
override fun weight(): Double = mst.map { it.weight() }.sum()
|
||||||
|
}
|
@ -73,6 +73,15 @@ object WeightDiGraphTest : Spek({
|
|||||||
Then("adjacent of 3 should equal listOf(3->4:3.4)") {
|
Then("adjacent of 3 should equal listOf(3->4:3.4)") {
|
||||||
graph.adjacentVertex(3) `should equal` listOf(Edge(3, 4, 3.4))
|
graph.adjacentVertex(3) `should equal` listOf(Edge(3, 4, 3.4))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Then("edges should equals listOf(1->3:1.3, 1->4:1.4, 1->5:1.5, 3->4:3.4") {
|
||||||
|
graph.edges().sorted() `should equal` listOf(
|
||||||
|
Edge(1, 3, 1.3),
|
||||||
|
Edge(1, 4, 1.4),
|
||||||
|
Edge(1, 5, 1.5),
|
||||||
|
Edge(3, 4, 3.4)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Scenario("reverse test") {
|
Scenario("reverse test") {
|
||||||
|
@ -76,6 +76,20 @@ object WeightGraphTest : Spek({
|
|||||||
Edge(3, 4, 3.4)
|
Edge(3, 4, 3.4)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Then("edges should equals listOf(1->3:1.3, 1->5:1.5, 3->4:3.4, 1->4:5.0,") {
|
||||||
|
graph.edges().sorted() `should equal` listOf(
|
||||||
|
Edge(1, 3, 1.1),
|
||||||
|
Edge(3, 1, 1.1),
|
||||||
|
Edge(1, 5, 1.5),
|
||||||
|
Edge(5, 1, 1.5),
|
||||||
|
Edge(3, 4, 3.4),
|
||||||
|
Edge(4, 3, 3.4),
|
||||||
|
Edge(1, 4, 5.0),
|
||||||
|
Edge(4, 1, 5.0)
|
||||||
|
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 norangebit
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package it.norangeb.algorithms.graph.operations
|
||||||
|
|
||||||
|
import it.norangeb.algorithms.graph.WeightGraph
|
||||||
|
import it.norangeb.algorithms.graph.data.Edge
|
||||||
|
import org.amshove.kluent.`should be equal to`
|
||||||
|
import org.amshove.kluent.`should equal`
|
||||||
|
import org.spekframework.spek2.Spek
|
||||||
|
import org.spekframework.spek2.style.gherkin.Feature
|
||||||
|
|
||||||
|
object KruskalTest : Spek({
|
||||||
|
Feature("kruskal") {
|
||||||
|
Scenario("compute mst") {
|
||||||
|
val graph by memoized { WeightGraph() }
|
||||||
|
|
||||||
|
Given("a graph") {
|
||||||
|
graph.addEdge(Edge(0, 2, 0.26))
|
||||||
|
graph.addEdge(Edge(0, 4, 0.38))
|
||||||
|
graph.addEdge(Edge(0, 7, 0.16))
|
||||||
|
graph.addEdge(Edge(1, 2, 0.36))
|
||||||
|
graph.addEdge(Edge(1, 3, 0.29))
|
||||||
|
graph.addEdge(Edge(1, 5, 0.32))
|
||||||
|
graph.addEdge(Edge(1, 7, 0.19))
|
||||||
|
graph.addEdge(Edge(2, 3, 0.17))
|
||||||
|
graph.addEdge(Edge(2, 7, 0.34))
|
||||||
|
graph.addEdge(Edge(3, 6, 0.52))
|
||||||
|
graph.addEdge(Edge(4, 5, 0.35))
|
||||||
|
graph.addEdge(Edge(4, 7, 0.37))
|
||||||
|
graph.addEdge(Edge(5, 7, 0.28))
|
||||||
|
graph.addEdge(Edge(6, 2, 0.40))
|
||||||
|
}
|
||||||
|
|
||||||
|
lateinit var result: MinimumSpanningTree
|
||||||
|
|
||||||
|
When("compute the mst") {
|
||||||
|
result = Kruskal(graph)
|
||||||
|
}
|
||||||
|
|
||||||
|
Then("weight should be 1.81") {
|
||||||
|
result.weight() `should be equal to` 1.81
|
||||||
|
}
|
||||||
|
|
||||||
|
Then("edge should be") {
|
||||||
|
result.edges() `should equal` listOf(
|
||||||
|
Edge(0, 7, 0.16),
|
||||||
|
Edge(2, 3, 0.17),
|
||||||
|
Edge(1, 7, 0.19),
|
||||||
|
Edge(0, 2, 0.26),
|
||||||
|
Edge(5, 7, 0.28),
|
||||||
|
Edge(4, 5, 0.35),
|
||||||
|
Edge(2, 6, 0.40)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 norangebit
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package it.norangeb.algorithms.graph.operations
|
||||||
|
|
||||||
|
import it.norangeb.algorithms.graph.WeightGraph
|
||||||
|
import it.norangeb.algorithms.graph.data.Edge
|
||||||
|
import org.amshove.kluent.`should be equal to`
|
||||||
|
import org.amshove.kluent.`should equal`
|
||||||
|
import org.spekframework.spek2.Spek
|
||||||
|
import org.spekframework.spek2.style.gherkin.Feature
|
||||||
|
|
||||||
|
object PrimTest : Spek({
|
||||||
|
Feature("prim") {
|
||||||
|
Scenario("compute mst") {
|
||||||
|
val graph by memoized { WeightGraph() }
|
||||||
|
|
||||||
|
Given("a graph") {
|
||||||
|
graph.addEdge(Edge(0, 2, 0.26))
|
||||||
|
graph.addEdge(Edge(0, 4, 0.38))
|
||||||
|
graph.addEdge(Edge(0, 7, 0.16))
|
||||||
|
graph.addEdge(Edge(1, 2, 0.36))
|
||||||
|
graph.addEdge(Edge(1, 3, 0.29))
|
||||||
|
graph.addEdge(Edge(1, 5, 0.32))
|
||||||
|
graph.addEdge(Edge(1, 7, 0.19))
|
||||||
|
graph.addEdge(Edge(2, 3, 0.17))
|
||||||
|
graph.addEdge(Edge(2, 7, 0.34))
|
||||||
|
graph.addEdge(Edge(3, 6, 0.52))
|
||||||
|
graph.addEdge(Edge(4, 5, 0.35))
|
||||||
|
graph.addEdge(Edge(4, 7, 0.37))
|
||||||
|
graph.addEdge(Edge(5, 7, 0.28))
|
||||||
|
graph.addEdge(Edge(6, 2, 0.40))
|
||||||
|
}
|
||||||
|
|
||||||
|
lateinit var result: MinimumSpanningTree
|
||||||
|
|
||||||
|
When("compute the mst") {
|
||||||
|
result = Prim(graph)
|
||||||
|
}
|
||||||
|
|
||||||
|
Then("weight should be 1.81") {
|
||||||
|
result.weight() `should be equal to` 1.81
|
||||||
|
}
|
||||||
|
|
||||||
|
Then("edge should be") {
|
||||||
|
result.edges().sorted() `should equal` listOf(
|
||||||
|
Edge(0, 7, 0.16),
|
||||||
|
Edge(2, 3, 0.17),
|
||||||
|
Edge(7, 1, 0.19),
|
||||||
|
Edge(0, 2, 0.26),
|
||||||
|
Edge(7, 5, 0.28),
|
||||||
|
Edge(5, 4, 0.35),
|
||||||
|
Edge(2, 6, 0.40)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
Loading…
Reference in New Issue
Block a user