mirror of
https://github.com/boostorg/graph.git
synced 2026-01-31 20:22:09 +00:00
729 lines
26 KiB
HTML
729 lines
26 KiB
HTML
<HTML>
|
|
<!--
|
|
-- Copyright (c) Jeremy Siek 2000
|
|
--
|
|
-- Permission to use, copy, modify, distribute and sell this software
|
|
-- and its documentation for any purpose is hereby granted without fee,
|
|
-- provided that the above copyright notice appears in all copies and
|
|
-- that both that copyright notice and this permission notice appear
|
|
-- in supporting documentation. Silicon Graphics makes no
|
|
-- representations about the suitability of this software for any
|
|
-- purpose. It is provided "as is" without express or implied warranty.
|
|
-->
|
|
<Head>
|
|
<Title>Quick Tour of Boost Graph Library</Title>
|
|
<BODY BGCOLOR="#ffffff" LINK="#0000ee" TEXT="#000000" VLINK="#551a8b"
|
|
ALINK="#ff0000">
|
|
<IMG SRC="../../../c++boost.gif"
|
|
ALT="C++ Boost">
|
|
|
|
<BR Clear>
|
|
|
|
<H1>A Quick Tour of the Boost Graph Library</H1>
|
|
|
|
<P>
|
|
The domain of graph data structures and algorithms is in some respects
|
|
more complicated than that of containers. The abstract iterator
|
|
interface used by STL is not sufficiently rich to encompass the
|
|
numerous ways that graph algorithms may traverse a graph. Instead, we
|
|
formulate an abstract interface that serves the same purpose for
|
|
graphs that iterators do for basic containers (though iterators still
|
|
play a large role). <A HREF="#fig:analogy">Figure 1</A> depicts
|
|
the analogy between the STL and the BGL.
|
|
|
|
<p></p>
|
|
<DIV ALIGN="CENTER"><A NAME="fig:analogy"></A><A NAME="752"></A>
|
|
<TABLE>
|
|
<CAPTION ALIGN="BOTTOM"><STRONG>Figure 1:</STRONG>
|
|
The analogy between the STL and the BGL.</CAPTION>
|
|
<TR><TD><IMG SRC="./figs/analogy.gif"></TD></TR>
|
|
</TABLE>
|
|
</DIV>
|
|
<p></p>
|
|
|
|
The graph abstraction consists of a set of vertices (or nodes), and a
|
|
set of edges (or arcs) that connect the vertices. <A
|
|
HREF="#fig:quick-start">Figure 2</A>
|
|
depicts a directed graph with five vertices (labeled 0 through 4) and
|
|
11 edges. The edges leaving a vertex are called the <I>out-edges</I>
|
|
of the vertex. The edges <tt>{(0,1),(0,2),(0,3),(0,4)}</tt> are all
|
|
out-edges of vertex 0. The edges entering a vertex are called the
|
|
<I>in-edges</I> of the vertex. The edges <tt>{(0,4),(2,4),(3,4)}</tt>
|
|
are all in-edges of vertex 4.
|
|
|
|
<p></p>
|
|
<DIV ALIGN="CENTER"><A NAME="fig:quick-start"></A></A>
|
|
<TABLE>
|
|
<CAPTION ALIGN="BOTTOM"><STRONG>Figure 2:</STRONG>
|
|
An example of a directed graph.</CAPTION>
|
|
<TR><TD><IMG SRC="./figs/quick_start.gif"></TD></TR>
|
|
</TABLE>
|
|
</DIV>
|
|
<p></p>
|
|
|
|
<P>
|
|
In the following sections we will use the BGL to construct this
|
|
example graph and manipulate it in various ways. The complete source
|
|
code for this example can be found in <a
|
|
href="../examples/quick_tour.cpp"><TT>examples/quick_tour.cpp</TT></a>.
|
|
Each of the following sections discusses a "slice" of this
|
|
example file. Excerpts from the output of the example program will
|
|
also be listed.
|
|
|
|
<P>
|
|
|
|
<H2>Constructing a Graph</H2>
|
|
|
|
<P>
|
|
In this example we will use the BGL <TT>adjacency_list</TT> class to
|
|
demonstrate the main ideas in the BGL interface. The
|
|
<TT>adjacency_list</TT> class provides a generalized version of the
|
|
classic "adjacency list" data structure. The
|
|
<TT>adjacency_list</TT> is a template class with six template
|
|
parameters, though here we only fill in the first three parameters and
|
|
use the defaults for the remaining three. The first two template
|
|
arguments (<TT>vecS, vecS</TT>) determine the data structure used to
|
|
represent the out-edges for each vertex in the graph and the data
|
|
structure used to represent the graph's vertex set (see section <a
|
|
href="using_adjacency_list.html#sec:choosing-graph-type">Choosing the
|
|
<TT>Edgelist</TT> and <TT>VertexList</TT></a> for information about
|
|
the tradeoffs of the different data structures). The third argument,
|
|
<TT>bidirectionalS</TT>, selects a directed graph that provides access
|
|
to both out and in-edges. The other options for the third argument are
|
|
<TT>directedS</TT> which selects a directed graph with only out-edges,
|
|
and <TT>undirectedS</TT> which selects an undirected graph.
|
|
|
|
<P>
|
|
Once we have the graph type selected, we can create the graph in <A
|
|
HREF="#fig:quick-start">Figure 2</A> by declaring a graph object and
|
|
filling in edges using the <TT>add_edge()</TT> function. We use the
|
|
array of pairs <TT>edge_array</TT> merely as a convenient way to
|
|
explicitly create the edges for this example.
|
|
|
|
<P>
|
|
<PRE>
|
|
#include <iostream> // for std::cout
|
|
#include <utility> // for std::pair
|
|
#include <algorithm> // for std::for_each
|
|
#include <boost/graph/graph_traits.hpp>
|
|
#include <boost/graph/adjacency_list.hpp>
|
|
|
|
using namespace ggcl;
|
|
using namespace boost;
|
|
|
|
int main(int,char*[])
|
|
{
|
|
typedef std::pair<int, int> E;
|
|
const int num_edges = 11;
|
|
// writing out the edges in the graph
|
|
E edge_array[num_edges] = { E(0,1), E(0,2), E(0,3), E(0,4),
|
|
E(2,0), E(3,0), E(2,4), E(3,1),
|
|
E(3,4), E(4,0), E(4,1) };
|
|
const int num_vertices = 5;
|
|
|
|
// create a typedef for the Graph type
|
|
typedef adjacency_list<vecS, vecS, bidirectionalS> Graph;
|
|
|
|
// declare a graph object
|
|
Graph g(num_vertices);
|
|
|
|
// add the edges to the graph object
|
|
for (int i = 0; i < num_edges; ++i)
|
|
add_edge(g, edge_array[i].first, edge_array[i].second);
|
|
...
|
|
return 0;
|
|
}
|
|
</PRE>
|
|
|
|
<P>
|
|
Instead of calling the <TT>add_edge()</TT> function for each edge, we
|
|
could use the iterator constructor of the graph. This is typically
|
|
more efficient than using <TT>add_edge()</TT>. Pointers to the
|
|
<TT>edge_array</TT> can be viewed as iterators, so we can call the
|
|
iterator constructor by passing pointers to the beginning and end of
|
|
the array.
|
|
|
|
<P>
|
|
<PRE>
|
|
Graph g(num_vertices, edge_array,
|
|
edge_array + sizeof(edge_array) / sizeof(E));
|
|
</PRE>
|
|
|
|
<P>
|
|
|
|
<H2>Accessing the Vertex Set</H2>
|
|
|
|
<P>
|
|
Now that we have created a graph, we can use the graph interface to
|
|
access the graph data in different ways. First we can access all of
|
|
the vertices in the graph using the <TT>vertices()</TT> function. This
|
|
function returns a <TT>std::pair</TT> of <I>vertex iterators</I> (the
|
|
<TT>first</TT> iterator points to the "beginning" of the vertices and
|
|
the <TT>second</TT> iterator points "past the end"). Dereferencing a
|
|
vertex iterator gives a vertex object. The type of the vertex
|
|
iterator is given by the <TT>graph_traits</TT> class. Note that
|
|
different graph classes can have different associated vertex iterator
|
|
types, which is why we need the <TT>graph_traits</TT> class. Given some
|
|
graph type, the <TT>graph_traits</TT> class will provide access to the
|
|
<TT>vertex_iterator</TT> type.
|
|
|
|
<P>
|
|
The following example prints out the ID for each of the vertices in
|
|
the graph. All vertex and edge properties, including ID, are accessed
|
|
via property map objects. The <TT>property_map</TT>
|
|
class is used to obtain the property map type for a specific
|
|
property (specified by <TT>vertex_index</TT>, one of the BGL
|
|
predefined tags) and function call <TT>get(vertex_index(), g)</TT>
|
|
returns the actual property map object.
|
|
|
|
<P>
|
|
<PRE>
|
|
// ...
|
|
int main(int,char*[])
|
|
{
|
|
// ...
|
|
|
|
// get the property map for vertex ID's
|
|
typedef property_map<Graph, vertex_index>::type ID;
|
|
ID id = get(vertex_index(), g);
|
|
|
|
std::cout << "vertices(g) = ";
|
|
typedef graph_traits<Graph>::vertex_iterator vertex_iter;
|
|
std::pair<vertex_iter, vertex_iter> vp;
|
|
for (vp = vertices(g); vp.first != vp.second; ++vp.first)
|
|
std::cout << id[*vp.first] << " ";
|
|
std::cout << std::endl;
|
|
// ...
|
|
return 0;
|
|
}
|
|
</PRE>
|
|
The output is:
|
|
<PRE>
|
|
vertices(g) = 0 1 2 3 4
|
|
</PRE>
|
|
|
|
<P>
|
|
|
|
<H2>Accessing the Edge Set</H2>
|
|
|
|
<P>
|
|
The set of edges for a graph can be accessed with the <TT>edges()</TT>
|
|
function. Similar to the <TT>vertices()</TT> function, this returns a
|
|
pair of iterators, but in this case the iterators are <I>edge
|
|
iterators</I>. Dereferencing an edge iterator gives an edge
|
|
object. The <TT>source()</TT> and <TT>target()</TT> functions return
|
|
the two vertices that are connected by the edge. Instead of explicitly
|
|
creating a <TT>std::pair</TT> for the iterators, this time we will use
|
|
the <a href="../../utility/tie.html"><TT>tie()</TT></a> helper
|
|
function. This handy function can be used to assign the parts of a
|
|
<TT>std::pair</TT> into two separate variables, in this case
|
|
<TT>ei</TT> and <TT>ei_end</TT>. This is usually more convenient than
|
|
creating a <TT>std::pair</TT> and is our method of choice for the BGL.
|
|
|
|
<P>
|
|
<PRE>
|
|
// ...
|
|
int main(int,char*[])
|
|
{
|
|
// ...
|
|
std::cout << "edges(g) = ";
|
|
graph_traits<Graph>::edge_iterator ei, ei_end;
|
|
for (tie(ei, ei_end) = edges(g); ei != ei_end; ++ei)
|
|
std::cout << "(" << id[source(*ei, g)]
|
|
<< "," << id[target(*ei, g)] << ") ";
|
|
std::cout << std::endl;
|
|
// ...
|
|
return 0;
|
|
}
|
|
</PRE>
|
|
The output is:
|
|
<PRE>
|
|
edges(g) = (0,1) (0,2) (0,3) (0,4) (2,0) (2,4) (3,0)
|
|
(3,1) (3,4) (4,0) (4,1)
|
|
</PRE>
|
|
|
|
<P>
|
|
|
|
<H2>The Adjacency Structure</H2>
|
|
|
|
<P>
|
|
In the next few examples we will explore the adjacency structure of
|
|
the graph from the point of view of a particular vertex. We will look
|
|
at the vertices' in-edges, out-edges, and its adjacent vertices. We
|
|
will encapsulate this in an "exercise vertex" function, and apply it
|
|
to each vertex in the graph. To demonstrate the STL-interoperability
|
|
of BGL, we will use the STL <TT>for_each()</TT> function to iterate
|
|
through the vertices and apply the function.
|
|
|
|
<P>
|
|
<PRE>
|
|
//...
|
|
int main(int,char*[])
|
|
{
|
|
//...
|
|
std::for_each(vertices(g).first, vertices(g).second,
|
|
exercise_vertex<Graph>(g));
|
|
return 0;
|
|
}
|
|
</PRE>
|
|
|
|
<P>
|
|
We use a functor for <TT>exercise_vertex</TT> instead of just a
|
|
function because the graph object will be needed when we access
|
|
information about each vertex; using a functor gives us a place to
|
|
keep a reference to the graph object during the execution of the
|
|
<TT>std::for_each()</TT>. Also we template the functor on the graph
|
|
type so that it is reusable with different graph classes. Here is the
|
|
start of the <TT>exercise_vertex</TT> functor:
|
|
|
|
<P>
|
|
<PRE>
|
|
template <class Graph> struct exercise_vertex {
|
|
exercise_vertex(Graph& g_) : g(g_) {}
|
|
//...
|
|
Graph& g;
|
|
};
|
|
</PRE>
|
|
|
|
<P>
|
|
|
|
<H3>Vertex Descriptors</H3>
|
|
|
|
<P>
|
|
The first thing we need to know in order to write the
|
|
<TT>operator()</TT> method of the functor is the type for the vertex
|
|
objects of the graph. The vertex type will be the parameter to the
|
|
<TT>operator()</TT> method. To be precise, we do not deal with actual
|
|
vertex objects, but rather with <I>vertex descriptors</I>. Many graph
|
|
representations (such as adjacency lists) do not store actual vertex
|
|
objects, while others do (e.g., pointer-linked graphs). This
|
|
difference is hidden underneath the "black-box" of the vertex
|
|
descriptor object. The vertex descriptor is something provided by each
|
|
graph type that can be used to access information about the graph via
|
|
the <TT>out_edges()</TT>, <TT>in_edges()</TT>,
|
|
<TT>adjacent_vertices()</TT>, and property map functions that are
|
|
described in the following sections. The <TT>vertex_descriptor</TT>
|
|
type is obtained through the <TT>graph_traits</TT> class. The
|
|
<TT>typename</TT> keyword used below is necessary because the type on
|
|
the left hand side of the scope <TT>::</TT> operator (the
|
|
<TT>graph_traits<Graph></TT> type) is dependent on a template parameter
|
|
(the <TT>Graph</TT> type). Here is how we define the functor's apply
|
|
method:
|
|
|
|
<P>
|
|
<PRE>
|
|
template <class Graph> struct exercise_vertex {
|
|
//...
|
|
typedef typename graph_traits<Graph>
|
|
::vertex_descriptor Vertex;
|
|
|
|
void operator()(const Vertex& v) const
|
|
{
|
|
//...
|
|
}
|
|
//...
|
|
};
|
|
</PRE>
|
|
|
|
<P>
|
|
|
|
<H3>Out-Edges, In-Edges, and Edge Descriptors</H3>
|
|
|
|
<P>
|
|
The out-edges of a vertex are accessed with the <TT>out_edges()</TT>
|
|
function. The <TT>out_edges()</TT> function takes two arguments: the
|
|
first argument is the vertex and the second is the graph object. The
|
|
function returns a pair of iterators which provide access to all of
|
|
the out-edges of a vertex (similar to how the <TT>vertices()</TT>
|
|
function returned a pair of iterators). The iterators are called
|
|
<I>out-edge iterators</I> and dereferencing one of these iterators
|
|
gives an <I>edge descriptor</I> object. An edge descriptor plays the
|
|
same kind of role as the vertex descriptor object, it is a "black
|
|
box" provided by the graph type. The following code snippet prints
|
|
the source-target pairs for each out-edge of vertex <TT>v</TT>.
|
|
|
|
<P>
|
|
<PRE>
|
|
template <class Graph> struct exercise_vertex {
|
|
//...
|
|
void operator()(const Vertex& v) const
|
|
{
|
|
typedef graph_traits<Graph> GraphTraits;
|
|
typename property_map<Graph, vertex_index>::type
|
|
id = get(vertex_index(), g);
|
|
|
|
std::cout << "out-edges: ";
|
|
typename GraphTraits::out_edge_iterator out_i, out_end;
|
|
typename GraphTraits::edge_descriptor e;
|
|
for (tie(out_i, out_end) = out_edges(v, g);
|
|
out_i != out_end; ++out_i) {
|
|
e = *out_i;
|
|
Vertex src = source(e, g), targ = target(e, g);
|
|
std::cout << "(" << id[src] << ","
|
|
<< id[targ] << ") ";
|
|
}
|
|
std::cout << std::endl;
|
|
//...
|
|
}
|
|
//...
|
|
};
|
|
</PRE>
|
|
For vertex 0 the output is:
|
|
<PRE>
|
|
out-edges: (0,1) (0,2) (0,3) (0,4)
|
|
</PRE>
|
|
|
|
<P>
|
|
The <TT>in_edges()</TT> function provides access to all the in-edges of
|
|
a vertex through <I>in-edge iterators</I>. The <TT>in_edges()</TT>
|
|
function is only available for the <TT>adjacency_list</TT> if
|
|
<TT>bidirectionalS</TT> is supplied for the <TT>Directed</TT> template
|
|
parameter. There is an extra cost in space when <TT>bidirectionalS</TT>
|
|
is specified instead of <TT>directedS</TT>.
|
|
|
|
<P>
|
|
<PRE>
|
|
template <class Graph> struct exercise_vertex {
|
|
//...
|
|
void operator()(const Vertex& v) const
|
|
{
|
|
//...
|
|
std::cout << "in-edges: ";
|
|
typedef typename graph_traits<Graph> GraphTraits;
|
|
typename GraphTraits::in_edge_iterator in_i, in_end;
|
|
for (tie(in_i, in_end) = in_edges(v,g);
|
|
in_i != in_end; ++in_i) {
|
|
e = *in_i;
|
|
Vertex src = source(e, g), targ = target(e, g);
|
|
std::cout << "(" << id[src] << "," << id[targ] << ") ";
|
|
}
|
|
std::cout << std::endl;
|
|
//...
|
|
}
|
|
//...
|
|
};
|
|
</PRE>
|
|
For vertex 0 the output is:
|
|
<PRE>
|
|
in-edges: (2,0) (3,0) (4,0)
|
|
</PRE>
|
|
|
|
<P>
|
|
|
|
<H3>Adjacent Vertices</H3>
|
|
|
|
<P>
|
|
Given the out-edges of a vertex, the target vertices of these edges
|
|
are <I>adjacent</I> to the source vertex. Sometimes an algorithm does
|
|
not need to look at the edges of the graph and only cares about the
|
|
vertices. Therefore the graph interface also includes the
|
|
<TT>adjacent_vertices()</TT> function which provides direct access to
|
|
the adjacent vertices. This function returns a pair of <I>adjacency
|
|
iterators</I>. Dereferencing an adjacency iterator gives a vertex
|
|
descriptor for an adjacent vertex.
|
|
|
|
<P>
|
|
<PRE>
|
|
template <class Graph> struct exercise_vertex {
|
|
//...
|
|
void operator()(Vertex v) const
|
|
{
|
|
//...
|
|
std::cout << "adjacent vertices: ";
|
|
typename graph_traits<Graph>::adjacency_iterator ai;
|
|
typename graph_traits<Graph>::adjacency_iterator ai_end;
|
|
for (tie(ai, ai_end) = adjacent_vertices(v, g);
|
|
ai != ai_end; ++ai)
|
|
std::cout << id[*ai] << " ";
|
|
std::cout << std::endl;
|
|
}
|
|
//...
|
|
};
|
|
</PRE>
|
|
For vertex 4 the output is:
|
|
<PRE>
|
|
adjacent vertices: 0 1
|
|
</PRE>
|
|
|
|
<P>
|
|
|
|
<H2>Adding Some Color to your Graph</H2>
|
|
|
|
<P>
|
|
BGL attempts to be as flexible as possible in terms of accommodating
|
|
how properties are attached to a graph. For instance, a property such
|
|
as edge weight may need to be used throughout a graph object's
|
|
lifespan and therefore it would be convenient to have the graph object
|
|
also manage the property storage. On the other hand, a property like
|
|
vertex color may only be needed for the duration of a single
|
|
algorithm, and it would be better to have the property stored
|
|
separately from the graph object. The first kind of property is called
|
|
an <I>internally stored property</I> while the second kind is called
|
|
an <I>externally stored property</I>. BGL uses a uniform mechanism to
|
|
access both kinds of properties inside its graph algorithms called the
|
|
<I>property map</I> interface, described in Section <a
|
|
href="../../property_map.html">Property Map Concepts</a>. In
|
|
addition, the <a
|
|
href="./VertexPropertyGraph.html">VertexPropertyGraph</a> and <a
|
|
href="./EdgePropertyGraph.html">EdgePropertyGraph</a> concepts define
|
|
the interface for obtaining a property map object for an
|
|
internally property.
|
|
|
|
<P>
|
|
The BGL <TT>adjacency_list</TT> class allows users to specify
|
|
internally stored properties through plug-in template parameters of
|
|
the graph class. How to do this is discussed in detail in Section <a
|
|
href="./using_adjacency_list.html#sec:adjacency-list-plugins">Plugins</a>.
|
|
Externally stored properties can be created in many different ways,
|
|
although they are ultimately passed as separate arguments to the graph
|
|
algorithms. One straightforward way to store properties is to create
|
|
an array indexed by vertex or edge ID. In the <TT>adjacency_list</TT>
|
|
with <TT>vecS</TT> specified for the <TT>VertexList</TT> template
|
|
parameter, vertices are automatically assigned ID numbers, which can
|
|
be accessed via the property map for the <TT>vertex_index</TT>. Edges
|
|
are not automatically assigned ID numbers. However the plugin
|
|
mechanism can be used to attach ID numbers to the edges which can be
|
|
used to index into other externally stored properties.
|
|
|
|
<P>
|
|
In the following example, we construct a graph and apply <a
|
|
href="./dijkstra_shortest_paths.html"><tt>dijkstra_shortest_paths()</tt></a>.
|
|
The complete source code for the example is in <a
|
|
href="../examples/dijkstra.cpp"><TT>examples/dijkstra.cpp</TT></a>. Dijkstra's
|
|
algorithm computes the shortest distance from the starting vertex to
|
|
every other vertex in the graph.
|
|
|
|
<P>
|
|
Dijkstra's algorithm requires that a weight property is associated
|
|
with each edge and a distance property with each vertex. Here we use
|
|
an internal property for the weight and an external property for the
|
|
distance. For the weight property we use the <TT>plugin</TT> class and
|
|
specify <TT>int</TT> as the type used to represent weight values and
|
|
<TT>edge_weight</TT> for the property tag (which is one of the BGL
|
|
predefined property tags). The weight plugin is then used as a
|
|
template argument for <TT>adjacency_list</TT>.
|
|
|
|
<P>
|
|
The <TT>listS</TT> and <TT>vecS</TT> types are selectors that
|
|
determine the data structure used inside the <TT>adjacency_list</TT>
|
|
(see Section <a
|
|
href="./using_adjacency_list.html#sec:choosing-graph-type">Choosing
|
|
the <TT>Edgelist</TT> and <TT>VertexList</TT></a>). The
|
|
<TT>directedS</TT> type specifies that the graph should be directed
|
|
(versus undirected). The following code shows the specification of
|
|
the graph type and then the initialization of the graph. The edges and
|
|
weights are passed to the graph constructor in the form of iterators
|
|
(a pointer qualifies as a <a
|
|
href="http://www.sgi.com/Technology/STL/RandomAccessIterator.html">RandomAccessIterator</a>).
|
|
|
|
<P>
|
|
<PRE>
|
|
typedef adjacency_list<listS, vecS, directedS,
|
|
no_plugin, plugin<edge_weight, int> > Graph;
|
|
typedef graph_traits<Graph>::vertex_descriptor Vertex;
|
|
typedef std::pair<int,int> E;
|
|
|
|
const int num_nodes = 5;
|
|
E edges[] = { E(0,2),
|
|
E(1,1), E(1,3), E(1,4),
|
|
E(2,1), E(2,3),
|
|
E(3,4),
|
|
E(4,0), E(4,1) };
|
|
int weights[] = { 1, 2, 1, 2, 7, 3, 1, 1, 1};
|
|
|
|
Graph G(num_nodes, edges,
|
|
edges + sizeof(edges) / sizeof(E), weights);
|
|
</PRE>
|
|
|
|
<P>
|
|
For the external distance property we will use a <TT>std::vector</TT>
|
|
for storage. BGL algorithms treat random access iterators as property
|
|
maps, so we can just pass the beginning iterator of the distance
|
|
vector to Dijkstra's algorithm. Continuing the above example, the
|
|
following code shows the creation of the distance vector, the call to
|
|
Dijkstra's algorithm (implicitly using the internal edge weight
|
|
property), and then the output of the results.
|
|
|
|
<P>
|
|
<PRE>
|
|
// vector for storing distance property
|
|
std::vector<int> d(num_vertices(G));
|
|
|
|
// get the first vertex
|
|
Vertex s = *(vertices(G).first);
|
|
// invoke variant 2 of Dijkstra's algorithm
|
|
dijkstra_shortest_paths(G, s, d.begin());
|
|
|
|
std::cout << "distances from start vertex:" << std::endl;
|
|
graph_traits<Graph>::vertex_iterator vi;
|
|
for(vi = vertices(G).first; vi != vertices(G).second; ++vi)
|
|
std::cout << "distance(" << index(*vi) << ") = "
|
|
<< d[*vi] << std::endl;
|
|
std::cout << std::endl;
|
|
</PRE>
|
|
The output is:
|
|
<PRE>
|
|
distances from start vertex:
|
|
distance(0) = 0
|
|
distance(1) = 6
|
|
distance(2) = 1
|
|
distance(3) = 4
|
|
distance(4) = 5
|
|
</PRE>
|
|
|
|
<P>
|
|
|
|
<H2>Extending Algorithms with Visitors</H2>
|
|
|
|
<P>
|
|
Often times an algorithm in a library <I>almost</I> does what you
|
|
need, but not quite. For example, in the previous section we used
|
|
Dijkstra's algorithm to calculate the shortest distances to each
|
|
vertex, but perhaps we also wanted to record the tree of shortest
|
|
paths. One way to do this is to record the predecessor (parent) for
|
|
each node in the shortest-paths tree.
|
|
|
|
<P>
|
|
It would be nice if we could avoid rewriting Dijkstra's algorithm, and
|
|
just add that little bit extra needed to record the predecessors. In
|
|
the STL, this kind of extensibility is provided by functors, which are
|
|
optional parameters to each algorithm. In the BGL this role is
|
|
fulfilled by <I>visitors</I>.
|
|
|
|
<P>
|
|
A visitor is like a functor, but instead of having just one
|
|
"apply" method, it has several. Each of these methods get
|
|
invoked at certain well-defined points within the algorithm. The
|
|
visitor methods are explained in detail in Section <a
|
|
href="./visitor_concepts.html">Visitor Concepts</a>.
|
|
|
|
The BGL provides a number of visitors for some common tasks including
|
|
a predecessor recording visitor. The user is encouraged to write his
|
|
or her own visitors as a way of extending the BGL. Here we will take a
|
|
quick look at the implementation and use of the predecessor recorder.
|
|
Since we will be using the <a
|
|
href="./dijkstra_shortest_paths.html">dijkstra_shortest_paths()</a>
|
|
algorithm, the visitor we create must be a (a <a
|
|
href="./UniformCostVisitor.html">UniformCostVisitor</a>).
|
|
|
|
<P>
|
|
The functionality of the <tt>record_predecessors</tt> visitor is
|
|
separated into two parts. For the storage and access of the
|
|
predecessor property, we will use a <a
|
|
href="../../property_map/property_map.html">property
|
|
map</a>. The predecessor visitor will then only be responsible
|
|
for what parent to record. To implement this, we create a
|
|
<TT>record_predecessors</TT> class and template it on the predecessor
|
|
property map <TT>PredecessorMap</TT>. Since this visitor
|
|
will only be filling in one of the visitor methods, we will inherit
|
|
from <a href="./ucs_visitor.html"><TT>ucs_visitor</TT></a> which will
|
|
provide empty methods for the rest. The constructor of the
|
|
<TT>predecessor_recorder</TT> will take the property map object
|
|
and save it away in a data member.
|
|
|
|
<P>
|
|
<PRE>
|
|
template <class PredecessorMap>
|
|
class record_predecessors : public ucs_visitor<>
|
|
{
|
|
public:
|
|
record_predecessors(PredecessorMap p)
|
|
: m_predecessor(p) { }
|
|
|
|
template <class Edge, class Graph>
|
|
void edge_relaxed(Edge e, Graph& g) {
|
|
// set the parent of the target(e) to source(e)
|
|
put(m_predecessor, target(e, g), source(e, g));
|
|
}
|
|
protected:
|
|
PredecessorMap m_predecessor;
|
|
};
|
|
</PRE>
|
|
|
|
<P>
|
|
The job of recording the predecessors is quite simple. When Dijkstra's
|
|
algorithm relaxes an edge (potentially adding it to the shortest-paths
|
|
tree) we record the source vertex as the predecessor of the target
|
|
vertex. Later, if the edge is relaxed again the predecessor property
|
|
will be overwritten by the new predecessor. Here we use the
|
|
<TT>put()</TT> function associated with the property map to
|
|
record the predecessor. The <TT>edge_filter</TT> of the visitor tells
|
|
the algorithm when to invoke the <TT>explore()</TT> method. In this
|
|
case we only want to be notified about edges in the shortest-paths
|
|
tree so we specify <TT>tree_edge_tag</TT>.
|
|
|
|
<P>
|
|
As a finishing touch, we create a helper function to make it more
|
|
convenient to create predecessor visitors. All BGL visitors have a
|
|
helper function like this.
|
|
|
|
<P>
|
|
<PRE>
|
|
template <class PredecessorMap>
|
|
record_predecessors<PredecessorMap>
|
|
make_predecessor_recorder(PredecessorMap p) {
|
|
return record_predecessors<PredecessorMap>(p);
|
|
}
|
|
</PRE>
|
|
|
|
<P>
|
|
We are now ready to use the <TT>record_predecessors</TT> in
|
|
Dijkstra's algorithm. Luckily, BGL's Dijkstra's algorithm is already
|
|
equipped to handle visitors, so we just have to call the four argument
|
|
version of the algorithm and pass in our new visitor. In this example
|
|
we only need to use one visitor, but the BGL is also equipped to
|
|
handle the use of multiple visitors in the same algorithm (see Section
|
|
<a href="./visitor_concepts.html">Visitor Concepts</a>).
|
|
|
|
<P>
|
|
<PRE>
|
|
using std::vector;
|
|
using std::cout;
|
|
using std::endl;
|
|
vector<Vertex> p(num_vertices(G)); //the predecessor array
|
|
dijkstra_shortest_paths(G, s, d.begin(),
|
|
make_predecessor_recorder(p.begin()));
|
|
|
|
cout << "parents in the tree of shortest paths:" << endl;
|
|
for(vi = vertices(G).first; vi != vertices(G).second; ++vi) {
|
|
cout << "parent(" << *vi;
|
|
if (p[*vi] == Vertex())
|
|
cout << ") = no parent" << endl;
|
|
else
|
|
cout << ") = " << p[*vi] << endl;
|
|
}
|
|
</PRE>
|
|
The output is:
|
|
<PRE>
|
|
parents in the tree of shortest paths:
|
|
parent(0) = no parent
|
|
parent(1) = 4
|
|
parent(2) = 0
|
|
parent(3) = 2
|
|
parent(4) = 3
|
|
</PRE>
|
|
|
|
|
|
<br>
|
|
<HR>
|
|
<TABLE>
|
|
<TR valign=top>
|
|
<TD nowrap>Copyright © 2000</TD><TD>
|
|
<A HREF=http://www.boost.org/people/jeremy_siek.htm>Jeremy Siek</A>, Univ.of Notre Dame (<A HREF="mailto:jsiek@lsc.nd.edu">jsiek@lsc.nd.edu</A>)
|
|
</TD></TR></TABLE>
|
|
|
|
</BODY>
|
|
</HTML>
|
|
<!-- LocalWords: STL BGL cpp vecS bidirectionalS directedS undirectedS hpp vp
|
|
-->
|
|
<!-- LocalWords: iostream namespace ggcl int const num sizeof map ID's
|
|
-->
|
|
<!-- LocalWords: iter ei interoperability struct typename GraphTraits src ai
|
|
-->
|
|
<!-- LocalWords: targ VertexPropertyGraph EdgePropertyGraph Plugins plugin
|
|
-->
|
|
<!-- LocalWords: VertexList dijkstra listS Edgelist RandomAccessIterator
|
|
-->
|
|
<!-- LocalWords: weightp UniformCostVisitor
|
|
-->
|