C++ Boost

breadth_first_search

Graphs: directed and undirected
Properties: color
Complexity: time: O(V + E)

  (1)
  template <class VertexListGraph, class BFSVisitor>
  void breadth_first_search(VertexListGraph& G, 
    typename graph_traits<VertexListGraph>::vertex_descriptor s, 
    BFSVisitor vis);

  (2)
  template <class VertexListGraph, class BFSVisitor, class ColorPA>
  void breadth_first_search(VertexListGraph& g, 
    typename graph_traits<VertexListGraph>::vertex_descriptor s, 
    BFSVisitor vis, ColorPA color);

  (3)
  template <class VertexListGraph, class BFSVisitor, class ColorPA>
  void breadth_first_search(VertexListGraph& g, 
    typename graph_traits<VertexListGraph>::vertex_descriptor s, 
    Buffer& Q, BFSVisitor vis, ColorPA color)

The breadth-first search (BFS) algorithm is not really an algorithm in the sense that it has a particular purpose. Instead BFS is more like an algorithm pattern. One can do many different things with BFS. For example, the BFS pattern is used in the BGL to build several other algorithms: Dijkstra's shortest paths, Prim's Minimum Spanning Tree and best-first search. The definition of a breadth-first search is given in Section [*].

The BGL BFS functions are highly parameterized so that they can be used in a wide variety of places. The way to customize the BFS algorithm to perform different operations is to supply a visitor, which is a function object with multiple functions. Each member function of the visitor gets invoked at special times during the algorithm. Also, visitors can be layered on top of each other so that one can do lots of things during a single run of BFS. See Chapter [*] for more details.

Another way to customize the BFS algorithm is change the type of queue used. For instance, dijkstra_shortest_paths() uses a priority queue.

Version 1 of the algorithm takes only three arguments: the graph object, the source vertex, and a visitor to specify the actions to be taken during the graph search. The algorithm will need to use a color property which must be provided by the graph object (through a color plugin).

Version 2 of the algorithm adds a color property argument to accommodate the use of an external property accessor.

Version 3 of the algorithm is the most generalized. It adds a parameter for the queue. Version 1 and 2 of breadth_first_search() are implemented using this generalized version. This version does not initialize the color of all the vertices to white at the start of the algorithm or invoke the initialize_vertex() visitor method.

Where Defined

boost/graph/breadth_first_search.hpp

Requirements on Types

Complexity

The time complexity is O(E + V).

Example

This example demonstrates using the BGL Breadth-first search algorithm on the graph from Figure [*]. The source code for this example is in examples/bfs_basics.cpp.

  // Select the graph type we wish to use
  typedef adjacency_list<vecS, undirectedS> Graph;
  // Set up the vertex ID's and names
  enum { r, s, t, u, v, w, x, y, N };
  char name[] = { 'r', 's', 't', 'u', 'v', 'w', 'x', 'y' };
  // Specify the edges in the graph
  typedef pair<int,int> E;
  E edge_array[] = { E(r,s), E(r,v), E(s,w), E(w,r), E(w,t), 
                     E(w,x), E(x,t), E(t,u), E(x,y), E(u,y) };
  // Create the graph object
  Graph G(N, edge_array, edge_array + sizeof(edge_array)/sizeof(E));

  // Some typedef's to save a little typing
  typedef Graph::vertex_descriptor Vertex;
  typedef std::vector<Vertex>::iterator Piter;
  typedef std::vector<Graph::size_type>::iterator Iiter;

  // vectors to hold color, discover time, and finish time properties
  std::vector<default_color_type> color(num_vertices(G));
  std::vector<Graph::size_type> dtime(num_vertices(G));
  std::vector<Graph::size_type> ftime(num_vertices(G));

  breadth_first_search(G, vertex(s,G),
                       visit_timestamp(dtime.begin(), ftime.begin()),
                       color.begin());

  // Use std::sort to order the vertices by their discover time
  vector<Graph::size_type> discover_order(N);
  iota(discover_order.begin(), discover_order.end(), 0);
  std::sort(discover_order.begin(), discover_order.end(),
            indirect_cmp<Iiter, std::less<Graph::size_type> >(dtime.begin()));

  cout << "order of discovery: ";
  for (int i = 0; i < N; ++i)
    cout << name[ discover_order[i] ] << " ";

  vector<Graph::size_type> finish_order(N);
  iota(finish_order.begin(), finish_order.end(), 0);
  std::sort(finish_order.begin(), finish_order.end(),
            indirect_cmp<Iiter, std::less<Graph::size_type> >(ftime.begin()));

  cout << endl << "order of finish: ";
  for (int i = 0; i < N; ++i)
    cout << name[ finish_order[i] ] << " ";
  cout << endl;
The output is:
  order of discovery: s r w v t x u y 
  order of finish: s r w v t x u y

See Also

graph_search() and depth_first_search()

Copyright © 2000 Jeremy Siek, Univ.of Notre Dame (jsiek@lsc.nd.edu)