我希望通过某种方式将一堆插件按其依赖关系排序,以便我可以线性加载它们而不会产生任何冲突。合同排除了依赖性循环(导致未定义的行为)。
想象一下深度为二的二叉树,其边缘指向叶子。让它成为一个人工依赖树。边集表示关系R.如果元组(lhs,rhs)在R中,则Compare返回true。
我可以使用std :: sort和一个表示 rhs取决于lhs 的关系来实现这个吗?
答案 0 :(得分:0)
我最近有同样的要求。我在代码中建模数据库实体,需要一种映射依赖关系的方法,以便可以按正确的顺序创建和销毁实体。
我找到了boost::graph
库的解决方案。我已经包含了一个代码片段(真实代码),希望它可以帮助您开始正确的方向。
在下面的代码中,函数create_order
按照必须创建的顺序生成实体向量,而drop_order
则相反(最依赖的实体首先出现):
using edge = std::pair<std::size_t, std::size_t>;
using edge_vector = std::vector<edge>;
using graph_properties = boost::property<
boost::vertex_color_t,
boost::default_color_type
>;
typedef boost::adjacency_list<boost::vecS, boost::vecS,
boost::bidirectionalS,
graph_properties
> Graph;
typedef boost::graph_traits<Graph>::vertex_descriptor Vertex;
struct cycle_detector : public boost::dfs_visitor<>
{
cycle_detector( edge_vector& back_edges)
: _back_edges(back_edges)
{ }
void back_edge(const boost::graph_traits<Graph>::edge_descriptor& e, const Graph&) const {
_back_edges.emplace_back(e.m_source, e.m_target);
}
protected:
edge_vector& _back_edges;
};
auto generate_graph() const {
Graph g(std::begin(_edges), std::end(_edges), _entities.size());
return g;
}
void check_cycles(const Graph& g) const
{
edge_vector back_edges;
cycle_detector vis(back_edges);
boost::depth_first_search(g, visitor(vis));
if (back_edges.size())
{
std::ostringstream ss;
ss << "cyclic dependency detected. Back edges are:\n";
for (auto& p : back_edges)
{
ss << value::debug::demangle(typeid(_entities[p.first].get()))
<< " <<==>> "
<< value::debug::demangle(typeid(_entities[p.second].get()))
<< std::endl;
}
throw std::logic_error(ss.str());
}
}
auto create_order() const {
using namespace boost;
auto g = generate_graph();
check_cycles(g);
std::vector<std::size_t> result_order;
vector_type result;
boost::topological_sort(g, std::back_inserter(result_order));
std::transform(std::begin(result_order), std::end(result_order),
std::back_inserter(result), [this](auto i) {
return _entities[i];
});
return result;
}
auto drop_order() const {
auto result = create_order();
std::reverse(std::begin(result), std::end(result));
return result;
}
答案 1 :(得分:0)
不 - 我不这么认为。
想象一下:
A
/ \
B C
\
D
B和C取决于A,D取决于C.现在:
第一个问题:B = C,B = D,但C 其次,未指定std :: sort使用的算法,但我们知道许多实现使用某种形式的quicksort。 Quicksort实现允许将值分区为三个桶 - 小于枢轴的那些桶,大于枢轴的那些桶,以及那些全部等于枢轴的桶,因此不需要任何额外的排序。 (请参阅维基百科上的"Repeated elements"部分。) 如果这样的快速选择选择B作为枢轴,那么C和D都会发现自己在这个&#34;胖分区&#34;在某些未指定的顺序中,std :: sort甚至不会使用您的比较函数对D进行C测试。