Kruskal's Algorithm
Kruskal's Algorithm is a popular algorithm in computer science used to find the Minimum Spanning Tree (MST) of a connected, weighted graph. The Minimum Spanning Tree is a subset of the edges of a graph that connects all the vertices together, without any cycles, and with the minimum possible total edge weight.
Kruskal’s algorithm is a greedy algorithm, meaning it builds the solution incrementally by choosing the smallest available option at each step. It was developed by Joseph Kruskal in 1956 and is widely used in network design, circuit design, and other optimization problems.
A spanning tree of a graph is a subgraph that:
The Minimum Spanning Tree (MST) is a spanning tree where the sum of the edge weights is minimized.
Kruskal's algorithm works by sorting all the edges of the graph in non-decreasing order of their weight and adding them to the MST, provided they don’t form a cycle. The algorithm follows these steps:
Consider the following graph with 4 nodes and 5 edges:
10 15
A --------- B --------- C
| | |
| 5 | 7 | 8
| | |
D --------- E --------- F
9 6
The Minimum Spanning Tree will be formed by choosing the smallest weight edges that connect all vertices without forming a cycle.
Now, let’s take a look at how to implement Kruskal’s algorithm using Python and C++.
class DisjointSet:
def __init__(self, n):
self.parent = [i for i in range(n)]
self.rank = [0] * n
def find(self, x):
if self.parent[x] != x:
self.parent[x] = self.find(self.parent[x])
return self.parent[x]
def union(self, x, y):
rootX = self.find(x)
rootY = self.find(y)
if rootX != rootY:
# Union by rank
if self.rank[rootX] > self.rank[rootY]:
self.parent[rootY] = rootX
elif self.rank[rootX] < self.rank[rootY]:
self.parent[rootX] = rootY
else:
self.parent[rootY] = rootX
self.rank[rootX] += 1
def kruskal(n, edges):
disjoint_set = DisjointSet(n)
mst = []
edges.sort(key=lambda x: x[2]) # Sort edges by weight
for u, v, weight in edges:
if disjoint_set.find(u) != disjoint_set.find(v):
disjoint_set.union(u, v)
mst.append((u, v, weight))
return mst
# Sample usage
edges = [
(0, 1, 10), # (Node A, Node B, weight)
(0, 3, 5), # (Node A, Node D, weight)
(1, 2, 15), # (Node B, Node C, weight)
(1, 4, 7), # (Node B, Node E, weight)
(2, 5, 8), # (Node C, Node F, weight)
(3, 4, 9), # (Node D, Node E, weight)
(4, 5, 6) # (Node E, Node F, weight)
]
n = 6 # Number of nodes
mst = kruskal(n, edges)
print("Edges in the Minimum Spanning Tree:", mst)
Explanation:
DisjointSet
class implements the Union-Find data structure to efficiently track and merge sets of connected nodes.kruskal
function sorts the edges by weight and iterates through them to add edges to the MST if they don’t form a cycle (checked using Union-Find).
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class DisjointSet {
public:
vector<int> parent, rank;
DisjointSet(int n) {
parent.resize(n);
rank.resize(n, 0);
for (int i = 0; i < n; ++i) {
parent[i] = i;
}
}
int find(int x) {
if (parent[x] != x)
parent[x] = find(parent[x]);
return parent[x];
}
void unionSets(int x, int y) {
int rootX = find(x);
int rootY = find(y);
if (rootX != rootY) {
if (rank[rootX] > rank[rootY])
parent[rootY] = rootX;
else if (rank[rootX] < rank[rootY])
parent[rootX] = rootY;
else {
parent[rootY] = rootX;
rank[rootX]++;
}
}
}
};
struct Edge {
int u, v, weight;
bool operator<(const Edge& other) {
return weight < other.weight;
}
};
vector<Edge> kruskal(int n, vector<Edge>& edges) {
DisjointSet ds(n);
vector<Edge> mst;
sort(edges.begin(), edges.end()); // Sort edges by weight
for (const auto& edge : edges) {
if (ds.find(edge.u) != ds.find(edge.v)) {
ds.unionSets(edge.u, edge.v);
mst.push_back(edge);
}
}
return mst;
}
int main() {
vector<Edge> edges = {
{0, 1, 10}, // (Node A, Node B, weight)
{0, 3, 5}, // (Node A, Node D, weight)
{1, 2, 15}, // (Node B, Node C, weight)
{1, 4, 7}, // (Node B, Node E, weight)
{2, 5, 8}, // (Node C, Node F, weight)
{3, 4, 9}, // (Node D, Node E, weight)
{4, 5, 6} // (Node E, Node F, weight)
};
int n = 6; // Number of nodes
vector<Edge> mst = kruskal(n, edges);
cout << "Edges in the Minimum Spanning Tree:\n";
for (const auto& edge : mst) {
cout << "(" << edge.u << ", " << edge.v << ") with weight " << edge.weight << "\n";
}
return 0;
}
Explanation:
DisjointSet
class is the implementation of the Union-Find data structure, which is used to track and merge components.kruskal
function sorts the edges and adds edges to the MST if they don’t form a cycle.Time Complexity:
Space Complexity: O(V + E), where V is the number of vertices and E is the number of edges, as we need to store the graph and the Disjoint Set.
Kruskal’s algorithm has several real-world applications, including: