C++ 在现有数据结构(边和顶点作为向量<;对象*>;)上使用BGL算法需要什么?

C++ 在现有数据结构(边和顶点作为向量<;对象*>;)上使用BGL算法需要什么?,c++,boost,graph,boost-graph,C++,Boost,Graph,Boost Graph,我有如下自定义数据结构: vector<myVertex *> my_vertices; vector<myEdge *> my_edges; MyGraph g(const& my_edges,const& my_vertices, undirected_tag, some_color, someweights, allow_parallel_edges_tag); 另外,我对在属性映射中填充对象指针不感兴趣。我不愿意使用“default vec

我有如下自定义数据结构:

vector<myVertex *> my_vertices;
vector<myEdge *> my_edges;
MyGraph g(const& my_edges,const& my_vertices,
  undirected_tag, some_color, someweights, allow_parallel_edges_tag);
另外,我对在属性映射中填充对象指针不感兴趣。我不愿意使用“default vecS”,这是一个描述符为整数的std::vector。 我愿意使用“自定义向量”作为对象指针的std::向量;对于OutEdgeList和VertexList

编辑:这是与的“1”完全相同的问题。除了它从未得到回答。。。建议的解决方案是针对“2”,具有属性_-map和昂贵的双映射:)。在挖掘了数百个SO主题数小时后,大多数人建议使用属性映射,而不是使用自定义容器。人们倾向于使用属性映射来存储实际的节点和边——它们的对象指针,并让顶点和边描述符保存绝对默认的整数索引。然而,有一个真正的索引层内部的“低于”顶点描述符来提升

作为背景:我计划使用dijkstra/johnson\u all\u pairs\u shortest\u Pathways(带前置地图和访客?),并进一步优化dreyfus wagner for steiner树,在bgl顶部有一个库。 为dbms erd工具pgmodeler制作sql连接求解器

19年5月20日:回复sehe的回答 这是一条很棒的信息,它将所有的部分粘在一起,让我赶上了一些核心点,比如图形概念。 我是来询问如何将邻接列表与自定义数据结构结合使用的,您是来解释如何定义一个完全自定义的图的

我将研究两种方法之间的权衡:

  • 使我的数据结构保持原样,并使您的自定义图形解决方案保持原样。我 将花费相当多的时间初始化,但可能很多 更多的时间去寻找边缘。空间复杂度低,但时间长 复杂性
  • 同样的方法,但重构我的库,添加专用存储,使用 每个顶点的入射边向量(作为属性类) 我的顶点?)。恒定超时边查找,而不是使用 (1) 标准::相等范围?也许是最好的选择
  • 使用邻接列表,但具有bgl时间复杂性 保证。
    • 实例化一个默认的邻接列表,用my 库容器/使用绑定/内部属性。高空 复杂性;时间复杂度低,但仅适用于bgl算法, 初始化将很长
    • 您是否还想详细说明是否有合适的OutEdgeList和 VertexList使用具有自定义属性的邻接列表类生成 集装箱是一种选择吗?保留对这些内容的引用?我怀疑 此时,邻接列表的实现可能不可用 这很灵活

  • 图概念的文档可以方便地在这里找到:

    所以-你从来没有告诉我们你打算使用什么算法

    让我举个例子:BFS。说它需要:

    有向图有向图或无向图。图形类型必须是和的模型

    查看您先前存在的数据结构,您似乎只轻松地介绍了顶点列表用例

    这些边更多地实现为一个边列表。如果没有运行时或存储开销(这是数学问题,与库或代码质量无关),就不可能从边缘列表模拟关联图

    实际上,很可能您忽略了与问题相关的部分现有数据结构,因为大多数算法仅在顶点+边列表上是高度次优的

    在实践中,我假设您的边列表可以像经典的邻接列表一样组织(例如,按源顶点排序,因此您可以按源顶点进行O(log(n))查找)

    对于下面的例子,我假设情况就是这样。请记住,我们只是在接近关联图概念的复杂性保证:

    复杂性保证
    source()
    target()
    out\u edges()
    函数都必须是常量时间。
    out\u degree()
    函数的输出边数必须是线性的

    要真正满足这些要求,您需要每个顶点都有专门的输出边存储

    那么,让我们试一试:

    嘲笑你的图书馆 这在功能上大致相当于顶点容器的邻接列表,具有
    集合

    查看它

    #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)));
    }
    
    运行BFS 除此之外,所需的是算法的参数。您需要颜色贴图和顶点索引贴图。这是完全正常的,如果您有邻接列表,这也是必需的

    我将把索引映射隐藏在
    MyGraph
    包装中,并公开颜色映射,以便您可以选择您的首选项:

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

    想把这个范围缩小到一个特定的使用范围吗#包括?我可以试试看。我知道一般原则。等待你们所说的“从未得到回答”的链接有一个被接受的答案,上面有投票。回答很好。1.时间复杂度成本可能不会太高。这取决于规模和分布(如果边缘确实有序,则log(N)非常快。在Glue wrapper构造函数(
    MyGraph
    )上添加一点查找缓存并不困难。我同意2。可能是最佳的,并且在概念上是最干净的(它确实需要特定于BGL的代码,但不具侵入性,因此避免了紧密耦合)。3。[ad 1st bullet]如果不需要经常修改图形并保持映射,则简单化似乎是最不符合BGL magic的代码/功能。您将最能利用StackOverflow3的现有工作主体。[ad 2nd bullet]我同意它不够灵活。我认为无论你如何旋转它,邻接列表都会假设它可以构造出边缘列表容器(所以引用是不存在的),即使你让它使用
    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;
        };
    
    }
    
    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);
        }
    }
    
    #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)));
    }
    
    assert(std::is_sorted(_edges.begin(), _edges.end(), EdgeOrder{}));