DSA
Minimum Spanning Tree: Kruskal's Algorithm
Graphs. Time O(ElogE), Space O(V+E).
Spanning Tree: Subset of edges of graph that forms a tree(acyclic), where every node is a part of tree.
- (Edges = Vertices-1)
- Shouldn't be disconnected
- Acyclic
- Multiple STs possible
Minimum Spanning Tree (MST): Spanning Tree that has minimum weight among all possible spanning Trees.
Aim is to craete a weighted, connected and undirected graph.
Kruskal's Algorithm#
Greedy Algorithm
- Suitable for Sparse Graph
- Use DSU
Intiution#
Kruskal's is a greedy algorithm: by always picking the globally smallest available edge that does not form a cycle, we build the MST from the cheapest connections first. The correctness relies on the "cut property" of MSTs — the minimum weight edge crossing any cut of the graph is always safe to include. Disjoint Set Union (DSU) is used to efficiently check in near-O(1) whether adding an edge would create a cycle (i.e., whether u and v already belong to the same component).
- Pick smallest weight edge that doesn't cause a cycle.
- For cycle detection between vertex u and v, use Union-Find (DSU with path compression + union by rank) — at most O(log V) per operation.
- Once V-1 edges are included, the MST is complete.
Algorithm#
- Sort all edges in increasing order of weight.
- Pick smallest edge
- Check if it forms a cycle
- No cycle: include egde
- cycle: doscard edge
- Repeat step 2, until V-1 edges are found.
Implementation#
class DSU {
vector<int> parent;
vector<int> rank;
public:
DSU(int n)
{
parent.resize(n);
rank.resize(n,0);
for(int i=0;i<n;i++)
parent[i]= i;
}
int find(int x)
{
if(x == parent[x])
return x;
return parent[x] = find(parent[x]);
}
void Union(int x, int y)
{
int x_rep = find(x);
int y_rep = find(y);
if(x_rep == y_rep)
return;
if(rank[x_rep] > rank[y_rep])
{
parent[y_rep] = x_rep;
}else if(rank[x_rep] < rank[y_rep]){
parent[x_rep] = y_rep;
}else{
parent[y_rep] = x_rep;
rank[x_rep]++;
}
}
};
struct Edge {
int u, v, weight;
Edge(int u, int v, int weight) : u(u), v(v), weight(weight) {}
};
class Solution {
public:
static bool cmp(const Edge &a, const Edge &b)
{
return a.weight < b.weight;
}
void preprocessAdjList(int V, vector<vector<int>> adj[], vector<Edge> &edges)
{
for(int i=0;i<V;i++)
{
for(auto neighbour: adj[i])
{
if(i<neighbour[0])
edges.push_back(Edge(i, neighbour[0], neighbour[1]));
}
}
}
// Function to find sum of weights of edges of the Minimum Spanning Tree.
int spanningTree(int V, vector<vector<int>> adj[]) {
vector<Edge> edges;
preprocessAdjList(V, adj, edges);
sort(edges.begin(), edges.end(), cmp);
DSU d(V);
int mstWeight=0;
for(auto edge: edges)
{
int u = edge.u;
int v = edge.v;
int wt = edge.weight;
if(d.find(u) != d.find(v))
{
mstWeight += wt;
d.Union(u,v);
}
}
return mstWeight;
}
};
Time Complexity: O(ElogE + VlogE) ~ O(ElogV) , Sort: O(ElogE), pick and check cycle: E x log(V)
Space Complexity: O(V+E)