Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/156.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何在BGL中按(捆绑)属性提供的顺序迭代顶点和边?_C++_Boost_Iterator_Boost Graph_Boost Property Map - Fatal编程技术网

C++ 如何在BGL中按(捆绑)属性提供的顺序迭代顶点和边?

C++ 如何在BGL中按(捆绑)属性提供的顺序迭代顶点和边?,c++,boost,iterator,boost-graph,boost-property-map,C++,Boost,Iterator,Boost Graph,Boost Property Map,假设我有一些助推图 包括 结构顶点{ 双重属性_1; int属性_2; }; 使用图形\u t=boost::邻接\u列表; 图5; 现在要以不同的顺序迭代顶点,比如: 根据它的id 以随机顺序 按属性2递减 按属性_1升序 以通用方式按更多绑定属性降序/升序。 我如何以最有效的方式完成这项工作 现在,我创建了带有属性的std::vectors和包含索引的向量,并按属性对它们进行排序。但是如果你有很多属性,这些属性创建了大量可以避免的结构 我还研究了boost::multi_索引映射,如中所示,

假设我有一些助推图

包括 结构顶点{ 双重属性_1; int属性_2; }; 使用图形\u t=boost::邻接\u列表; 图5; 现在要以不同的顺序迭代顶点,比如:

根据它的id 以随机顺序 按属性2递减 按属性_1升序 以通用方式按更多绑定属性降序/升序。 我如何以最有效的方式完成这项工作


现在,我创建了带有属性的std::vectors和包含索引的向量,并按属性对它们进行排序。但是如果你有很多属性,这些属性创建了大量可以避免的结构

我还研究了boost::multi_索引映射,如中所示,但对我来说,这也并不苗条


我该怎么做?很高兴听到任何提示

这显然不是图书馆的特色

但是,您可以像在任何其他情况下一样使用量程或量程适配器:

更多,从这里开始 std::ranges可以为您提供其中的大部分,但根据我的经验,还有一些限制。然而,它通常会更安全,因为助推范围V2非常旧

要像数据库一样拥有活索引,请让顶点容器选择器选择一个多索引容器。参见此处的建议

要为自己的图形数据结构建模,请参见此处,以获取灵感

使用boostpfr更新代码生成 作为对这些评论的回应,您可以使用Boost PFR静态生成一个带有比较器简单类型的数组:

template <typename T, typename Op = std::less<> >
constexpr static inline auto make_field_comparers(Op op = {}) {
    namespace pfr = boost::pfr;
    auto constexpr N = pfr::tuple_size<T>::value;
    using A = std::array<std::function<bool(T const&, T const&)>, N>;

    auto lift = [op](auto prj) {
        return [=](T const& a, T const& b) { return op(prj(a), prj(b)); };
    };

    return [lift]<size_t... I>(std::index_sequence<I...>){
        return A{lift([](T const& v) { return pfr::get<I>(v); })...};
    }
    (std::make_index_sequence<N>{});
}

这显然不是图书馆的特色

但是,您可以像在任何其他情况下一样使用量程或量程适配器:

更多,从这里开始 std::ranges可以为您提供其中的大部分,但根据我的经验,还有一些限制。然而,它通常会更安全,因为助推范围V2非常旧

要像数据库一样拥有活索引,请让顶点容器选择器选择一个多索引容器。参见此处的建议

要为自己的图形数据结构建模,请参见此处,以获取灵感

使用boostpfr更新代码生成 作为对这些评论的回应,您可以使用Boost PFR静态生成一个带有比较器简单类型的数组:

template <typename T, typename Op = std::less<> >
constexpr static inline auto make_field_comparers(Op op = {}) {
    namespace pfr = boost::pfr;
    auto constexpr N = pfr::tuple_size<T>::value;
    using A = std::array<std::function<bool(T const&, T const&)>, N>;

    auto lift = [op](auto prj) {
        return [=](T const& a, T const& b) { return op(prj(a), prj(b)); };
    };

    return [lift]<size_t... I>(std::index_sequence<I...>){
        return A{lift([](T const& v) { return pfr::get<I>(v); })...};
    }
    (std::make_index_sequence<N>{});
}

Boost.MultiIndex可以以一种非常复杂的、未记录的方式插入:

4月14日更新:我对一些东西进行了重构,以使生成的用户代码更加直观:

struct vertex_t
{
  double property_1;
  int    property_2;
};

using graph_t= boost::adjacency_list<
  boost::listS,
  mic_listS<
    boost::multi_index::ordered_non_unique<
      boost::multi_index::member<vertex_t,double,&vertex_t::property_1>
    >,
    boost::multi_index::ordered_non_unique<
      boost::multi_index::member<vertex_t,int,&vertex_t::property_2>,
      std::greater<int>
    >
  >,
  boost::undirectedS,
  vertex_t
>;

Boost.MultiIndex可以以一种非常复杂的、未记录的方式插入:

4月14日更新:我对一些东西进行了重构,以使生成的用户代码更加直观:

struct vertex_t
{
  double property_1;
  int    property_2;
};

using graph_t= boost::adjacency_list<
  boost::listS,
  mic_listS<
    boost::multi_index::ordered_non_unique<
      boost::multi_index::member<vertex_t,double,&vertex_t::property_1>
    >,
    boost::multi_index::ordered_non_unique<
      boost::multi_index::member<vertex_t,int,&vertex_t::property_2>,
      std::greater<int>
    >
  >,
  boost::undirectedS,
  vertex_t
>;

一如既往的酷!谢谢Joaquin!我需要一些时间来理解这些嵌套的多索引说明符:一如既往的酷!谢谢Joaquin!不过,我需要一些时间来理解这些嵌套的多索引说明符:再次感谢@sehe的快速而详细的回复和鼓舞人心的参考。可能会带着一个后续问题回到这里:我如何迭代&Vertex::property_1,&Vertex::property_2。。。调用less_by函数?如何迭代&Vertex::property_1,&Vertex::property_2。。。用于按函数调用less_?-你可以更好地描述这个问题。我想您正在寻找复合键订购。写下比较器:尽管现在放弃mem_fn假设是合理的:也许你想要一个合适的库来做这些,我认为cppsort有更好的投影实用性,就像g[v][I],其中I=0,1。。。。这是我的问题的第五部分,我想了解一下。我不知道这和第五部分有什么关系。不能使用[]为结构编制索引。这从来都不是C++。如果您需要它,您可能可以编写它,例如使用结构化绑定。我完全不知道它能给你带来什么,除了失去可读的命名。也许Boost PFR有你想要的:再次感谢@sehe的快速详细回复,以及鼓舞人心的参考资料。可能会带着一个后续问题回到这里:我如何迭代&Vertex::property_1,&Vertex::property_2。。。调用less_by函数?如何迭代&Vertex::property_1,&Vertex::property_2。。。用于按函数调用less_?-你可以更好地描述这个问题。我想您正在寻找复合键订购。写下比较器:尽管现在放弃mem_fn假设是合理的:也许你想要一个合适的库来做这些,我认为cppsort有更好的投影实用性,就像g[v][I],其中I=0,1。。。。这是我的问题的第五部分,我想了解一下。我不知道这和第五部分有什么关系。不能使用[]为结构编制索引。这从来都不是C++。如果您需要它,您可能可以编写它,例如使用结构化绑定。我完全不知道它能给你带来什么,除了失去可读的命名。也许Boost PFR有你想要的
你正在寻找:但是如果你有很多可以避免的创造大量结构的属性。需要引用。有些复杂性是内在的,但如果你有许多属性,创造了大量可以避免的结构。需要引用。有些复杂性是内在的。
by field #0 asc: {V(-16.6667, 55), V(-13.3333, 44), V(-10, 33), V(-6.66667, 22), V(-3.33333, 11)}
by field #1 asc: {V(-3.33333, 11), V(-6.66667, 22), V(-10, 33), V(-13.3333, 44), V(-16.6667, 55)}
by field #0 desc: {V(-3.33333, 11), V(-6.66667, 22), V(-10, 33), V(-13.3333, 44), V(-16.6667, 55)}
by field #1 desc: {V(-16.6667, 55), V(-13.3333, 44), V(-10, 33), V(-6.66667, 22), V(-3.33333, 11)}
#include <boost/graph/adjacency_list.hpp>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/random_access_index.hpp>
#include <boost/multi_index/ordered_index.hpp>

struct mic_tag:
  /* it is assumed first index is random-access */
  virtual public boost::graph_detail::random_access_container_tag,
  virtual public boost::graph_detail::back_insertion_sequence_tag{};

namespace boost{

template<typename... Args>
mic_tag container_category(boost::multi_index_container<Args...>&){return {};}

}

template<typename GraphType,typename KeyExtractor>
struct vertex_adapted
{
  using result_type=typename KeyExtractor::result_type;
        
  decltype(auto) operator()(void* p)const
  {
    return key(
      static_cast<typename GraphType::stored_vertex*>(p)->m_property);
  }
  
  KeyExtractor key;
};

struct vertex_t
{
  double property_1;
  int    property_2;
};

struct graph_t;
struct graph_t_vertex_list;

namespace boost{
    
template<typename Value>
struct container_gen<graph_t_vertex_list,Value>
{
  using type=boost::multi_index_container<
    Value,
    boost::multi_index::indexed_by<
      boost::multi_index::random_access<>,
      boost::multi_index::ordered_non_unique<
        vertex_adapted<
          graph_t,
          boost::multi_index::member<vertex_t,double,&vertex_t::property_1>
        >
      >,
      boost::multi_index::ordered_non_unique<
        vertex_adapted<
          graph_t,
          boost::multi_index::member<vertex_t,int,&vertex_t::property_2>
        >,
        std::greater<int>
      >
    >
  >;
};

}

struct graph_t:
boost::adjacency_list<
  boost::listS,
  graph_t_vertex_list,
  boost::undirectedS,
  vertex_t
>{};

/* testing */

#include <iostream>

std::ostream& operator<<(std::ostream& os,const vertex_t& v)
{
  os<<"{"<<v.property_1<<","<<v.property_2<<"}";
  return os;
}
  
int main()
{
  graph_t g;
  add_vertex(vertex_t{0.0,0},g);
  add_vertex(vertex_t{0.1,1},g);
  add_vertex(vertex_t{0.2,2},g);
  
  for(void* p:g.m_vertices.get<1>()){
    std::cout<<static_cast<graph_t::stored_vertex*>(p)->m_property;
  }
  std::cout<<"\n";

  for(void* p:g.m_vertices.get<2>()){
    std::cout<<static_cast<graph_t::stored_vertex*>(p)->m_property;
  }
  std::cout<<"\n";
}
{0,0}{0.1,1}{0.2,2}
{0.2,2}{0.1,1}{0,0}
struct vertex_t
{
  double property_1;
  int    property_2;
};

using graph_t= boost::adjacency_list<
  boost::listS,
  mic_listS<
    boost::multi_index::ordered_non_unique<
      boost::multi_index::member<vertex_t,double,&vertex_t::property_1>
    >,
    boost::multi_index::ordered_non_unique<
      boost::multi_index::member<vertex_t,int,&vertex_t::property_2>,
      std::greater<int>
    >
  >,
  boost::undirectedS,
  vertex_t
>;
#include <boost/graph/adjacency_list.hpp>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/random_access_index.hpp>

template<typename KeyExtractor>
struct mic_list_key_extractor
{
  using result_type=typename KeyExtractor::result_type;
        
  template<typename StoredVertex>
  decltype(auto) operator()(StoredVertex& v)const{return key(v.m_property);}
  
  KeyExtractor key;
};

template<typename IndexSpecifier,typename=void>
struct mic_list_index_specifier{using type=IndexSpecifier;};

template<
  template<typename...> class IndexSpecifier,
  typename Arg1,typename Arg2,typename... Args
>
struct mic_list_index_specifier<
  IndexSpecifier<Arg1,Arg2,Args...>,
  std::void_t<typename IndexSpecifier<Arg1,Arg2,Args...>::key_from_value_type>>
{
  static constexpr bool has_tag=boost::multi_index::detail::is_tag<Arg1>::value;
  using arg1=std::conditional_t<has_tag,Arg1,mic_list_key_extractor<Arg1>>;
  using arg2=std::conditional_t<has_tag,mic_list_key_extractor<Arg2>,Arg2>;
  using type=IndexSpecifier<arg1,arg2,Args...>;
};

template<typename IndexSpecifier>
using mic_list_index_specifier_t=
  typename mic_list_index_specifier<IndexSpecifier>::type;

template<typename Value,typename... IndexSpecifiers>
struct mic_list:boost::multi_index_container<
  Value,
  boost::multi_index::indexed_by<
    boost::multi_index::random_access<>,
    mic_list_index_specifier_t<IndexSpecifiers>...
  >
>
{};

template<typename... IndexSpecifiers>
struct mic_listS;

struct mic_list_tag:
  virtual public boost::graph_detail::random_access_container_tag,
  virtual public boost::graph_detail::back_insertion_sequence_tag{};

namespace boost{

template<typename... Args>
mic_list_tag container_category(const mic_list<Args...>&){return {};}

template<typename Value,typename... IndexSpecifiers>
struct container_gen<mic_listS<IndexSpecifiers...>,Value>
{
  using type=mic_list<Value,IndexSpecifiers...>;
};

namespace detail
{

template<typename... IndexSpecifiers>
struct is_random_access<mic_listS<IndexSpecifiers...>>
{
  static constexpr bool value=true;
  using type=boost::mpl::true_;
};

}
}

/* testing */

#include <boost/multi_index/ordered_index.hpp>
#include <iostream>

struct vertex_t
{
  double property_1;
  int    property_2;
};

using graph_t= boost::adjacency_list<
  boost::listS,
  mic_listS<
    boost::multi_index::ordered_non_unique<
      boost::multi_index::member<vertex_t,double,&vertex_t::property_1>
    >,
    boost::multi_index::ordered_non_unique<
      boost::multi_index::member<vertex_t,int,&vertex_t::property_2>,
      std::greater<int>
    >
  >,
  boost::undirectedS,
  vertex_t
>;

std::ostream& operator<<(std::ostream& os,const vertex_t& v)
{
  os<<"{"<<v.property_1<<","<<v.property_2<<"}";
  return os;
}
  
int main()
{
  graph_t g;
  add_vertex(vertex_t{0.0,0},g);
  add_vertex(vertex_t{0.1,1},g);
  add_vertex(vertex_t{0.2,2},g);
  
  for(const auto& v:g.m_vertices.get<1>()){
    std::cout<<v.m_property;
  }
  std::cout<<"\n";

  for(const auto& v:g.m_vertices.get<2>()){
    std::cout<<v.m_property;
  }
  std::cout<<"\n";
}
{0,0}{0.1,1}{0.2,2}
{0.2,2}{0.1,1}{0,0}