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

C++实现游戏树BFS时遍历std::set类型nextMoves集合的问题求解

问题修正说明

标"fix me"的set遍历逻辑修正

原代码的范围for循环存在可优化点,并非完全不符合std::set的遍历要求:

  • std::set是有序关联容器,迭代器解引用返回的是const修饰的存储元素,即const std::shared_ptr<GameTreeNode>。原代码按值拷贝生成普通shared_ptr的写法虽然可以通过编译,但会触发智能指针引用计数的原子增减操作,产生不必要的性能开销。
  • 正确的遍历写法直接通过const引用绑定容器内的元素,完全适配set的存储特性,无语法兼容问题:
for (const auto& child_node : cur_node->nextMoves) {
  // 后续节点访问判断逻辑保持原有逻辑即可
}

连带发现的代码逻辑问题

  • 原代码用if(!visited[node])判断节点是否访问的写法存在副作用:std::map::operator[]在目标键不存在时,会自动插入值为0的默认键值对,这个无意义的插入操作会拉低BFS的遍历效率。推荐改用visited.find(child_node) == visited.end()判断节点访问状态,避免多余的内存操作。
  • 原代码的大括号存在不闭合问题,会直接导致编译失败,需要补齐while循环、外层函数的结构括号。
  • 缺少根节点为空的边界判断,会在空树场景下触发非法内存访问,需要在函数开头增加空指针校验。
  • 原代码遍历时的元素拷贝没有做类型适配,结合set的const元素特性,用auto推导类型可以避免手写类型带来的不一致问题。

修正后的完整可运行BFS代码

std::list<Board> GameTree::bfs() const {
  std::list<Board> ret;
  std::map<std::shared_ptr<GameTreeNode>, int> visited;
  std::queue<std::shared_ptr<GameTreeNode>> q;
  
  // 空树边界处理
  if (!root) return ret;

  q.push(root);
  ret.push_back(root->board);
  visited[root] = 1;

  while (!q.empty()) {
    auto cur_node = q.front();
    q.pop();
    // 正确适配set的遍历写法
    for (const auto& child_node : cur_node->nextMoves) {
      // 避免map[]的副作用
      if (visited.find(child_node) == visited.end()) {
        ret.push_back(child_node->board);
        q.push(child_node);
        visited[child_node] = 1;
      }
    }
  }
  return ret;
}

补充说明:nextMoves集合内的元素会按照CompareGameTreeNodeSharedPtr的规则排序,BFS遍历子节点的顺序会完全匹配这个排序结果,这是std::set的固有容器特性,并非遍历逻辑错误。按照课程要求无需关注比较器实现的场景下,直接使用上述遍历写法即可满足需求,不需要额外调整顺序。


内容的提问来源于stack exchange,提问作者List-Pop Smoke

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.22 11:06:03