Live · 1419 articles
dsa

Shortest Path Algorithms from Scratch (2026)

Complete Shortest Path Algorithms from Scratch tutorial covering fundamentals, practical examples, and best practices for modern development.

dsa4 Mar 2026

Shortest path algorithms are fundamental to graph theory, determining the minimal distance between nodes in a weighted graph. Dijkstra, Bellman-Ford, and Floyd-Warshall each serve distinct use cases with different trade-offs.

Dijkstra's algorithm handles non-negative weights efficiently using a priority queue, Bellman-Ford detects negative cycles through iterative relaxation, and Floyd-Warshall computes all-pairs shortest paths via dynamic programming.

Dijkstra's Algorithm

Dijkstra's algorithm finds the shortest path from a source to all vertices using a greedy approach. It maintains a priority queue of vertices ordered by their current distance and relaxes edges from the closest unprocessed vertex.

The algorithm runs in O((V+E) log V) with a binary heap and fails on negative weight edges because it assumes earlier settled distances are final.

vector dijkstra(vector>>& graph, int src) {
    int V = graph.size();
    vector dist(V, INT_MAX);
    dist[src] = 0;
    priority_queue, vector>, greater<>> pq;
    pq.push({0, src});
    while (!pq.empty()) {
        auto [d, u] = pq.top(); pq.pop();
        if (d > dist[u]) continue;
        for (auto [v, w] : graph[u])
            if (dist[u] + w < dist[v])
                dist[v] = dist[u] + w, pq.push({dist[v], v});
    }
    return dist;
}

Bellman-Ford Algorithm

Bellman-Ford iteratively relaxes all edges V-1 times to guarantee shortest paths. A final pass detects negative cycles reachable from the source.

Its O(VE) complexity makes it slower than Dijkstra, but it handles negative weights and cycle detection, making it essential for general-purpose shortest path problems.

vector bellmanFord(int V, vector>& edges, int src) {
    vector dist(V, INT_MAX);
    dist[src] = 0;
    for (int i = 0; i < V - 1; i++)
        for (auto& e : edges)
            if (dist[e[0]] != INT_MAX && dist[e[0]] + e[2] < dist[e[1]])
                dist[e[1]] = dist[e[0]] + e[2];
    for (auto& e : edges)
        if (dist[e[0]] != INT_MAX && dist[e[0]] + e[2] < dist[e[1]])
            return {}; // negative cycle
    return dist;
}

Floyd-Warshall Algorithm

Floyd-Warshall computes shortest paths between all pairs using a 2D DP matrix. For each intermediate vertex k, it checks whether path i->k->j is shorter than i->j.

With O(V³) time, it is ideal for dense graphs or when all-pairs distances are needed, and it can detect negative cycles by checking diagonal entries.

vector> floydWarshall(vector>& graph) {
    int V = graph.size();
    vector> dist = graph;
    for (int k = 0; k < V; k++)
        for (int i = 0; i < V; i++)
            for (int j = 0; j < V; j++)
                if (dist[i][k] != INT_MAX && dist[k][j] != INT_MAX)
                    dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]);
    return dist;
}

Frequently Asked Questions

When should I use Dijkstra over Bellman-Ford?

Use Dijkstra when all edge weights are non-negative and you need better O((V+E) log V) performance. Use Bellman-Ford when negative weights exist or you need to detect negative cycles.

Can Floyd-Warshall handle negative weights?

Yes, Floyd-Warshall handles negative weights and detects negative cycles, but it does not work with negative cycles in the shortest path computation as distances become -infinity.

Originally published on Ayodhyya. Last updated June 1, 2026.

Sandip Mhaske
Sandip Mhaske
Senior Engineer · Author of 1419 guides · Follow for System Design & .NET deep-dives
About