ITC 120 › Final › Graphs
Graphs · Lesson 2 of 3
Breadth-First Search (BFS)
This lesson teaches:AlgorithmVisit a graph in waves: first the start, then everything one step away, then two steps away, and so on.
By the end, you can:
- explain what a graph traversal is and why it needs a "seen" list;
- run BFS by hand with a queue (neighbors in alphabetical order) and write the BFS order, for undirected and directed graphs;
- give each vertex's level and recover a shortest path (fewest edges) from the start using the "found by" table;
- use BFS to tell whether an undirected graph is connected, count its pieces, and list what a directed graph can reach;
- match each line of a Java BFS to the steps of the procedure.
You need: the Graphs lesson, the Queues lesson, and scratch paper.
Part 1 · The idea
Exploring in waves
Graph traversal
A graph traversal visits every vertex that can be reached from a starting vertex, each one exactly once. There are two main types: breadth-first search (this lesson) and depth-first search (next lesson).
For trees, you learned pre-order, in-order, and post-order. Graphs need something new: they have no root and can have cycles, so if we are not careful, we could go around a cycle forever. The fix is to remember which vertices we have already seen.
Breadth-first search (BFS)
Breadth-first search (BFS) is a graph traversal algorithm that visits every vertex reachable from a starting vertex, nearest first: the start, then every vertex 1 edge away, then every vertex 2 edges away, and so on. This is called going level by level. BFS uses a queue to keep track of which vertex to visit next.
Level
A vertex's level is how many edges away it is from the start. The start itself is level 0 (0 edges away). Its neighbors are level 1, their new neighbors are level 2, and so on. In this course, the start is always level 0.
Good to know: some books start at 1
Some textbooks count levels from 1 instead, mostly for trees: the root is level 1, its children are level 2, and so on. It is the same picture; only the numbers move up by one. If a quiz or a book from somewhere else says "level", check which way it counts. "Number of edges from the start" (also called the distance) always starts at 0, so it never changes.
Think of news spreading in a barangay
You tell the news to your next-door neighbors first. Then each of them tells their neighbors. Then those people tell theirs. The news spreads outward in waves: everyone 1 house away hears it before anyone 2 houses away. That is BFS.
Where you see BFS in IT
"People you may know" suggestions often come from level 2: friends of your friends. In networks, BFS can find the route with the fewest hops between two computers.
A web crawler is a program that search engines use to find web pages by following links. It can go level by level, like BFS: first the pages 1 link away, then 2 links away.
Part 2 · The tool
Why a queue?
Recall the queue from the linear data structures lessons: you enqueue at the rear and dequeue from the front, like a line at the canteen. First in, first out.
BFS puts every newly found vertex at the rear of the queue. Since all level-1 vertices are found before any level-2 vertex, they are also in line first. So the queue automatically keeps the waves in order: closer vertices are always visited before farther ones.
Seen list
A seen list is a checklist of every vertex BFS has already found. A vertex gets its ✓ the moment it joins the queue, and a vertex with a ✓ is never added again. That is what stops BFS from going around a cycle forever (Part 1 ).
Seen is not the same as visited. A vertex is seen when it joins the queue, and visited later, when it leaves the front.
One queue, step by step
BFS uses only one queue. Tap Next and watch it: a vertex leaves from the front, new ones join at the rear.
Start: tick A on the seen list (✓) and put it in the queue. This is the only queue BFS uses.
The BFS procedure
Every BFS follows these steps:
- Mark the start vertex as seen (give it a ✓ on the seen list) and enqueue it.
- While the queue is not empty:
- Dequeue the vertex at the front. Visit it (write it in the BFS order).
- Look at its neighbors, in alphabetical order (or smallest number first, if the vertices are numbers). For each one that is not seen yet (no ✓): give it a ✓ and enqueue it. Skip the ones that already have a ✓.
- When the queue is empty, BFS is done.
Exam traps
- Mark a vertex as seen when you enqueue it, not when you dequeue it. Otherwise it can enter the queue twice.
- When a vertex has several unseen neighbors, the order you enqueue them changes the answer. Use alphabetical order (for numbered vertices, smallest number first, comparing them as numbers: 2 before 10) unless the question gives another rule. The box below explains why.
- In a directed graph, follow the arrows only. An arrow into a vertex does not let you leave through it.
Good to know: why "alphabetical order"?
BFS itself does not say which neighbor comes first, so one graph can have several correct BFS orders. Many books, courses, and exams add a rule, usually alphabetical order (or smallest number first), for one reason: so everyone gets the same answer. Then answers are easy to check and compare. An order is only wrong if it breaks the BFS steps or the rule the question gives. In a program, there is no alphabet: the code takes the neighbors in the order they are stored.
Part 3 · Watch it
BFS, step by step
In Part 2 you watched BFS from A. Now it is your turn to predict: this lab starts at D. Before each tap of Next step, say out loud which vertex leaves the queue next and which ones join. Then pick other starting vertices with the round buttons.
BFS lab
Orange = being visited now. Light teal = seen, waiting in the queue. Dark teal = visited. The small L-numbers are levels.
Queue (first in, first out)
Visited order
Color key
Whatever start you pick, the order follows the levels. From A (Part 2), the BFS order was A, B, D, C, E, F, G: A (level 0), then B and D (level 1), then C and E (level 2), then F and G (level 3).
The other two graphs
The lab also has two other graphs. They are not different kinds of BFS: the steps are exactly the same. They only show what BFS does on other kinds of graphs:
- Directed graph: the edges are arrows (from the Graphs lesson ). BFS can only follow an arrow forward. From A, BFS never reaches F, because F's only arrow points away from F.
- Separate pieces: the graph is in three parts with no edges between them. From A, BFS stops after A, B, and C, because no edge leads to the other parts. Part 5 uses this.
Part 4 · Bonus from BFS
Levels and shortest paths
BFS gives you more than a visit order. While it runs, it also answers a very common question: what is the fewest number of steps from the start to each vertex?
You saw this question in Part 1 : the route with the fewest hops between two computers, and "people you may know" (people 2 friendships away). Another example: the fewest links you must click to get from one web page to another. When every edge counts the same (an unweighted graph), "fewest steps" means "fewest edges".
BFS gets this answer for free because of the waves. It reaches every level-1 vertex before any level-2 vertex, and so on, so the first time BFS finds a vertex, it found it the shortest way. That is why a vertex's level is exactly the fewest edges needed to reach it from the start.
Fewest edges from A to G
Each L-number is the vertex's level. G is at level 3, so a shortest path from A to G uses 3 edges: A → B → E → G.
How to recover the path
The level tells you how far G is (3 edges). To also know which way to go, write down who found each vertex while doing BFS (its parent in the BFS). Then start at G and follow the parents back to A:
| Vertex | B | C | D | E | F | G |
|---|---|---|---|---|---|---|
| Found by | A | B | A | B | C | E |
G was found by E, E by B, B by A. Reversed: A → B → E → G.
A → D → E → G also uses 3 edges, so there are two shortest paths. BFS gives the one through B because B left the queue before D and reached E first. On an exam, any path with the fewest edges is correct unless the question asks for the BFS path.
The vertex with the highest level is the one farthest from the start (here, F and G, at level 3).
Careful
"Shortest" here means fewest edges. In a weighted graph, the path with fewer edges is not always the cheapest one. For example, in the travel-time graph from the Graphs lesson, A → B → C takes 19 minutes. If there were also a direct A–C road taking 30 minutes, A → C would have fewer edges but take 11 minutes longer. Weighted shortest paths use other algorithms, such as Dijkstra's algorithm.
Part 5 · Bonus from BFS
Is everything connected?
BFS visits everything reachable from the start, and nothing else. That makes it a quick test:
- Undirected graph: run BFS from any vertex. If every vertex gets visited, the graph is connected. If not, it is in separate pieces.
- Directed graph: BFS from S tells you exactly which vertices can be reached from S by following arrows.
Separate pieces
BFS from A visits only A, B, C. To count the pieces, start a new BFS from any vertex not yet visited (D visits D, E, F; then G alone). Three BFS runs = 3 pieces. Try "Separate pieces" in the lab above.
In IT
This is how a network tool can check whether every computer in an office can still reach the server after a cable is unplugged.
Part 6 · Your turn
Try it on paper
How to set up your paper
- Draw the queue as a row of boxes. When you dequeue, cross out the front box. Add new vertices at the right end.
- Keep a "seen" list beside it, and write the BFS order underneath.
- Write each vertex's level next to it on the drawing.
Problem 1
- Do a BFS starting at D (neighbors in alphabetical order). Write the BFS order.
- Give the level of every vertex.
- Which vertex or vertices are farthest from D?
Show the answer
BFS order: D, B, C, F, G, A, E
| Level | Vertices |
|---|---|
| 0 | D |
| 1 | B, C, F, G |
| 2 | A, E |
Farthest: A and E (level 2). D's neighbors B, C, F, G all go in the queue first; A and E are found only on the second wave.
Problem 2 (directed)
- Do a BFS starting at A, following the arrows. Write the BFS order.
- Which vertex is never visited? Why?
Show the answer
BFS order: A, B, C, D, E
| Level | Vertices |
|---|---|
| 0 | A |
| 1 | B, C |
| 2 | D |
| 3 | E |
Never visited: F. F has an arrow to A, but no arrow comes into F, so there is no way to reach F from A. When E looks at C, C is already seen, so it is skipped.
Part 7 · In code
BFS in Java
This program builds the main example as an adjacency matrix, then runs BFS from A. Java's Queue works like the queue you learned: offer = enqueue at the rear, poll = dequeue from the front. LinkedList is one of Java's built-in queue types.
import java.util.LinkedList;
import java.util.Queue;
public class BFS {
static char[] names = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};
static int n = names.length;
static int[][] adj = new int[n][n];
static void addEdge(int a, int b) { // undirected
adj[a][b] = 1;
adj[b][a] = 1;
}
static void bfs(int start) {
boolean[] seen = new boolean[n]; // all false
Queue<Integer> queue = new LinkedList<>();
seen[start] = true;
queue.offer(start); // enqueue
while (!queue.isEmpty()) {
int u = queue.poll(); // dequeue (front)
System.out.print(names[u] + " "); // visit
for (int v = 0; v < n; v++) { // A to Z order
if (adj[u][v] == 1 && !seen[v]) {
seen[v] = true; // mark now...
queue.offer(v); // ...then enqueue
}
}
}
}
public static void main(String[] args) {
addEdge(0, 1); addEdge(0, 3); // A-B, A-D
addEdge(1, 2); addEdge(1, 4); // B-C, B-E
addEdge(2, 5); addEdge(3, 4); // C-F, D-E
addEdge(4, 5); addEdge(4, 6); // E-F, E-G
addEdge(5, 6); // F-G
bfs(0); // prints: A B D C E F G
}
} ▶ Try it in the Programiz online compiler: tap Copy, paste it there, change public class BFS to public class Main (Programiz saves your code as Main.java, and Java needs the file name and the public class name to match), then press Run.
Here is how to read the new lines aloud. The matrix lines (names, adj, addEdge) are the same as in the Graphs lesson, Part 8.
| Code | Read it as |
|---|---|
import java.util.Queue; | "let this program use Java's Queue" (and the line above it, LinkedList). Both are in java.util. |
boolean[] seen = new boolean[n]; | "make n true/false slots named seen." Every slot starts false. seen[v] answers: has v been put in the queue yet? |
Queue<Integer> queue = new LinkedList<>(); | "queue is a Queue of Integers, built as a LinkedList." Queue is the type we use (it gives us offer, poll, isEmpty); LinkedList is the built-in class that does the work. <Integer> means it holds vertex numbers (why Integer, not int). |
queue.offer(start); | "enqueue start at the rear." |
while (!queue.isEmpty()) | "while the queue is not empty." The ! means not. |
int u = queue.poll(); | "dequeue: remove the front vertex and call it u." |
adj[u][v] == 1 && !seen[v] | "v is a neighbor of u and v has not been seen yet." With &&, both parts must be true. |
Match the code to the procedure
seen[start] = true; queue.offer(start); is step 1. The while loop is step 2: poll is "dequeue and visit", and the for loop checks row u of the matrix from A to Z, enqueuing every neighbor not yet seen.
Your coding task: BFS with levels
In Part 4 , every vertex got a level: the fewest edges from the start. Now make the BFS program find the levels too. Instead of seen, it keeps one int array named level. A level of -1 means "not seen yet". Any other number is the vertex's level.
Write the for loop in about 6 lines where it says YOUR CODE. It is the neighbor loop from the program above, with two changes: check level[v] == -1 instead of !seen[v], and set v's level instead of seen[v] = true. The graph is the main example plus H, a vertex with no edges (like the separate pieces in Part 5). Run it: each printed line must match its expected comment.
1import java.util.LinkedList;
2import java.util.Queue;
3
4public class Main {
5 static char[] names = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'};
6 static int n = names.length;
7 static int[][] adj = new int[n][n];
8
9 static void addEdge(int a, int b) { // undirected
10 adj[a][b] = 1;
11 adj[b][a] = 1;
12 }
13
14 // BFS from start. Returns the level of every vertex.
15 // level[v] == -1 means "not seen yet" (it works like seen[v] == false).
16 static int[] bfsLevels(int start) {
17 int[] level = new int[n];
18 for (int i = 0; i < n; i++) {
19 level[i] = -1;
20 }
21 Queue<Integer> queue = new LinkedList<>();
22
23 level[start] = 0; // the start is level 0
24 queue.offer(start);
25
26 while (!queue.isEmpty()) {
27 int u = queue.poll(); // dequeue (front)
28 // YOUR CODE:
29 // Check every v from 0 to n - 1 (A to Z order).
30 // If v is a neighbor of u and v is not seen yet (level -1):
31 // v is one level below u, so set its level,
32 // then enqueue v.
33
34 }
35 return level;
36 }
37
38 // Given: prints the levels, like "A=0 B=1 ...".
39 static void printLevels(int[] level) {
40 for (int i = 0; i < n; i++) {
41 System.out.print(names[i] + "=" + level[i] + " ");
42 }
43 System.out.println();
44 }
45
46 public static void main(String[] args) {
47 // the main example (H has no edges)
48 addEdge(0, 1); addEdge(0, 3); // A-B, A-D
49 addEdge(1, 2); addEdge(1, 4); // B-C, B-E
50 addEdge(2, 5); addEdge(3, 4); // C-F, D-E
51 addEdge(4, 5); addEdge(4, 6); // E-F, E-G
52 addEdge(5, 6); // F-G
53
54 printLevels(bfsLevels(0));
55 // expected: A=0 B=1 C=2 D=1 E=2 F=3 G=3 H=-1
56 printLevels(bfsLevels(6));
57 // expected: A=3 B=2 C=2 D=2 E=1 F=1 G=0 H=-1
58 printLevels(bfsLevels(7));
59 // expected: A=-1 B=-1 C=-1 D=-1 E=-1 F=-1 G=-1 H=0
60 }
61} ▶ This program runs as is. Try it in the Programiz online compiler: tap Copy, paste it there, and press Run.
Show one possible answer
1for (int v = 0; v < n; v++) { // A to Z order
2 if (adj[u][v] == 1 && level[v] == -1) {
3 level[v] = level[u] + 1; // one level below u
4 queue.offer(v);
5 }
6} Output, one per line: A=0 B=1 C=2 D=1 E=2 F=3 G=3 H=-1, then A=3 B=2 C=2 D=2 E=1 F=1 G=0 H=-1, then A=-1 B=-1 C=-1 D=-1 E=-1 F=-1 G=-1 H=0.
BFS finds v from u, so v is one edge farther from the start than u: level[u] + 1. The first test matches the L-numbers in Part 4. H stays -1 in the first two tests, because BFS never reaches it: H is not connected to the rest. In the last test, BFS starts at H and finds nothing else.
Here are two common mistakes:
level[v] = level[v] + 1(v instead of u).level[v]is still-1there, so every vertex BFS reaches gets −1 + 1 = 0. The first test printsA=0 B=0 C=0 D=0 E=0 F=0 G=0 H=-1.- Leaving out
level[v] == -1. Then vertices go into the queue again and again: A adds B, then B adds A again, and so on. The queue never empties, so the program never stops. In the end, Java runs out of memory (OutOfMemoryError). This is why BFS marks a vertex when it enters the queue.
Part 8 · Check yourself
Self-check
Not graded. Tap an answer to see if you got it, and read why.
-
Which data structure does BFS use to decide which vertex to visit next?
BFS uses a queue (first in, first out). Vertices found first are visited first, so BFS finishes one level before starting the next.
-
In the main example graph, starting at A, which vertices are at level 1?
Level 1 = the start's direct neighbors. A is joined to B and D.
-
Why does BFS mark a vertex as "seen" when it is enqueued?
Graphs can have cycles and many paths to the same vertex. Marking it right away stops it from entering the queue again from another neighbor.
-
In an unweighted graph, BFS from S finds:
Because BFS goes level by level, the first time it reaches a vertex is through the fewest possible edges. (For weighted graphs, other algorithms such as Dijkstra's are used.)
-
You run BFS from vertex A, but vertices X and Y are never visited. What does that tell you?
BFS visits everything reachable from the start. Anything left over cannot be reached from A. In an undirected graph, that means the graph is not connected.
-
The queue currently holds [C, E] (C at the front). You dequeue C, and C has unseen neighbors F and G. What is the queue now?
Dequeue removes C from the front. New vertices go to the rear: [E, F, G]. E was waiting longer, so it is visited before F and G.
Score: 0 / 6
Key takeaways
- BFS visits a graph level by level, starting from one vertex. The start is level 0.
- It uses a queue: dequeue the front, enqueue unseen neighbors at the rear.
- Mark vertices as seen when you enqueue them, so nothing is visited twice.
- In an unweighted graph, BFS levels give the fewest edges from the start, and the "found by" table gives a shortest path.
- Anything BFS does not visit cannot be reached from the start.
Next lesson: Depth-first search (DFS), which goes deep first instead of wide.
References
- A. Bhargava, Grokking Algorithms. Manning, 2016, Chapter 6 (Breadth-first search).
- T. H. Cormen, C. E. Leiserson, R. L. Rivest, and C. Stein, Introduction to Algorithms, 4th ed. MIT Press, 2022, Section 20.2 (Breadth-first search).
- Programiz, "Breadth First Search (BFS) Algorithm." programiz.com/dsa/graph-bfs
- Oracle, "Queue (Java SE 21 & JDK 21)," Java API documentation.