For convenience, we will define two functions for extracting what we need out of a vertex or a graph.

Breadth-First Search (BFS)

BFS is a way to traverse or travel a graph and output a tree (a spanning tree if the graph is connected). The output tree being a sub-graph with a root vertex, no cycles, and includes every vertex (reachable from the root) in the graph but not necessarily all of the graph’s edges. This tree grows out from the start vertex or root. Each vertex in each branch of the tree lists the distance back to the root (start vertex). Applications for BFS include determining if there is a path from vertex A to B and finding the shortest path from A to vertex B in unweighted graphs.

We start at a certain vertex (making it the root) and look at its edges. For each edge, we write down the neighboring vertex. Before we leave, we take each neighbor vertex and set its distance to one more than the current distance. We also set the parent or predecessor vertex as the current vertex we are standing on. Just before we are done with the current vertex, we need to add all of its neighbors (minus any we added before) to a queue or waiting line.

If we added vertexes we added before, we may never finish our travels since there might be a cycle in the graph. With the neighbors added, we pluck the next vertex from the queue and do it all over again. If the queue is empty, we are done and we output our BFS tree.

a --- b a.0 --- b.1------>>>------
c --- d c.1 d.2

-- In Out Queue Seen Outbfs ::Graph->Graph-> [Vertex] -> [Vertex] ->Graph
bfs (Graph []) _ _ _ =Graph []
-- If the queue is empty, output the breadth-first search tree (graph).
bfs _ outGraph [] _ = outGraph
bfs (Graph (a:b)) (Graph (c:d)) (e:f) (g:h) = bfs inGraph outGraph queue seen'
where inGraph =Graph (a:b)
-- Get the current vertex label.
eLabel = vertexLabel e
-- Get the list of labels that are the neighbors of the current vertex.
eNeighbors = vertexNeighbors e
-- Get the vertexes from the vertex neighbor labels.
eVertexNeighbors = graphVertexes inGraph eNeighbors
-- The current distance, for the current vertex neighbors, is one more then-- the distance the current vertex is at.
dist = vertexDistance e +1-- Seen is the vertexes that have been queued before.
seen = g : h
-- Remove all neighbors, to the current vertex, that have-- been queued up before.
filteredNeighbors = filterVertexNeighbors seen eVertexNeighbors
-- Update the predecessor label and distance for each current vertex neighbor.
enqueue = updateDistPred filteredNeighbors dist eLabel
-- Update our breadth-first search tree/graph.
outGraph =Graph$ (c:d) ++ enqueue
-- Add the neighbors to the queue.
queue = f ++ enqueue
-- Update seen with the enqueued vertexes.
seen' = seen ++ enqueue

If the input graph is empty, just output an empty graph. When the queue is empty, output the BFS tree we recursively built. Otherwise, call the function again with the input graph, the BFS tree plus the have-not-seen-yet neighbors, the queue minus the current vertex plus the neighbors we haven’t seen yet, and all of the seen or added-to-the-queue-already vertexes.

We will generate some static input consisting of a graph with nine vertexes. You can see the graph drawn below. Before we can kick off bfs, we start the queue, the BFS tree, and the seen list off with the root vertex (in this case e).

Recap

Using Haskell, we defined a graph as a list of vertexes and a vertex as a data structure consisting of a label, an adjacency list, a distance to the root, and a parent vertex label. Our BFS function traversed our input graph recursively and output a BFS tree. For each vertex in the output tree, it specifies how far away from the root it is and its parent vertex.