使用std :: sort来排序依赖关系树

时间:2016-11-21 13:34:14

标签: c++ sorting graph-theory

我希望通过某种方式将一堆插件按其依赖关系排序,以便我可以线性加载它们而不会产生任何冲突。合同排除了依赖性循环(导致未定义的行为)。

想象一下深度为二的二叉树,其边缘指向叶子。让它成为一个人工依赖树。边集表示关系R.如果元组(lhs,rhs)在R中,则Compare返回true。

我可以使用std :: sort和一个表示 rhs取决于lhs 的关系来实现这个吗?

2 个答案:

答案 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.现在:

  1. B不依赖于C,因此B不小于C.
  2. C不依赖于B,因此C不小于B.
  3. 因此B&#34;等于&#34; C就排序算法而言。
  4. 同样,D&#34;等于&#34;乙
  5. 第一个问题:B = C,B = D,但C

    其次,未指定std :: sort使用的算法,但我们知道许多实现使用某种形式的quicksort。 Quicksort实现允许将值分区为三个桶 - 小于枢轴的那些桶,大于枢轴的那些桶,以及那些全部等于枢轴的桶,因此不需要任何额外的排序。 (请参阅维基百科上的"Repeated elements"部分。)

    如果这样的快速选择选择B作为枢轴,那么C和D都会发现自己在这个&#34;胖分区&#34;在某些未指定的顺序中,std :: sort甚至不会使用您的比较函数对D进行C测试。