From eccec5deeb573a9b974c724cd474fb68747d9a19 Mon Sep 17 00:00:00 2001 From: William Fiset Date: Sun, 15 Mar 2026 22:47:23 -0700 Subject: [PATCH 1/5] Refactor Boruvkas: add docs, fix compareTo overflow, clean up Fix integer overflow bug in Edge.compareTo (cost - other.cost) by using Integer.compare. Add algorithm Javadoc, remove unused UnionFind methods, and simplify main example. Co-Authored-By: Claude Opus 4.6 --- .../algorithms/graphtheory/Boruvkas.java | 176 +++++++++++------- 1 file changed, 105 insertions(+), 71 deletions(-) diff --git a/src/main/java/com/williamfiset/algorithms/graphtheory/Boruvkas.java b/src/main/java/com/williamfiset/algorithms/graphtheory/Boruvkas.java index ff3dd82f2..84a588c58 100644 --- a/src/main/java/com/williamfiset/algorithms/graphtheory/Boruvkas.java +++ b/src/main/java/com/williamfiset/algorithms/graphtheory/Boruvkas.java @@ -1,6 +1,28 @@ +/** + * Boruvka's Minimum Spanning Tree Algorithm — Edge List + * + *

Finds the MST of a weighted undirected graph by repeatedly selecting the + * cheapest outgoing edge from each connected component and merging components. + * + *

Algorithm: + *

    + *
  1. Start with each node as its own component (using Union-Find).
  2. + *
  3. For each component, find the minimum-weight edge crossing to another component.
  4. + *
  5. Add all such cheapest edges to the MST and merge the components.
  6. + *
  7. Repeat until only one component remains, or no more merges are possible.
  8. + *
+ * + *

If the graph is disconnected, no MST exists and the solver returns null. + * + *

Time: O(E log V) + *

Space: O(V + E) + * + * @author William Fiset, william.alexandre.fiset@gmail.com + */ package com.williamfiset.algorithms.graphtheory; -import java.util.*; +import java.util.ArrayList; +import java.util.List; public class Boruvkas { @@ -20,79 +42,77 @@ public String toString() { @Override public int compareTo(Edge other) { - int cmp = cost - other.cost; - // Break ties by picking lexicographically smallest edge pair. - if (cmp == 0) { - cmp = u - other.u; - if (cmp == 0) return v - other.v; + int cmp = Integer.compare(cost, other.cost); + if (cmp != 0) { return cmp; } - return cmp; + cmp = Integer.compare(u, other.u); + if (cmp != 0) { + return cmp; + } + return Integer.compare(v, other.v); } } - // Inputs - private final int n; // Number of nodes - private final Edge[] graph; // Edge list - - // Internal + private final int n; + private final Edge[] graph; private boolean solved; private boolean mstExists; - - // Outputs private long minCostSum; private List mst; public Boruvkas(int n, Edge[] graph) { - if (graph == null) throw new IllegalArgumentException(); + if (graph == null) { + throw new IllegalArgumentException(); + } this.graph = graph; this.n = n; } - // Returns the edges used in finding the minimum spanning tree, or returns - // null if no MST exists. + /** + * Returns the edges in the MST, or null if the graph is disconnected. + */ public List getMst() { solve(); return mstExists ? mst : null; } + /** + * Returns the total cost of the MST, or null if the graph is disconnected. + */ public Long getMstCost() { solve(); return mstExists ? minCostSum : null; } - // Given a graph represented as an edge list this method finds - // the Minimum Spanning Tree (MST) cost if there exists - // a MST, otherwise it returns null. private void solve() { - if (solved) return; + if (solved) { + return; + } mst = new ArrayList<>(); UnionFind uf = new UnionFind(n); while (uf.components > 1) { - boolean stop = true; Edge[] cheapest = new Edge[n]; + boolean merged = false; - // Find the cheapest edge for each component + // For each edge, track the cheapest crossing edge for each component. for (Edge e : graph) { int root1 = uf.find(e.u); int root2 = uf.find(e.v); - if (root1 == root2) continue; - + if (root1 == root2) { + continue; + } if (cheapest[root1] == null || e.cost < cheapest[root1].cost) { cheapest[root1] = e; - stop = false; } if (cheapest[root2] == null || e.cost < cheapest[root2].cost) { cheapest[root2] = e; - stop = false; } } - if (stop) break; - - // Add the cheapest edges to the MST + // Merge components using their cheapest crossing edges. for (int i = 0; i < n; i++) { Edge e = cheapest[i]; if (e == null) { @@ -104,44 +124,62 @@ private void solve() { uf.union(root1, root2); mst.add(e); minCostSum += e.cost; + merged = true; } } + + if (!merged) { + break; + } } mstExists = (mst.size() == n - 1); solved = true; } + // ==================== Main ==================== + + // + // 5 4 + // 0 ----- 1 ----- 2 + // | \ 2 | |\ 2 + // 1| 3 |2 | 9 + // | / 2 | 1 |/ + // 4 ----- 3 --- 7 --- 8 + // \ 1 / 5 / 0 | + // 5 / \ 1 \| + // \ / 7 6 -- 4 9 + // 5 8 + // + // MST cost: 14 + // public static void main(String[] args) { - - int n = 10, m = 18, i = 0; - Edge[] g = new Edge[m]; - - // Edges are treated as undirected - g[i++] = new Edge(0, 1, 5); - g[i++] = new Edge(0, 3, 4); - g[i++] = new Edge(0, 4, 1); - g[i++] = new Edge(1, 2, 4); - g[i++] = new Edge(1, 3, 2); - g[i++] = new Edge(2, 7, 4); - g[i++] = new Edge(2, 8, 1); - g[i++] = new Edge(2, 9, 2); - g[i++] = new Edge(3, 6, 11); - g[i++] = new Edge(3, 7, 2); - g[i++] = new Edge(4, 3, 2); - g[i++] = new Edge(4, 5, 1); - g[i++] = new Edge(5, 3, 5); - g[i++] = new Edge(5, 6, 7); - g[i++] = new Edge(6, 7, 1); - g[i++] = new Edge(6, 8, 4); - g[i++] = new Edge(7, 8, 6); - g[i++] = new Edge(9, 8, 0); - - Boruvkas solver = new Boruvkas(n, g); - - Long ans = solver.getMstCost(); - if (ans != null) { - System.out.println("MST cost: " + ans); + Edge[] g = { + new Edge(0, 1, 5), + new Edge(0, 3, 4), + new Edge(0, 4, 1), + new Edge(1, 2, 4), + new Edge(1, 3, 2), + new Edge(2, 7, 4), + new Edge(2, 8, 1), + new Edge(2, 9, 2), + new Edge(3, 6, 11), + new Edge(3, 7, 2), + new Edge(4, 3, 2), + new Edge(4, 5, 1), + new Edge(5, 3, 5), + new Edge(5, 6, 7), + new Edge(6, 7, 1), + new Edge(6, 8, 4), + new Edge(7, 8, 6), + new Edge(9, 8, 0), + }; + + Boruvkas solver = new Boruvkas(10, g); + + Long cost = solver.getMstCost(); + if (cost != null) { + System.out.println("MST cost: " + cost); // 14 for (Edge e : solver.getMst()) { System.out.println(e); } @@ -150,7 +188,7 @@ public static void main(String[] args) { } } - // Union find data structure + // Union-Find with path compression and union by size. private static class UnionFind { int components; int[] id, sz; @@ -167,8 +205,10 @@ public UnionFind(int n) { public int find(int p) { int root = p; - while (root != id[root]) root = id[root]; - while (p != root) { // Do path compression + while (root != id[root]) { + root = id[root]; + } + while (p != root) { int next = id[p]; id[p] = root; p = next; @@ -176,17 +216,11 @@ public int find(int p) { return root; } - public boolean connected(int p, int q) { - return find(p) == find(q); - } - - public int size(int p) { - return sz[find(p)]; - } - public void union(int p, int q) { int root1 = find(p), root2 = find(q); - if (root1 == root2) return; + if (root1 == root2) { + return; + } if (sz[root1] < sz[root2]) { sz[root2] += sz[root1]; id[root1] = root2; From f73f2c34e8a0d2f0c63577a1adf55f4fe8062a84 Mon Sep 17 00:00:00 2001 From: William Fiset Date: Sun, 15 Mar 2026 22:50:32 -0700 Subject: [PATCH 2/5] Simplify UnionFind find to recursive implementation Co-Authored-By: Claude Opus 4.6 --- .../algorithms/graphtheory/Boruvkas.java | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/williamfiset/algorithms/graphtheory/Boruvkas.java b/src/main/java/com/williamfiset/algorithms/graphtheory/Boruvkas.java index 84a588c58..7c97ea527 100644 --- a/src/main/java/com/williamfiset/algorithms/graphtheory/Boruvkas.java +++ b/src/main/java/com/williamfiset/algorithms/graphtheory/Boruvkas.java @@ -204,16 +204,10 @@ public UnionFind(int n) { } public int find(int p) { - int root = p; - while (root != id[root]) { - root = id[root]; + if (id[p] != p) { + id[p] = find(id[p]); } - while (p != root) { - int next = id[p]; - id[p] = root; - p = next; - } - return root; + return id[p]; } public void union(int p, int q) { From e2502c85c34ff89f5ab3e76c084d739c901a43b5 Mon Sep 17 00:00:00 2001 From: William Fiset Date: Sun, 15 Mar 2026 22:58:39 -0700 Subject: [PATCH 3/5] Remove unused Edge methods, replace example with planar grid graph Co-Authored-By: Claude Opus 4.6 --- .../algorithms/graphtheory/Boruvkas.java | 75 ++++++------------- .../algorithms/graphtheory/BoruvkasTest.java | 43 +++++------ 2 files changed, 41 insertions(+), 77 deletions(-) diff --git a/src/main/java/com/williamfiset/algorithms/graphtheory/Boruvkas.java b/src/main/java/com/williamfiset/algorithms/graphtheory/Boruvkas.java index 7c97ea527..8dda78e02 100644 --- a/src/main/java/com/williamfiset/algorithms/graphtheory/Boruvkas.java +++ b/src/main/java/com/williamfiset/algorithms/graphtheory/Boruvkas.java @@ -26,7 +26,7 @@ public class Boruvkas { - static class Edge implements Comparable { + static class Edge { int u, v, cost; public Edge(int u, int v, int cost) { @@ -34,24 +34,6 @@ public Edge(int u, int v, int cost) { this.v = v; this.cost = cost; } - - @Override - public String toString() { - return String.format("%d %d, cost: %d", u, v, cost); - } - - @Override - public int compareTo(Edge other) { - int cmp = Integer.compare(cost, other.cost); - if (cmp != 0) { - return cmp; - } - cmp = Integer.compare(u, other.u); - if (cmp != 0) { - return cmp; - } - return Integer.compare(v, other.v); - } } private final int n; @@ -140,48 +122,39 @@ private void solve() { // ==================== Main ==================== // - // 5 4 - // 0 ----- 1 ----- 2 - // | \ 2 | |\ 2 - // 1| 3 |2 | 9 - // | / 2 | 1 |/ - // 4 ----- 3 --- 7 --- 8 - // \ 1 / 5 / 0 | - // 5 / \ 1 \| - // \ / 7 6 -- 4 9 - // 5 8 + // 1 7 2 + // 0 --------------- 1 --------------- 2 --------------- 3 + // | | | | + // | | | | + // 4 | 3 | 5 | 6 | + // | | | | + // | | | | + // 4 --------------- 5 --------------- 6 --------------- 7 + // 8 2 9 // - // MST cost: 14 + // MST cost: 23 // public static void main(String[] args) { Edge[] g = { - new Edge(0, 1, 5), - new Edge(0, 3, 4), - new Edge(0, 4, 1), - new Edge(1, 2, 4), - new Edge(1, 3, 2), - new Edge(2, 7, 4), - new Edge(2, 8, 1), - new Edge(2, 9, 2), - new Edge(3, 6, 11), - new Edge(3, 7, 2), - new Edge(4, 3, 2), - new Edge(4, 5, 1), - new Edge(5, 3, 5), - new Edge(5, 6, 7), - new Edge(6, 7, 1), - new Edge(6, 8, 4), - new Edge(7, 8, 6), - new Edge(9, 8, 0), + new Edge(0, 1, 1), + new Edge(1, 2, 7), + new Edge(2, 3, 2), + new Edge(0, 4, 4), + new Edge(1, 5, 3), + new Edge(2, 6, 5), + new Edge(3, 7, 6), + new Edge(4, 5, 8), + new Edge(5, 6, 2), + new Edge(6, 7, 9), }; - Boruvkas solver = new Boruvkas(10, g); + Boruvkas solver = new Boruvkas(8, g); Long cost = solver.getMstCost(); if (cost != null) { - System.out.println("MST cost: " + cost); // 14 + System.out.println("MST cost: " + cost); // 23 for (Edge e : solver.getMst()) { - System.out.println(e); + System.out.printf("Edge %d-%d, cost: %d%n", e.u, e.v, e.cost); } } else { System.out.println("No MST exists"); diff --git a/src/test/java/com/williamfiset/algorithms/graphtheory/BoruvkasTest.java b/src/test/java/com/williamfiset/algorithms/graphtheory/BoruvkasTest.java index 4d0585c65..266f24ea3 100644 --- a/src/test/java/com/williamfiset/algorithms/graphtheory/BoruvkasTest.java +++ b/src/test/java/com/williamfiset/algorithms/graphtheory/BoruvkasTest.java @@ -58,32 +58,23 @@ public void testDisconnectedGraph() { @Test public void testExampleFromMainMethod() { - int n = 10, m = 18, i = 0; - Edge[] g = new Edge[m]; - - g[i++] = new Edge(0, 1, 5); - g[i++] = new Edge(0, 3, 4); - g[i++] = new Edge(0, 4, 1); - g[i++] = new Edge(1, 2, 4); - g[i++] = new Edge(1, 3, 2); - g[i++] = new Edge(2, 7, 4); - g[i++] = new Edge(2, 8, 1); - g[i++] = new Edge(2, 9, 2); - g[i++] = new Edge(3, 6, 11); - g[i++] = new Edge(3, 7, 2); - g[i++] = new Edge(4, 3, 2); - g[i++] = new Edge(4, 5, 1); - g[i++] = new Edge(5, 3, 5); - g[i++] = new Edge(5, 6, 7); - g[i++] = new Edge(6, 7, 1); - g[i++] = new Edge(6, 8, 4); - g[i++] = new Edge(7, 8, 6); - g[i++] = new Edge(9, 8, 0); - - Boruvkas solver = new Boruvkas(n, g); - - assertThat(solver.getMstCost()).isEqualTo(14L); - assertThat(solver.getMst()).hasSize(n - 1); + Edge[] g = { + new Edge(0, 1, 1), + new Edge(1, 2, 7), + new Edge(2, 3, 2), + new Edge(0, 4, 4), + new Edge(1, 5, 3), + new Edge(2, 6, 5), + new Edge(3, 7, 6), + new Edge(4, 5, 8), + new Edge(5, 6, 2), + new Edge(6, 7, 9), + }; + + Boruvkas solver = new Boruvkas(8, g); + + assertThat(solver.getMstCost()).isEqualTo(23L); + assertThat(solver.getMst()).hasSize(7); } @Test From 5a4d9669584262d4d4611054bf9664cf8b5c6955 Mon Sep 17 00:00:00 2001 From: William Fiset Date: Sun, 15 Mar 2026 23:05:20 -0700 Subject: [PATCH 4/5] Simplify solve loop and move mst init to constructor Co-Authored-By: Claude Opus 4.6 --- .../algorithms/graphtheory/Boruvkas.java | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/williamfiset/algorithms/graphtheory/Boruvkas.java b/src/main/java/com/williamfiset/algorithms/graphtheory/Boruvkas.java index 8dda78e02..607dc05ab 100644 --- a/src/main/java/com/williamfiset/algorithms/graphtheory/Boruvkas.java +++ b/src/main/java/com/williamfiset/algorithms/graphtheory/Boruvkas.java @@ -49,6 +49,7 @@ public Boruvkas(int n, Edge[] graph) { } this.graph = graph; this.n = n; + this.mst = new ArrayList<>(); } /** @@ -72,12 +73,10 @@ private void solve() { return; } - mst = new ArrayList<>(); UnionFind uf = new UnionFind(n); while (uf.components > 1) { Edge[] cheapest = new Edge[n]; - boolean merged = false; // For each edge, track the cheapest crossing edge for each component. for (Edge e : graph) { @@ -95,22 +94,16 @@ private void solve() { } // Merge components using their cheapest crossing edges. - for (int i = 0; i < n; i++) { - Edge e = cheapest[i]; - if (e == null) { - continue; - } - int root1 = uf.find(e.u); - int root2 = uf.find(e.v); - if (root1 != root2) { - uf.union(root1, root2); + int prevComponents = uf.components; + for (Edge e : cheapest) { + if (e != null && uf.find(e.u) != uf.find(e.v)) { + uf.union(e.u, e.v); mst.add(e); minCostSum += e.cost; - merged = true; } } - if (!merged) { + if (uf.components == prevComponents) { break; } } From 96e9813445fcbe6353dcc1bb91e7628cb4756cd2 Mon Sep 17 00:00:00 2001 From: William Fiset Date: Mon, 16 Mar 2026 09:05:18 -0700 Subject: [PATCH 5/5] Return Optional instead of null for MST and cost Co-Authored-By: Claude Opus 4.6 --- .../algorithms/graphtheory/Boruvkas.java | 22 +++--- .../algorithms/graphtheory/BoruvkasTest.java | 67 +++++++++---------- 2 files changed, 45 insertions(+), 44 deletions(-) diff --git a/src/main/java/com/williamfiset/algorithms/graphtheory/Boruvkas.java b/src/main/java/com/williamfiset/algorithms/graphtheory/Boruvkas.java index 607dc05ab..331bcba7c 100644 --- a/src/main/java/com/williamfiset/algorithms/graphtheory/Boruvkas.java +++ b/src/main/java/com/williamfiset/algorithms/graphtheory/Boruvkas.java @@ -23,6 +23,8 @@ import java.util.ArrayList; import java.util.List; +import java.util.Optional; +import java.util.OptionalLong; public class Boruvkas { @@ -53,19 +55,19 @@ public Boruvkas(int n, Edge[] graph) { } /** - * Returns the edges in the MST, or null if the graph is disconnected. + * Returns the edges in the MST, or empty if the graph is disconnected. */ - public List getMst() { + public Optional> getMst() { solve(); - return mstExists ? mst : null; + return mstExists ? Optional.of(mst) : Optional.empty(); } /** - * Returns the total cost of the MST, or null if the graph is disconnected. + * Returns the total cost of the MST, or empty if the graph is disconnected. */ - public Long getMstCost() { + public OptionalLong getMstCost() { solve(); - return mstExists ? minCostSum : null; + return mstExists ? OptionalLong.of(minCostSum) : OptionalLong.empty(); } private void solve() { @@ -143,10 +145,10 @@ public static void main(String[] args) { Boruvkas solver = new Boruvkas(8, g); - Long cost = solver.getMstCost(); - if (cost != null) { - System.out.println("MST cost: " + cost); // 23 - for (Edge e : solver.getMst()) { + OptionalLong cost = solver.getMstCost(); + if (cost.isPresent()) { + System.out.println("MST cost: " + cost.getAsLong()); // 23 + for (Edge e : solver.getMst().get()) { System.out.printf("Edge %d-%d, cost: %d%n", e.u, e.v, e.cost); } } else { diff --git a/src/test/java/com/williamfiset/algorithms/graphtheory/BoruvkasTest.java b/src/test/java/com/williamfiset/algorithms/graphtheory/BoruvkasTest.java index 266f24ea3..6c084c501 100644 --- a/src/test/java/com/williamfiset/algorithms/graphtheory/BoruvkasTest.java +++ b/src/test/java/com/williamfiset/algorithms/graphtheory/BoruvkasTest.java @@ -18,24 +18,24 @@ public void testNullGraphThrowsException() { public void testSingleNode() { Edge[] graph = new Edge[0]; Boruvkas solver = new Boruvkas(1, graph); - assertThat(solver.getMstCost()).isEqualTo(0L); - assertThat(solver.getMst()).isEmpty(); + assertThat(solver.getMstCost().getAsLong()).isEqualTo(0L); + assertThat(solver.getMst().get()).isEmpty(); } @Test public void testTwoNodesConnected() { Edge[] graph = new Edge[] {new Edge(0, 1, 5)}; Boruvkas solver = new Boruvkas(2, graph); - assertThat(solver.getMstCost()).isEqualTo(5L); - assertThat(solver.getMst()).hasSize(1); + assertThat(solver.getMstCost().getAsLong()).isEqualTo(5L); + assertThat(solver.getMst().get()).hasSize(1); } @Test public void testTwoNodesDisconnected() { Edge[] graph = new Edge[0]; Boruvkas solver = new Boruvkas(2, graph); - assertThat(solver.getMstCost()).isNull(); - assertThat(solver.getMst()).isNull(); + assertThat(solver.getMstCost().isEmpty()).isTrue(); + assertThat(solver.getMst().isEmpty()).isTrue(); } @Test @@ -43,8 +43,8 @@ public void testSimpleTriangle() { Edge[] graph = new Edge[] {new Edge(0, 1, 1), new Edge(1, 2, 2), new Edge(0, 2, 3)}; Boruvkas solver = new Boruvkas(3, graph); - assertThat(solver.getMstCost()).isEqualTo(3L); - assertThat(solver.getMst()).hasSize(2); + assertThat(solver.getMstCost().getAsLong()).isEqualTo(3L); + assertThat(solver.getMst().get()).hasSize(2); } @Test @@ -52,8 +52,8 @@ public void testDisconnectedGraph() { // Two separate components: {0,1} and {2,3} Edge[] graph = new Edge[] {new Edge(0, 1, 1), new Edge(2, 3, 2)}; Boruvkas solver = new Boruvkas(4, graph); - assertThat(solver.getMstCost()).isNull(); - assertThat(solver.getMst()).isNull(); + assertThat(solver.getMstCost().isEmpty()).isTrue(); + assertThat(solver.getMst().isEmpty()).isTrue(); } @Test @@ -73,8 +73,8 @@ public void testExampleFromMainMethod() { Boruvkas solver = new Boruvkas(8, g); - assertThat(solver.getMstCost()).isEqualTo(23L); - assertThat(solver.getMst()).hasSize(7); + assertThat(solver.getMstCost().getAsLong()).isEqualTo(23L); + assertThat(solver.getMst().get()).hasSize(7); } @Test @@ -85,8 +85,8 @@ public void testLinearGraph() { new Edge(0, 1, 1), new Edge(1, 2, 2), new Edge(2, 3, 3), new Edge(3, 4, 4) }; Boruvkas solver = new Boruvkas(5, graph); - assertThat(solver.getMstCost()).isEqualTo(10L); - assertThat(solver.getMst()).hasSize(4); + assertThat(solver.getMstCost().getAsLong()).isEqualTo(10L); + assertThat(solver.getMst().get()).hasSize(4); } @Test @@ -103,8 +103,8 @@ public void testCompleteGraphK4() { }; Boruvkas solver = new Boruvkas(4, graph); // MST should be: 0-1 (1), 1-2 (2), 0-3 (3) = 6 - assertThat(solver.getMstCost()).isEqualTo(6L); - assertThat(solver.getMst()).hasSize(3); + assertThat(solver.getMstCost().getAsLong()).isEqualTo(6L); + assertThat(solver.getMst().get()).hasSize(3); } @Test @@ -112,8 +112,8 @@ public void testGraphWithZeroWeightEdges() { Edge[] graph = new Edge[] {new Edge(0, 1, 0), new Edge(1, 2, 0), new Edge(2, 3, 0)}; Boruvkas solver = new Boruvkas(4, graph); - assertThat(solver.getMstCost()).isEqualTo(0L); - assertThat(solver.getMst()).hasSize(3); + assertThat(solver.getMstCost().getAsLong()).isEqualTo(0L); + assertThat(solver.getMst().get()).hasSize(3); } @Test @@ -121,8 +121,8 @@ public void testGraphWithNegativeWeightEdges() { Edge[] graph = new Edge[] {new Edge(0, 1, -5), new Edge(1, 2, -3), new Edge(0, 2, 10)}; Boruvkas solver = new Boruvkas(3, graph); - assertThat(solver.getMstCost()).isEqualTo(-8L); - assertThat(solver.getMst()).hasSize(2); + assertThat(solver.getMstCost().getAsLong()).isEqualTo(-8L); + assertThat(solver.getMst().get()).hasSize(2); } @Test @@ -137,8 +137,8 @@ public void testGraphWithEqualWeightEdges() { new Edge(0, 2, 5) }; Boruvkas solver = new Boruvkas(4, graph); - assertThat(solver.getMstCost()).isEqualTo(15L); - assertThat(solver.getMst()).hasSize(3); + assertThat(solver.getMstCost().getAsLong()).isEqualTo(15L); + assertThat(solver.getMst().get()).hasSize(3); } @Test @@ -149,8 +149,8 @@ public void testStarGraph() { new Edge(0, 1, 1), new Edge(0, 2, 2), new Edge(0, 3, 3), new Edge(0, 4, 4) }; Boruvkas solver = new Boruvkas(5, graph); - assertThat(solver.getMstCost()).isEqualTo(10L); - assertThat(solver.getMst()).hasSize(4); + assertThat(solver.getMstCost().getAsLong()).isEqualTo(10L); + assertThat(solver.getMst().get()).hasSize(4); } @Test @@ -160,10 +160,10 @@ public void testMstIsIdempotent() { Boruvkas solver = new Boruvkas(3, graph); // Call multiple times to verify idempotency - Long cost1 = solver.getMstCost(); - Long cost2 = solver.getMstCost(); - List mst1 = solver.getMst(); - List mst2 = solver.getMst(); + long cost1 = solver.getMstCost().getAsLong(); + long cost2 = solver.getMstCost().getAsLong(); + List mst1 = solver.getMst().get(); + List mst2 = solver.getMst().get(); assertThat(cost1).isEqualTo(cost2); assertThat(mst1).isEqualTo(mst2); @@ -191,8 +191,8 @@ public void testLargerGraph() { }; Boruvkas solver = new Boruvkas(9, graph); // Known MST cost for this classic graph - assertThat(solver.getMstCost()).isEqualTo(37L); - assertThat(solver.getMst()).hasSize(8); + assertThat(solver.getMstCost().getAsLong()).isEqualTo(37L); + assertThat(solver.getMst().get()).hasSize(8); } @Test @@ -206,9 +206,8 @@ public void testMstEdgesFormSpanningTree() { new Edge(0, 2, 5) }; Boruvkas solver = new Boruvkas(4, graph); - List mst = solver.getMst(); + List mst = solver.getMst().get(); - assertThat(mst).isNotNull(); assertThat(mst).hasSize(3); // Verify MST connects all nodes (using simple connectivity check) @@ -244,7 +243,7 @@ public void testParallelEdges() { }; Boruvkas solver = new Boruvkas(3, graph); // Should pick the minimum weight edge between 0 and 1 - assertThat(solver.getMstCost()).isEqualTo(5L); - assertThat(solver.getMst()).hasSize(2); + assertThat(solver.getMstCost().getAsLong()).isEqualTo(5L); + assertThat(solver.getMst().get()).hasSize(2); } }