std::sort的严格弱序问题

参考:

LeetCode 179题:要求将数组中的数字拼接成最大的数。我的做法有点蠢,排序时的思路大概是下面这样的:

{#code-block}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
auto mycmp = [](string first, string& second){
if(first.length() == second.length()){
return first.compare(second) >= 0;
}
// 大的为true
auto i1 = 0, i2 = 0;
while(true){
if(first[i1] > second[i2]){
return true;
}
else if(first[i1] < second[i2]){
return false;
}
else{
i1 = (i1+1) % first.length();
i2 = (i2+1) % second.length();
if(i1 == 0 && i2 == 0){
return true;
}
}
}
};
sort(strs.begin(),strs.end(),mycmp);

测试时,出现了奇怪的现象:当输入为[0,0,0,0]时,函数正常运行;而当输入为[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]的超多0时,程序会在if(first[i1] > second[i2])崩溃。我自然是一脸懵,全0输入,肯定会在比较时由于长度相等而不进入while循环。

调试时发现first莫名其妙为空了,于是我在while前加上了非空判断,结果还是崩溃。好吧,求助了qwen,他和我说要把参数的两个string改为const引用,所以我就把函数头部修改成了const形式:

1
auto mycmp = [](const string& first, const string& second)

结果还是无效。已经超出我的理解了,所以就上网看了看,发现std::sort对其排序规则有额外要求,即严格弱序:

  • 1.非自反性:comp(a, a) 必须为 false。
  • 2.非对称性:若 comp(a, b) 为 true,则 comp(b, a) 必须为 false。
  • 3.传递性:若 comp(a, b) 和 comp(b, c) 为 true,则 comp(a, c) 必须为 true。
    如果比较函数不满足这些条件,排序算法的内部逻辑会崩溃,导致未定义行为。

未定义行为的后果:

当比较函数违反严格弱序时,std::sort 的内部逻辑(如快速排序的分区)会陷入混乱:

  • 迭代器越界:在比较中误判元素的顺序,导致访问非法内存。
  • 空字符串问题:错误的元素交换可能导致字符串被意外清空。
  • 死循环:无法正确终止分区过程。
  • 当输入全为 0 时,所有字符串都是 “0”,每次比较都会触发 first.compare(second) >= 0,导致未定义行为。

将>=修改为>,即可恢复排序规则的严格弱序,程序正常运行。


std::sort的严格弱序问题
http://example.com/2025/03/13/my_std_sort_error/
作者
icyyoung
发布于
2025年3月13日
许可协议