C++类方法中std::unordered_set调用set_intersection异常而std::set正常
问题原因分析
- 核心原因是
std::set_intersection算法对输入范围有强制前置要求:两个输入范围必须按照同一比较规则升序排序,否则会产生未定义行为。 std::set是有序关联容器,内部元素默认按照升序排列,完全满足std::set_intersection的输入要求,替换后运行结果自然正常。std::unordered_set是哈希实现的无序关联容器,内部元素的遍历顺序由哈希规则、插入顺序、哈希冲突处理逻辑共同决定,没有固定的升序排列规则,传入std::set_intersection时不符合前置条件,结果不可预测。
为什么前两次测试能正常运行?
你最初手动初始化unordered_set时给定的初始化列表元素,碰巧在你的编译环境下遍历顺序是升序的,刚好满足set_intersection的要求,所以得到了正确结果。
而封装到Counter类之后,元素是按0→1→2的顺序逐个插入到unordered_set中,最终容器的遍历顺序不符合升序要求,set_intersection无法正确识别交集,所以返回了错误的0。
解决方案
- 保持现有逻辑不变,将所有
std::unordered_set替换为std::set,利用std::set的有序性兼容std::set_intersection算法,你已经验证过该方案可行。 - 如果需要保留
std::unordered_set的读写性能优势,不要使用std::set_intersection,改为手动遍历更小的集合查询交集:
size_t count(const std::pair<int,int>& pt) { const auto& x_set = _xs.at(pt.first); const auto& y_set = _ys.at(pt.second); size_t cnt = 0; // 优先遍历元素更少的集合,降低总查询次数 if (x_set.size() <= y_set.size()) { for (size_t idx : x_set) { if (y_set.count(idx)) cnt++; } } else { for (size_t idx : y_set) { if (x_set.count(idx)) cnt++; } } return cnt; }
内容的提问来源于stack exchange,提问作者janreggie
相关产品推荐
相关产品推荐

