Minimum Spanning Tree - Kruskal's Algorithm
What is Minimum Spanning Tree (MST)?
- A Minimum Spanning Tree (MST) is a subset of the edges of a connected, undirected and weighted graph. Thus MST is a tree.
- MST connects all the vertices/nodes of the graph together.
- MST does not contain any cycles.
- MST finds minimum edge weight.
- MST contains (V-1) edges, where V is the number of vertices/nodes in the graph.
- No. of Spanning Trees possible for a graph (caution: Here I am not talking about Minimum Spanning Tree, but Spanning Tree in general): [ |E|C|V-1| ] - [no. of cycles] ( here C is Combination of pnc)
- Kruskal's Algorithm uses a Disjoint Set Data Structure to find Minimum Spanning Tree.
- Kruskal's Algorithm is a greedy algorithm.
Kruskal's Algorithm
1. for each node perform makeSet() operation of disjoint set
2. sort each edge of the graph in non-decreasing order by weight
3. for each edge (u,v):
4. if findSet(u) != findSet(v) [This means if parent/representative of two disjoint sets is different]
5. perform union(u,v) operation of disjoint set
6. update minWeightEdge += weight of edge(u,v)
7. else if findSet(u) == findSet(v) [This means if parent/representative of two disjoint sets is same]
8. this means we have a cycle if we include edge(u,v) in our MST. so we skip this edge.
Code:
import java.util.*;
// The Graph Nodeclass GraphNode{ String data; // adjacent nodes ArrayList<GraphNode> neighbours; // weight od edges connecting this node to it's adjacent nodes HashMap<GraphNode,Integer> weightMap; // Constructor GraphNode(String x){ this.data = x; this.neighbours = new ArrayList<>(); this.weightMap = new HashMap<>(); } }
// class representing an undirected weighted edge between two nodes: 'firstNode' and 'secondNode'class UndirectedEdge{ GraphNode firstNode; GraphNode secondNode; // weight of edge int weight; // constructor UndirectedEdge(GraphNode x, GraphNode y, int wt){ this.firstNode = x; this.secondNode = y; this.weight = wt; }}
// class to represent a disjoint set containing a graph nodeclass DisjointSet{ GraphNode node; // rank of this disjont set int rank; // parent/representative of this disjoint set DisjointSet parent; // constructor DisjointSet(GraphNode node){ this.node = node; this.rank = 1; this.parent = null; }}
public class Main { // list to store all nodes ArrayList<GraphNode> nodesList; // list to store all edges in the graph ArrayList<UndirectedEdge> edgesList; // a hashmap that to get the disjoint set associated with a graphnode HashMap<GraphNode,DisjointSet> nodeDisjointSetMap; // constructor Main(){ this.nodesList = new ArrayList<>(); this.edgesList = new ArrayList<>(); this.nodeDisjointSetMap = new HashMap<>(); } // method to add an undirected weighted edge between nodes at index i and j of nodesList public void addUndirectedWeightedEdge(int i, int j, int weight){ GraphNode node1 = this.nodesList.get(i); GraphNode node2 = this.nodesList.get(j); // adding node 2 in neighbours of node1 node1.neighbours.add(node2); // adding node2 with weight in the weightmap of node 1 node1.weightMap.put(node2,weight); // similarly for node 2 as well node2.neighbours.add(node1); node2.weightMap.put(node1,weight); // adding the newly created edge into the edge list too this.edgesList.add(new UndirectedEdge(node1,node2,weight)); } // method to sort th undirected Weighted edges in edgesList on the basis of weight in non-decreasing order // this is done to ensure that we pick the least cost/weight edges for out minimum spanning tree. public void sortUndirectedEdgesByWeight(){ // we have to provide a comparator and overload the compareTo method to sort the arraylist containing 'UndirectedEdge' Comparator<UndirectedEdge> comparator = new Comparator<UndirectedEdge>() { @Override public int compare(UndirectedEdge o1, UndirectedEdge o2) { return o1.weight - o2.weight; } }; // finally sorting the edgesList on the basis of edge weight with the help of comparator Collections.sort(this.edgesList, comparator); } // method to do makeset operation of disjoint set public void makeSet(){ for(int i=0;i<this.nodesList.size();i++){ DisjointSet disJointSet = new DisjointSet(this.nodesList.get(i)); disJointSet.parent = disJointSet; nodeDisjointSetMap.put(this.nodesList.get(i),disJointSet); } } // mehod to implement find set method of disjoint set using path compression public DisjointSet find(DisjointSet node){ DisjointSet parent = node.parent; if(parent==node){ return parent; } else{ parent = find(parent); } node.parent = parent; return parent; } // method to find the union of two disjoint sets public int union(DisjointSet node1Set, DisjointSet node2Set){ DisjointSet parentNode1 = find(node1Set); DisjointSet parentNode2 = find(node2Set); // if same parent if(parentNode1==parentNode2){ // returning -1 indicates we have encountered a cycle return -1; } // if parents/representatives are different for both disjoint sets if(parentNode1.rank>=parentNode2.rank){ parentNode1.rank = parentNode1.rank + parentNode2.rank; parentNode2.parent = parentNode1; } else{ parentNode2.rank = parentNode2.rank + parentNode1.rank; parentNode1.parent = parentNode2; } return 0; } // method to implement Kruskal Algorithm to find Minimum Spanning Tree (MST) public void kruskal(){ makeSet(); sortUndirectedEdgesByWeight(); int totalWeight = 0; // for each edge in the graph for(int i=0;i<edgesList.size();i++){ UndirectedEdge currentEdge = this.edgesList.get(i); GraphNode node1 = currentEdge.firstNode; GraphNode node2 = currentEdge.secondNode; DisjointSet node1Set = this.nodeDisjointSetMap.get(node1); DisjointSet node2Set = this.nodeDisjointSetMap.get(node2); int unionSet = union(node1Set,node2Set); // if cycle exits if(unionSet==-1){ continue; } else{ System.out.println("Edge: " + node1.data + "------" + node2.data +" || weight= " + currentEdge.weight); totalWeight += currentEdge.weight; } } System.out.println("Total weight of MST: " + totalWeight); } public static void main(String[] args) throws Exception { Main graph = new Main(); // adding vertices/nodes for(int i=0;i<4;i++){ graph.nodesList.add(new GraphNode("V"+i)); } // adding undirected, weighted edges graph.addUndirectedWeightedEdge(0,1,10); graph.addUndirectedWeightedEdge(1,3,15); graph.addUndirectedWeightedEdge(3,2,4); graph.addUndirectedWeightedEdge(2,0,6); graph.addUndirectedWeightedEdge(3,0,5); graph.kruskal(); }}
Output:
Edge: V3------V2 || weight= 4
Edge: V3------V0 || weight= 5
Edge: V0------V1 || weight= 10
Total weight of MST: 19
Comments
Post a Comment