如何用Boost Graph Library获取顶点v距离d的可达诱导子图?是否用bfs_visitors?
使用Boost库实现指定深度的可达诱导子图
核心思路
对应你提供的NetworkX代码逻辑,我们需要完成两步:
- 从顶点
v出发,通过BFS筛选出深度不超过d的所有可达顶点(对应原代码中从bfs_edges提取的节点集合); - 基于这些顶点生成原图的诱导子图(即包含选中顶点及它们在原图中的所有关联边)。
Boost库不需要强制使用自定义bfs_visitor,有两种可行实现方式:
方法一:使用内置BFS工具记录距离(简单易读)
这种方式借助Boost内置的record_distances工具记录每个顶点的距离,再筛选符合条件的顶点,最后复制生成子图。
代码实现
#include <boost/graph/adjacency_list.hpp> #include <boost/graph/breadth_first_search.hpp> #include <boost/graph/copy.hpp> #include <vector> #include <set> // 定义图类型(以无向图为例,有向图替换为boost::directedS) typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS> Graph; typedef boost::graph_traits<Graph>::vertex_descriptor Vertex; Graph reachable_subgraph(const Graph& G, Vertex v, int d) { if (d < 0) return Graph(); // 初始化距离数组:-1表示不可达,起点v距离为0 std::vector<int> distances(boost::num_vertices(G), -1); distances[v] = 0; // 执行BFS并记录每个顶点的距离 boost::breadth_first_search(G, v, boost::visitor( boost::make_bfs_visitor( boost::record_distances(distances.data(), boost::on_tree_edge()) ) ) ); // 收集符合条件的顶点:对应原代码逻辑,d=0时返回空,d>0时包含距离≤d的所有可达顶点 std::set<Vertex> target_nodes; if (d > 0) { for (Vertex u : boost::make_iterator_range(boost::vertices(G))) { if (distances[u] != -1 && distances[u] <= d) { target_nodes.insert(u); } } } // 复制生成诱导子图:仅保留选中顶点及它们之间的边 Graph subgraph; boost::copy_graph(G, subgraph, boost::vertex_filter([&target_nodes](Vertex u) { return target_nodes.count(u) > 0; }) ); return subgraph; }
代码说明
record_distances是Boost内置的BFS访问工具,会在遍历树边时自动记录子节点的距离;copy_graph结合vertex_filter,只复制选中的顶点,同时自动保留这些顶点在原图中的所有关联边,实现诱导子图的效果;- 针对
d=0的情况,严格对应原代码逻辑,返回空的子图。
方法二:自定义BFS访问者(高效提前终止)
如果希望在BFS过程中一旦遍历到超过深度d的节点就停止处理其邻居,可以自定义bfs_visitor来实现,减少不必要的遍历。
代码实现
#include <boost/graph/adjacency_list.hpp> #include <boost/graph/breadth_first_search.hpp> #include <boost/graph/copy.hpp> #include <vector> #include <set> typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS> Graph; typedef boost::graph_traits<Graph>::vertex_descriptor Vertex; typedef boost::graph_traits<Graph>::edge_descriptor Edge; // 自定义深度限制BFS访问者 struct DepthLimitedVisitor : public boost::bfs_visitor<> { int max_depth; std::set<Vertex>& target_nodes; std::vector<int>& distances; DepthLimitedVisitor(int d, std::set<Vertex>& nodes, std::vector<int>& dist) : max_depth(d), target_nodes(nodes), distances(dist) {} // 发现顶点时,若深度符合则加入集合 void discover_vertex(Vertex u, const Graph&) { if (distances[u] <= max_depth) { target_nodes.insert(u); } } // 遍历树边时,设置子节点深度,超过限制则标记为已访问(不再处理其邻居) void tree_edge(Edge e, const Graph& G) { Vertex src = boost::source(e, G); Vertex dst = boost::target(e, G); distances[dst] = distances[src] + 1; if (distances[dst] > max_depth) { boost::put(boost::vertex_color, G, dst, boost::black_color); } } }; Graph reachable_subgraph_visitor(const Graph& G, Vertex v, int d) { if (d < 0) return Graph(); std::vector<int> distances(boost::num_vertices(G), -1); distances[v] = 0; std::set<Vertex> target_nodes; if (d > 0) { target_nodes.insert(v); std::vector<boost::default_color_type> colors(boost::num_vertices(G)); DepthLimitedVisitor visitor(d, target_nodes, distances); boost::breadth_first_search(G, v, boost::visitor(visitor) .color_map(colors.data()) ); } // 复制生成诱导子图 Graph subgraph; boost::copy_graph(G, subgraph, boost::vertex_filter([&target_nodes](Vertex u) { return target_nodes.count(u) > 0; }) ); return subgraph; }
代码说明
- 自定义访问者通过
tree_edge方法检查子节点深度,超过d时将其标记为black_color,BFS会跳过对该节点邻居的遍历; discover_vertex方法在首次访问顶点时,将符合深度要求的节点加入集合。
是否需要使用BFS访问者?
不需要强制使用。
- 如果你追求代码简洁、易维护,方法一完全够用,借助Boost内置的工具就能完成需求;
- 只有当你需要深度定制BFS过程(比如提前终止遍历、记录额外信息)时,才需要自定义
bfs_visitor。
内容的提问来源于stack exchange,提问作者ne_tv
相关产品推荐
相关产品推荐

