Shortest path in an unweighted graph
If every edge has weight 1, the shortest path from a source s to any vertex v is found by BFS layers: the first time we reach v, we have used the minimum number of edges. Store dist[v] = number of edges from s; initialize dist[s]=0 and relax neighbors when first discovered.
- Idea — BFS distance = edge count
- Algorithm
- Example in C — same graph as BFS lesson
- Complexity — O(V + E)
1) Relation to BFS
Use the same queue-based BFS as BFS using queue. When dequeuing u and seeing neighbor v unvisited, set dist[v] = dist[u] + 1 (and optionally record parent for path reconstruction).
2) Algorithm sketch
| Step | Action |
|---|---|
| 1 | Set dist[u] = -1 for all u; dist[s]=0; enqueue s. |
| 2 | While queue not empty: dequeue u. |
| 3 | For each neighbor v with dist[v] < 0: set dist[v] = dist[u]+1, enqueue v. |
3) Example in C
Same undirected graph as the BFS page: vertices 0–4, edges 0–1, 0–2, 1–3, 2–4. Source s = 0.
#include <stdio.h>
#define V 5
#define MAXE 16
#define INF -1
static int adj[V][MAXE];
static int deg[V];
static int dist[V];
static void add_edge(int a, int b) {
adj[a][deg[a]++] = b;
adj[b][deg[b]++] = a;
}
int main(void) {
int q[V * V], front = 0, rear = 0;
int s = 0;
add_edge(0, 1);
add_edge(0, 2);
add_edge(1, 3);
add_edge(2, 4);
for (int i = 0; i < V; i++) dist[i] = INF;
dist[s] = 0;
q[rear++] = s;
while (front < rear) {
int u = q[front++];
for (int i = 0; i < deg[u]; i++) {
int v = adj[u][i];
if (dist[v] == INF) {
dist[v] = dist[u] + 1;
q[rear++] = v;
}
}
}
printf("Shortest edge-count from %d:\n", s);
for (int i = 0; i < V; i++)
printf(" dist[%d] = %d\n", i, dist[i]);
return 0;
}
Graph structure (same as previous)
Edges:
0-10-21-32-4
Visual graph:
3
|
1
|
0 --- 2 --- 4
Initial state
| Variable | Value |
|---|---|
s (source) | 0 |
dist[0] | 0 |
dist[1] | INF (-1) |
dist[2] | INF (-1) |
dist[3] | INF (-1) |
dist[4] | INF (-1) |
| Queue (initial) | [0, _, _, _, _, ...] |
front | 0 |
rear | 1 |
BFS execution step-by-step
| Step | u (dequeued) | dist[u] | Neighbors v | dist[v] before | Condition (dist[v] == INF?) | Action | dist[v] after | Queue (front->rear) |
|---|---|---|---|---|---|---|---|---|
| Start | - | - | - | - | - | Initial enqueue: s=0 | - | [0] |
| 1 | 0 | 0 | 1 | INF | Yes | dist[1]=0+1, enqueue 1 | 1 | [0, 1] |
| 2 | 0 | 0 | 2 | INF | Yes | dist[2]=0+1, enqueue 2 | 1 | [0, 1, 2] |
| 3 | 1 | 1 | 0 | 0 | No (already 0) | skip | 0 | [1, 2] |
| 4 | 1 | 1 | 3 | INF | Yes | dist[3]=1+1, enqueue 3 | 2 | [1, 2, 3] |
| 5 | 2 | 1 | 0 | 0 | No | skip | 0 | [2, 3] |
| 6 | 2 | 1 | 4 | INF | Yes | dist[4]=1+1, enqueue 4 | 2 | [2, 3, 4] |
| 7 | 3 | 2 | 1 | 1 | No | skip | 1 | [3, 4] |
| 8 | 4 | 2 | 2 | 1 | No | skip | 1 | [4] |
| 9 | (loop ends) | - | - | - | - | front=5, rear=5 -> exit | - | [] |
Queue evolution
| Stage | Operation | front index | rear index | Queue Contents | front < rear? |
|---|---|---|---|---|---|
| 0 | Initial enqueue (s=0) | 0 | 1 | [0] | Yes |
| 1 | Dequeue 0, enqueue 1,2 | 0->1 | 1->3 | [0, 1, 2] | Yes |
| 2 | Dequeue 1, enqueue 3 | 1->2 | 3->4 | [0, 1, 2, 3] | Yes |
| 3 | Dequeue 2, enqueue 4 | 2->3 | 4->5 | [0, 1, 2, 3, 4] | Yes |
| 4 | Dequeue 3 (no enqueue) | 3->4 | 5 | [0, 1, 2, 3, 4] | Yes |
| 5 | Dequeue 4 (no enqueue) | 4->5 | 5 | [0, 1, 2, 3, 4] | No (exit) |
Distance array updates
| Vertex | Initial dist[] | Updated in Step | Final dist[] | Meaning (shortest edges from 0) |
|---|---|---|---|---|
| 0 | 0 | Step 0 | 0 | Source vertex (0 edges away) |
| 1 | INF (-1) | Step 1 (via 0) | 1 | 0->1 (1 edge) |
| 2 | INF (-1) | Step 1 (via 0) | 1 | 0->2 (1 edge) |
| 3 | INF (-1) | Step 2 (via 1) | 2 | 0->1->3 (2 edges) |
| 4 | INF (-1) | Step 3 (via 2) | 2 | 0->2->4 (2 edges) |
BFS levels (layers from source)
| Level | Vertices | Distance from 0 |
|---|---|---|
| 0 | {0} | 0 |
| 1 | {1, 2} | 1 |
| 2 | {3, 4} | 2 |
Visual level graph:
Level 2 Level 1 Level 0 Level 1 Level 2 3 <<<<<<<<< 1 <<<<<<<<< 0 >>>>>>>>> 2 >>>>>>>>> 4 (dist=2) (dist=1) (dist=0) (dist=1) (dist=2)
Final output
Shortest edge-count from 0: dist[0] = 0 dist[1] = 1 dist[2] = 1 dist[3] = 2 dist[4] = 2
Key differences from previous BFS code
| Aspect | Previous BFS (with vis[]) | This BFS (with dist[]) |
|---|---|---|
| Tracking mechanism | vis[] boolean array | dist[] integer array |
| Initialization | memset(vis, 0, sizeof vis) | dist[i] = INF for all i |
| Source marking | vis[start] = 1 | dist[s] = 0 |
| Visited check | if (!vis[v]) | if (dist[v] == INF) |
| Additional info | None | Stores shortest path length |
| Output | BFS traversal order | Shortest distance from source |
Time Complexity: O(V + E) = O(5 + 4) = O(9)
Space Complexity: O(V) = O(5) for queue + distance array
4) Weighted graphs
If edges have different positive weights, use Dijkstra (non-negative weights) or Bellman–Ford (general edge weights). BFS distance is only for unit edges.
Key takeaway
Unweighted shortest path = BFS layering. The queue order does not change; only dist[] (and optional parent pointers) are added.
Next up: BFS using queue · Time complexity · All queue topics