Dijkstra's Algorithm – Complete Example with Code, Diagrams & Step-by-Step Explanation

Dijkstra's Algorithm – Complete Example with Code, Diagrams & Step-by-Step Explanation

Dijkstra's Algorithm

Dijkstra's Algorithm – Complete Example with Code, Diagrams & Step-by-Step Explanation


1. What is Dijkstra's Algorithm?

Finds the shortest path from a single source vertex to all other vertices in a weighted graph with non-negative edge weights.

  • Uses Greedy approach.
  • Relies on Priority Queue (Min-Heap) to always expand the closest unvisited node.

2. Key Concepts

Term Meaning
Distance Array dist[v] = shortest distance from source to v
Priority Queue Stores nodes with current shortest distance
Relaxation If dist[u] + weight(u,v) < dist[v], update dist[v]

3. Algorithm Steps

1. Initialize:
   dist[source] = 0
   dist[others] = ∞
   Insert (source, 0) into priority queue

2. While priority queue is not empty:
   u = extractMin()  // Node with smallest dist

   If u already processed → skip

   Mark u as processed

   For each neighbor v of u:
       if dist[u] + weight(u,v) < dist[v]:
           dist[v] = dist[u] + weight(u,v)
           Insert (v, dist[v]) into priority queue

4. Example Graph

    A
   / \  
  1   4
 /     \
B-------C
  \    / \
   2  1   8
    \ |   |
     D----E
       3

Adjacency List Representation

A  (B,1), (C,4)
B  (A,1), (C,2), (D,5)
C  (A,4), (B,2), (D,1), (E,8)
D  (B,5), (C,1), (E,3)
E  (C,8), (D,3)

5. Step-by-Step Execution (Source = A)

Step Extract dist[] Priority Queue Processed
0 - [0, ∞, ∞, ∞, ∞] (A,0) {}
1 A [0, 1, 4, ∞, ∞] (B,1), (C,4) {A}
2 B [0, 1, 3, 6, ∞] (C,3), (C,4), (D,6) {A,B}
3 C [0, 1, 3, 4, 11] (D,4), (D,6), (E,11) {A,B,C}
4 D [0, 1, 3, 4, 7] (E,7), (E,11) {A,B,C,D}
5 E [0, 1, 3, 4, 7] - {A,B,C,D,E}

Final Shortest Distances from A

Node Shortest Distance Path
A 0 A
B 1 A → B
C 3 A → B → C
D 4 A → B → C → D
E 7 A → B → C → D → E

6. Full C Code Implementation

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

#define V 5  // Number of vertices

// Node for priority queue
typedef struct {
    int vertex;
    int dist;
} PQNode;

// Min-Heap Priority Queue
typedef struct {
    PQNode heap[V];
    int size;
} PriorityQueue;

void initPQ(PriorityQueue* pq) {
    pq->size = 0;
}

void swap(PQNode* a, PQNode* b) {
    PQNode t = *a;
    *a = *b;
    *b = t;
}

void heapifyUp(PriorityQueue* pq, int i) {
    while (i > 0) {
        int parent = (i - 1) / 2;
        if (pq->heap[i].dist < pq->heap[parent].dist) {
            swap(&pq->heap[i], &pq->heap[parent]);
            i = parent;
        } else break;
    }
}

void heapifyDown(PriorityQueue* pq, int i) {
    int smallest = i;
    int left = 2 * i + 1;
    int right = 2 * i + 2;

    if (left < pq->size && pq->heap[left].dist < pq->heap[smallest].dist)
        smallest = left;
    if (right < pq->size && pq->heap[right].dist < pq->heap[smallest].dist)
        smallest = right;

    if (smallest != i) {
        swap(&pq->heap[i], &pq->heap[smallest]);
        heapifyDown(pq, smallest);
    }
}

void insert(PriorityQueue* pq, int vertex, int dist) {
    PQNode node = {vertex, dist};
    pq->heap[pq->size++] = node;
    heapifyUp(pq, pq->size - 1);
}

PQNode extractMin(PriorityQueue* pq) {
    PQNode min = pq->heap[0];
    pq->heap[0] = pq->heap[--pq->size];
    heapifyDown(pq, 0);
    return min;
}

int isEmpty(PriorityQueue* pq) {
    return pq->size == 0;
}

// Graph using adjacency list
typedef struct AdjNode {
    int dest;
    int weight;
    struct AdjNode* next;
} AdjNode;

typedef struct {
    AdjNode* head[V];
} Graph;

Graph* createGraph() {
    Graph* g = (Graph*)malloc(sizeof(Graph));
    for(int i = 0; i < V; i++) g->head[i] = NULL;
    return g;
}

void addEdge(Graph* g, int src, int dest, int weight) {
    AdjNode* newNode = (AdjNode*)malloc(sizeof(AdjNode));
    newNode->dest = dest;
    newNode->weight = weight;
    newNode->next = g->head[src];
    g->head[src] = newNode;

    // For undirected graph, add reverse edge
    newNode = (AdjNode*)malloc(sizeof(AdjNode));
    newNode->dest = src;
    newNode->weight = weight;
    newNode->next = g->head[dest];
    g->head[dest] = newNode;
}

// Dijkstra's Algorithm
void dijkstra(Graph* g, int src) {
    int dist[V];
    int processed[V] = {0};
    PriorityQueue pq;
    initPQ(&pq);

    for(int i = 0; i < V; i++) dist[i] = INT_MAX;
    dist[src] = 0;
    insert(&pq, src, 0);

    while (!isEmpty(&pq)) {
        PQNode curr = extractMin(&pq);
        int u = curr.vertex;

        if (processed[u]) continue;
        processed[u] = 1;

        AdjNode* temp = g->head[u];
        while (temp != NULL) {
            int v = temp->dest;
            int weight = temp->weight;

            if (!processed[v] && dist[u] + weight < dist[v]) {
                dist[v] = dist[u] + weight;
                insert(&pq, v, dist[v]);
            }
            temp = temp-> mcc;
        }
    }

    // Print result
    printf("Vertex\tDistance from %c\n", 'A' + src);
    for(int i = 0; i < V; i++) {
        printf("%c \t", 'A' + i);
        if(dist[i] == INT_MAX) printf("INF\n");
        else printf("%d\n", dist[i]);
    }
}

// Main Function
int main() {
    Graph* g = createGraph();

    addEdge(g, 0, 1, 1);  // A-B
    addEdge(g, 0, 2, 4);  // A-C
    addEdge(g, 1, 2, 2);  // B-C
    addEdge(g, 1, 3, 5);  // B-D
    addEdge(g, 2, 3, 1);  // C-D
    addEdge(g, 2, 4, 8);  // C-E
    addEdge(g, 3, 4, 3);  // D-E

    printf("Dijkstra's Algorithm (Source = A)\n");
    dijkstra(g, 0);

    return 0;
}

7. Output

Dijkstra's Algorithm (Source = A)
Vertex  Distance from A
A       0
B       1
C       3
D       4
E       7

8. Visual Step-by-Step (Diagram)

Step 1: Start at A

dist: [0, ∞, ∞, ∞, ∞]
PQ: (A,0)

Step 2: Visit A → Relax B, C

dist: [0, 1, 4, ∞, ∞]
PQ: (B,1), (C,4)

Step 3: Visit B → Relax C, D

C: 1+2=3 < 4  Update C to 3
D: 1+5=6
PQ: (C,3), (D,6)

Step 4: Visit C → Relax D, E

D: 3+1=4 < 6  Update D to 4
E: 3+8=11

Step 5: Visit D → Relax E

E: 4+3=7 < 11  Update E to 7

Done!


9. Time Complexity

Operation Complexity
With Binary Heap O((V + E) log V)
With Fibonacci Heap O(E + V log V)

For dense graph: O(V² log V)
For sparse graph: Nearly O(E log V)


10. Applications

Use Case Example
GPS Navigation Shortest route
Network Routing OSPF, IS-IS
Flight Scheduling Minimum cost path
Game AI Pathfinding with weights

11. Limitations

  • No negative weights (Use Bellman-Ford instead)
  • Does not give path, only distance → Store parent[] to reconstruct path

12. Path Reconstruction (Extra Code)

int parent[V];

void dijkstraWithPath(Graph* g, int src) {
    // ... same as above ...
    for(int i = 0; i < V; i++) parent[i] = -1;

    // Inside relaxation:
    if (dist[u] + weight < dist[v]) {
        dist[v] = dist[u] + weight;
        parent[v] = u;  // Track path
        insert(&pq, v, dist[v]);
    }
}

// Print path
void printPath(int parent[], int v) {
    if (parent[v] == -1) {
        printf("%c ", 'A' + v);
        return;
    }
    printPath(parent, parent[v]);
    printf("→ %c ", 'A' + v);
}

Summary

Feature Detail
Algorithm Greedy + Priority Queue
Data Structure Min-Heap
Time O((V+E) log V)
Best For Non-negative weighted graphs
Output Shortest distances (and paths)

Practice Problems

  1. Find shortest path in a maze with weights
  2. Currency exchange arbitrage (negative cycle → Bellman-Ford)
  3. Implement Dijkstra using set in C++
  4. Compare Dijkstra vs BFS (unweighted)

Key Takeaway:

Dijkstra = BFS + Priority Queue
Always pick the closest unvisited node!


End of Example

Last updated: Nov 12, 2025

Dijkstra's Algorithm – Complete Example with Code, Diagrams & Step-by-Step Explanation

Dijkstra's Algorithm – Complete Example with Code, Diagrams & Step-by-Step Explanation

Dijkstra's Algorithm

Dijkstra's Algorithm – Complete Example with Code, Diagrams & Step-by-Step Explanation


1. What is Dijkstra's Algorithm?

Finds the shortest path from a single source vertex to all other vertices in a weighted graph with non-negative edge weights.

  • Uses Greedy approach.
  • Relies on Priority Queue (Min-Heap) to always expand the closest unvisited node.

2. Key Concepts

Term Meaning
Distance Array dist[v] = shortest distance from source to v
Priority Queue Stores nodes with current shortest distance
Relaxation If dist[u] + weight(u,v) < dist[v], update dist[v]

3. Algorithm Steps

1. Initialize:
   dist[source] = 0
   dist[others] = ∞
   Insert (source, 0) into priority queue

2. While priority queue is not empty:
   u = extractMin()  // Node with smallest dist

   If u already processed → skip

   Mark u as processed

   For each neighbor v of u:
       if dist[u] + weight(u,v) < dist[v]:
           dist[v] = dist[u] + weight(u,v)
           Insert (v, dist[v]) into priority queue

4. Example Graph

    A
   / \  
  1   4
 /     \
B-------C
  \    / \
   2  1   8
    \ |   |
     D----E
       3

Adjacency List Representation

A  (B,1), (C,4)
B  (A,1), (C,2), (D,5)
C  (A,4), (B,2), (D,1), (E,8)
D  (B,5), (C,1), (E,3)
E  (C,8), (D,3)

5. Step-by-Step Execution (Source = A)

Step Extract dist[] Priority Queue Processed
0 - [0, ∞, ∞, ∞, ∞] (A,0) {}
1 A [0, 1, 4, ∞, ∞] (B,1), (C,4) {A}
2 B [0, 1, 3, 6, ∞] (C,3), (C,4), (D,6) {A,B}
3 C [0, 1, 3, 4, 11] (D,4), (D,6), (E,11) {A,B,C}
4 D [0, 1, 3, 4, 7] (E,7), (E,11) {A,B,C,D}
5 E [0, 1, 3, 4, 7] - {A,B,C,D,E}

Final Shortest Distances from A

Node Shortest Distance Path
A 0 A
B 1 A → B
C 3 A → B → C
D 4 A → B → C → D
E 7 A → B → C → D → E

6. Full C Code Implementation

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

#define V 5  // Number of vertices

// Node for priority queue
typedef struct {
    int vertex;
    int dist;
} PQNode;

// Min-Heap Priority Queue
typedef struct {
    PQNode heap[V];
    int size;
} PriorityQueue;

void initPQ(PriorityQueue* pq) {
    pq->size = 0;
}

void swap(PQNode* a, PQNode* b) {
    PQNode t = *a;
    *a = *b;
    *b = t;
}

void heapifyUp(PriorityQueue* pq, int i) {
    while (i > 0) {
        int parent = (i - 1) / 2;
        if (pq->heap[i].dist < pq->heap[parent].dist) {
            swap(&pq->heap[i], &pq->heap[parent]);
            i = parent;
        } else break;
    }
}

void heapifyDown(PriorityQueue* pq, int i) {
    int smallest = i;
    int left = 2 * i + 1;
    int right = 2 * i + 2;

    if (left < pq->size && pq->heap[left].dist < pq->heap[smallest].dist)
        smallest = left;
    if (right < pq->size && pq->heap[right].dist < pq->heap[smallest].dist)
        smallest = right;

    if (smallest != i) {
        swap(&pq->heap[i], &pq->heap[smallest]);
        heapifyDown(pq, smallest);
    }
}

void insert(PriorityQueue* pq, int vertex, int dist) {
    PQNode node = {vertex, dist};
    pq->heap[pq->size++] = node;
    heapifyUp(pq, pq->size - 1);
}

PQNode extractMin(PriorityQueue* pq) {
    PQNode min = pq->heap[0];
    pq->heap[0] = pq->heap[--pq->size];
    heapifyDown(pq, 0);
    return min;
}

int isEmpty(PriorityQueue* pq) {
    return pq->size == 0;
}

// Graph using adjacency list
typedef struct AdjNode {
    int dest;
    int weight;
    struct AdjNode* next;
} AdjNode;

typedef struct {
    AdjNode* head[V];
} Graph;

Graph* createGraph() {
    Graph* g = (Graph*)malloc(sizeof(Graph));
    for(int i = 0; i < V; i++) g->head[i] = NULL;
    return g;
}

void addEdge(Graph* g, int src, int dest, int weight) {
    AdjNode* newNode = (AdjNode*)malloc(sizeof(AdjNode));
    newNode->dest = dest;
    newNode->weight = weight;
    newNode->next = g->head[src];
    g->head[src] = newNode;

    // For undirected graph, add reverse edge
    newNode = (AdjNode*)malloc(sizeof(AdjNode));
    newNode->dest = src;
    newNode->weight = weight;
    newNode->next = g->head[dest];
    g->head[dest] = newNode;
}

// Dijkstra's Algorithm
void dijkstra(Graph* g, int src) {
    int dist[V];
    int processed[V] = {0};
    PriorityQueue pq;
    initPQ(&pq);

    for(int i = 0; i < V; i++) dist[i] = INT_MAX;
    dist[src] = 0;
    insert(&pq, src, 0);

    while (!isEmpty(&pq)) {
        PQNode curr = extractMin(&pq);
        int u = curr.vertex;

        if (processed[u]) continue;
        processed[u] = 1;

        AdjNode* temp = g->head[u];
        while (temp != NULL) {
            int v = temp->dest;
            int weight = temp->weight;

            if (!processed[v] && dist[u] + weight < dist[v]) {
                dist[v] = dist[u] + weight;
                insert(&pq, v, dist[v]);
            }
            temp = temp-> mcc;
        }
    }

    // Print result
    printf("Vertex\tDistance from %c\n", 'A' + src);
    for(int i = 0; i < V; i++) {
        printf("%c \t", 'A' + i);
        if(dist[i] == INT_MAX) printf("INF\n");
        else printf("%d\n", dist[i]);
    }
}

// Main Function
int main() {
    Graph* g = createGraph();

    addEdge(g, 0, 1, 1);  // A-B
    addEdge(g, 0, 2, 4);  // A-C
    addEdge(g, 1, 2, 2);  // B-C
    addEdge(g, 1, 3, 5);  // B-D
    addEdge(g, 2, 3, 1);  // C-D
    addEdge(g, 2, 4, 8);  // C-E
    addEdge(g, 3, 4, 3);  // D-E

    printf("Dijkstra's Algorithm (Source = A)\n");
    dijkstra(g, 0);

    return 0;
}

7. Output

Dijkstra's Algorithm (Source = A)
Vertex  Distance from A
A       0
B       1
C       3
D       4
E       7

8. Visual Step-by-Step (Diagram)

Step 1: Start at A

dist: [0, ∞, ∞, ∞, ∞]
PQ: (A,0)

Step 2: Visit A → Relax B, C

dist: [0, 1, 4, ∞, ∞]
PQ: (B,1), (C,4)

Step 3: Visit B → Relax C, D

C: 1+2=3 < 4  Update C to 3
D: 1+5=6
PQ: (C,3), (D,6)

Step 4: Visit C → Relax D, E

D: 3+1=4 < 6  Update D to 4
E: 3+8=11

Step 5: Visit D → Relax E

E: 4+3=7 < 11  Update E to 7

Done!


9. Time Complexity

Operation Complexity
With Binary Heap O((V + E) log V)
With Fibonacci Heap O(E + V log V)

For dense graph: O(V² log V)
For sparse graph: Nearly O(E log V)


10. Applications

Use Case Example
GPS Navigation Shortest route
Network Routing OSPF, IS-IS
Flight Scheduling Minimum cost path
Game AI Pathfinding with weights

11. Limitations

  • No negative weights (Use Bellman-Ford instead)
  • Does not give path, only distance → Store parent[] to reconstruct path

12. Path Reconstruction (Extra Code)

int parent[V];

void dijkstraWithPath(Graph* g, int src) {
    // ... same as above ...
    for(int i = 0; i < V; i++) parent[i] = -1;

    // Inside relaxation:
    if (dist[u] + weight < dist[v]) {
        dist[v] = dist[u] + weight;
        parent[v] = u;  // Track path
        insert(&pq, v, dist[v]);
    }
}

// Print path
void printPath(int parent[], int v) {
    if (parent[v] == -1) {
        printf("%c ", 'A' + v);
        return;
    }
    printPath(parent, parent[v]);
    printf("→ %c ", 'A' + v);
}

Summary

Feature Detail
Algorithm Greedy + Priority Queue
Data Structure Min-Heap
Time O((V+E) log V)
Best For Non-negative weighted graphs
Output Shortest distances (and paths)

Practice Problems

  1. Find shortest path in a maze with weights
  2. Currency exchange arbitrage (negative cycle → Bellman-Ford)
  3. Implement Dijkstra using set in C++
  4. Compare Dijkstra vs BFS (unweighted)

Key Takeaway:

Dijkstra = BFS + Priority Queue
Always pick the closest unvisited node!


End of Example

Last updated: Nov 12, 2025