diff --git a/docs/adjacency_list.html b/docs/adjacency_list.html
index 1de0f401..60c88414 100644
--- a/docs/adjacency_list.html
+++ b/docs/adjacency_list.html
@@ -702,14 +702,20 @@ for the new edge. For graphs that do not allow parallel edges, if the
edge is already in the graph then a duplicate will not be added and
the bool flag will be false. Also, if u and
v are descriptors for the same vertex (creating a self loop)
-then the edge will not be added and the flag will be false.
-When the flag is false, the edge descriptor is invalid and
-any use of it is undefined. The location of the placement of the edge
-in the out-edge list for u is unspecified. If the
-VertexList selector is vecS, and if either vertex
-descriptor u or v (which are integers) has a value
-greater than the current number of vertices in the graph, the graph is
-enlarged so that the number of vertices is std::max(u,v) + 1.
+and the graph is undirected, then the edge will not be added and the
+flag will be false. When the flag is false, the
+edge descriptor is invalid and any use of it is undefined.
+
+
+The placement of the new edge in the out-edge list is in general
+unspecified, though ordering of the out-edge list can be accomplished
+through the choice of EdgeList.
+
+If the VertexList selector is
+vecS, and if either vertex descriptor u or
+v (which are integers) has a value greater than the current
+number of vertices in the graph, the graph is enlarged so that the
+number of vertices is std::max(u,v) + 1.
If the EdgeList selector is vecS then this operation
@@ -777,7 +783,8 @@ void remove_edge(out_edge_iterator iter, adjacency_list& g)
This has the same effect as remove_edge(*iter, g). The
difference is that this function has constant time complexity
-in the case of directed graphs.
+in the case of directed graphs, whereas remove_edge(e, g)
+has time complexity O(E/V).
diff --git a/examples/city_visitor.cpp b/examples/city_visitor.cpp
index e92bb708..9825dce1 100644
--- a/examples/city_visitor.cpp
+++ b/examples/city_visitor.cpp
@@ -32,6 +32,7 @@
#include
#include
#include
+#include // for boost::make_list
/*
@@ -51,16 +52,16 @@
The visitor has three main functions:
- discover(u) is invoked when the algorithm first arrives at the
+ discover_vertex(u,g) is invoked when the algorithm first arrives at the
vertex u. This will happen in the depth first or breadth first
order depending on which algorithm you use.
- process(e) is invoked when the algorithm first checks an edge to see
+ examine_edge(e,g) is invoked when the algorithm first checks an edge to see
whether it has already been there. Whether using BFS or DFS, all
the edges of vertex u are examined immediately after the call to
visit(u).
- finish(u) is called when after all the vertices reachable from vertex
+ finish_vertex(u,g) is called when after all the vertices reachable from vertex
u have already been visited.
*/
@@ -68,32 +69,37 @@
using namespace std;
using namespace boost;
-struct city_visitor
- : public null_visitor
-{
- city_visitor(string* n) : names(n) { }
-
- template
- inline void discover(Vertex u) {
+struct city_arrival {
+ city_arrival(string* n) : names(n) { }
+ typedef on_discover_vertex event_filter;
+ template
+ inline void operator()(Vertex u, Graph&) {
cout << endl << "arriving at " << names[u] << endl
<< " neighboring cities are: ";
}
-
- template
- inline void process(Edge e, Graph& g) {
- cout << names[ target(e,g) ] << ", ";
- }
-
- template
- inline void finish(Vertex u) {
- cout << endl << "finished with " << names[u] << endl;
- }
-
string* names;
};
+struct neighbor_cities {
+ neighbor_cities(string* n) : names(n) { }
+ typedef on_examine_edge event_filter;
+ template
+ inline void operator()(Edge e, Graph& g) {
+ cout << names[ target(e, g) ] << ", ";
+ }
+ string* names;
+};
+struct finish_city {
+ finish_city(string* n) : names(n) { }
+ typedef on_finish_vertex event_filter;
+ template
+ inline void operator()(Vertex u, Graph&) {
+ cout << endl << "finished with " << names[u] << endl;
+ }
+ string* names;
+};
int main(int argc, char* argv[])
{
@@ -123,7 +129,11 @@ int main(int argc, char* argv[])
colors_t colors(N);
cout << "*** Depth First ***" << endl;
- depth_first_search(G, city_visitor(names), colors.begin());
+ depth_first_search
+ (G, make_dfs_visitor(boost::make_list(city_arrival(names),
+ neighbor_cities(names),
+ finish_city(names))),
+ &colors[0]);
cout << endl;
/* Get the source vertex */
@@ -131,8 +141,11 @@ int main(int argc, char* argv[])
s = vertex(SanJose,G);
cout << "*** Breadth First ***" << endl;
- breadth_first_search(G, s, city_visitor(names), colors.begin());
-
- //end
+ breadth_first_search
+ (G, s, make_bfs_visitor(boost::make_list(city_arrival(names),
+ neighbor_cities(names),
+ finish_city(names))),
+ &colors[0]);
+
return 0;
}
diff --git a/examples/gerdemann.cpp b/examples/gerdemann.cpp
index cb853bf1..91df6016 100644
--- a/examples/gerdemann.cpp
+++ b/examples/gerdemann.cpp
@@ -81,6 +81,8 @@ struct order_by_name
: public std::binary_function
{
bool operator()(const StoredEdge& e1, const StoredEdge& e2) const {
+ // Using std::pair operator< as an easy way to get lexicographical
+ // compare over tuples.
return std::make_pair(e1.get_target(), boost::get(boost::edge_name, e1))
< std::make_pair(e2.get_target(), boost::get(boost::edge_name, e2));
}
diff --git a/include/boost/graph/depth_first_search.hpp b/include/boost/graph/depth_first_search.hpp
index d9849662..d07902e3 100644
--- a/include/boost/graph/depth_first_search.hpp
+++ b/include/boost/graph/depth_first_search.hpp
@@ -43,6 +43,7 @@ namespace boost {
vis.initialize_vertex(u, g);
vis.start_vertex(u, g);
vis.discover_vertex(u, g);
+ vis.examine_edge(e, g);
vis.tree_edge(e, g);
vis.back_edge(e, g);
vis.forward_or_cross_edge(e, g);
diff --git a/include/boost/graph/detail/adjacency_list.hpp b/include/boost/graph/detail/adjacency_list.hpp
index 763c0785..95bdcfeb 100644
--- a/include/boost/graph/detail/adjacency_list.hpp
+++ b/include/boost/graph/detail/adjacency_list.hpp
@@ -57,16 +57,6 @@ namespace boost {
namespace detail {
- template
- struct target_is {
- target_is(const Vertex& v) : m_target(v) { }
- template
- bool operator()(const StoredEdge& e) const {
- return e.get_target() == m_target;
- }
- Vertex m_target;
- };
-
template
struct directed_category_traits {
typedef directed_tag directed_category;
@@ -85,6 +75,35 @@ namespace boost {
typedef bidirectional_tag directed_category;
};
+ template
+ struct target_is {
+ target_is(const Vertex& v) : m_target(v) { }
+ template
+ bool operator()(const StoredEdge& e) const {
+ return e.get_target() == m_target;
+ }
+ Vertex m_target;
+ };
+
+ // O(E/V)
+ template
+ void erase_from_incidence_list(EdgeList& el, vertex_descriptor v,
+ allow_parallel_edge_tag)
+ {
+ boost::erase_if(el, detail::target_is(v));
+ }
+ // O(log(E/V))
+ template
+ void erase_from_incidence_list(EdgeList& el, vertex_descriptor v,
+ disallow_parallel_edge_tag)
+ {
+ typedef typename EdgeList::value_type StoredEdge;
+ el.erase(StoredEdge(v));
+ }
+
+ //=========================================================================
+ // Adjacency Iterator Implementation
+
#ifndef BOOST_NO_ITERATOR_ADAPTORS
template
struct adjacency_iterator_traits {
@@ -163,18 +182,6 @@ namespace boost {
};
#endif
- template
- struct has_property {
- enum { value = true };
- typedef true_type type;
- };
- template <>
- struct has_property {
- enum { value = false };
- typedef false_type type;
- };
-
-
//=========================================================================
// Out-Edge and In-Edge Iterator Implementation
@@ -395,11 +402,9 @@ namespace boost {
directed_graph_helper& g_)
{
typedef typename Config::graph_type graph_type;
- typedef typename Config::StoredEdge StoredEdge;
- typedef typename Config::vertex_descriptor Vertex;
+ typedef typename Config::edge_parallel_category Cat;
graph_type& g = static_cast(g_);
- typename Config::OutEdgeList& el = g.out_edge_list(u);
- boost::erase_if(el, detail::target_is(v));
+ detail::erase_from_incidence_list(g.out_edge_list(u), v, Cat());
}
namespace detail {
@@ -513,12 +518,11 @@ namespace boost {
directed_graph_helper& g_)
{
typedef typename Config::graph_type graph_type;
- typedef typename Config::StoredEdge StoredEdge;
- typedef typename Config::vertex_descriptor Vertex;
+ typedef typename Config::edge_parallel_category Cat;
graph_type& g = static_cast(g_);
typename Config::vertex_iterator vi, viend;
for (boost::tie(vi, viend) = vertices(g); vi != viend; ++vi)
- boost::erase_if(g.out_edge_list(*vi), detail::target_is(u));
+ detail::erase_from_incidence_list(g.out_edge_list(*vi), u, Cat());
g.out_edge_list(u).clear();
// clear() should be a req of Sequence and AssociativeContainer,
// or maybe just Container
@@ -694,12 +698,10 @@ namespace boost {
undirected_graph_helper& g_)
{
typedef typename Config::graph_type graph_type;
- typedef typename Config::StoredEdge StoredEdge;
- typedef typename Config::vertex_descriptor Vertex;
graph_type& g = static_cast(g_);
typedef typename Config::edge_parallel_category Cat;
detail::remove_edge_and_property(g, g.out_edge_list(u), v, Cat());
- boost::erase_if(g.out_edge_list(v), detail::target_is(u));
+ detail::erase_from_incidence_list(g.out_edge_list(v), u, Cat());
}
template
@@ -781,15 +783,14 @@ namespace boost {
undirected_graph_helper& g_)
{
typedef typename Config::graph_type graph_type;
- typedef typename Config::StoredEdge StoredEdge;
- typedef typename Config::vertex_descriptor Vertex;
+ typedef typename Config::edge_parallel_category Cat;
graph_type& g = static_cast(g_);
typename Config::OutEdgeList& el = g.out_edge_list(u);
typename Config::OutEdgeList::iterator
ei = el.begin(), ei_end = el.end();
for (; ei != ei_end; ++ei) {
- boost::erase_if(g.out_edge_list((*ei).get_target()),
- detail::target_is(u));
+ detail::erase_from_incidence_list
+ (g.out_edge_list((*ei).get_target()), u, Cat());
g.m_edges.erase((*ei).get_iter());
}
g.out_edge_list(u).clear();
@@ -852,14 +853,14 @@ namespace boost {
template
inline void
remove_edge_and_property(Graph& g, EdgeList& el, Vertex v,
- boost::allow_parallel_edge_tag)
+ boost::allow_parallel_edge_tag cat)
{
typedef typename EdgeList::value_type StoredEdge;
typename EdgeList::iterator i = el.begin(), end = el.end();
for (; i != end; ++i)
if ((*i).get_target() == v)
g.m_edges.erase((*i).get_iter());
- boost::erase_if(el, target_is(v));
+ detail::erase_from_incidence_list(el, v, cat);
}
// O(log(E/V))
template
@@ -1017,12 +1018,10 @@ namespace boost {
bidirectional_graph_helper_with_property& g_)
{
typedef typename Config::graph_type graph_type;
- typedef typename Config::StoredEdge StoredEdge;
- typedef typename Config::vertex_descriptor Vertex;
graph_type& g = static_cast(g_);
typedef typename Config::edge_parallel_category Cat;
detail::remove_edge_and_property(g, g.out_edge_list(u), v, Cat());
- boost::erase_if(g.in_edge_list(v), detail::target_is(u));
+ detail::erase_from_incidence_list(g.in_edge_list(v), u, Cat());
}
// O(E/V)
template
@@ -1049,23 +1048,22 @@ namespace boost {
bidirectional_graph_helper_with_property& g_)
{
typedef typename Config::graph_type graph_type;
- typedef typename Config::StoredEdge StoredEdge;
- typedef typename Config::vertex_descriptor Vertex;
+ typedef typename Config::edge_parallel_category Cat;
graph_type& g = static_cast(g_);
typename Config::OutEdgeList& el = g.out_edge_list(u);
typename Config::OutEdgeList::iterator
ei = el.begin(), ei_end = el.end();
for (; ei != ei_end; ++ei) {
- boost::erase_if(g.in_edge_list((*ei).get_target()),
- detail::target_is(u));
+ detail::erase_from_incidence_list
+ (g.in_edge_list((*ei).get_target()), u, Cat());
g.m_edges.erase((*ei).get_iter());
}
typename Config::InEdgeList& in_el = g.in_edge_list(u);
typename Config::InEdgeList::iterator
in_ei = in_el.begin(), in_ei_end = in_el.end();
for (; in_ei != in_ei_end; ++in_ei) {
- boost::erase_if(g.out_edge_list((*in_ei).get_target()),
- detail::target_is(u));
+ detail::erase_from_incidence_list
+ (g.out_edge_list((*in_ei).get_target()), u, Cat());
g.m_edges.erase((*in_ei).get_iter());
}
g.out_edge_list(u).clear();
@@ -1202,11 +1200,10 @@ namespace boost {
bidirectional_graph_helper_without_property& g_)
{
typedef typename Config::graph_type graph_type;
- typedef typename Config::StoredEdge StoredEdge;
- typedef typename Config::vertex_descriptor Vertex;
+ typedef typename Config::edge_parallel_category Cat;
graph_type& g = static_cast(g_);
- boost::erase_if(g.out_edge_list(u), detail::target_is(v));
- boost::erase_if(g.in_edge_list(v), detail::target_is(u));
+ detail::erase_from_incidence_list(g.out_edge_list(u), v, Cat());
+ detail::erase_from_incidence_list(g.in_edge_list(v), u, Cat());
}
// O(E/V)
template
@@ -1236,20 +1233,19 @@ namespace boost {
bidirectional_graph_helper_without_property& g_)
{
typedef typename Config::graph_type graph_type;
- typedef typename Config::StoredEdge StoredEdge;
- typedef typename Config::vertex_descriptor Vertex;
+ typedef typename Config::edge_parallel_category Cat;
graph_type& g = static_cast(g_);
typename Config::out_edge_iterator out_ei, out_ei_end;
for (boost::tie(out_ei, out_ei_end) = out_edges(u, g);
out_ei != out_ei_end; ++out_ei)
- boost::erase_if(g.in_edge_list(target(*out_ei,g)),
- detail::target_is(u));
+ detail::erase_from_incidence_list
+ (g.in_edge_list(target(*out_ei,g)), u, Cat());
typename Config::in_edge_iterator in_ei, in_ei_end;
for (boost::tie(in_ei, in_ei_end) = in_edges(u, g);
in_ei != in_ei_end; ++in_ei)
- boost::erase_if(g.out_edge_list(source(*in_ei,g)),
- detail::target_is(u));
+ detail::erase_from_incidence_list
+ (g.out_edge_list(source(*in_ei,g)), u, Cat());
g.out_edge_list(u).clear();
g.in_edge_list(u).clear();
@@ -1932,6 +1928,17 @@ namespace boost {
namespace detail {
+ template
+ struct has_property {
+ enum { value = true };
+ typedef true_type type;
+ };
+ template <>
+ struct has_property {
+ enum { value = false };
+ typedef false_type type;
+ };
+
//=========================================================================
// Adjacency List Generator
diff --git a/include/boost/graph/graph_utility.hpp b/include/boost/graph/graph_utility.hpp
index a819957f..c10d6ccf 100644
--- a/include/boost/graph/graph_utility.hpp
+++ b/include/boost/graph/graph_utility.hpp
@@ -276,6 +276,25 @@ namespace boost {
return false;
}
+ template
+ std::pair
+ make_list(const T1& t1, const T2& t2)
+ { return std::make_pair(t1, t2); }
+
+ template
+ std::pair >
+ make_list(const T1& t1, const T2& t2, const T3& t3)
+ { return std::make_pair(t1, std::make_pair(t2, t3)); }
+
+ template
+ std::pair > >
+ make_list(const T1& t1, const T2& t2, const T3& t3, const T4& t4)
+ { return std::make_pair(t1, std::make_pair(t2, std::make_pair(t3, t4))); }
+
+ template
+ std::pair > > >
+ make_list(const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5)
+ { return std::make_pair(t1, std::make_pair(t2, std::make_pair(t3, std::make_pair(t4, t5)))); }
} /* namespace boost */