Dijkstra’s Algorithm for Adjacency List Representation | Greedy Algo-8
We recommend reading the following two posts as a prerequisite for this post.
We have discussed Dijkstra’s algorithm and its implementation for adjacency matrix representation of graphs. The time complexity for the matrix representation is O(V^2). In this post, O(ELogV) algorithm for adjacency list representation is discussed.
As discussed in the previous post, in Dijkstra’s algorithm, two sets are maintained, one set contains a list of vertices already included in SPT (Shortest Path Tree), and another set contains vertices not yet included. With adjacency list representation, all vertices of a graph can be traversed in O(V+E) time using BFS. The idea is to traverse all vertices of the graph using BFS and use a Min Heap to store the vertices not yet included in SPT (or the vertices for which the shortest distance is not finalized yet). Min Heap is used as a priority queue to get the minimum distance vertex from a set of not yet included vertices. The time complexity of operations like extract-min and decrease-key value is O(LogV) for Min Heap.
Following are the detailed steps.
- Create a Min Heap of size V where V is the number of vertices in the given graph. Every node of the min-heap contains the vertex number and distance value of the vertex.
- Initialize Min Heap with source vertex as root (the distance value assigned to source vertex is 0). The distance value assigned to all other vertices is INF (infinite).
- While Min Heap is not empty, do the following :
- Extract the vertex with minimum distance value node from Min Heap. Let the extracted vertex be u.
- For every adjacent vertex v of u, check if v is in Min Heap. If v is in Min Heap and the distance value is more than the weight of u-v plus the distance value of u, then update the distance value of v.
Let us understand with the following example. Let the given source vertex be 0
Initially, the distance value of the source vertex is 0 and INF (infinite) for all other vertices. So source vertex is extracted from Min Heap and distance values of vertices adjacent to 0 (1 and 7) are updated. Min Heap contains all vertices except vertex 0.
The vertices in green color are the vertices for which minimum distances are finalized and are not in Min Heap
Since the distance value of vertex 1 is minimum among all nodes in Min Heap, it is extracted from Min Heap and distance values of vertices adjacent to 1 are updated (distance is updated if the vertex is in Min Heap and distance through 1 is shorter than the previous distance). Min Heap contains all vertices except vertex 0 and 1.
Pick the vertex with a minimum distance value from the min-heap. Vertex 7 is picked. So min-heap now contains all vertices except 0, 1, and 7. Update the distance values of adjacent vertices of 7. The distance value of vertex 6 and 8 becomes finite (15 and 9 respectively).
Pick the vertex with a minimum distance from the min-heap. Vertex 6 is picked. So min-heap now contains all vertices except 0, 1, 7, and 6. Update the distance values of adjacent vertices of 6. The distance value of vertex 5 and 8 are updated.
The above steps are repeated till the min-heap doesn’t become empty. Finally, we get the following shortest-path tree.
Below is the implementation of the above approach:
Vertex Distance from Source 0 0 1 4 2 12 3 19 4 21 5 11 6 9 7 8 8 14
Time Complexity: The time complexity of the above code/algorithm looks O(V^2) as there are two nested while loops. If we take a closer look, we can observe that the statements in the inner loop are executed O(V+E) times (similar to BFS). The inner loop has decreaseKey() operation which takes O(LogV) time. So overall time complexity is O(E+V)*O(LogV) which is O((E+V)*LogV) = O(ELogV)
Note that the above code uses Binary Heap for Priority Queue implementation. Time complexity can be reduced to O(E + VLogV) using Fibonacci Heap. The reason is, that Fibonacci Heap takes O(1) time for decrease-key operation while Binary Heap takes O(Logn) time.
Space Complexity: O(V)
The space complexity of Dijkstra’s algorithm is O(V) as we maintain two priority queues or heaps (in case of binary heap). The heap stores the nodes which are not yet included in SPT (shortest path tree). We also maintain an array to store the distance values of each node.
- The code calculates the shortest distance but doesn’t calculate the path information. We can create a parent array, update the parent array when distance is updated (like prim’s implementation), and use it to show the shortest path from source to different vertices.
- The code is for undirected graphs, same Dijkstra function can be used for directed graphs also.
- The code finds the shortest distances from the source to all vertices. If we are interested only in the shortest distance from the source to a single target, we can break the for loop when the picked minimum distance vertex is equal to the target (Step 3.a of an algorithm).
- Dijkstra’s algorithm doesn’t work for graphs with negative weight edges. For graphs with negative weight edges, Bellman–Ford algorithm can be used, we will soon be discussing it as a separate post.
Printing Paths in Dijkstra’s Shortest Path Algorithm
Dijkstra’s shortest path algorithm using set in STL
Introduction to Algorithms by Clifford Stein, Thomas H. Cormen, Charles E. Leiserson, Ronald L.
Algorithms by Sanjoy Dasgupta, Christos Papadimitriou, Umesh Vazirani
Please write comments if you find anything incorrect, or if you want to share more information about the topic discussed above.
Please Login to comment...