ma'am audrey's lessons

ITC 120 › Final › Graphs

Graphs · Lesson 2 of 3

Breadth-First Search (BFS)

This lesson teaches:Algorithm

Visit a graph in waves: first the start, then everything one step away, then two steps away, and so on.

By the end, you can:

  1. explain what a graph traversal is and why it needs a "seen" list;
  2. run BFS by hand with a queue (neighbors in alphabetical order) and write the BFS order, for undirected and directed graphs;
  3. give each vertex's level and recover a shortest path (fewest edges) from the start using the "found by" table;
  4. use BFS to tell whether an undirected graph is connected, count its pieces, and list what a directed graph can reach;
  5. 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.

TreeABCDEFrootone root: start hereno cycles: paths endGraphABCDA, B, C, D, A, B, C, D, …no root: start anywherecycles: can loop foreverThe fix: remember what you have seenABCD✗seen:A ✓ B ✓ C ✓ D ✓At D, the next vertex is A.A is already seen: skip it.Each vertex is visited once.
A tree has one root and no cycles, so every path down ends. A graph can have a cycle: A, B, C, D, and back to A. Without a "seen" list, a traversal could go around forever. With one, it skips A the second time, so each vertex is visited once.

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.

BFS from A: one wave at a timeLevel 0the startLevel 11 edgeLevel 22 edgesLevel 33 edgesABDCEFGThe queue gets them in the same order:AL0BDL1CEL2FGL3
The graph you will use in Part 3, sorted into levels from A. A level is how many edges away a vertex is from the start. BFS visits all of level 1 before any of level 2, and the queue holds the vertices in exactly that order.

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.

3212321You12321230level 01level 12level 23level 3
Each number is the house's level. You start with the news, so you are level 0. Orange arrows: you tell your next-door neighbors (level 1, the first wave). Amber arrows: one of them tells its own neighbors (level 2). The corner houses hear it last (level 3). Here the houses are the vertices, and "next door" is an edge.

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.

People you may knowBea and Carlo are friends of your friends (level 2).YouL0AnaL1MigsL1BeaL2CarloL2SuggestedBea +Carlo +Fewest hopsOne link = one hop. BFS finds the fewest hops.your PCserver3 hops ✓4 hopsWeb crawlerIt visits pages 1 link away, then 2 links away.level 0level 1level 2crawler
Three places BFS shows up. Friend suggestions come from level 2 (people, with friendships as edges). Network routes count hops (devices, with links as edges). A crawler collects pages level by level (pages, with links as edges).

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.

Canteen1234newfrontrearserved first, leavesthe front = dequeuejoins at the rear= enqueue
A canteen line is a queue. Student 1 came first, so student 1 is served first and leaves from the front (dequeue). A new student joins at the rear (enqueue), so the new student waits for students 1 to 4.

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 ( ).

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.

ABDCEFGfrontrearthe queueAnewVisited: (none yet)Seen:A✓new ✓BCDEFG

Start: tick A on the seen list (✓) and put it in the queue. This is the only queue BFS uses.

Step 1 of 8

The BFS procedure

Every BFS follows these steps:

  1. Mark the start vertex as seen (give it a ✓ on the seen list) and enqueue it.
  2. While the queue is not empty:
    1. Dequeue the vertex at the front. Visit it (write it in the BFS order).
    2. 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 ✓.
  3. 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.

BFS from A: which orders are correct?Level 0Level 1Level 2ABCDE✓ABCDECorrect: alphabetical (B before C)the order most answer keys expect✓ACBEDAlso correct: C first, so C’s E comes first toostill nearest first, level by level✗ABDCEWrong: D (level 2) came before C (level 1)that is going deep, not wideA rule like “alphabetical” just picks one correct order.
Each box is colored by its level. Both correct orders go level by level: all of level 1 before any of level 2. They differ only in which neighbor goes first, and C first also puts C's neighbor E first. The wrong order jumps to D (level 2) while C (level 1) is still waiting.

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.

Start at:

Queue (first in, first out)

Visited order

    Color key
    current seen, waiting in queue visited edges being checked edges used L1, L2… = level (steps from start)

    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 ( ). 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 : 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

    AL0BL1CL2DL1EL2FL3GL3

    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:

    VertexBCDEFG
    Found byABABCE

    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 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

    ABCDEFG

    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

    ABCDEFG
    1. Do a BFS starting at D (neighbors in alphabetical order). Write the BFS order.
    2. Give the level of every vertex.
    3. Which vertex or vertices are farthest from D?
    Show the answer

    BFS order: D, B, C, F, G, A, E

    LevelVertices
    0D
    1B, C, F, G
    2A, 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)

    ABCDEF
    1. Do a BFS starting at A, following the arrows. Write the BFS order.
    2. Which vertex is never visited? Why?
    Show the answer

    BFS order: A, B, C, D, E

    LevelVertices
    0A
    1B, C
    2D
    3E

    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.

    CodeRead 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 , 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 -1 there, so every vertex BFS reaches gets −1 + 1 = 0. The first test prints A=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.

    1. Which data structure does BFS use to decide which vertex to visit next?

    2. In the main example graph, starting at A, which vertices are at level 1?

    3. Why does BFS mark a vertex as "seen" when it is enqueued?

    4. In an unweighted graph, BFS from S finds:

    5. You run BFS from vertex A, but vertices X and Y are never visited. What does that tell you?

    6. 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?

    Score: 0 / 6

    Key takeaways

    1. BFS visits a graph level by level, starting from one vertex. The start is level 0.
    2. It uses a queue: dequeue the front, enqueue unseen neighbors at the rear.
    3. Mark vertices as seen when you enqueue them, so nothing is visited twice.
    4. In an unweighted graph, BFS levels give the fewest edges from the start, and the "found by" table gives a shortest path.
    5. 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

    1. A. Bhargava, Grokking Algorithms. Manning, 2016, Chapter 6 (Breadth-first search).
    2. 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).
    3. Programiz, "Breadth First Search (BFS) Algorithm." programiz.com/dsa/graph-bfs
    4. Oracle, "Queue (Java SE 21 & JDK 21)," Java API documentation.