Given a weighted, undirected graph of V vertices, numbered from 0 to V-1, and an adjacency list adj where adj[i] is a list of lists containing two integers where the first integer of each list j denotes there is edge between i and j , second integers corresponds to the weight of that edge .
Given a source node S. Find the shortest distance of all the vertex from the source vertex S. Return a list of integers denoting shortest distance between each node and source vertex S. If a vertex is not reachable from source then its distance will be 109.
Input: V = 2, adj [] = [[[1, 9]], [[0, 9]]], S=0
Output: [0, 9]
Explanation: The shortest distance from node 0(source) to node 0 is 0 and the shortest distance from node 0 to node 1 is 6.
Input: V = 3,adj = [[[1, 1], [2, 6]], [[2, 3], [0, 1]], [[1, 3], [0, 6]]], S=2
Output: [4, 3, 0]
Explanation:
For node 0, the shortest path is 2->1->0 (distance=4)
For node 1, the shortest path is 2->1 (distance=3)
Input: V=4, adj = [[[1, 1], [3, 2]],[[0, 1], [2, 4]],[[1, 4], [3, 3]], [[0, 2], [2, 3]]], S=0
Dijkstra's Algorithm is used in connected graphs (undirected as well as directed) whenever it is required to find out the shortest distance from the source node to every other node.
To implement the Dijkstra's Algorithm, a minimum heap data structure (Priority Queue) can be used. The priority queue will store the pair {dist, node} storing the tentative distance required to reach the node from the source node. If this distance is found to be smaller than the known distance, we update the distance to reach node and push to newly found pair of {dist, node} in the priority queue.
#include <bits/stdc++.h>
using namespace std;
/* Define P as a shorthand
for the pair<int, int> type */
#define P pair<int,int>
class Solution {
public:
/* Function to find the shortest distance of all
the vertices from the source vertex S. */
vector <int> dijkstra(int V, vector<vector<int>> adj[],
int S) {
// Priority queue
priority_queue <P, vector<P>, greater<P>> pq;
// Distance array
vector<int> dist(V, 1e9);
// Distance of source node from itself is 0
dist[S] = 0;
// Add the source node to the priority queue
pq.push({0, S});
// Until the priority queue is empty
while(!pq.empty()) {
// Get the tentative distance
int dis = pq.top().first;
// Get the node
int node = pq.top().second;
pq.pop();
// Traverse all its neighbors
for(auto it : adj[node]) {
int adjNode = it[0]; // node
int edgeWt = it[1]; // edge weight
/* If the tentative distance to
reach adjacent node is smaller
than the known distance */
if(dis + edgeWt < dist[adjNode]) {
// Update the known distance
dist[adjNode] = dis + edgeWt;
// Push the new pair in priority queue
pq.push({dist[adjNode], adjNode});
}
}
}
// Return the result
return dist;
}
};
int main() {
int V = 2, S = 0;
vector<vector<int>> adj[V] = {
{{1, 9}},
{{0, 9}}
};
/* Creating an instance of
Solution class */
Solution sol;
/* Function call to find the shortest distance
of each node from the source node */
vector<int> ans = sol.dijkstra(V, adj, S);
// Output
cout << "The shortest distance of nodes from the source node is: ";
for(int i=0; i < V; i++) {
cout << ans[i] << " ";
}
return 0;
}
import java.util.*;
class Solution {
/* Function to find the shortest distance of all
the vertices from the source vertex S. */
public int[] dijkstra(int V,
ArrayList<ArrayList<ArrayList<Integer>>> adj, int S) {
// Priority queue
PriorityQueue<int[]> pq = new PriorityQueue<>(
Comparator.comparingInt(a -> a[0])
);
// Distance array
int[] dist = new int[V];
Arrays.fill(dist, (int) 1e9);
// Distance of source node from itself is 0
dist[S] = 0;
// Add the source node to the priority queue
pq.add(new int[]{0, S});
// Until the priority queue is empty
while (!pq.isEmpty()) {
// Get the tentative distance
int dis = pq.peek()[0];
// Get the node
int node = pq.peek()[1];
pq.poll();
// Traverse all its neighbors
for (ArrayList<Integer> it : adj.get(node)) {
int adjNode = it.get(0); // node
int edgeWt = it.get(1); // edge weight
/* If the tentative distance to
reach adjacent node is smaller
than the known distance */
if (dis + edgeWt < dist[adjNode]) {
// Update the known distance
dist[adjNode] = dis + edgeWt;
// Push the new pair in priority queue
pq.add(new int[]{dist[adjNode], adjNode});
}
}
}
// Return the result
return dist;
}
}
class Main {
public static void main(String[] args) {
int V = 2, S = 0;
// Create adjacency list
ArrayList<ArrayList<ArrayList<Integer>>> adj = new ArrayList<>();
ArrayList<ArrayList<Integer>> node0 = new ArrayList<>();
node0.add(new ArrayList<>(Arrays.asList(1, 9)));
adj.add(node0);
ArrayList<ArrayList<Integer>> node1 = new ArrayList<>();
node1.add(new ArrayList<>(Arrays.asList(0, 9)));
adj.add(node1);
/* Creating an instance of
Solution class */
Solution sol = new Solution();
/* Function call to find the shortest distance
of each node from the source node */
int[] ans = sol.dijkstra(V, adj, S);
// Output
System.out.print("The shortest distance of nodes from the source node is: ");
for (int i = 0; i < V; i++) {
System.out.print(ans[i] + " ");
}
System.out.println();
}
}
import heapq
class Solution:
# Function to find the shortest distance of all
# the vertices from the source vertex S.
def dijkstra(self, V, adj, S):
# Priority queue
pq = []
# Distance array
dist = [int(1e9)] * V
# Distance of source node from itself is 0
dist[S] = 0
# Add the source node to the priority queue
heapq.heappush(pq, (0, S))
# Until the priority queue is empty
while pq:
# Get the tentative distance
dis, node = heapq.heappop(pq)
# Traverse all its neighbors
for adjNode, edgeWt in adj[node]:
# If the tentative distance to reach adjacent node
# is smaller than the known distance
if dis + edgeWt < dist[adjNode]:
# Update the known distance
dist[adjNode] = dis + edgeWt
# Push the new pair in priority queue
heapq.heappush(pq, (dist[adjNode], adjNode))
# Return the result
return dist
# Main method
if __name__ == "__main__":
V, S = 2, 0
# Create adjacency list
adj = [
[(1, 9)],
[(0, 9)]
]
# Creating an instance of Solution class
sol = Solution()
# Function call to find the shortest distance
# of each node from the source node
ans = sol.dijkstra(V, adj, S)
# Output
print("The shortest distance of nodes from the source node is:", end=" ")
for i in ans:
print(i, end=" ")
print()
// Minimum Priority Queue Implementation
class MinPriorityQueue {
constructor() {
this.heap = [];
}
// Insert a new element in the priority queue
push(element) {
this.heap.push(element);
this.bubbleUp(this.heap.length - 1);
}
/* Remove and return the element with the
highest priority (smallest element) */
pop() {
if (this.heap.length === 1) return this.heap.pop();
const min = this.heap[0];
this.heap[0] = this.heap.pop();
this.bubbleDown(0);
return min;
}
// Get the element with the highest priority without removing it
peek() {
return this.heap[0];
}
// Return true if the priority queue is empty */
isEmpty() {
return this.heap.length === 0;
}
// Restore heap order after adding a new element
bubbleUp(index) {
const element = this.heap[index];
while (index > 0) {
const parentIndex = Math.floor((index - 1) / 2);
const parent = this.heap[parentIndex];
if (element[0] >= parent[0]) break;
this.heap[index] = parent;
index = parentIndex;
}
this.heap[index] = element;
}
// Restore heap order after removing an element
bubbleDown(index) {
const length = this.heap.length;
const element = this.heap[index];
while (true) {
let leftIndex = 2 * index + 1;
let rightIndex = 2 * index + 2;
let swapIndex = null;
if (leftIndex < length) {
if (this.heap[leftIndex][0] < element[0]) {
swapIndex = leftIndex;
}
}
if (rightIndex < length) {
if (
(swapIndex === null && this.heap[rightIndex][0] < element[0]) ||
(swapIndex !== null && this.heap[rightIndex][0] < this.heap[swapIndex][0])
) {
swapIndex = rightIndex;
}
}
if (swapIndex === null) break;
this.heap[index] = this.heap[swapIndex];
index = swapIndex;
}
this.heap[index] = element;
}
}
class Solution {
/* Function to find the shortest distance of all
the vertices from the source vertex S. */
dijkstra(V, adj, S) {
// Custom min-priority queue
let pq = new MinPriorityQueue();
// Distance array
let dist = new Array(V).fill(1e9);
// Distance of source node from itself is 0
dist[S] = 0;
// Add the source node to the priority queue
pq.push([0, S]);
// Until the priority queue is empty
while (!pq.isEmpty()) {
// Get the tentative distance
let [dis, node] = pq.pop();
// Traverse all its neighbors
for (let it of adj[node]) {
let adjNode = it[0]; // node
let edgeWt = it[1]; // edge weight
/* If the tentative distance to
reach adjacent node is smaller
than the known distance */
if (dis + edgeWt < dist[adjNode]) {
// Update the known distance
dist[adjNode] = dis + edgeWt;
// Push the new pair in priority queue
pq.push([dist[adjNode], adjNode]);
}
}
}
// Return the result
return dist;
}
}
let V = 2, S = 0;
let adj = [
[[1, 9]],
[[0, 9]]
];
/* Creating an instance of
Solution class */
let sol = new Solution();
/* Function call to find the shortest distance
of each node from the source node */
let ans = sol.dijkstra(V, adj, S);
// Output
console.log("The shortest distance of nodes from the source node is: ");
for (let i = 0; i < V; i++) {
console.log(ans[i] + " ");
}
Time Complexity: O((V+E)*logV) (where V and E represent the number of nodes and edges of the graph)
Space Complexity: O(V)
Dijkstra's Algorithm is used in connected graphs (undirected as well as directed) whenever it is required to find out the shortest distance from the source node to every other node.
To implement the Dijkstra's Algorithm, a set data structure can be used. The set will store the pair {dist, node} storing the tentative distance required to reach the node from the source node. If this distance is found to be smaller than the known distance, we update the distance to reach node and insert the newly found pair of {dist, node} in the set.
#include <bits/stdc++.h>
using namespace std;
class Solution {
public:
/* Function to find the shortest distance of all
the vertices from the source vertex S. */
vector <int> dijkstra(int V, vector<vector<int>> adj[],
int S) {
// Set to store {dist, node}
set <pair<int,int>> st;
// Distance array
vector<int> dist(V, 1e9);
// Distance of source node from itself is 0
dist[S] = 0;
// Adding the source node to set
st.insert({0, S});
// Until the set is empty
while(!st.empty()) {
// Get the distance
int dis = st.begin()->first;
// Get the node
int node = st.begin()->second;
st.erase(st.begin());
// Traverse all its neighbors
for(auto it : adj[node]) {
int adjNode = it[0]; // node
int edgeWt = it[1]; // edge weight
/* If the tentative distance to
reach adjacent node is smaller
than the known distance */
if(dis + edgeWt < dist[adjNode]) {
/* If another longer known distance
is found, erase it from the set */
if(dist[adjNode] != 1e9)
st.erase({dist[adjNode] , adjNode});
// Update the known distance
dist[adjNode] = dis + edgeWt;
// Add the new pair to the set
st.insert({dist[adjNode] , adjNode});
}
}
}
// Return the result
return dist;
}
};
int main() {
int V = 2, S = 0;
vector<vector<int>> adj[V] =
{
{{1, 9}},
{{0, 9}}
};
/* Creating an instance of
Solution class */
Solution sol;
/* Function call to find the shortest distance
of each node from the source node */
vector<int> ans = sol.dijkstra(V, adj, S);
// Output
cout << "The shortest distance of nodes from the source node is: ";
for(int i=0; i < V; i++) {
cout << ans[i] << " ";
}
return 0;
}
import java.util.*;
class Solution {
public int[] dijkstra(int V, ArrayList<ArrayList<ArrayList<Integer>>> adj, int S) {
// TreeSet to store {dist, node}
TreeSet<int[]> set = new TreeSet<>((a, b) -> {
if (a[0] != b[0]) return Integer.compare(a[0], b[0]); // Compare by distance
return Integer.compare(a[1], b[1]); // If distances are equal, compare by node
});
// Distance array
int[] dist = new int[V];
Arrays.fill(dist, (int)1e9);
// Distance of source node from itself is 0
dist[S] = 0;
// Adding the source node to the set
set.add(new int[]{0, S});
// Until the set is empty
while (!set.isEmpty()) {
// Get the pair with the smallest distance
int[] current = set.pollFirst();
int dis = current[0];
int node = current[1];
// Traverse all its neighbors
for (ArrayList<Integer> neighbor : adj.get(node)) {
int adjNode = neighbor.get(0); // adjacent node
int edgeWt = neighbor.get(1); // edge weight
/* If the tentative distance to
reach adjacent node is smaller
than the known distance */
if (dis + edgeWt < dist[adjNode]) {
/* If another longer known distance
is found, erase it from the set */
set.remove(new int[]{dist[adjNode], adjNode});
// Update the known distance
dist[adjNode] = dis + edgeWt;
// Add the new pair to the set
set.add(new int[]{dist[adjNode], adjNode});
}
}
}
// Return the result
return dist;
}
}
class Main {
public static void main(String[] args) {
int V = 2, S = 0;
ArrayList<ArrayList<ArrayList<Integer>>> adj = new ArrayList<>();
// Adjacency list for the graph
for (int i = 0; i < V; i++) {
adj.add(new ArrayList<>());
}
adj.get(0).add(new ArrayList<>(Arrays.asList(1, 9)));
adj.get(1).add(new ArrayList<>(Arrays.asList(0, 9)));
// Creating an instance of Solution class
Solution sol = new Solution();
/* Function call to find the shortest distance
of each node from the source node */
int[] ans = sol.dijkstra(V, adj, S);
// Output
System.out.println("The shortest distance of nodes from the source node is: ");
for (int i : ans) {
System.out.print(i + " ");
}
}
}
import heapq
class Solution:
# Function to find the shortest distance of all
# the vertices from the source vertex S.
def dijkstra(self, V, adj, S):
# Min-heap to store {dist, node}
st = []
# Distance array
dist = [int(1e9)] * V
# Distance of source node from itself is 0
dist[S] = 0
# Adding the source node to heap
heapq.heappush(st, (0, S))
# Until the heap is empty
while st:
# Get the distance
dis, node = heapq.heappop(st)
# Traverse all its neighbors
for it in adj[node]:
adjNode, edgeWt = it # node, edge weight
# If the tentative distance to
# reach adjacent node is smaller
# than the known distance
if dis + edgeWt < dist[adjNode]:
# Update the known distance
dist[adjNode] = dis + edgeWt
# Add the new pair to the heap
heapq.heappush(st, (dist[adjNode], adjNode))
# Return the result
return dist
# Main function
if __name__ == "__main__":
V = 2
S = 0
adj = [
[(1, 9)],
[(0, 9)]
]
# Creating an instance of
# Solution class
sol = Solution()
# Function call to find the shortest distance
# of each node from the source node
ans = sol.dijkstra(V, adj, S)
# Output
print("The shortest distance of nodes from the source node is: ", end="")
for i in range(V):
print(ans[i], end=" ")
class Solution {
/* Function to find the shortest distance of all
the vertices from the source vertex S. */
dijkstra(V, adj, S) {
// Set to store {dist, node}
let st = new Set();
// Distance array
let dist = Array(V).fill(1e9);
// Distance of source node from itself is 0
dist[S] = 0;
// Adding the source node to set
st.add([0, S]);
// Until the set is empty
while (st.size) {
// Get the distance
let [dis, node] = [...st][0];
st.delete([...st][0]);
// Traverse all its neighbors
for (let it of adj[node]) {
let adjNode = it[0]; // node
let edgeWt = it[1]; // edge weight
// If the tentative distance to
// reach adjacent node is smaller
// than the known distance
if (dis + edgeWt < dist[adjNode]) {
// If another longer known distance
// is found, erase it from the set
if (dist[adjNode] !== Infinity)
st.delete([dist[adjNode], adjNode]);
// Update the known distance
dist[adjNode] = dis + edgeWt;
// Add the new pair to the set
st.add([dist[adjNode], adjNode]);
}
}
}
// Return the result
return dist;
}
}
// Main function
const main = () => {
let V = 2, S = 0;
let adj = [
[[1, 9]],
[[0, 9]]
];
// Creating an instance of
// Solution class
let sol = new Solution();
// Function call to find the shortest distance
// of each node from the source node
let ans = sol.dijkstra(V, adj, S);
// Output
console.log("The shortest distance of nodes from the source node is: ", ans.join(" "));
};
main();
Time Complexity: O((V+E)*logV) (where V and E represent the number of nodes and edges of the graph)
Space Complexity: O(V)
Even if a Queue data structure is used, the shortest path can be found, but it will act like a brute force solution as all paths are explored, and out of them the shortest one is picked.
On the other hand, using the Minimum Heap data structure ensures that the shortest path among all the paths is always explored first so that unnecessary iterations can be saved.
Q: Why does Dijkstra’s Algorithm not work with negative weights?
A: Since it processes each node once, it assumes that once a node is processed, its shortest distance is finalized. Negative weights can lead to situations where a better path appears after processing, causing incorrect results.
Q: Why do we use a priority queue in Dijkstra’s Algorithm?
A: The priority queue always picks the next closest node, ensuring that we process the shortest known path first, improving efficiency.
Q: How would you modify this to return the actual shortest path, not just the distance?
A: Maintain a parent array to track the previous node in the shortest path. After computing distances, backtrack from each node to reconstruct the path.
Q: What if the graph had negative weight edges?
A: We would need to use Bellman-Ford Algorithm (O(VE)), which can handle negative weights but not negative cycles.