Home > Backend Development > C++ > body text

Boruvka algorithm in C++ for minimum spanning tree

PHPz
Release: 2023-08-27 14:53:13
forward
859 people have browsed it

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;
};
Copy after login

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;
}
Copy after login

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: 2
Copy after login
The 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;
}
Copy after login

Output

Shortest distances from source vertex 0:
Vertex 0: 0
Vertex 1: 2
Vertex 2: 3
Vertex 3: 6
Copy after login
The 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!

source:tutorialspoint.com
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template