Prim’s method was created in 1930 by Vojtěch Jarník, a mathematician from the Czech Republic.

Subsequently, the algorithm was rediscovered in 1957 by Edsger W. Dijkstra and in 1959 by Robert C. Prim. As a result, the algorithm is sometimes occasionally referred to as “Prim-Jarník algorithm” or “Jarník’s algorithm.”

Prim's Algorithm

A linked and undirected graph’s Minimum Spanning Tree (MST) can be discovered using Prim’s approach.

==== EXAMPLE MUKAVU ====

The set of edges in a graph that joins all of the vertices and has a minimum sum of edge weights is known as the MST, which is discovered by Prim’s algorithm.

By adding a random vertex to the MST initially, Prim’s algorithm determines the MST. Next, from the current MST, the algorithm determines which vertex has the lowest edge weight and adds it to the MST. Prim’s technique continues in this manner until every node is incorporated into the MST.

Prim’s algorithm produces a minimum spanning tree in an easy-to-understand manner, however it is greedy.

All of the nodes need to be connected for Prim’s algorithm to function. An alternative method is to apply Kruskal’s algorithm to locate the MSTs in an unconnected graph. The following page contains information regarding Kruskal’s algorithm.

How it works:

1.As the starting point, pick a random vertex and make it the first vertex in the MST.

2.Examine the margins extending beyond the MST. Select the edge that joins a vertex inside the MST to a vertex outside the MST that has the least weight.

3.To the MST, add that vertex and edge.

4.Continue with steps 2 and 3 until every vertex is part of the MST.

NOTE: Different edges may be included in the MST for the same graph because the starting vertex is selected at random, but the MST’s total edge weight will always have the same minimum value.

Manual Run Through

Before we attempt to program Prim’s algorithm, let’s take a closer look at the graph below and see how each stage of the process works by hand.

Although vertex A is used as the beginning vertex in this demonstration, Prim’s technique begins growing the Minimum Spanning Tree (MST) from a random vertex.

DSA Prim's -

The MST expands along the edge with the least weight starting at vertex A. For this reason, vertices A and D are now included in the set of vertices that make up the Minimum Spanning Tree.

DSA Prim's -

Prim’s approach relies heavily on a parents array to grow the edges in the MST.

The parents array now appears as follows:

				
					parents = [-1,  0, -1,  0,  3,  3, -1, -1]
#vertices [ A,  B,  C,  D,  E,  F,  G,  H]
				
			

The first vertex, vertex A, has value -1 since it lacks a parent. Since vertex A is situated at index 0, vertex D’s parent value is 0 because its parent is vertex A. A is also B’s parent, and D is E and F’s parent.

Since a vertex can only have one parent, the parents array aids in maintaining the MST tree structure.

Additionally, the in_mst array is used to track which vertices are currently in the MST and to prevent cycles.

Right now, the in_mst array appears like this:

				
					 in_mst = [ true, false, false,  true, false, false, false, false]
#vertices [    A,     B,     C,     D,     E,     F,     G,     H]
				
			

Prim’s algorithm then adds one additional vertex to the MST, selecting the vertex that is closest to the existing MST nodes, A and D.

Either B or F can be selected as the subsequent MST vertex since A-B and D-F have the same lowest edge weight of 4. For this demonstration, we select vertex B as the next MST.

DSA Prim's -

As you can see, because B-E with weight 6 is lower than D-E with weight 7, the MST edge to E now originates from vertex B rather than vertex D. B-E and D-E cannot both be MST edges to E since vertex E can only have one parent in the parents array and the MST tree structure.

Since edge B-C, with weight 3, is the shortest edge weight among the vertices that make up the current MST, vertex C is the next vertex in the MST.

DSA Prim's -

Given that vertex C is a part of the MST, all edges extending from it are examined to determine whether any of them have a lower weight when compared to vertices that are not part of the MST. The C-H edge is included in the MST with edge weight 2, while edge C-E has a lower weight (3) than the prior B-E MST edge (6).

Since vertex H has the lowest edge weight of 6, it is the next vertex to be included in the MST. In the parents array, vertex H becomes the parent of vertex G.

DSA Prim's -

E or F, with their respective lowest edge weight of 4, are the next vertices to be included in the MST.

For the purposes of this illustration, we decide to add vertex E to the MST next.

DSA Prim's -

Vertices F and G are the final two vertices to be added to the MST. Since these edges have the lowest weight from the present MST, D-F is the MST edge to F and E-G is the MST edge to G.

To observe Prim’s algorithm perform the manual steps we just completed, run the simulation below.

==== EXAMPLE MUKAVU ====

Implementation of Prim's Algorithm

We define a Graph class so that Prim’s algorithm can find a Minimum Spanning Tree (MST). Later on, we’ll utilize the methods in this Graph class to build the graph from the previous example and apply Prim’s algorithm to it.

				
					class Graph:
    def __init__(self, size):
        self.adj_matrix = [[0] * size for _ in range(size)]
        self.size = size
        self.vertex_data = [''] * size

    def add_edge(self, u, v, weight):
        if 0 <= u < self.size and 0 <= v < self.size:
            self.adj_matrix[u][v] = weight
            self.adj_matrix[v][u] = weight  # For undirected graph

    def add_vertex_data(self, vertex, data):
        if 0 <= vertex < self.size:
            self.vertex_data[vertex] = data
				
			

Lines 3-5: The adjacency matrix is initially empty, indicating that the graph has no edges. Moreover, there are no initial names for the vertices.

Lines 7–10: An edge with an edge weight value can be added to an undirected graph using the add_edge method.

Lines 12–14: The vertices can be given names, such as “A” or “B,” by using the add_vertex_data method.

Having established the framework for generating a graph, we can now incorporate Prim’s algorithm as a function within the Graph class:

				
					 def prims_algorithm(self):
        in_mst = [False] * self.size
        key_values = [float('inf')] * self.size
        parents = [-1] * self.size

        key_values[0] = 0  # Starting vertex

        print("Edge \tWeight")
        for _ in range(self.size):
            u = min((v for v in range(self.size) if not in_mst[v]), key=lambda v: key_values[v])

            in_mst[u] = True

            if parents[u] != -1:  # Skip printing for the first vertex since it has no parent
                print(f"{self.vertex_data[parents[u]]}-{self.vertex_data[u]} \t{self.adj_matrix[u][parents[u]]}")

            for v in range(self.size):
                if 0 < self.adj_matrix[u][v] < key_values[v] and not in_mst[v]:
                    key_values[v] = self.adj_matrix[u][v]
                    parents[v] = u
				
			

Line 17: The vertices that are presently in the MST are stored in the in_mst array. At the beginning, the MST has none of the vertices.

Line 18: The current shortest path between each vertex outside the MST and the MST vertices is stored in the key_values array.

Line 19: The parents array contains the MST edges. The parent index of each vertex is saved in order to store each MST edge.

Line 21: The first vertex (vertex A at index 0) is set as the staring vertex in order to keep things simple and have the code operate like in the “Manual Run Through” animation/example above. Prim’s algorithm can be executed from vertex E by changing the index to 4, and that also functions nicely.

Line 25: The vertex that has the lowest key value and is not yet included in the MST is identified by its index. To gain a better understanding of this Python code line, refer to these explanations of min and lambda.

Lines 32–35: This section of the algorithm examines whether any edges from the newly added MST vertex can now decrease the key values to other vertices outside the MST once the new vertex is added to the MST (line 27). The key_values and parents arrays are changed appropriately if that is the case. When a new vertices is added to the MST and becomes the active (current) vertex, this is evidently apparent in the animation.

Let’s now construct the graph from the “Manual Run Through” and apply Prim’s method to it:

Example

Python:

				
					class Graph:
    def __init__(self, size):
        self.adj_matrix = [[0] * size for _ in range(size)]
        self.size = size
        self.vertex_data = [''] * size

    def add_edge(self, u, v, weight):
        if 0 <= u < self.size and 0 <= v < self.size:
            self.adj_matrix[u][v] = weight
            self.adj_matrix[v][u] = weight  # For undirected graph

    def add_vertex_data(self, vertex, data):
        if 0 <= vertex < self.size:
            self.vertex_data[vertex] = data

    def prims_algorithm(self):
        in_mst = [False] * self.size
        key_values = [float('inf')] * self.size
        parents = [-1] * self.size

        key_values[0] = 0  # Starting vertex

        print("Edge \tWeight")
        for _ in range(self.size):
            u = min((v for v in range(self.size) if not in_mst[v]), key=lambda v: key_values[v])

            in_mst[u] = True

            if parents[u] != -1:  # Skip printing for the first vertex since it has no parent
                print(f"{self.vertex_data[parents[u]]}-{self.vertex_data[u]} \t{self.adj_matrix[u][parents[u]]}")

            for v in range(self.size):
                if 0 < self.adj_matrix[u][v] < key_values[v] and not in_mst[v]:
                    key_values[v] = self.adj_matrix[u][v]
                    parents[v] = u

g = Graph(8)

g.add_vertex_data(0, 'A')
g.add_vertex_data(1, 'B')
g.add_vertex_data(2, 'C')
g.add_vertex_data(3, 'D')
g.add_vertex_data(4, 'E')
g.add_vertex_data(5, 'F')
g.add_vertex_data(6, 'G')
g.add_vertex_data(7, 'H')

g.add_edge(0, 1, 4)  # A - B
g.add_edge(0, 3, 3)  # A - D
g.add_edge(1, 2, 3)  # B - C
g.add_edge(1, 3, 5)  # B - D
g.add_edge(1, 4, 6)  # B - E
g.add_edge(2, 4, 4)  # C - E
g.add_edge(2, 7, 2)  # C - H
g.add_edge(3, 4, 7)  # D - E
g.add_edge(3, 5, 4)  # D - F
g.add_edge(4, 5, 5)  # E - F
g.add_edge(4, 6, 3)  # E - G
g.add_edge(5, 6, 7)  # F - G
g.add_edge(6, 7, 5)  # G - H

print("Prim's Algorithm MST:")
g.prims_algorithm()
				
			

Line 32: By altering this to for _ in range(self.size – 1):, we may really escape the final loop in Prim’s method. This is because the MST is actually already identified at this stage when there is just one vertex that is not yet in the MST because the parent vertex for that vertex is already set appropriately in the parents array.

Time Complexity for Prim's Algorithm

See this article for a broad description of time complexity.

Along with V The temporal complexity of Prim’s algorithm is the same as the number of vertices in our graph.

O(V2)

The nested loops in Prim’s algorithm—one for-loop with two more for-loops inside of it—are the cause of this time complexity.

Line 24’s initial for-loop traverses each vertex in the graph.This involves temporal complexity. O(V)..

In order for the next vertex to be included in the MST, the second for-loop (line 25) searches through all of the graph’s neighboring vertices to identify the vertex with the lowest key value that is outside the MST. This involves temporal complexity. O(V)..

A third for-loop (line 32) is triggered when a new vertex is added to the MST. Its purpose is to determine if there are any outgoing edges from the newly added MST vertex to vertices outside the MST, which could result in modified parent relations and lower key values. Additionally, this has O time complexity.V)..

When we combine the time complexities, we obtain:

==== CODE MUKAVO ====

Prim’s algorithm’s time complexity can be decreased to: if key values are managed using a priority queue data structure rather of an array as we do here.

O(E⋅logV)

where E is the graph’s edge count, and V is how many vertices there are.

Sparse graphs are ideally suited for this kind of priority queue-based Prim’s algorithm implementation. When each vertex in a graph is only connected to a small number of other vertices, it is said to be sparse.

Share this Doc

DSA Prim's

Or copy link

Explore Topic