3.5.4 · D2Graphs

Visual walkthrough — BFS — algorithm, queue-based, O(V+E), shortest path in unweighted graphs

1,760 words8 min readBack to topic

Step 0 — What is a graph, really? (nothing assumed)

We will call our starting dot the source and label it (the letter just stands for "start" — it is a name, not a number).

Unweighted means every line is the same length — one hop is one hop, no line is "longer" than another. That single assumption is the reason everything below works.

Look at the figure: five dots, some lines, and the source circled. Right now no dot has a number. Our whole job is to write the fewest-hops number on every dot.


Step 1 — The number we want to compute:

WHY count edges and not something fancier? Because the graph is unweighted — every line costs exactly . So the cost of a path is literally how many lines it uses. Minimising cost = minimising line count.

PICTURE: In the figure below, the source has (you cross zero lines to stand where you already are), and a dot two lines away has .


Step 2 — The ripple idea: sort dots into rings

The key claim we will lean on the whole page:

WHY must ring dots be neighbours of ring ? Because to reach a ring- dot in hops, your second-to-last dot must be reachable in hops — i.e. it lives in ring . There is nowhere else the shortest path could have come from.


Step 3 — We need a waiting line that respects rings: the queue

The mechanism, term by term: put in the line. Serve the front dot . For each neighbour of , if has never been in the line, put it at the back. Because (a ring- dot) entered before any ring- dot, the queue always keeps lower rings ahead.


Step 4 — Setting the number the moment we discover a dot

WHY fix it now and never change it? Because came off the front of a FIFO queue, has the smallest remaining distance. Any other route to would pass through some dot whose distance is , so that route is length . No route can beat what we just found. This is the heart of correctness.

WHY mark "visited" at push time (not later)? So the same dot is never queued twice. If two ring- dots both border , only the first one gets to enqueue it — the second sees "already visited" and skips.


Step 5 — Watch the queue never mix more than two rings

WHY does this stay true? When we serve a ring- dot , we only ever push its neighbours, which are ring (already visited → skipped) or ring (pushed to the back). We never create a ring while any ring remains. So the line drains ring by ring.

Consequence — the payoff: dots leave the queue in non-decreasing order of . Therefore the first time we touch any dot, no smaller distance is still possible. ∎ (This is the shortest-path tree being built one edge at a time.)


Step 6 — Edge & degenerate cases (never leave the reader stranded)


The one-picture summary

This final figure stacks the whole derivation: the source at ring 0, rings colouring outward, the FIFO queue draining lowest-ring-first, and each edge writing on a fresh dot exactly once.

Recall Feynman retelling — the whole walkthrough in plain words

Start at your home dot and write 0 on it. Line up everyone connected to home and, one at a time, walk to each brand-new neighbour, writing one more than the number you came from. Because you always serve the person who got in line first (a fair queue), you finish everyone marked "1" before anyone marked "2", and everyone "2" before any "3". So the moment you first reach a dot, no shorter way could still be waiting — the number on it is the fewest hops. The visited stamp stops you from looping in circles or writing on the same dot twice. That is the entire proof, and every arrow you saw crossed exactly one same-length line, which is why it only works when all lines cost the same.


Active Recall

Why does the first arrival at a dot give its shortest distance?
Dots leave a FIFO queue in non-decreasing distance order, so any alternative route is at least as long.
Why does and not something else?
The graph is unweighted — crossing one line always costs exactly 1.
What keeps the queue from mixing three ring levels at once?
Serving a ring- dot only ever pushes ring- dots to the back; ring can't appear while ring remains.
What happens to a dot with no path to the source?
It is never enqueued; its distance stays undefined (/).
What single assumption makes the ring argument valid?
Every edge has equal (unit) weight.

Connections

  • 3.5.04 BFS — algorithm, queue-based, O(V+E), shortest path in unweighted graphs (Hinglish) (parent topic)
  • DFS — depth-first traversal (the stack-based cousin that dives deep)
  • Dijkstra's Algorithm (what to use once edges have weights)
  • 0-1 BFS (deque trick for 0/1 weights)
  • Graph Representations — adjacency list vs matrix (how neighbours are stored)
  • Connected Components (re-run BFS on untouched dots)
  • Bipartite Check (colour by ring parity)
  • Shortest Path Tree (the tree built by the parent links)