2
0
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:
Jeremy Siek
2000-10-30 14:27:12 +00:00
parent d5bfd92f7b
commit ad26a784ae
6 changed files with 140 additions and 91 deletions

View File

@@ -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&amp; 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>

View File

@@ -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;
}

View File

@@ -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));
}

View File

@@ -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);

View File

@@ -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

View File

@@ -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 */