diff --git a/graph/kruskals/Readme.md b/graph/kruskals/Readme.md new file mode 100644 index 0000000..8df32a4 --- /dev/null +++ b/graph/kruskals/Readme.md @@ -0,0 +1,92 @@ +# Kruskal Algorithm for Minimum Spanning Tree + +A Minimum Spanning Tree is a tree that include all the vertex of a graph such that the total sum of all the edges are minimized. Kruskal alogorithm suggest a greedy approach for this, We sorts all the edges in non decreasing way and keep selecting the minimum edges and adding it to our MST. When we add an Edge to existing MST it should not form a cycle. + +Let's look at it with example. +Suppose we have a graph as described below +``` + + 0 -------[4]----------- 1 -----[8]------ 2 + | | + | | + [8] -- [7] -------- 5 ------[2]-----| + | / | + | / [6] + | / | + 3 ------[1]-------- 4 ---| +``` + +it can be summarized as +``` + Vertex From Vertex To Weight + 0 1 4 + 0 3 8 + 1 2 8 + 2 5 2 + 3 4 1 + 4 5 6 + 5 3 7 + +``` + +Our Aim is to find the Minimum Spanning Tree From this Graph. +First we will Sort the Edges in a non decreasing order. After sorting in non decreasing order we would have following order of edges. +``` + Vertex From Vertex To Weight + 3 4 1 + 2 5 2 + 0 1 4 + 4 5 6 + 5 3 7 + 0 3 8 + 1 2 8 + +``` +Now we will Select the minimum edges one by one try to add it to the MST if it does not form a cycle +then we will add it to the MST else we will skip that edge. + +The first edge we select is +``` + + 3-------[1]-------- 4 + + current MST. total weight 1 +``` + +Then we move to next minimum edge. Similarly If we keep repeating at some point after adding 4 edges we will have our MST like this +``` + 0 -------[4]----------- 1 2 + | + | + 5 ------[2]-----| + | + [6] + | + 3 ------[1]-------- 4 ---| +``` + +now the next minim edge is 5-3 with weight 7 but addding it will make a cycle so we will skip this edge. We will then try to add the edge 0-3 [weight=8] + +``` + 0 -------[4]----------- 1 -----[8]------ 2 + | + | + 5 ------[2]-----| + | + [6] + | + 3 ------[1]-------- 4 ---| + + Total Weight : 21 +``` +Thus we have obtained out Minimum Spanning Tree. + + + +# Algorithm + +The algorithm for kruskal works following way +1. Sort all the edges in non-decreasing order of their weight. +2. Pick the smallest edge. Check if it forms a cycle with the spanning tree formed so far. If cycle is not formed, include this edge. Else, discard it. +3. Repeat step#2 until there are (V-1) edges in the spanning tree. + diff --git a/graph/kruskals/kruskals.go b/graph/kruskals/kruskals.go new file mode 100644 index 0000000..345dfdc --- /dev/null +++ b/graph/kruskals/kruskals.go @@ -0,0 +1,166 @@ +package graph + +import ( + "fmt" + "sort" +) + +//======================================== Graph Structure Implementation starts========================================// + +//Edge => an edge struct which represent a edge from vertex A to vertex B having X Weight +type Edge struct { + From int + To int + Weight int +} + +//Graph => graph data structure +type Graph struct { + vertices int + edges [][]Edge +} + +//Initialize => initializes the graph +func (g *Graph) Initialize(vertices int) { + + //set the vertices we have + g.vertices = vertices + + // initialize the vertices + if g.edges == nil { + g.edges = make([][]Edge, vertices) + } + + //initialize each vertex as an empty array + for i := 0; i < vertices; i++ { + g.edges[i] = []Edge{} + } +} + +//AddEdge => weighted edge add +func (g *Graph) AddEdge(u int, v int, w int) { + currEdge := Edge{u, v, w} + + //for undirected graph both should have the entry + currEdgeU := Edge{v, u, w} + + //set the v is reachabe from u + g.edges[u] = append(g.edges[u], currEdge) + g.edges[v] = append(g.edges[v], currEdgeU) + +} + +//Print the graph to see the Adjacency List +func (g *Graph) Print() { + + for i := range g.edges { + fmt.Printf("%v\n", g.edges[i]) + } + +} + +//========================================= Graph Implementation Ends Here =======================================// + +/* +# A utility function to find set of an element i + + + # A function that does union of two sets of x and y + # (uses union by rank) + def union(self, parent, rank, x, y): + xroot = self.find(parent, x) + yroot = self.find(parent, y) + + # Attach smaller rank tree under root of + # high rank tree (Union by Rank) + if rank[xroot] < rank[yroot]: + parent[xroot] = yroot + elif rank[xroot] > rank[yroot]: + parent[yroot] = xroot + + # If ranks are same, then make one as root + # and increment its rank by one + else : + parent[yroot] = xroot + rank[xroot] += 1 +*/ + +//traverses the parents array and fetches the representative parent of the vertex x +func findParent(parent []int, i int) int { + if parent[i] == i { + return i + } + return findParent(parent, parent[i]) +} + +//Merges two vertices and sets the parent by rank +func union(parent []int, rank []int, x int, y int) { + xroot := findParent(parent, x) + yroot := findParent(parent, y) + + if rank[x] > rank[y] { + parent[yroot] = xroot + } else if rank[x] < rank[y] { + parent[xroot] = yroot + } else { + parent[yroot] = xroot + rank[xroot] = 1 + } +} + +// Kruskals algorithm +func Kruskals(g Graph) { + + //get all the edges in an array and then sort it + sortedEdges := []Edge{} + MST := []Edge{} + + //TODO : Use a min Heap to optimize the following + for i := range g.edges { + for edge := range g.edges[i] { + sortedEdges = append(sortedEdges, g.edges[i][edge]) + } + } + + sort.Slice(sortedEdges, func(i, j int) bool { + return sortedEdges[i].Weight < sortedEdges[j].Weight + }) + + //initialize parent and the rank + parent := make([]int, g.vertices) + rank := make([]int, g.vertices) + + for i := 0; i < g.vertices; i++ { + parent[i] = i + rank[i] = 0 + } + + i := 0 + e := 0 + + //we need to select V-1 edges for all the edges to connect + for e < g.vertices-1 { + + //select the minumum edge not choosen yet + currEdge := sortedEdges[i] + i++ + + //find the parent of the vertices of current edge + x := findParent(parent, currEdge.From) + y := findParent(parent, currEdge.To) + + //if parent of x is not equal to parent of y means both have different sets and thus wont form a cycle when merged + //so we select this edge and increase the edges count + if x != y { + e++ + //add it to mst + MST = append(MST, currEdge) + //since the vertices are now connected union both of them for future use. + union(parent, rank, x, y) + } + + } + fmt.Println("PRINTING THE MST") + fmt.Println(MST) + +} diff --git a/graph/kruskals/kruskals_test.go b/graph/kruskals/kruskals_test.go new file mode 100644 index 0000000..ce71715 --- /dev/null +++ b/graph/kruskals/kruskals_test.go @@ -0,0 +1,21 @@ +package graph + +import ( + "testing" +) + +func TestGraph(t *testing.T) { + var graph = Graph{} + graph.Initialize(6) + graph.AddEdge(0, 1, 4) + graph.AddEdge(0, 3, 8) + graph.AddEdge(3, 4, 1) + graph.AddEdge(3, 5, 7) + graph.AddEdge(4, 5, 6) + graph.AddEdge(2, 5, 2) + graph.AddEdge(1, 3, 11) + graph.AddEdge(1, 2, 8) + graph.Print() + Kruskals(graph) + +}