Kruskal’s Minimum Spanning Tree Implementation | by Karan Kharecha | Towards Data Science

Graph is a non linear data structure that has nodes and edges. Minimum Spanning Tree is a set of edges in an undirected weighted graph that connects all the vertices with no cycles and minimum total edge weight. For finding the spanning tree, Kruskal’s algorithm is the simplest one. This content is about implementing the algorithm for undirected weighted graph.
First step is to create two classes GraphNode and Edge.
class GraphNode {    String alias;                     // it is a label of node    Object data;                      // data that is stored in node        GraphNode(String alias, Object data) {       this.alias = alias;       this.data = data;    }}class Edge {    GraphNode src;                  // edge's origin    GraphNode dest;                 // edge's end    Integer cost;                   // cost of the edge    Edge(GraphNode src, GraphNode dest, Integer cost) {        this.src = src;        this.dest = dest;        this.cost = cost;    }}
A class named Graph is created that will have methods and several data structures. For ease, Java’s library guava is used for various Sets operations.
HashSet<HashSet<String>> universalNodes = new HashSet<>();HashSet<String> subSet1,subSet2;HashSet<HashSet<String>> kUniversal = new HashSet<>();Integer totalCost;ArrayList<Edge> kruskalEdges = new ArrayList<>();
Following are the methods in class Graph:
public void addEdge(GraphNode src,GraphNode dest,Integer cost) {    universalNodes.add(Sets.newHashSet(src.alias));    universalNodes.add(Sets.newHashSet(dest.alias));    kruskalEdges.add(new Edge(src, dest, cost));}public ArrayList<Edge> kruskalMST() {    totalCost = 0;    kUniversal = new HashSet<>(universalNodes);    int edgesLimit = kUniversal.size() - 1;    ArrayList<Edge> MSTEdges = new ArrayList<>();    kruskalEdges.sort(Comparator.comparing(edge -> edge.cost));    for(Edge edge: kruskalEdges){        if (MSTEdges.size() == edgesLimit) break;        if (isAcyclic(edge.src.alias, edge.dest.alias)) {            kUniversal.add(Sets.newHashSet(Sets.union(subSet1,                                                           subSet2)))            kUniversal.remove(subSet1);            kUniversal.remove(subSet2);            MSTEdges.add(edge);            totalCost += edge.cost;        }    }    return MSTEdges;}public boolean isAcyclic(String srcAlias, String destAlias) {    subSet1 = new HashSet<>();    subSet2 = new HashSet<>();    HashSet<HashSet<String>> targetSet;    targetSet = kUniversal;        for (HashSet<String> subSet : targetSet) {        if (subSet.contains(srcAlias)) subSet1 = subSet;        if (subSet.contains(destAlias)) subSet2 = subSet;        if (subSet1 == subSet2) return false;    }    return true;}
Description of all three methods:
A) addEdge(GraphNode src, GraphNode dest, Integer cost):This method has 3 arguments that denotes source, destination and cost of the edge. It adds edge to the list named kruskalEdges. Along with this, when edges are being added, the nodes are appended as Set in a Set called universalNodes. Hereby, kruskalEdges contains list of all the edges that a graph has, whereas universalNodes contains all unique node sets. For an instance, universalNodes would look like:
universalNodes = { {node1}, {node2}, {node3}........ {node n}}Here, each node is stored as a Set so that it becomes further easy to check whether the spanning tree forms a cycle.
B) kruskalMST():Initially, kUniversal set is created that is nothing but a copy of universalNodes, which will be used to find if selected edge forms a cycle if appended to the spanning tree. Variable named edgesLimit is the number of total possible edges. If the graph has n nodes then minimum spanning tree will contain n-1 edges. Next, MSTEdges contains edges that are to be selected in the spanning tree.
A loop iterates through kruskalEdges but first it checks whether the spanning tree has n-1 edges. If true, then the loop breaks, else it checks if the current edge forms a cycle, using the method isAcyclic(..).
If its acyclic then, kUniversal adds a new set which is the union of two subsets. These subsets are set of edges that are selected previously. For example, consider following iterative steps and changes in kruskalEdges.→ {{node1}, {node2}, {node3}, {node 4}, {node 5}}→ {{node1, node3}, {node2}, {node4}, {node5}}→ {{node1, node3}, {node2}, {node4, node5}}→{{node1, node3, node2}, {node4, node5}}
After completion of the loop, a list of edges is returned that is considered as Minimum Spanning Tree.
C) isAcyclic(String srcAlias, String destAlias):Firstly, subSet1 and subSet2 are created. Loop iterates through kUniversal and updates aforementioned two sets when src or dest node is found. If they belong in the same set then that edge is responsible for forming a cycle and hence the method will return false, otherwise true.
Following lines of code builds a graph mentioned in Fig. 1:
// Create object of class GraphGraph testGraph = new Graph();// here second argument is data for node, it is optional and not// required currently for spanning tree. Data can be anything.// String, integer, custom class object, etc.// Create objects of class GraphNodeGraphNode A = new GraphNode("A", "Data for node A");GraphNode B = new GraphNode("B", "Data for node B");GraphNode C = new GraphNode("C", "Data for node C");....GraphNode J = new GraphNode("J", "Data for node J");// Add edges to the testGraph, as per the above image (Fig.1)testGraph.addEdge(A, B, 3);testGraph.addEdge(E, A, 9);testGraph.addEdge(A, D, 6);....testGraph.addEdge(E, F, 8);// Print MSTEdges, the list that has all the edges and lastly, total // cost of minimum spanning treefor (Edge edge: testGraph.kruskalMST()) {    System.out.println(edge.src.alias + " - " + edge.dest.alias + "                                                     : " + edge.cost);}System.out.println(testGraph.getTotalCost());
Final Result with total cost of 38 units:
Link to the entire program: Graph.java