Skip to main content

Section 34.6 Breadth-First Search

Most graph algorithms are based on a traversal of the graph, which is a systematic way of visiting all the vertices and edges in the graph. The two most common types of graph traversals are breadth-first search (BFS) and depth-first search (DFS). Both of these algorithms start at a given vertex and explore the graph to find all the vertices that are reachable from that starting point.
We will first explore breadth-first search. Breadth first search explores the graph in layers, starting from the given vertex and visiting all of its neighbors before moving on to the neighbors of those neighbors. (It spreads out wide or β€œbroadly” from the starting vertex.) It does so by storing a queue of vertices to be explored. At each step, it removes the front item from the queue and explores all of its neighbors that have not yet been explored. Those neighbors are added to the back of the queue to be explored later.
Listing 34.6.1.
BFS(graph, start):
Queue searchQueue
searchQueue.enqueue(start)
Map parentMap
Map knownMap
knownMap[start] = true
  while not searchQueue.isEmpty():
    vertex = searchQueue.dequeue()
    for each neighbor of vertex:
      if not knownMap.contains(neighbor):
        knownMap[neighbor] = true
        parentMap[neighbor] = vertex
        searchQueue.enqueue(neighbor)

Exploration 34.6.1.

A breadth-first search over a graph.

(a)

We will do a breadth-first search over the graph shown below starting from vertex 1. To do so we add 1 to the search queue.
Current search queue: [1]
A graph with 8 nodes

(b)

Remove the first element from the search queue: 1. Get the list of neighbors of 1. For each neighbor that we do not yet know about, add it to the search queue and remember that we will reach it from 1.
Current search queue: [2 3 5]
Node 1 is connected to nodes 2, 3, and 5

(c)

Remove the first element from the search queue: 2. Get the list of neighbors of 2. For each neighbor that we do not yet know about, add it to the search queue and remember that we will reach it from 2.
2 has two neighbors: 0 and 1. We already know about 1, so it is ignored. We add 0 to the search queue. Because we are using a queue, the newly added vertex will be at the back of the line to be explored.
Current search queue: [3 5 0]
Node 2 is connected to 0 and 1

(d)

Remove the first element from the search queue: 3. Get the list of neighbors of 3. For each neighbor that we do not yet know about, add it to the search queue and remember that we will reach it from 3.
3 has neighbors 1 and 7. 1 is known. 7 goes in the search queue.
Current search queue: [5 0 7]
Node 3 is connected to nodes 1 and 7

(e)

Remove the first element from the search queue: 5. Get the list of neighbors of 5. For each neighbor that we do not yet know about, add it to the search queue and remember that we will reach it from 5.
5 has neighbors 1 and 7. Both are already known.
Current search queue: [0 7]
Node 5 is connected to nodes 1 and 7

(f)

Remove the first element from the search queue: 0. Get the list of neighbors of 0. For each neighbor that we do not yet know about, add it to the search queue and remember that we will reach it from 0.
0 has neighbor 2. It is already known.
Current search queue: [7]
Node 0 is connected to node 2

(g)

Remove the first element from the search queue: 7. Get the list of neighbors of 7. For each neighbor that we do not yet know about, add it to the search queue and remember that we will reach it from 7.
7 has neighbors 3, 5, 4, and 6. 3 and 5 are known. 4 and 6 are new, so we add them to the search queue.
Current search queue: [4 6]
Node 7 is connected to nodes 3, 5, 4, and 6

(h)

Remove the first element from the search queue: 4. Get the list of neighbors of 4. For each neighbor that we do not yet know about, add it to the search queue and remember that we will reach it from 4.
4’s only neighbor is 7 which is already known.
Current search queue: [6]
Node 4 is only connected to 7

(i)

Remove the first element from the search queue: 6. Get the list of neighbors of 6. For each neighbor that we do not yet know about, add it to the search queue and remember that we will reach it from 6.
6’s only neighbor is 7 which is already known.
Current search queue: []
Because the search queue is now empty, we are done with the search.
Node 6 is only connected to 7
A breadth or depth first search always produces a search tree, which is a subgraph of the original graph that contains all the vertices that were reached during the search and the edges that were used to reach those vertices. Below, this search tree is shown in the original graph and then isolated and restructured to make the tree shape more clear.
Search tree for breadth-first search
Figure 34.6.2. Search tree (red edges) within the original graph. Note that not every edge in the original graph is in the search tree.
Search tree for breadth-first search
Figure 34.6.3. Search tree produced by the breadth-first search in the investigation above.
Examining the search tree helps to clarify why this is called β€œbreadth-first search”. It explores out in layers, first exploring all the vertices that are one edge away from the starting vertex, then all the vertices that are two edges away, and so on. This means that the path from the starting vertex to any other vertex in the search tree is the shortest path (in terms of number of edges) from the starting vertex to that vertex in the original graph.
Starting from a different vertex in the same graph would produce a different search tree - one that contains the shortest path from that vertex to every other vertex in the search tree.

Insight 34.6.1.

Breadth-first search produces a search tree with the shortest (unweighted) path from the starting vertex to every other vertex in the search tree.
Use the interactive below to explore breadth-first search.

Activity 34.6.2. Breadth-First Search.

The animation will load a random graph and start a breadth-first search from vertex 0. Step through the animation. As you do so, note how the Known and Parent tables are updated.
Once you are done exploring from 0, explore from a different starting vertex by entering a Start Vertex number in the input field and clicking on the Run BFS button.
Use New Graph button to generate a new random graph. (You may need to fast forward to the end before being able to create a new graph.

Instructions.

When the > button is highlighted, an animation is prepared to run. Use the Step button to step through the animation one step at a time.
When no animation is in progress, you can use the data controls to start a new animation.
You can click and drag on the animation area to pan around. Use the Ctrl + mouse wheel (or touchpad scroll gesture) while over the animation area to zoom in and out.
  • Core Controls.
    • << : Skip to the beginning of the animation.
    • < : Step backwards one step in the animation.
    • > : Step forward one step in the animation.
    • >> : Skip to the end of the animation.
    • Auto Step Speed Set to anything other than off to automatically step through the animation at the selected speed.
    • Zoom Set the zoom level. You can also use Ctrl + Mouse Wheel to zoom in and out.
  • Graph Controls.
    • New Graph Randomly generate a new graph with the same settings.
    • Directed Graph Randomly generate a new directed graph.
    • Undirected Graph Randomly generate a new undirected graph.
    • Small Graph Randomly generate a graph with 8 vertices.
    • Large Graph Randomly generate a graph with 19 vertices.
    • Logical Representation Display current graph’s logical representation.
    • Adjacency List Representation Display current graph’s adjacency list representation.
    • Adjacency Matrix Representation Display current graph’s adjacency matrix representation.
The final results of this process can be represented as a full Graph object that contains all the vertices and edges in the search tree. Or, as shown in the animation, we can simply keep track of the parent of each vertex and use that as the search tree representation. With it , we can find the path from the starting vertex to any other vertex in the search tree by following the parent mappings back to the starting vertex. We will know that we have reached the starting vertex when we encounter a vertex that does not have a parent.
For example, consider the parent mapping below (turned horizontal for readability). We can see that vertex 0 was the starting point of the search since it has no parent. To determine the path to vertex 7, we can see that we reach it from vertex 3, which we reach from vertex 1, which we reach from vertex 0. So the path from vertex 0 to vertex 7 is 0 -> 1 -> 3 -> 7.
Vertex 0 1 2 3 4 5 6 7
Parent 1 1 2 7 1 7 3
Figure 34.6.4. A parent table resulting from a search

Checkpoint 34.6.1.

Put the following code blocks in the correct order to implement breadth-first search:

Checkpoint 34.6.2.

You have attempted of activities on this page.