是否可以在BGL中更改广度优先搜索终止条件?

时间:2013-04-11 07:18:33

标签: boost breadth-first-search boost-graph

我是BGL(增强图库)的新手。我正在学习breadth_first_search接口,它看起来很方便。但是,在我的应用程序中,我需要在遇到其他一些终止条件时剪切breadth_first_search,例如搜索空间节点数满足最大值。

我可以在BFSVisitors中添加新的终止条件,还是有其他技巧?

谢谢!

1 个答案:

答案 0 :(得分:3)

关于@yuyoyuppe评论(稍晚),您可以创建一个代理访问者,它将包装一个实际访问者并在满足给定谓词时抛出。我选择解决的实现使您能够在cloneWithRowsAndSectionsdiscover_vertex上运行谓词。首先,我们定义一个返回始终为false的默认谓词:

examine_edge

然后,模板本身。

namespace details {

struct no_halting {
    template <typename GraphElement, typename Graph>
    bool operator()(GraphElement const&, Graph const&) {
        return false;
    }
};
} // namespace details

需要3个模板参数:

  1. 每次调用template <typename VertexPredicate = details::no_halting, typename EdgePredicate = details::no_halting, typename BFSVisitor = boost::default_bfs_visitor> struct bfs_halting_visitor : public BFSVisitor { // ... Actual implementation ... private: VertexPredicate vpred; EdgePredicate epred; }; 时应用的顶点谓词(每个顶点最多一次)
  2. 边缘谓词,适用于每次调用discover_vertex(每边最多一次)
  3. 我们将继承的实际访客实现
  4. 要构建它,我们只需初始化基本访问者和我们的两个谓词:

    examine_edge

    然后,我们必须创建一个(私有)代理函数来执行对基本实现的适当调用并检查谓词:

    template <typename VPred, typename EPred, typename ... VisArgs>
    bfs_halting_visitor(VPred&& vpred, EPred&& epred, VisArgs&&... args) :
                        BFSVisitor(std::forward<VisArgs>(args)...),
                        vpred(vpred), epred(epred) {}
    

    当然,我懒得使用template <typename Pred, typename R, typename ... FArgs, typename ... Args> void throw_on_predicate(R (BFSVisitor::*base_fct)(FArgs...), Pred&& pred, Args&&... args) { bool result = pred(args...); (this->*base_fct)(std::forward<Args>(args)...); if (result) { throw std::runtime_error("A predicate returned true"); } } ,但您应该定义自己的异常类型,派生自std::runtime_error或您使用的任何基本异常类。

    现在我们可以轻松定义两个回调:

    std::exception

    我们将在自定义顶点谓词上测试我们的设施,该谓词在发现第N个顶点时返回true。

    template <typename Edge, typename Graph>
    void examine_edge(Edge&& e, Graph&& g) {
        throw_on_predicate(&BFSVisitor::template examine_edge<Edge, Graph>, epred,
                           std::forward<Edge>(e), std::forward<Graph>(g));
    }
    
    template <typename Vertex, typename Graph>
    void discover_vertex(Vertex&& v, Graph&& g) {
        throw_on_predicate(&BFSVisitor::template discover_vertex<Vertex, Graph>, vpred,
                           std::forward<Vertex>(v), std::forward<Graph>(g));
    }
    

    要在给定图表上执行bfs,这将很容易:

    struct VertexCounter {
        VertexCounter(std::size_t limit) : count(0), limit(limit) {}
        VertexCounter() : VertexCounter(0) {}
    
        template <typename V, typename G>
        bool operator()(V&&, G&&) {
            return ((++count) > limit);
        }
    private:
        std::size_t count;
        std::size_t const limit;
    };
    

    live demo on Coliru可以帮助您查看所有操作内容。