在现有数据结构上使用BGL算法需要什么(边和顶点作为矢量<对象*>)?
What is needed to use BGL algorithms on existing data structures ( edges and vertices as vector<Object *>)?
我有这样的自定义数据结构:
vector<myVertex *> my_vertices;
vector<myEdge *> my_edges;
我的课程MyEdge具有source((和target((方法,返回myvertex*,因此应该已经准备就绪,对吗?
我需要做什么才能使用我的容器使用BGL图?我知道文档中的适配器示例,但要感谢一些帮助!
我很感兴趣的是纯粹的aidcencency_list基本图类型,尚不确定我需要的图形遍历概念。
到目前为止,我对Adjacency_list参数的了解:
adjacency_list<OutEdgeListS, VertexListS, DirectedS,
VertexProperty, EdgeProperty, GraphProperty, EdgeListS>
-
OutEdgeListS
和VertexListS
是用于代表每个顶点的(1(边缘列表的容器的选择器,以及(2(顶点列表。这些容器分别以vertex_descriptor
和edge_descriptor
为元素。我的容器类型是简单的std :: vector,所以我想我不需要像示例/Container_gen.cpp中创建新的容器类型。我必须简单地需要精确,可能是使用graph_traits,我的容器元素的类型是指向对象。 -
VertexProperty
和EdgeProperty
旨在用作内部批量存储,以获取其他信息,例如颜色标签,边缘权重...并提供了几年以来的捆绑 - 属性功能。
我希望顶点和边缘描述符默认为整数,而是对我的对象的指示。BGL文档明确指出,这在本书的2002年中是可行的,12.1.2:
面向对象的图形实现可能会使用指针来堆 分配的顶点对象。使用图形特征类,这些 差异被顶点描述符相关类型隐藏。
尽管它似乎已经从当前的1.70在线文档中失去了
我理想地想这样初始化:
MyGraph g(const& my_edges,const& my_vertices,
undirected_tag, some_color, someweights, allow_parallel_edges_tag);
P.S。我对property_map中的对象指针不感兴趣。我愿意不使用"默认vecs",一个std ::向量,其中描述符是整数。我愿意将"自定义vecs"用作对象指针的std ::向量;对于OutedGelist和Pertexlist。
编辑:这与" 1."是完全相同的问题这是一个。除了它从未得到回答...拟议的解决方案是" 2",带有属性_映射和昂贵的双映射:)。在挖掘了数百个主题数小时后,大多数人建议使用property_maps而不是使用自定义容器。人们倾向于使用property_maps存储实际节点和边缘 - 其对象指针,并让顶点&amp; edge_descriptor保留纯粹的默认整数索引。然而,从我在这里阅读的内容,有"下面" vertex_descriptor一个内部内部的Real-Index层。
作为上下文:我计划使用dijkstra/johnson_all_pairs_shortest_paths(带有前身映射和访客?(,以及带有http://paal.mimuw.edu.pl/的steiner树的最佳dreyfus-wagner,BGL的顶部。要为DBMS-ARD工具制作SQL Join-Solver PGModeler https://github.com/pgmodeler/pgmodeler/pgmodeler/pull/1232。
20/05/19:回复Sehe的答案
很棒的信息,这些信息 glues 将我赶上了一些核心点,例如图形概念。我来询问如何使用自定义数据结构使用邻接列表,然后您去解释了如何定义一个完全自定义的图形。
我即将研究方法之间的权衡:
- 保持我的数据结构,以及您对自定义图的解决方案。我初始化将花费很少的时间,但可能很多更多的时间找到外边缘。低空间复杂性,但时间很高复杂性。
- 同样的方法,但是重构我的库,添加专用存储,带有每个顶点的事件边缘向量(作为类属性Mervertex?(。恒定时间外观查找而不是O(log(n(((1(std :: quare_range?可能是最好的选择。
- 使用Adjacency_list,但具有BGL时间复杂性保证。
- 实例化默认邻接列表,用我的设置双向映射库容器/使用捆绑/内部属性。高空复杂性;低时间复杂性,但仅适用于BGL算法,初始化将很长。
- 您是否愿意详细说明是否有适当的OUTEDGELIST和dertexlist使用自定义使用邻接列表类容器一个选项?继续提及那些持久?我猜测在这一点上,aidcency_list的实现可能不是这个灵活的。
图形概念的文档很方便:https://www.boost.org/doc/libs/1_70_0_0/libs/graph/graph/doc/graph/doc/graph_coneptss.html
所以 - 您从未告诉过我们打算使用哪种算法。
所以让我选一个示例:bfs。文档说这需要:
有向或无向图。图类型必须是顶点列表图和发射率图的模型。
查看您先前存在的数据结构,看起来您只能轻松覆盖顶点列表用例。
边缘更多地作为边缘列表实现。没有运行时或存储开销的情况下,不可能从边缘列表中模拟入击图(这是数学,与库或代码质量无关(。
实际上,您很可能会省略与问题相关的已存在的数据结构的部分,因为大多数算法在Just Pertex Edge Lists上都非常优势。
。实际上,我想您的边缘列表可能像经典的邻接列表一样组织(例如,通过源顶点订购,因此您可以通过source dertex进行O(log(log(n((查找(。
对于下面的示例我假设是这种情况。请记住,我们只是接近从发病率图概念中保证的复杂性:
复杂性保证
source()
,target()
和out_edges()
功能都必须是恒定的时间。out_degree()
函数必须在外边的数量中线性。要真正满足这些要求,您需要专用于每个顶点的外艇
所以,让我们去吧:
嘲笑你的library
namespace YourLibrary {
struct myVertex {
};
struct myEdge {
myVertex* _s = nullptr;
myVertex* _t = nullptr;
myVertex* source() const { return _s; }
myVertex* target() const { return _t; }
};
using Vertices = std::vector<myVertex *>;
using Edges = std::vector<myEdge *>;
}
实现图形概念
您想继续引用预先存在的数据结构:
namespace Glue {
struct MyGraph {
struct EdgeOrder {
template <typename A, typename B>
bool operator()(A const* a, B const* b) const { return source(a) < source(b); }
private:
static auto source(YourLibrary::myVertex const* v) { return v; }
static auto source(YourLibrary::myEdge const* e) { return e->source(); }
};
using Vertices = YourLibrary::Vertices;
using Edges = YourLibrary::Edges;
Vertices& _vertices;
Edges& _edges;
MyGraph(Vertices& vv, Edges& ee) : _vertices(vv), _edges(ee) { }
};
}
现在,我将按照概念的列表列出所需特质类型的列表:
namespace boost {
template <> struct graph_traits<Glue::MyGraph> {
// Due to Graph concept
using vertex_descriptor = YourLibrary::myVertex*;
using edge_descriptor = YourLibrary::myEdge*;
using directed_category = directed_tag;
using edge_parallel_category = allow_parallel_edge_tag;
static vertex_descriptor null_vertex() { return nullptr; }
// Due to Vertex List concept
struct traversal_category : vertex_list_graph_tag, incidence_graph_tag { };
using vertex_iterator = Glue::MyGraph::Vertices::const_iterator;
using vertices_size_type = std::size_t;
// Due to Incidence Graph concept
using out_edge_iterator = Glue::MyGraph::Edges::const_iterator;
using degree_size_type = std::size_t;
};
}
最后重新打开了名称空间,以便ADL可以找到满足"有效表达式"标准所需的这些功能:
namespace Glue {
// Due to Vertex List concept
auto vertices(MyGraph const& g) {
return std::make_pair(g._vertices.begin(), g._vertices.end());
}
std::size_t num_vertices(MyGraph const& g) {
return g._vertices.size();
}
// Due to Incidence Graph concept
auto source(YourLibrary::myEdge const* e, MyGraph const& g) {
return e->source();
}
auto target(YourLibrary::myEdge const* e, MyGraph const& g) {
return e->target();
}
auto out_edges(YourLibrary::myVertex const* v, MyGraph const& g) {
return std::equal_range(g._edges.begin(), g._edges.end(), v, MyGraph::EdgeOrder{});;
}
std::size_t out_degree(YourLibrary::myVertex const* v, MyGraph const& g) {
auto oee = std::equal_range(g._edges.begin(), g._edges.end(), v, MyGraph::EdgeOrder{});
return std::distance(oee.first, oee.second);
}
}
这将大致在功能上等同于aidjencency_list,for setS
用于顶点容器。
请参阅 Live on Coliru
运行BFS
另外所需的一切都是算法的参数。您需要颜色映射和顶点索引图。这是完全正常的,如果您有例如adjacency_list<vecS, listS, directedS>
。
我将在MyGraph
包装器中隐藏索引图并揭露颜色地图,以便您选择您的偏好:
活在coliru
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/breadth_first_search.hpp>
#include <boost/container/flat_map.hpp>
#include <algorithm>
namespace YourLibrary {
struct myVertex {
};
struct myEdge {
myVertex* _s = nullptr;
myVertex* _t = nullptr;
myVertex* source() const { return _s; }
myVertex* target() const { return _t; }
};
using Vertices = std::vector<myVertex *>;
using Edges = std::vector<myEdge *>;
}
namespace Glue {
struct MyGraph {
struct EdgeOrder {
template <typename A, typename B>
bool operator()(A const* a, B const* b) const { return source(a) < source(b); }
private:
static auto source(YourLibrary::myVertex const* v) { return v; }
static auto source(YourLibrary::myEdge const* e) { return e->source(); }
};
using Vertices = YourLibrary::Vertices;
using Edges = YourLibrary::Edges;
using Index = boost::container::flat_map<Vertices::value_type, std::size_t>;
Vertices& _vertices;
Edges& _edges;
Index _index;
MyGraph(Vertices& vv, Edges& ee) : _vertices(vv), _edges(ee) {
_index.reserve(vv.size());
std::size_t i = 0;
for(auto v : vv) { _index[v] = i++; }
}
};
}
namespace boost {
template <> struct graph_traits<Glue::MyGraph> {
// Due to Graph concept
using vertex_descriptor = YourLibrary::myVertex*;
using edge_descriptor = YourLibrary::myEdge*;
using directed_category = directed_tag;
using edge_parallel_category = allow_parallel_edge_tag;
static vertex_descriptor null_vertex() { return nullptr; }
// Due to Vertex List concept
struct traversal_category : vertex_list_graph_tag, incidence_graph_tag { };
using vertex_iterator = Glue::MyGraph::Vertices::const_iterator;
using vertices_size_type = std::size_t;
// Due to Incidence Graph concept
using out_edge_iterator = Glue::MyGraph::Edges::const_iterator;
using degree_size_type = std::size_t;
};
}
namespace Glue {
// Due to Vertex List concept
auto vertices(MyGraph const& g) {
return std::make_pair(g._vertices.begin(), g._vertices.end());
}
std::size_t num_vertices(MyGraph const& g) {
return g._vertices.size();
}
// Due to Incidence Graph concept
auto source(YourLibrary::myEdge const* e, MyGraph const& g) {
return e->source();
}
auto target(YourLibrary::myEdge const* e, MyGraph const& g) {
return e->target();
}
auto out_edges(YourLibrary::myVertex const* v, MyGraph const& g) {
return std::equal_range(g._edges.begin(), g._edges.end(), v, MyGraph::EdgeOrder{});;
}
std::size_t out_degree(YourLibrary::myVertex const* v, MyGraph const& g) {
auto oee = std::equal_range(g._edges.begin(), g._edges.end(), v, MyGraph::EdgeOrder{});
return std::distance(oee.first, oee.second);
}
// Due to BFD requiring the index_map
auto get(boost::vertex_index_t, MyGraph const& g) {
return boost::make_assoc_property_map(g._index);
}
}
int main() {
// I hate manual memory management, so let's own some objects
auto a = std::make_unique<YourLibrary::myVertex>();
auto b = std::make_unique<YourLibrary::myVertex>();
auto c = std::make_unique<YourLibrary::myVertex>();
auto ab = std::make_unique<YourLibrary::myEdge>(YourLibrary::myEdge{a.get(), b.get()});
auto bc = std::make_unique<YourLibrary::myEdge>(YourLibrary::myEdge{b.get(), c.get()});
// These were given in your question:
YourLibrary::Vertices vv { a.get(), b.get(), c.get() };
YourLibrary::Edges ee { ab.get(), bc.get() };
// this is the glue required to fulfill the BGL concepts:
Glue::MyGraph g(vv, ee);
// this is showing that you can now BFS on it
using V = boost::graph_traits<Glue::MyGraph>::vertex_descriptor;
V start_vertex = a.get();
std::map<V, boost::default_color_type> color_data;
boost::breadth_first_search(g, start_vertex,
boost::visitor(boost::default_bfs_visitor{})
.color_map(boost::make_assoc_property_map(color_data)));
}
结论
算法有要求,只要您满足它们,就可以使用所需的任何数据结构。
在这种情况下,您可能想真正确定所做的假设,然后将其添加到MyGraph
构造函数:
assert(std::is_sorted(_edges.begin(), _edges.end(), EdgeOrder{}));
- 如何循环打印顶点结构
- 请解释这句话(cout<<1+int((a<b)^((b-a)&1) )<<endl
- 呼叫运营商<<临时
- 如何防止clang格式在流运算符调用之间添加换行符<<
- <<操作员在下面的行中工作
- D3D11-将混合权重和索引传递到顶点着色器
- 从返回的顶点缓冲区查询顶点结构
- Vulkan 中的动态顶点缓冲区格式设置
- 在顶点着色器中使用 OpenGl 的未声明标识符,我在顶点着色器中绘制三角形时遇到问题
- 如何将一半传递给顶点着色器?
- 在 DirectX 11 中从 GPU 读回顶点缓冲区(并获取顶点)
- QT QOpenGLWidget:如何在不使用数据块复制的情况下修改VBO中的单个顶点值?
- 使用 OpenGL 4.5 更改所选顶点的颜色
- Direct3D 11 - HLSL - 获取顶点索引 ID
- 创建异构顶点数据数组的可移植方法
- 使用 glvertex4i 传递网格面索引时的顶点着色器错误
- 无法从 cso 文件创建顶点着色器(从 fx 文件创建)
- OpenGL 相机移动程序顶点着色器问题
- 使用 std::list 存储顶点并使用 SFML 绘制它们
- 为什么顶点数组对象会导致错误?