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.
grammar
struct Edge { int src, dest, weight; }; // Define the structure to represent a subset for union-find struct Subset { int parent, rank; };
algorithm
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.
method
In the Boruvka algorithm, there are multiple ways to find the cheapest edge connecting each subset. The following are two common methods −
Method 1: Simple method
For each subset, traverse all edges and find the smallest edge connecting it to another subset.
Track selected edges and perform joint operations.
Example
#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; }
Output
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
Explanation
is:Explanation
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.
Method 2: Use priority queue
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.
Example
#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; }
Output
Shortest distances from source vertex 0: Vertex 0: 0 Vertex 1: 2 Vertex 2: 3 Vertex 3: 6The Chinese translation of
Explanation
is:Explanation
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.
in conclusion
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!

There are significant differences in how C# and C implement and features in object-oriented programming (OOP). 1) The class definition and syntax of C# are more concise and support advanced features such as LINQ. 2) C provides finer granular control, suitable for system programming and high performance needs. Both have their own advantages, and the choice should be based on the specific application scenario.

Converting from XML to C and performing data operations can be achieved through the following steps: 1) parsing XML files using tinyxml2 library, 2) mapping data into C's data structure, 3) using C standard library such as std::vector for data operations. Through these steps, data converted from XML can be processed and manipulated efficiently.

C# uses automatic garbage collection mechanism, while C uses manual memory management. 1. C#'s garbage collector automatically manages memory to reduce the risk of memory leakage, but may lead to performance degradation. 2.C provides flexible memory control, suitable for applications that require fine management, but should be handled with caution to avoid memory leakage.

C still has important relevance in modern programming. 1) High performance and direct hardware operation capabilities make it the first choice in the fields of game development, embedded systems and high-performance computing. 2) Rich programming paradigms and modern features such as smart pointers and template programming enhance its flexibility and efficiency. Although the learning curve is steep, its powerful capabilities make it still important in today's programming ecosystem.

C Learners and developers can get resources and support from StackOverflow, Reddit's r/cpp community, Coursera and edX courses, open source projects on GitHub, professional consulting services, and CppCon. 1. StackOverflow provides answers to technical questions; 2. Reddit's r/cpp community shares the latest news; 3. Coursera and edX provide formal C courses; 4. Open source projects on GitHub such as LLVM and Boost improve skills; 5. Professional consulting services such as JetBrains and Perforce provide technical support; 6. CppCon and other conferences help careers

C# is suitable for projects that require high development efficiency and cross-platform support, while C is suitable for applications that require high performance and underlying control. 1) C# simplifies development, provides garbage collection and rich class libraries, suitable for enterprise-level applications. 2)C allows direct memory operation, suitable for game development and high-performance computing.

C Reasons for continuous use include its high performance, wide application and evolving characteristics. 1) High-efficiency performance: C performs excellently in system programming and high-performance computing by directly manipulating memory and hardware. 2) Widely used: shine in the fields of game development, embedded systems, etc. 3) Continuous evolution: Since its release in 1983, C has continued to add new features to maintain its competitiveness.

The future development trends of C and XML are: 1) C will introduce new features such as modules, concepts and coroutines through the C 20 and C 23 standards to improve programming efficiency and security; 2) XML will continue to occupy an important position in data exchange and configuration files, but will face the challenges of JSON and YAML, and will develop in a more concise and easy-to-parse direction, such as the improvements of XMLSchema1.1 and XPath3.1.


Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

AI Hentai Generator
Generate AI Hentai for free.

Hot Article

Hot Tools

Zend Studio 13.0.1
Powerful PHP integrated development environment

SublimeText3 Linux new version
SublimeText3 Linux latest version

Atom editor mac version download
The most popular open source editor

SublimeText3 Mac version
God-level code editing software (SublimeText3)

VSCode Windows 64-bit Download
A free and powerful IDE editor launched by Microsoft