Home >Backend Development >C++ >Boruvka algorithm in C++ for minimum spanning tree
In graph theory, finding the minimum spanning tree (MST) of a connected weighted graph is a common problem. MST is a subset of graph edges that connects all vertices and minimizes the total edge weight. An efficient algorithm to solve this problem is Boruvka algorithm.
struct Edge { int src, dest, weight; }; // Define the structure to represent a subset for union-find struct Subset { int parent, rank; };
Now, let us outline the steps involved in finding the minimum spanning tree in the Boruvka algorithm −
Initialize MST to the empty set.
Create a subset for each vertex, where each subset contains only one vertex.
Repeat the following steps until the minimum spanning tree (MST) has V-1 edges (V is the number of vertices in the graph) −
For each subset, find the cheapest edge connecting it to the other subset.
Add selected edges to the minimum spanning tree.
Perform a union operation on a subset of selected edges.
Output the minimum spanning tree.
In the Boruvka algorithm, there are multiple ways to find the cheapest edge connecting each subset. The following are two common methods −
For each subset, traverse all edges and find the smallest edge connecting it to another subset.
Track selected edges and perform joint operations.
#include <iostream> #include <vector> #include <algorithm> struct Edge { int src, dest, weight; }; // Define the structure to represent a subset for union-find struct Subset { int parent, rank; }; // Function to find the subset of an element using path compression int find(Subset subsets[], int i) { if (subsets[i].parent != i) subsets[i].parent = find(subsets, subsets[i].parent); return subsets[i].parent; } // Function to perform union of two subsets using union by rank void unionSets(Subset subsets[], int x, int y) { int xroot = find(subsets, x); int yroot = find(subsets, y); if (subsets[xroot].rank < subsets[yroot].rank) subsets[xroot].parent = yroot; else if (subsets[xroot].rank > subsets[yroot].rank) subsets[yroot].parent = xroot; else { subsets[yroot].parent = xroot; subsets[xroot].rank++; } } // Function to find the minimum spanning tree using Boruvka's algorithm void boruvkaMST(std::vector<Edge>& edges, int V) { std::vector<Edge> selectedEdges; // Stores the edges of the MST Subset* subsets = new Subset[V]; int* cheapest = new int[V]; // Initialize subsets and cheapest arrays for (int v = 0; v < V; v++) { subsets[v].parent = v; subsets[v].rank = 0; cheapest[v] = -1; } int numTrees = V; int MSTWeight = 0; // Keep combining components until all components are in one tree while (numTrees > 1) { for (int i = 0; i < edges.size(); i++) { int set1 = find(subsets, edges[i].src); int set2 = find(subsets, edges[i].dest); if (set1 != set2) { if (cheapest[set1] == -1 || edges[cheapest[set1]].weight > edges[i].weight) cheapest[set1] = i; if (cheapest[set2] == -1 || edges[cheapest[set2]].weight > edges[i].weight) cheapest[set2] = i; } } for (int v = 0; v < V; v++) { if (cheapest[v] != -1) { int set1 = find(subsets, edges[cheapest[v]].src); int set2 = find(subsets, edges[cheapest[v]].dest); if (set1 != set2) { selectedEdges.push_back(edges[cheapest[v]]); MSTWeight += edges[cheapest[v]].weight; unionSets(subsets, set1, set2); numTrees--; } cheapest[v] = -1; } } } // Output the MST weight and edges std::cout << "Minimum Spanning Tree Weight: " << MSTWeight << std::endl; std::cout << "Selected Edges:" << std::endl; for (const auto& edge : selectedEdges) { std::cout << edge.src << " -- " << edge.dest << " \tWeight: " << edge.weight << std::endl; } delete[] subsets; delete[] cheapest; } int main() { // Pre-defined input for testing purposes int V = 6; int E = 9; std::vector<Edge> edges = { {0, 1, 4}, {0, 2, 3}, {1, 2, 1}, {1, 3, 2}, {1, 4, 3}, {2, 3, 4}, {3, 4, 2}, {4, 5, 1}, {2, 5, 5} }; boruvkaMST(edges, V); return 0; }
Minimum Spanning Tree Weight: 9 Selected Edges: 0 -- 2 Weight: 3 1 -- 2 Weight: 1 1 -- 3 Weight: 2 4 -- 5 Weight: 1 3 -- 4 Weight: 2The Chinese translation of
We first define two structures - Edge and Subset. Edge represents an edge in the graph, including the source, destination and weight of the edge. Subset represents a subset of the union query data structure, including parent and ranking information.
The find function is a helper function that uses path compression to find a subset of elements. It recursively finds the representatives (parent nodes) of the subset to which the element belongs and compresses the path to optimize future queries.
The unionSets function is another auxiliary function that uses rank-based merging to merge two subsets. It finds representatives of two subsets and merges them based on rank to maintain a balanced tree.
The boruvkaMST function takes as input an edge vector and a number of vertices (V). It implements Boruvka algorithm to find MST.
Inside the boruvkaMST function, we create a vector selectedEdges to store the edges of MST.
We create an array of Subset structures to represent subsets and initialize them with default values.
We also create an array cheapest to keep track of the cheapest edge for each subset.
The variable numTrees is initialized to the number of vertices, and MSTWeight is initialized to 0.
The algorithm proceeds by repeatedly combining components until all components are in a tree. The main loop runs until numTrees becomes 1.
In each iteration of the main loop, we iterate over all edges and find the minimum weighted edge for each subset. If an edge connects two different subsets, we update the cheapest array with the index of the least weighted edge.
Next, we traverse all subsets. If a subset has an edge with minimum weight, we add it to the selectedEdges vector, update MSTWeight, perform the union operation of the subsets, and reduce the value of numTrees.
Finally, we output the MST weights and selected edges.
The main function prompts the user to enter the number of vertices and edges. It then takes the input (source, target, weight) for each edge and calls the boruvkaMST function with the input.
Create a priority queue sorted by weight to store edges.
For each subset, find the minimum weight edge connecting it to another subset from the priority queue.
Track selected edges and perform joint operations.
#include <iostream> #include <vector> #include <queue> #include <climits> using namespace std; // Edge structure representing a weighted edge in the graph struct Edge { int destination; int weight; Edge(int dest, int w) : destination(dest), weight(w) {} }; // Function to find the shortest path using Dijkstra's algorithm vector<int> dijkstra(const vector<vector<Edge>>& graph, int source) { int numVertices = graph.size(); vector<int> dist(numVertices, INT_MAX); vector<bool> visited(numVertices, false); dist[source] = 0; priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq; pq.push(make_pair(0, source)); while (!pq.empty()) { int u = pq.top().second; pq.pop(); if (visited[u]) { continue; } visited[u] = true; for (const Edge& edge : graph[u]) { int v = edge.destination; int weight = edge.weight; if (dist[u] + weight < dist[v]) { dist[v] = dist[u] + weight; pq.push(make_pair(dist[v], v)); } } } return dist; } int main() { int numVertices = 4; vector<vector<Edge>> graph(numVertices); // Adding edges to the graph graph[0].push_back(Edge(1, 2)); graph[0].push_back(Edge(2, 5)); graph[1].push_back(Edge(2, 1)); graph[1].push_back(Edge(3, 7)); graph[2].push_back(Edge(3, 3)); int source = 0; vector<int> shortestDistances = dijkstra(graph, source); cout << "Shortest distances from source vertex " << source << ":\n"; for (int i = 0; i < numVertices; i++) { cout << "Vertex " << i << ": " << shortestDistances[i] << endl; } return 0; }
Shortest distances from source vertex 0: Vertex 0: 0 Vertex 1: 2 Vertex 2: 3 Vertex 3: 6The Chinese translation of
In this approach, we use a priority queue to optimize the process of finding the minimum weighted edge for each subset. The following is a detailed explanation of the code −
The code structure and helper functions (such as find and unionSets) remain the same as the previous method.
The boruvkaMST function is modified to use a priority queue to efficiently find the minimum weighted edge for each subset.
Instead of using the cheapest array, we now create a edge priority queue (pq). We initialize it with the edges of the graph.
The main loop runs until numTrees becomes 1, similar to the previous method.
In each iteration, we extract the minimum weight edge (minEdge) from the priority queue.
Then we use the find function to find the subset to which the source and target of minEdge belong.
If the subsets are different, we add minEdge to the selectedEdges vector, update MSTWeight, perform a merge of the subsets, and reduce numTrees.
The process will continue until all components are in a tree.
Finally, we output the MST weights and selected edges.
The main functionality is the same as the previous method, we have predefined inputs for testing purposes.
Boruvka's algorithm provides an efficient solution for finding the minimum spanning tree of a weighted graph. Our team explored two different paths in depth when implementing the algorithm in C: a traditional or "naive" approach. Another utilizes priority queues. Depends on the specific requirements of the given problem at hand. Each method has certain advantages and can be implemented accordingly. By understanding and implementing Boruvka's algorithm, you can efficiently solve minimum spanning tree problems in C projects.
The above is the detailed content of Boruvka algorithm in C++ for minimum spanning tree. For more information, please follow other related articles on the PHP Chinese website!