Minimum Spanning Tree Kruskal's Algorithm in DSA Go - Time & Space Complexity
We want to understand how the time needed to find a minimum spanning tree using Kruskal's algorithm changes as the graph grows.
Specifically, how does the number of edges and vertices affect the work done?
Analyze the time complexity of the following code snippet.
// Kruskal's algorithm to find MST
func Kruskal(edges []Edge, n int) []Edge {
sort.Slice(edges, func(i, j int) bool {
return edges[i].weight < edges[j].weight
})
uf := NewUnionFind(n)
mst := []Edge{}
for _, e := range edges {
if uf.Find(e.u) != uf.Find(e.v) {
uf.Union(e.u, e.v)
mst = append(mst, e)
}
}
return mst
}
This code sorts all edges by weight, then adds edges to the MST if they connect different sets, using union-find to check.
- Primary operation: Sorting all edges and iterating over them once.
- How many times: Sorting takes about E log E steps for E edges; the loop runs E times.
- Union-Find operations happen up to E times, each almost constant time.
As the number of edges grows, sorting takes more time, roughly increasing by the number of edges times the log of edges.
| Input Size (Edges E) | Approx. Operations |
|---|---|
| 10 | About 10 * log 10 ≈ 33 |
| 100 | About 100 * log 100 ≈ 664 |
| 1000 | About 1000 * log 1000 ≈ 9965 |
Pattern observation: The work grows faster than just the number of edges, but slower than edges squared.
Time Complexity: O(E log E)
This means the time grows roughly proportional to the number of edges times the logarithm of edges, mainly due to sorting.
[X] Wrong: "The algorithm runs in linear time because it just loops over edges once."
[OK] Correct: Sorting the edges before looping takes extra time that grows faster than just looping, so the sorting step dominates.
Understanding Kruskal's time complexity shows you can analyze how sorting and union-find affect performance, a key skill for graph problems.
"What if we used a different data structure that made sorting unnecessary? How would the time complexity change?"
Practice
Solution
Step 1: Understand the purpose of Kruskal's Algorithm
Kruskal's Algorithm is designed to connect all nodes in a graph with edges that have the smallest total weight without forming cycles.Step 2: Compare with other graph algorithms
Unlike shortest path or cycle detection, Kruskal's focuses on building a minimum spanning tree, which is a tree connecting all vertices with minimum edge sum.Final Answer:
To find the minimum spanning tree connecting all vertices with the least total edge weight -> Option BQuick Check:
Minimum Spanning Tree = Kruskal's Goal [OK]
- Confusing MST with shortest path
- Thinking Kruskal detects cycles only
- Assuming it sorts vertices
Solution
Step 1: Identify the correct data structure for edges
Kruskal's Algorithm requires edges with two vertices and a weight, so a slice of Edge structs is appropriate.Step 2: Check each option's suitability
edges := []Edge{{0, 1, 10}, {1, 2, 5}, {0, 2, 15}} correctly creates a slice of Edge structs with start, end, and weight. Options A, C, and D do not represent edges properly.Final Answer:
edges := []Edge{{0, 1, 10}, {1, 2, 5}, {0, 2, 15}} -> Option AQuick Check:
Slice of Edge structs = Correct initialization [OK]
- Using map instead of slice for edges
- Using simple int slices without struct
- Incorrect initialization syntax
type Edge struct {
u, v, weight int
}
func main() {
edges := []Edge{{0,1,4}, {0,2,3}, {1,2,1}, {1,3,2}, {2,3,4}, {3,4,2}}
// Assume union-find and sorting implemented correctly
// MST edges chosen: (1,2), (1,3), (3,4), (0,2)
totalWeight := 1 + 2 + 2 + 3
fmt.Println(totalWeight)
}Solution
Step 1: Sum the weights of chosen MST edges
The edges chosen are (1,2)=1, (1,3)=2, (3,4)=2, (0,2)=3. Adding these: 1 + 2 + 2 + 3 = 8.Step 2: Verify the total weight printed
The code sums these weights and prints totalWeight. The sum is 8, which corresponds to 8.Step 3: Recalculate carefully
1 + 2 = 3, 3 + 2 = 5, 5 + 3 = 8. So total is 8.Final Answer:
8 -> Option DQuick Check:
Sum MST edges weights = 8 [OK]
- Adding weights incorrectly
- Confusing edges chosen
- Ignoring union-find correctness
type Edge struct {
u, v, weight int
}
func find(parent []int, i int) int {
if parent[i] == i {
return i
}
return find(parent, parent[i])
}
func union(parent []int, x, y int) {
xset := find(parent, x)
yset := find(parent, y)
parent[xset] = yset
}
func main() {
edges := []Edge{{0,1,10}, {0,2,6}, {0,3,5}, {1,3,15}, {2,3,4}}
parent := make([]int, 4)
for i := 0; i < 4; i++ {
parent[i] = i
}
// Missing sorting edges by weight
for _, edge := range edges {
x := find(parent, edge.u)
y := find(parent, edge.v)
if x != y {
union(parent, x, y)
fmt.Println(edge)
}
}
}Solution
Step 1: Check the Kruskal's Algorithm requirements
Kruskal's requires edges to be sorted by weight ascending before processing to ensure minimum total weight.Step 2: Analyze the code for sorting
The code does not sort edges before the loop, so edges are processed in input order, which can lead to incorrect MST.Final Answer:
Edges are not sorted by weight before processing -> Option AQuick Check:
Sorting edges first = Required for correct MST [OK]
- Skipping edge sorting
- Ignoring union-find path compression
- Incorrect parent initialization
(0,1,4), (0,2,3), (1,2,1), (1,3,2), (2,3,4), (3,4,2), (4,5,6), (3,5,1)Using Kruskal's Algorithm, which edges will be included in the minimum spanning tree?
Solution
Step 1: Sort edges by weight ascending
Edges sorted: (1,2,1), (3,5,1), (1,3,2), (3,4,2), (0,2,3), (0,1,4), (2,3,4), (4,5,6)Step 2: Pick edges without forming cycles
Pick (1,2), (3,5), (1,3), (3,4), (0,2) - these connect all vertices without cycles. Skip (4,5) as it forms a cycle (4 and 5 already connected via 3).Final Answer:
(1,2), (1,3), (3,5), (3,4), (0,2) -> Option CQuick Check:
Sorted edges + no cycles = MST edges [OK]
- Including edges that form cycles
- Not sorting edges properly
- Missing last vertex connection
Ready to prove it?
Pass the test and this pattern moves unknown
