Sahithyan's S2 — Data Structures and Algorithms
Kruskal's Algorithm
A greedy algorithm to find MST of a graph. Sorts all edges by increasing weights and adds them one by one to the MST, ensuring that no cycles are formed.
Steps
- Sort Edges: All edges are sorted by their weights in ascending order.
- Initialize Union-Find: To manage the connected components of the graph.
- Iterate through edges: For each edge in the sorted list:
- Check if the edge connects two different components using the Union-Find structure.
- If it does, add the edge to the MST and merge the two components.
- If it forms a cycle, skip the edge.
- Stop When MST is Complete: The algorithm stops when the MST contains exactly
edges
Implementation
#include <iostream>#include <vector>#include <algorithm>
using namespace std;
// Structure to represent an edge in the graphstruct Edge { int src, dest, weight;};
// Comparator function to sort edges by weight in non-decreasing orderbool compareEdges(const Edge &a, const Edge &b) { return a.weight < b.weight;}
// Union-Find data structure to detect cyclesclass UnionFind { vector<int> parent, rank;
public: UnionFind(int n) : parent(n), rank(n, 0) { for (int i = 0; i < n; ++i) { parent[i] = i; } }
int find(int u) { if (u != parent[u]) { parent[u] = find(parent[u]); // Path compression } return parent[u]; }
bool unionSets(int u, int v) { int rootU = find(u); int rootV = find(v);
if (rootU == rootV) { return false; // Cycle detected }
// Union by rank if (rank[rootU] > rank[rootV]) { parent[rootV] = rootU; } else if (rank[rootU] < rank[rootV]) { parent[rootU] = rootV; } else { parent[rootV] = rootU; rank[rootU]++; }
return true; }};
// Function to implement Kruskal's Algorithm to find the MSTvoid kruskalMST(int V, vector<Edge> &edges) { // Step 1: Sort all edges in non-decreasing order of their weight sort(edges.begin(), edges.end(), compareEdges);
UnionFind uf(V); vector<Edge> result; // To store the edges included in the MST
// Iterate through all sorted edges for (const auto &edge : edges) { // Check if adding this edge forms a cycle if (uf.unionSets(edge.src, edge.dest)) { result.push_back(edge); // Include the edge in the MST }
// Stop if we already have V-1 edges in the MST if (result.size() == V - 1) { break; } }
// Print the edges in the constructed MST cout << "Following are the edges in the constructed MST\n"; for (const auto &edge : result) { cout << edge.src << " -- " << edge.dest << " == " << edge.weight << "\n"; }}
int main() { int V = 6; vector<Edge> edges = { {0, 1, 1}, {1, 2, 2}, {0, 4, 3}, {0, 3, 4}, {1, 4, 5}, {2, 5, 6}, {3, 4, 7}, {4, 5, 8} };
kruskalMST(V, edges);
return 0;}
Example
-
Sort the edges by weight:
- (A-B, 1), (B-C, 2), (A-E, 3), (A-D, 4), (B-E, 5), (C-F, 6), (D-E, 7), (E-F, 8)
-
Add edges to the MST, ensuring no cycles are formed:
- Add (A-B, 1)
- Add (B-C, 2)
- Add (A-E, 3)
- Add (A-D, 4)
- Add (C-F, 6)
The resulting MST will have the edges: (A-B, 1), (B-C, 2), (A-E, 3), (A-D, 4), (C-F, 6).
Time and Space Complexity
Time Complexity
- Sorting all edges: Takes
. Since is equivalent to in a connected graph, this step dominates the overall complexity. - Union-Find operations: The union-find data structure is used to detect cycles and merge sets. Each union or find operation has an amortized time complexity of
, where is the inverse Ackermann function, which grows extremely slowly. For edges, the total complexity of union-find operations is .
Thus, the overall time complexity of Kruskal’s Algorithm is:
Space Complexity
- Edge list:
is required to store all edges. - Union-Find data structure: The parent and rank arrays used in the union-find operations require
space.
Therefore, the total space complexity is: