mirror of
https://github.com/boostorg/graph.git
synced 2026-02-01 08:32:11 +00:00
some work on out-edge list ordering
[SVN r8069]
This commit is contained in:
@@ -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 <TT>bool</TT> flag will be <TT>false</TT>. Also, if <i>u</i> and
|
||||
<i>v</i> are descriptors for the same vertex (creating a self loop)
|
||||
then the edge will not be added and the flag will be <TT>false</TT>.
|
||||
When the flag is <TT>false</TT>, 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 <i>u</i> is unspecified. If the
|
||||
<tt>VertexList</tt> selector is <tt>vecS</tt>, and if either vertex
|
||||
descriptor <tt>u</tt> or <tt>v</tt> (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 <tt>std::max(u,v) + 1</tt>.
|
||||
and the graph is undirected, then the edge will not be added and the
|
||||
flag will be <TT>false</TT>. When the flag is <TT>false</TT>, the
|
||||
edge descriptor is invalid and any use of it is undefined.
|
||||
|
||||
<p>
|
||||
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 <tt>EdgeList</tt>.
|
||||
|
||||
If the <tt>VertexList</tt> selector is
|
||||
<tt>vecS</tt>, and if either vertex descriptor <tt>u</tt> or
|
||||
<tt>v</tt> (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 <tt>std::max(u,v) + 1</tt>.
|
||||
|
||||
<p>
|
||||
If the <TT>EdgeList</TT> selector is <TT>vecS</TT> then this operation
|
||||
@@ -777,7 +783,8 @@ void remove_edge(out_edge_iterator iter, adjacency_list& g)
|
||||
</pre>
|
||||
This has the same effect as <tt>remove_edge(*iter, g)</tt>. The
|
||||
difference is that this function has constant time complexity
|
||||
in the case of directed graphs.
|
||||
in the case of directed graphs, whereas <tt>remove_edge(e, g)</tt>
|
||||
has time complexity <i>O(E/V)</i>.
|
||||
|
||||
<hr>
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <boost/graph/depth_first_search.hpp>
|
||||
#include <boost/graph/breadth_first_search.hpp>
|
||||
#include <boost/property_map.hpp>
|
||||
#include <boost/graph/graph_utility.hpp> // 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 <class Vertex>
|
||||
inline void discover(Vertex u) {
|
||||
struct city_arrival {
|
||||
city_arrival(string* n) : names(n) { }
|
||||
typedef on_discover_vertex event_filter;
|
||||
template <class Vertex, class Graph>
|
||||
inline void operator()(Vertex u, Graph&) {
|
||||
cout << endl << "arriving at " << names[u] << endl
|
||||
<< " neighboring cities are: ";
|
||||
}
|
||||
|
||||
template <class Edge, class Graph>
|
||||
inline void process(Edge e, Graph& g) {
|
||||
cout << names[ target(e,g) ] << ", ";
|
||||
}
|
||||
|
||||
template <class Vertex>
|
||||
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 <class Edge, class Graph>
|
||||
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 <class Vertex, class Graph>
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -81,6 +81,8 @@ struct order_by_name
|
||||
: public std::binary_function<StoredEdge,StoredEdge,bool>
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -57,16 +57,6 @@ namespace boost {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <class Vertex>
|
||||
struct target_is {
|
||||
target_is(const Vertex& v) : m_target(v) { }
|
||||
template <class StoredEdge>
|
||||
bool operator()(const StoredEdge& e) const {
|
||||
return e.get_target() == m_target;
|
||||
}
|
||||
Vertex m_target;
|
||||
};
|
||||
|
||||
template <typename DirectedS>
|
||||
struct directed_category_traits {
|
||||
typedef directed_tag directed_category;
|
||||
@@ -85,6 +75,35 @@ namespace boost {
|
||||
typedef bidirectional_tag directed_category;
|
||||
};
|
||||
|
||||
template <class Vertex>
|
||||
struct target_is {
|
||||
target_is(const Vertex& v) : m_target(v) { }
|
||||
template <class StoredEdge>
|
||||
bool operator()(const StoredEdge& e) const {
|
||||
return e.get_target() == m_target;
|
||||
}
|
||||
Vertex m_target;
|
||||
};
|
||||
|
||||
// O(E/V)
|
||||
template <class EdgeList, class vertex_descriptor>
|
||||
void erase_from_incidence_list(EdgeList& el, vertex_descriptor v,
|
||||
allow_parallel_edge_tag)
|
||||
{
|
||||
boost::erase_if(el, detail::target_is<vertex_descriptor>(v));
|
||||
}
|
||||
// O(log(E/V))
|
||||
template <class EdgeList, class vertex_descriptor>
|
||||
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 <class Vertex, class Traits>
|
||||
struct adjacency_iterator_traits {
|
||||
@@ -163,18 +182,6 @@ namespace boost {
|
||||
};
|
||||
#endif
|
||||
|
||||
template <class P>
|
||||
struct has_property {
|
||||
enum { value = true };
|
||||
typedef true_type type;
|
||||
};
|
||||
template <>
|
||||
struct has_property<no_property> {
|
||||
enum { value = false };
|
||||
typedef false_type type;
|
||||
};
|
||||
|
||||
|
||||
//=========================================================================
|
||||
// Out-Edge and In-Edge Iterator Implementation
|
||||
|
||||
@@ -395,11 +402,9 @@ namespace boost {
|
||||
directed_graph_helper<Config>& 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<graph_type&>(g_);
|
||||
typename Config::OutEdgeList& el = g.out_edge_list(u);
|
||||
boost::erase_if(el, detail::target_is<Vertex>(v));
|
||||
detail::erase_from_incidence_list(g.out_edge_list(u), v, Cat());
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
@@ -513,12 +518,11 @@ namespace boost {
|
||||
directed_graph_helper<Config>& 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<graph_type&>(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<Vertex>(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<Config>& g_)
|
||||
{
|
||||
typedef typename Config::graph_type graph_type;
|
||||
typedef typename Config::StoredEdge StoredEdge;
|
||||
typedef typename Config::vertex_descriptor Vertex;
|
||||
graph_type& g = static_cast<graph_type&>(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<Vertex>(u));
|
||||
detail::erase_from_incidence_list(g.out_edge_list(v), u, Cat());
|
||||
}
|
||||
|
||||
template <class Config, class Predicate>
|
||||
@@ -781,15 +783,14 @@ namespace boost {
|
||||
undirected_graph_helper<Config>& 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<graph_type&>(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<Vertex>(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 <class Graph, class EdgeList, class Vertex>
|
||||
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<Vertex>(v));
|
||||
detail::erase_from_incidence_list(el, v, cat);
|
||||
}
|
||||
// O(log(E/V))
|
||||
template <class Graph, class EdgeList, class Vertex>
|
||||
@@ -1017,12 +1018,10 @@ namespace boost {
|
||||
bidirectional_graph_helper_with_property<Config>& g_)
|
||||
{
|
||||
typedef typename Config::graph_type graph_type;
|
||||
typedef typename Config::StoredEdge StoredEdge;
|
||||
typedef typename Config::vertex_descriptor Vertex;
|
||||
graph_type& g = static_cast<graph_type&>(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<Vertex>(u));
|
||||
detail::erase_from_incidence_list(g.in_edge_list(v), u, Cat());
|
||||
}
|
||||
// O(E/V)
|
||||
template <class EdgeOrIter, class Config>
|
||||
@@ -1049,23 +1048,22 @@ namespace boost {
|
||||
bidirectional_graph_helper_with_property<Config>& 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<graph_type&>(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<Vertex>(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<Vertex>(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<Config>& 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<graph_type&>(g_);
|
||||
boost::erase_if(g.out_edge_list(u), detail::target_is<Vertex>(v));
|
||||
boost::erase_if(g.in_edge_list(v), detail::target_is<Vertex>(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 <class EdgeOrIter, class Config>
|
||||
@@ -1236,20 +1233,19 @@ namespace boost {
|
||||
bidirectional_graph_helper_without_property<Config>& 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<graph_type&>(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<Vertex>(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<Vertex>(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 <class P>
|
||||
struct has_property {
|
||||
enum { value = true };
|
||||
typedef true_type type;
|
||||
};
|
||||
template <>
|
||||
struct has_property<no_property> {
|
||||
enum { value = false };
|
||||
typedef false_type type;
|
||||
};
|
||||
|
||||
//=========================================================================
|
||||
// Adjacency List Generator
|
||||
|
||||
|
||||
@@ -276,6 +276,25 @@ namespace boost {
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class T1, class T2>
|
||||
std::pair<T1,T2>
|
||||
make_list(const T1& t1, const T2& t2)
|
||||
{ return std::make_pair(t1, t2); }
|
||||
|
||||
template <class T1, class T2, class T3>
|
||||
std::pair<T1,std::pair<T2,T3> >
|
||||
make_list(const T1& t1, const T2& t2, const T3& t3)
|
||||
{ return std::make_pair(t1, std::make_pair(t2, t3)); }
|
||||
|
||||
template <class T1, class T2, class T3, class T4>
|
||||
std::pair<T1,std::pair<T2,std::pair<T3,T4> > >
|
||||
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 <class T1, class T2, class T3, class T4, class T5>
|
||||
std::pair<T1,std::pair<T2,std::pair<T3,std::pair<T4,T5> > > >
|
||||
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 */
|
||||
|
||||
|
||||
Reference in New Issue
Block a user