Skip to main content

Overview

A Minimum Spanning Tree (MST) is a subset of edges in a weighted undirected graph that connects all vertices with minimum total edge weight and no cycles. Kruskal’s algorithm efficiently finds the MST using a greedy approach with Disjoint Set Union.

Kruskal’s Algorithm

Kruskal’s algorithm builds the MST by:
  1. Sorting all edges by weight in ascending order
  2. Adding edges one by one if they don’t create a cycle
  3. Using DSU to efficiently detect cycles

Implementation

// graph_graph
// graph_undigraph
// graph_dsu

template <typename T>
vector<edge<T>> find_kruskal(const undigraph<T> &g, T &ans) {
    vector<edge<T>> edges(g.edges);
    sort(edges.begin(), edges.end(), [&g](const edge<T> &a, const edge<T> &b) {
        return a.cost < b.cost;
    });
    ans = 0;
    vector<edge<T>> mst;
    DisjointSet dsu(g.n);
    for(edge<T> e : edges) {
        if(dsu.unite(e.from, e.to)) {
            mst.push_back(e);
            ans += e.cost;
        }
    }
    return mst;
}

Usage Example

// Create an undirected graph
int n = 5;
undigraph<int> g(n);

// Add edges: (from, to, cost)
g.add(0, 1, 2);
g.add(0, 3, 6);
g.add(1, 2, 3);
g.add(1, 3, 8);
g.add(1, 4, 5);
g.add(2, 4, 7);
g.add(3, 4, 9);

// Find MST
int total_cost = 0;
vector<edge<int>> mst = find_kruskal(g, total_cost);

cout << "MST Cost: " << total_cost << "\n";
cout << "MST Edges:\n";
for(auto &e : mst) {
    cout << e.from << " - " << e.to << " (cost: " << e.cost << ")\n";
}
Output:
MST Cost: 16
MST Edges:
0 - 1 (cost: 2)
1 - 2 (cost: 3)
1 - 4 (cost: 5)
0 - 3 (cost: 6)
Time Complexity: O(E log E) for sorting + O(E × α(V)) for DSU operations ≈ O(E log E)Space Complexity: O(E) for storing edgeswhere α is the inverse Ackermann function (effectively constant)

Disjoint Set Union (DSU)

Kruskal’s algorithm relies on DSU for efficient cycle detection. The DSU implementation is included:
class DisjointSet {
    int n;
    vector<int> parents;
    vector<int> sizes;
public:
    
    int comps;  // Number of connected components
 
    DisjointSet(int _n): n(_n), parents(n), sizes(n), comps(n) {
        fill(sizes.begin(), sizes.end(), 1);
        iota(parents.begin(), parents.end(), 0);
    }
 
    int find(int x) { 
        assert(0 <= x && x < n);
        if (parents[x] != x)
            parents[x] = find(parents[x]); 
        return parents[x]; 
    }
 
    bool unite(int left, int right) {
        assert(0 <= left && left < n);
        assert(0 <= right && right < n); 
        int x = find(left);
        int y = find(right);
        if(x == y)
            return false;
        if(sizes[x] < sizes[y])
            swap(x, y);
        sizes[x] += sizes[y];
        parents[y] = x;
        comps--;
        return true;
    };
 
    bool united(int left, int right) {
        assert(0 <= left && left < n);
        assert(0 <= right && right < n);
        return find(left) == find(right);
    }
 
    int size(int x) {
        assert(0 <= x && x < n);
        return sizes[find(x)];
    }
 
    int id(int x) {
        assert(0 <= x && x < n);
        return parents[find(x)];
    }
};

using DSU = DisjointSet;

DSU Operations

  • find(x): Returns the representative of the set containing x - O(α(n))
  • unite(x, y): Merges the sets containing x and y - O(α(n))
  • united(x, y): Checks if x and y are in the same set - O(α(n))
  • size(x): Returns the size of the set containing x - O(α(n))
  • comps: Tracks the number of connected components

Complete Example

#include <bits/stdc++.h>
using namespace std;

// Include graph structures and DSU
// ... (graph definitions)
// ... (DSU definition)
// ... (find_kruskal function)

int main() {
    int n, m;
    cin >> n >> m;  // nodes and edges
    
    undigraph<long long> g(n);
    
    for(int i = 0; i < m; ++i) {
        int u, v;
        long long w;
        cin >> u >> v >> w;
        g.add(u, v, w);
    }
    
    long long mst_cost = 0;
    vector<edge<long long>> mst = find_kruskal(g, mst_cost);
    
    // Check if we have a spanning tree
    if(mst.size() == n - 1) {
        cout << "MST exists with cost: " << mst_cost << "\n";
    } else {
        cout << "Graph is not connected\n";
    }
    
    return 0;
}
A spanning tree of a graph with n vertices must have exactly n-1 edges. Check mst.size() == n - 1 to verify the graph is connected.

Properties of MST

  1. Uniqueness: If all edge weights are distinct, the MST is unique
  2. Edges: An MST of a graph with n vertices has exactly n-1 edges
  3. Connectivity: The MST connects all vertices with minimum total weight
  4. Cycle Property: For any cycle in the graph, the maximum weight edge is not in any MST

Common Applications

  • Network Design: Connecting cities with minimum cable length
  • Clustering: Grouping data points by removing expensive edges
  • Approximation Algorithms: TSP approximations
  • Image Segmentation: Computer vision applications
Kruskal’s algorithm only works on undirected graphs. For directed graphs, consider using the Chu-Liu/Edmonds’ algorithm for minimum spanning arborescence.

Build docs developers (and LLMs) love