You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Boost的带权图最小生成树深度优先遍历自定义访问器问题

解决Boost Graph自定义深度优先访问器的问题

嘿,我懂你现在卡在自定义DFS访问器这儿的苦恼!结合你提到的已经完成图和最小生成树构建的背景,我给你整理了一套完整的解决方案,包括自定义访问器的正确写法,以及如何在最小生成树上执行DFS的步骤。

核心思路:自定义DFS访问器的正确姿势

Boost的depth_first_search需要一个符合Visitor Concept的对象,最简单的方式是继承boost::default_dfs_visitor,然后重写你需要的回调方法(比如发现顶点、完成顶点、遍历树边等),不用实现所有方法——默认访问器会提供空实现。

完整代码示例

下面是结合你已有逻辑的完整代码,包含图构建、Kruskal最小生成树生成、自定义DFS访问器实现和遍历:

#include <iostream>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/kruskal_min_spanning_tree.hpp>
#include <boost/graph/depth_first_search.hpp>
#include <boost/graph/graph_traits.hpp>
#include <vector>
#include <string>

// 定义顶点和边的属性结构
struct VertexProperty {
    std::string name; // 顶点可以带名称属性
};

struct EdgeProperty {
    int weight; // 边的权重属性
};

// 定义图类型:无向图,顶点/边用向量存储,带自定义属性
using Graph = boost::adjacency_list<
    boost::vecS,
    boost::vecS,
    boost::undirectedS,
    VertexProperty,
    EdgeProperty
>;

using Vertex = boost::graph_traits<Graph>::vertex_descriptor;
using Edge = boost::graph_traits<Graph>::edge_descriptor;

// 自定义DFS访问器:继承默认访问器,重写需要的回调
struct CustomDFSVisitor : public boost::default_dfs_visitor {
    // 第一次访问到顶点时触发
    template <typename Vertex, typename Graph>
    void discover_vertex(Vertex v, const Graph& g) const {
        std::cout << "🔍 发现顶点:" << g[v].name << std::endl;
    }

    // 完成该顶点所有邻接顶点的访问后触发
    template <typename Vertex, typename Graph>
    void finish_vertex(Vertex v, const Graph& g) const {
        std::cout << "✅ 完成顶点:" << g[v].name << std::endl;
    }

    // 遍历生成树的树边时触发
    template <typename Edge, typename Graph>
    void tree_edge(Edge e, const Graph& g) const {
        auto src = source(e, g);
        auto tgt = target(e, g);
        std::cout << "🔗 遍历树边:" << g[src].name << " -> " << g[tgt].name 
                  << " | 权重:" << g[e].weight << std::endl;
    }
};

int main() {
    // 1. 构建原始带权图
    Graph g;
    Vertex v0 = add_vertex(VertexProperty{"A"}, g);
    Vertex v1 = add_vertex(VertexProperty{"B"}, g);
    Vertex v2 = add_vertex(VertexProperty{"C"}, g);
    Vertex v3 = add_vertex(VertexProperty{"D"}, g);

    // 添加带权边
    add_edge(v0, v1, EdgeProperty{2}, g);
    add_edge(v0, v2, EdgeProperty{3}, g);
    add_edge(v1, v2, EdgeProperty{1}, g);
    add_edge(v1, v3, EdgeProperty{4}, g);
    add_edge(v2, v3, EdgeProperty{5}, g);

    // 2. 用Kruskal算法生成最小生成树
    std::vector<Edge> mst_edges;
    boost::kruskal_minimum_spanning_tree(g, std::back_inserter(mst_edges));

    std::cout << "=== 最小生成树的边 ===" << std::endl;
    for (const Edge& e : mst_edges) {
        std::cout << g[source(e, g)].name << " - " << g[target(e, g)].name 
                  << " | 权重:" << g[e].weight << std::endl;
    }

    // 3. 构建最小生成树的独立图(方便DFS遍历,避免遍历原始图的非树边)
    Graph mst_graph;
    std::vector<Vertex> mst_vertex_map(num_vertices(g));
    // 复制原始图的顶点属性到生成树图
    for (Vertex v : boost::make_iterator_range(vertices(g))) {
        mst_vertex_map[v] = add_vertex(g[v], mst_graph);
    }
    // 添加生成树的边
    for (const Edge& e : mst_edges) {
        add_edge(mst_vertex_map[source(e, g)], mst_vertex_map[target(e, g)], g[e], mst_graph);
    }

    // 4. 执行自定义DFS遍历
    std::cout << "\n=== 深度优先遍历最小生成树 ===" << std::endl;
    CustomDFSVisitor visitor;
    // 必须提供颜色映射:跟踪顶点的访问状态(未访问/正在访问/已访问)
    std::vector<boost::default_color_type> vertex_colors(num_vertices(mst_graph));
    boost::depth_first_search(
        mst_graph,
        boost::visitor(visitor)
        .color_map(&vertex_colors[0]) // 颜色映射是DFS的必填参数
    );

    return 0;
}

你可能踩坑的几个关键点

  • 忘记继承boost::default_dfs_visitor:如果不继承,你需要实现所有Visitor Concept要求的方法,很容易出错。继承默认访问器只需要重写你关心的回调。
  • 缺少颜色映射(color_map):DFS必须跟踪顶点的访问状态,否则会陷入循环或者无法正确遍历。一定要提供color_map参数。
  • 回调函数签名错误:每个回调都是模板函数,参数必须包含顶点/边描述符和const引用的图,否则Boost的DFS算法无法正确调用。
  • 遍历原始图而非生成树:如果你直接在原始图上执行DFS,会遍历所有边,包括非生成树的边。所以单独构建生成树的图,或者用edge_filter来过滤出树边,都是可行的方案,上面的示例用了更直观的独立图方式。

内容的提问来源于stack exchange,提问作者Maecky

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 12:28:21