【发布时间】:2016-12-04 21:21:26
【问题描述】:
使用 BGL adjacency_list,我希望顶点的出边按目标顶点的属性进行排序。
在 BGL 中,出边列表已经按目标顶点描述符排序,但我碰巧使用 listS 作为我的顶点容器,所以我的顶点描述符是 void* 指针。不幸的是,我发现按这些地址排序会使我的图遍历的顺序不确定。我的顶点确实有一个自定义属性类,它的 ID 可用于对出边进行排序,但我无法使其工作。 (见下面的代码。)
我参考了这个问题,这对诊断问题很有帮助,但我没有看到一个好的解决方案:boost graph library: deterministic order of iteration of in_edges?
未分类的 MWE
这是一个没有任何排序尝试的 MWE。请注意,我以 0、5、2、8 的顺序使用id 创建顶点,以模拟与id 的顺序不同的顶点地址。在我的实际应用中,我不能保证这些顶点的地址会遵循id 的顺序。
#include <iostream>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/directed_graph.hpp>
class VertexInfo
{
public:
VertexInfo(int i) : id(i) {}
int id;
};
int main()
{
typedef boost::adjacency_list< boost::setS,
boost::listS,
boost::bidirectionalS,
VertexInfo,
boost::no_property,
boost::no_property,
boost::listS
> Graph;
//typedef boost::graph_traits<Graph>::edge_descriptor Edge;
typedef boost::graph_traits<Graph>::vertex_descriptor Vertex;
Graph g;
Vertex src = boost::add_vertex(VertexInfo(0), g);
Vertex tar1 = boost::add_vertex(VertexInfo(5), g);
Vertex tar2 = boost::add_vertex(VertexInfo(2), g);
Vertex tar3 = boost::add_vertex(VertexInfo(8), g);
boost::add_edge(src, tar1, g);
boost::add_edge(src, tar2, g);
boost::add_edge(src, tar3, g);
// If sorted by address, the order would probably be:
// 0 --> 5
// 0 --> 2
// 0 --> 8
// If sorted by ID, the order should be:
// 0 --> 2
// 0 --> 5
// 0 --> 8
typename boost::graph_traits<Graph>::out_edge_iterator ei, ei_end;
for(boost::tie(ei, ei_end) = boost::out_edges(src, g); ei != ei_end; ++ei)
{
std::cout << g[boost::source(*ei, g)].id
<< " --> "
<< g[boost::target(*ei, g)].id
<< std::endl;
}
return 0;
}
目前这给我的是:
0 --> 5
0 --> 2
0 --> 8
但我需要它给我这个:
0 --> 2
0 --> 5
0 --> 8
尝试排序,不工作
我查看了 Boost 文档,发现这两部分很有帮助。
BGL 提供了一个示例,说明如何通过创建自定义容器选择器并为该容器使用自定义比较器来订购外边缘 (ordered_out_edges.cpp)。不幸的是,示例中的比较器使用目标顶点描述符和边的默认属性来进行比较。我需要一个基于目标顶点的自定义属性进行比较的比较器;无法访问图形对象。
BGL 还展示了如何将custom vertex property tag 添加到顶点;我曾希望我可以在没有图形对象的情况下从顶点描述符访问标记的顶点属性;但这似乎也不起作用
#include <iostream>
#include <functional>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/directed_graph.hpp>
// http://www.boost.org/doc/libs/1_55_0/libs/graph/example/ordered_out_edges.cpp
// http://www.boost.org/doc/libs/1_55_0/libs/graph/doc/using_adjacency_list.html#sec:custom-vertex-properties
// https://stackoverflow.com/questions/30968690/boost-graph-library-deterministic-order-of-iteration-of-in-edges
// http://www.boost.org/doc/libs/1_55_0/libs/graph/doc/adjacency_list.html
// ??
// https://stackoverflow.com/questions/9169276/bgl-edgeu-v-g-with-custom-associative-container-for-edge-lists
#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
#error BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION not supported
#endif
// See custom-vetex-properties
struct vertex_info_t
{
typedef boost::vertex_property_tag kind;
};
class VertexInfo
{
public:
VertexInfo(int i) : id(i) {}
int id;
};
////////////////////////////////////////
// See libs/graph/example/ordered_out_edges.cpp
template <class StoredEdge>
struct Comparator : public std::binary_function<StoredEdge, StoredEdge, bool>
{
bool operator()(const StoredEdge& e1, const StoredEdge& e2)
{
return boost::get(vertex_info_t(), e1.get_target()).id < boost::get(vertex_info_t(), e2.get_target()).id;
//return e2.get_target() < e1.get_target(); // reverse order of insertion, an example to prove custom OrderedSetS but does not use vertex properties
}
};
struct OrderedSetS {};
namespace boost
{
template <class ValueType>
struct container_gen<OrderedSetS, ValueType>
{
typedef std::set<ValueType, Comparator<ValueType> > type;
};
template <>
struct parallel_edge_traits<OrderedSetS>
{
typedef allow_parallel_edge_tag type;
};
}
////////////////////////////////////////
int main()
{
typedef boost::adjacency_list< OrderedSetS, //boost::setS,
boost::listS,
boost::bidirectionalS,
boost::property<vertex_info_t, VertexInfo>, //VertexInfo,
boost::no_property,
boost::no_property,
boost::listS
> Graph;
//typedef boost::graph_traits<Graph>::edge_descriptor Edge;
typedef boost::graph_traits<Graph>::vertex_descriptor Vertex;
Graph g;
Vertex src = boost::add_vertex(VertexInfo(0), g);
Vertex tar1 = boost::add_vertex(VertexInfo(5), g);
Vertex tar2 = boost::add_vertex(VertexInfo(2), g);
Vertex tar3 = boost::add_vertex(VertexInfo(8), g);
boost::add_edge(src, tar1, g);
boost::add_edge(src, tar2, g);
boost::add_edge(src, tar3, g);
// If sorted by address, the order would probably be:
// 0 --> 5
// 0 --> 2
// 0 --> 8
// If sorted by ID, the order should be:
// 0 --> 2
// 0 --> 5
// 0 --> 8
typename boost::graph_traits<Graph>::out_edge_iterator ei, ei_end;
for(boost::tie(ei, ei_end) = boost::out_edges(src, g); ei != ei_end; ++ei)
{
std::cout << boost::get( boost::get(vertex_info_t(), g), boost::source(*ei, g) ).id
<< " --> "
<< boost::get( boost::get(vertex_info_t(), g), boost::target(*ei, g) ).id
<< std::endl;
}
return 0;
}
这会导致编译错误
main.cpp:38:26: error: no matching function for call to 'get(vertex_info_t, void*&)'
return boost::get(vertex_info_t(), e1.get_target()).id < boost::get(vertex_info_t(), e2.get_target()).id;
它不允许我通过 vertex_info_t 标记获取 VertexInfo 属性类,其中只有一个顶点描述符 (void*) 而没有图形。
问题
谁能想出一种方法来通过目标顶点的外部或内部标记属性对外边进行排序?
【问题讨论】:
标签: c++ boost boost-graph