C++ 按绝对值排序时如何保留模相等元素的原始顺序?
问题原因与解决方案
核心错误原因
你使用<=作为比较器的写法违反了C++标准库对排序比较器的严格弱序要求:
- 标准库所有排序算法(包括
std::sort、std::stable_sort)要求比较器comp满足:对于两个等价的元素a和b(此处等价指绝对值相等),comp(a,b)和comp(b,a)必须同时返回false - 使用
abs(a) <= abs(b)时,两个绝对值相等的元素互相比较都会返回true,完全不符合上述规则,属于未定义行为,因此无论使用哪种排序算法都会出现异常结果,和算法本身是否稳定无关。
正确实现方案
方案1:使用std::stable_sort + 严格小于比较器(最简便)
std::stable_sort本身会保证等价元素的原始相对顺序不变,你只需要传入符合严格弱序的比较器即可:
std::stable_sort(v.begin(), v.end(), [](int a, int b) { return abs(a) < abs(b); });
这个方案完全满足你的需求:绝对值小的排前面,绝对值相等的元素保留原始顺序。
方案2:使用std::sort + 绑定原始下标(无需稳定排序)
如果你只能用不稳定的std::sort,可以把元素和它的原始下标绑定后再排序,绝对值相等时按下标从小到大排列,强制保留原始顺序:
// 绑定元素和原始下标 std::vector<std::pair<int, size_t>> indexed_v; indexed_v.reserve(v.size()); for (size_t i = 0; i < v.size(); ++i) { indexed_v.emplace_back(v[i], i); } // 排序逻辑:先比绝对值,再比原始下标 std::sort(indexed_v.begin(), indexed_v.end(), [](const auto& x, const auto& y) { int abs_x = abs(x.first); int abs_y = abs(y.first); return abs_x != abs_y ? abs_x < abs_y : x.second < y.second; }); // 回写结果到原数组 for (size_t i = 0; i < v.size(); ++i) { v[i] = indexed_v[i].first; }
常见误区解释
你之前用<时测试用例结果正确只是巧合:std::sort是不稳定排序,等价元素的顺序没有被打乱只是特定测试用例、特定排序实现下的偶然结果,换个输入或者编译器版本就可能不符合预期,不能作为通用方案使用。
内容的提问来源于stack exchange,提问作者Evgeny
相关产品推荐
相关产品推荐

