c++ - 使用 std::sort 对依赖树进行排序

标签 c++ sorting graph-theory

我想根据插件之间的依赖关系对一堆插件进行排序,这样我就可以线性加载它们而不会发生任何冲突。契约(Contract)排除了依赖循环(导致未定义的行为)。

想象一棵深度为 2 的二叉树,它的边指向叶子。让它成为一个人工依赖树。边集表示关系 R。如果元组 (lhs, rhs) 在 R 中,比较返回真。

我能否将 std::sort 与表示关系 rhs 取决于 lhs 的比较一起使用来实现此目的?

最佳答案

我最近也有同样的需求。我在代码中对数据库实体进行建模,需要一种映射依赖关系的方法,以便可以按正确的顺序创建和销毁实体。

我找到了一个使用 boost::graph 库的解决方案。我包含了一个(真实代码的)片段,希望它能帮助您朝着正确的方向开始。

在下面的代码中,函数 create_order 按照必须创建的顺序生成实体 vector ,而 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;
    }

关于c++ - 使用 std::sort 对依赖树进行排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40721470/

相关文章:

c++ - 从枚举值中获取正确的模板化类实例化

C++ 并发修改和读取单个全局变量

java - 如何获取新创建的文件中的月份总数?

ios - 按 NSNumber 值对 NSDictionary 键进行排序

python - 从带有边标签的邻接矩阵绘制加权图

c++ - vector的构造函数中的size_type是什么意思?

c++ - 带有 Placement New 的自定义析构函数

string - 什么是字典顺序?

graph-theory - 3-sat 和 Tutte 多项式

algorithm - 带权有向图的邻接矩阵