Your Progress

25/30 completed

83% complete. Continue learning to master DSA!

Shortest Path Algorithms

Shortest path algorithms find the paths with minimum distance or cost between vertices in a graph. These algorithms are fundamental in navigation systems, network routing, and many optimization problems.

Key Takeaways

  • Dijkstra's algorithm is optimal for graphs with non-negative edge weights
  • Bellman-Ford handles negative weights and detects negative cycles
  • Floyd-Warshall efficiently finds shortest paths between all pairs of vertices
  • BFS finds shortest paths in unweighted graphs
  • A* algorithm uses heuristics to optimize path finding in large search spaces

Understanding Shortest Path Problems

Shortest path problems involve finding paths between vertices in a graph such that the sum of the weights of the constituent edges is minimized.

Types of Shortest Path Problems

  • Single-Source Shortest Path (SSSP): Find shortest paths from a source vertex to all other vertices
  • Single-Destination Shortest Path: Find shortest paths from all vertices to a single destination vertex
  • Single-Pair Shortest Path: Find the shortest path between two specific vertices
  • All-Pairs Shortest Path (APSP): Find shortest paths between every pair of vertices

Example Graph

     B
      /|\
     / | \
    /  |  \
   2   4   3
  /    |    \
 /     |     \
A------+------C
 \     |     /
  \    |    /
   6   1   5
    \  |  /
     \ | /
      \|/
       D

In this example, the shortest path from A to D would be A → C → D with a total weight of 3 (2 + 1).

Dijkstra's Algorithm

Dijkstra's algorithm solves the single-source shortest path problem for a graph with non-negative edge weights. It works by greedily selecting the vertex with the minimum distance, then relaxing all of its outgoing edges.

Algorithm Steps

  1. Initialize distances of all vertices as infinite and distance of the source vertex as 0
  2. Create a priority queue and insert all vertices with their distances
  3. While the priority queue is not empty:
    • Extract the vertex with the minimum distance
    • For each adjacent vertex, if the distance through the current vertex is shorter than the known distance, update the distance and predecessor

Implementation

function dijkstra(graph, source) {
  const vertices = graph.vertices.length;
  const adj = graph.adjList;
  
  // Initialize distances as infinity
  const dist = Array(vertices).fill(Infinity);
  const prev = Array(vertices).fill(-1);
  
  // Distance to source is 0
  dist[source] = 0;
  
  // Priority queue to store vertices that need to be processed
  const pq = new MinPriorityQueue();
  pq.enqueue(source, 0);
  
  while (!pq.isEmpty()) {
    // Extract vertex with minimum distance
    const { element: u, priority: dist_u } = pq.dequeue();
    
    // If we've found a longer path, skip
    if (dist_u > dist[u]) continue;
    
    // Relax all adjacent vertices
    for (const [v, weight] of adj[u]) {
      const alt = dist[u] + weight;
      
      // If we found a shorter path to v
      if (alt < dist[v]) {
        dist[v] = alt;
        prev[v] = u;
        pq.enqueue(v, alt);
      }
    }
  }
  
  return { dist, prev };
}

// Helper function to reconstruct path
function getPath(prev, target) {
  const path = [];
  let current = target;
  
  while (current !== -1) {
    path.unshift(current);
    current = prev[current];
  }
  
  return path;
}

Key Characteristics

  • Time Complexity: O((V + E) log V) with a binary heap
  • Space Complexity: O(V)
  • Limitations: Does not work with negative edge weights
  • Applications: GPS navigation, network routing, flight scheduling

Bellman-Ford Algorithm

The Bellman-Ford algorithm solves the single-source shortest path problem, even in graphs with negative edge weights. It can also detect negative weight cycles, which are cycles whose edges sum to a negative value.

Algorithm Steps

  1. Initialize distances of all vertices as infinite and distance of the source vertex as 0
  2. Relax all edges |V| - 1 times (where |V| is the number of vertices):
    • For each edge (u, v) with weight w, if dist(u) + w < dist(v), update dist(v) = dist(u) + w
  3. Check for negative weight cycles by attempting one more round of relaxation:
    • If any distance can still be reduced, there's a negative weight cycle

Implementation

function bellmanFord(graph, source) {
  const vertices = graph.vertices.length;
  const edges = graph.edges;
  
  // Initialize distances as infinity
  const dist = Array(vertices).fill(Infinity);
  const prev = Array(vertices).fill(-1);
  
  // Distance to source is 0
  dist[source] = 0;
  
  // Relax all edges |V| - 1 times
  for (let i = 0; i < vertices - 1; i++) {
    for (const edge of edges) {
      const { src: u, dest: v, weight } = edge;
      
      if (dist[u] !== Infinity && dist[u] + weight < dist[v]) {
        dist[v] = dist[u] + weight;
        prev[v] = u;
      }
    }
  }
  
  // Check for negative weight cycles
  for (const edge of edges) {
    const { src: u, dest: v, weight } = edge;
    
    if (dist[u] !== Infinity && dist[u] + weight < dist[v]) {
      // Negative weight cycle exists
      return { hasNegativeCycle: true };
    }
  }
  
  return { dist, prev, hasNegativeCycle: false };
}

Key Characteristics

  • Time Complexity: O(V × E)
  • Space Complexity: O(V)
  • Advantages: Works with negative edge weights, detects negative cycles
  • Disadvantages: Slower than Dijkstra's algorithm for non-negative weights
  • Applications: Currency exchange arbitrage detection, network routing with quality of service constraints

Floyd-Warshall Algorithm

The Floyd-Warshall algorithm solves the all-pairs shortest path problem, finding the shortest paths between every pair of vertices in a weighted graph. It works with positive and negative edge weights, but no negative cycles.

Algorithm Steps

  1. Initialize the distance matrix with direct edge weights (set to infinity if no direct edge exists)
  2. For each vertex k as an intermediate vertex:
    • For each pair of vertices (i, j), check if the path through k is shorter than the known direct path
    • If so, update the shortest path: dist[i][j] = dist[i][k] + dist[k][j]

Implementation

function floydWarshall(graph) {
  const vertices = graph.vertices.length;
  
  // Initialize distance matrix
  const dist = Array(vertices).fill().map(() => Array(vertices).fill(Infinity));
  const next = Array(vertices).fill().map(() => Array(vertices).fill(null));
  
  // Set distance to self as 0
  for (let i = 0; i < vertices; i++) {
    dist[i][i] = 0;
  }
  
  // Set direct edge weights and initialize next matrix
  for (const edge of graph.edges) {
    const { src: u, dest: v, weight } = edge;
    dist[u][v] = weight;
    next[u][v] = v;
  }
  
  // Main algorithm
  for (let k = 0; k < vertices; k++) {
    for (let i = 0; i < vertices; i++) {
      for (let j = 0; j < vertices; j++) {
        if (dist[i][k] !== Infinity && dist[k][j] !== Infinity && dist[i][k] + dist[k][j] < dist[i][j]) {
          dist[i][j] = dist[i][k] + dist[k][j];
          next[i][j] = next[i][k];
        }
      }
    }
  }
  
  // Check for negative cycles
  for (let i = 0; i < vertices; i++) {
    if (dist[i][i] < 0) {
      return { hasNegativeCycle: true };
    }
  }
  
  return { dist, next, hasNegativeCycle: false };
}

// Helper function to reconstruct path
function getPath(next, start, end) {
  if (next[start][end] === null) return [];
  
  const path = [start];
  let current = start;
  
  while (current !== end) {
    current = next[current][end];
    path.push(current);
  }
  
  return path;
}

Key Characteristics

  • Time Complexity: O(V³)
  • Space Complexity: O(V²)
  • Advantages: Simple implementation, finds all pairs of shortest paths in a single run
  • Disadvantages: Cubic time complexity makes it impractical for very large graphs
  • Applications: Road networks, network routing tables, finding transitive closure of a graph

Other Important Shortest Path Algorithms

Breadth-First Search (BFS)

For unweighted graphs or graphs where all edges have the same weight:

  • Visits vertices in order of their distance from the source
  • Time Complexity: O(V + E)
  • Optimal for unweighted graphs

A* Algorithm

An extension of Dijkstra's algorithm using heuristics:

  • Uses a heuristic function to estimate the distance to the target
  • Prioritizes paths that seem to lead closer to the goal
  • Widely used in pathfinding for games and navigation systems

Johnson's Algorithm

For sparse graphs with all-pairs shortest paths:

  • Combines Bellman-Ford and Dijkstra's algorithms
  • Time Complexity: O(V² log V + VE)
  • More efficient than Floyd-Warshall for sparse graphs

Bidirectional Search

For single-pair shortest path problems:

  • Runs two simultaneous searches: one from source and one from destination
  • Stops when the searches meet in the middle
  • Can significantly reduce the search space

Real-World Applications

ApplicationAlgorithmDescription
GPS NavigationDijkstra's, A*Finding fastest/shortest routes between locations
Network RoutingBellman-Ford, OSPFRouting packets through internet/network infrastructure
RoboticsA*, RRTPath planning for autonomous robots
Flight SchedulingFloyd-WarshallFinding optimal flight connections between cities
Arbitrage DetectionBellman-FordFinding profitable currency exchange cycles

Algorithm Comparison

AlgorithmTime ComplexityNegative EdgesNegative CyclesBest For
BFSO(V + E)N/AN/AUnweighted graphs
Dijkstra'sO((V + E) log V)NoNoNon-negative weights
Bellman-FordO(V × E)YesDetects themNegative weights
Floyd-WarshallO(V³)YesDetects themAll-pairs paths
A*O(E)NoNoHeuristic search

Conclusion

Shortest path algorithms are fundamental tools in computer science with applications spanning from navigation systems to network routing. The choice of algorithm depends on the specific problem constraints such as graph size, edge weights, and whether you need single-source or all-pairs shortest paths.

Algorithm Selection Guide

  • For unweighted graphs: Use BFS
  • For weighted graphs with non-negative weights: Use Dijkstra's algorithm
  • For graphs with negative weights: Use Bellman-Ford
  • For all-pairs shortest paths: Use Floyd-Warshall
  • For informed search with large search spaces: Use A*

Next Steps

To continue learning about graph algorithms and path finding, explore these related topics:

Related Tutorials

Related Tutorials

Graphs

Master the fundamentals of graph theory needed for shortest path algorithms.

Learn more

Minimum Spanning Tree

Compare shortest path algorithms with minimum spanning tree algorithms.

Learn more

Breadth-First Search

Learn about the algorithm that finds shortest paths in unweighted graphs.

Learn more