Skip to main content

Borůvka's Algorithm

1. What is Borůvka's Algorithm?

Borůvka's Algorithm is an algorithm for finding the Minimum Spanning Tree (MST) of a connected, weighted, undirected graph. It is one of the oldest MST algorithms and works by repeatedly adding the shortest edge from each component to another component until all components are connected.

2. Algorithm for Borůvka's Algorithm

  1. Initialize Components: Start with each vertex as a separate component.
  2. Find Minimum Edge: For each component, find the minimum weight edge that connects it to a vertex in another component.
  3. Add Minimum Edge: Add all such edges to the MST and merge the corresponding components.
  4. Repeat: Repeat the process until there is only one component left, which represents the MST.

3. How Does Borůvka's Algorithm Work?

  • Component Initialization: Initially, every vertex is its own component.
  • Minimum Edge Selection: For each component, select the edge with the smallest weight that connects to a different component.
  • Component Merging: Add these edges to the MST and merge the components they connect.
  • Iteration: Repeat the process until all vertices are in a single component.

4. Problem Description

Given a connected, weighted, undirected graph, find the Minimum Spanning Tree (MST) using Borůvka's Algorithm.

5. Examples

Example graph:

    2       3
(0)---(1)---(2)
| \ | / |
6 8 5 7 4
| |/ |
(3)----(4)---(5)
9 10

Minimum Spanning Tree: Edges (0-1, 0-3, 1-2, 1-4, 2-5)

6. Constraints

  • The graph must be connected and undirected.
  • The edges must have non-negative weights.

7. Implementation

Borůvka's Algorithm

class Graph:
def __init__(self, vertices):
self.V = vertices
self.graph = []

def add_edge(self, u, v, w):
self.graph.append([u, v, w])

def find(self, parent, i):
if parent[i] == i:
return i
return self.find(parent, parent[i])

def union(self, parent, rank, x, y):
xroot = self.find(parent, x)
yroot = self.find(parent, y)
if rank[xroot] < rank[yroot]:
parent[xroot] = yroot
elif rank[xroot] > rank[yroot]:
parent[yroot] = xroot
else:
parent[yroot] = xroot
rank[xroot] += 1

def boruvka_mst(self):
parent = []
rank = []
cheapest = []

num_trees = self.V
mst_weight = 0

for node in range(self.V):
parent.append(node)
rank.append(0)
cheapest = [-1] * self.V

while num_trees > 1:
for i in range(len(self.graph)):
u, v, w = self.graph[i]
set1 = self.find(parent, u)
set2 = self.find(parent, v)
if set1 != set2:
if cheapest[set1] == -1 or cheapest[set1][2] > w:
cheapest[set1] = [u, v, w]
if cheapest[set2] == -1 or cheapest[set2][2] > w:
cheapest[set2] = [u, v, w]

for node in range(self.V):
if cheapest[node] != -1:
u, v, w = cheapest[node]
set1 = self.find(parent, u)
set2 = self.find(parent, v)
if set1 != set2:
mst_weight += w
self.union(parent, rank, set1, set2)
num_trees -= 1

cheapest = [-1] * self.V

return mst_weight

g = Graph(6)
g.add_edge(0, 1, 2)
g.add_edge(0, 3, 6)
g.add_edge(1, 2, 3)
g.add_edge(1, 3, 8)
g.add_edge(1, 4, 5)
g.add_edge(2, 4, 7)
g.add_edge(2, 5, 4)
g.add_edge(3, 4, 9)
g.add_edge(4, 5, 10)

print("Weight of MST is", g.boruvka_mst())

8. Complexity Analysis

  • Time Complexity: O(ElogV)O(E \log V), where EE is the number of edges and VV is the number of vertices.
  • Space Complexity: O(V+E)O(V + E) due to the storage required for the parent, rank, and cheapest arrays.

9. Advantages and Disadvantages

Advantages:

  • Suitable for parallel computation.
  • Efficient for dense graphs.

Disadvantages:

  • Not as straightforward to implement as other MST algorithms like Kruskal's or Prim's.

10. References