2
0
mirror of https://github.com/boostorg/graph.git synced 2026-01-31 20:22:09 +00:00
Files
graph/docs/quick_tour.html
2000-09-21 18:34:54 +00:00

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 &quot;slice&quot; 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 &quot;adjacency list&quot; 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 &lt;iostream&gt; // for std::cout
#include &lt;utility&gt; // for std::pair
#include &lt;algorithm&gt; // for std::for_each
#include &lt;boost/graph/graph_traits.hpp&gt;
#include &lt;boost/graph/adjacency_list.hpp&gt;
using namespace ggcl;
using namespace boost;
int main(int,char*[])
{
typedef std::pair&lt;int, int&gt; 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&lt;vecS, vecS, bidirectionalS&gt; Graph;
// declare a graph object
Graph g(num_vertices);
// add the edges to the graph object
for (int i = 0; i &lt; 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 &quot;beginning&quot; of the vertices and
the <TT>second</TT> iterator points &quot;past the end&quot;). 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&lt;Graph, vertex_index&gt;::type ID;
ID id = get(vertex_index(), g);
std::cout &lt;&lt; "vertices(g) = ";
typedef graph_traits&lt;Graph&gt;::vertex_iterator vertex_iter;
std::pair&lt;vertex_iter, vertex_iter&gt; vp;
for (vp = vertices(g); vp.first != vp.second; ++vp.first)
std::cout &lt;&lt; id[*vp.first] &lt;&lt; " ";
std::cout &lt;&lt; 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 &lt;&lt; "edges(g) = ";
graph_traits&lt;Graph&gt;::edge_iterator ei, ei_end;
for (tie(ei, ei_end) = edges(g); ei != ei_end; ++ei)
std::cout &lt;&lt; "(" &lt;&lt; id[source(*ei, g)]
&lt;&lt; "," &lt;&lt; id[target(*ei, g)] &lt;&lt; ") ";
std::cout &lt;&lt; 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 &quot;exercise vertex&quot; 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&lt;Graph&gt;(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 &lt;class Graph&gt; struct exercise_vertex {
exercise_vertex(Graph&amp; g_) : g(g_) {}
//...
Graph&amp; 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 &quot;black-box&quot; 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&lt;Graph&gt;</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 &lt;class Graph&gt; struct exercise_vertex {
//...
typedef typename graph_traits&lt;Graph&gt;
::vertex_descriptor Vertex;
void operator()(const Vertex&amp; 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 &quot;black
box&quot; 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 &lt;class Graph&gt; struct exercise_vertex {
//...
void operator()(const Vertex&amp; v) const
{
typedef graph_traits&lt;Graph&gt; GraphTraits;
typename property_map&lt;Graph, vertex_index&gt;::type
id = get(vertex_index(), g);
std::cout &lt;&lt; "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 &lt;&lt; "(" &lt;&lt; id[src] &lt;&lt; ","
&lt;&lt; id[targ] &lt;&lt; ") ";
}
std::cout &lt;&lt; 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 &lt;class Graph&gt; struct exercise_vertex {
//...
void operator()(const Vertex&amp; v) const
{
//...
std::cout &lt;&lt; "in-edges: ";
typedef typename graph_traits&lt;Graph&gt; 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 &lt;&lt; "(" &lt;&lt; id[src] &lt;&lt; "," &lt;&lt; id[targ] &lt;&lt; ") ";
}
std::cout &lt;&lt; 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 &lt;class Graph&gt; struct exercise_vertex {
//...
void operator()(Vertex v) const
{
//...
std::cout &lt;&lt; "adjacent vertices: ";
typename graph_traits&lt;Graph&gt;::adjacency_iterator ai;
typename graph_traits&lt;Graph&gt;::adjacency_iterator ai_end;
for (tie(ai, ai_end) = adjacent_vertices(v, g);
ai != ai_end; ++ai)
std::cout &lt;&lt; id[*ai] &lt;&lt; " ";
std::cout &lt;&lt; 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&lt;listS, vecS, directedS,
no_plugin, plugin&lt;edge_weight, int&gt; &gt; Graph;
typedef graph_traits&lt;Graph&gt;::vertex_descriptor Vertex;
typedef std::pair&lt;int,int&gt; 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&lt;int&gt; 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 &lt;&lt; "distances from start vertex:" &lt;&lt; std::endl;
graph_traits&lt;Graph&gt;::vertex_iterator vi;
for(vi = vertices(G).first; vi != vertices(G).second; ++vi)
std::cout &lt;&lt; "distance(" &lt;&lt; index(*vi) &lt;&lt; ") = "
&lt;&lt; d[*vi] &lt;&lt; std::endl;
std::cout &lt;&lt; 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
&quot;apply&quot; 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 &lt;class PredecessorMap&gt;
class record_predecessors : public ucs_visitor&lt;&gt;
{
public:
record_predecessors(PredecessorMap p)
: m_predecessor(p) { }
template &lt;class Edge, class Graph&gt;
void edge_relaxed(Edge e, Graph&amp; 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 &lt;class PredecessorMap&gt;
record_predecessors&lt;PredecessorMap&gt;
make_predecessor_recorder(PredecessorMap p) {
return record_predecessors&lt;PredecessorMap&gt;(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&lt;Vertex&gt; p(num_vertices(G)); //the predecessor array
dijkstra_shortest_paths(G, s, d.begin(),
make_predecessor_recorder(p.begin()));
cout &lt;&lt; "parents in the tree of shortest paths:" &lt;&lt; endl;
for(vi = vertices(G).first; vi != vertices(G).second; ++vi) {
cout &lt;&lt; "parent(" &lt;&lt; *vi;
if (p[*vi] == Vertex())
cout &lt;&lt; ") = no parent" &lt;&lt; endl;
else
cout &lt;&lt; ") = " &lt;&lt; p[*vi] &lt;&lt; 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 &copy 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
-->