C++ sort比较规则需要满足严格弱序
1. 起因
刷题时,遇到的一个问题。
C++自定义sortsortsort的排序规则<
,发生的情况。
有两种异常的表现:
- 一是程序直接中断退出
- 二是程序直接卡死在
cmp
函数
由于是ub
,所以发生什么都不奇怪了。
2. 解决
后来查资料才知道,c++
容器在排序时都需要满足严格弱序。
那么什么是严格弱序呢?
2.1 严格弱序
我们时常用到的<
<=
数学符号,其实都是定义在一个集合中的二元关系。
这些概念在离散数学中有涉及,可以自行查阅相关资料。
对于我们使用的一些二元关系,他们需要满足一定的性质。
而严格弱序需要满足
- 非自反:a<aa<aa<a 为假,通俗讲就是一个元素不小于自身
- 传递性:a<b∩b<c→a<ca<b \cap b <c \rightarrow a <ca<b∩b<c→a<c,这个比较好理解,就是aaa比bbb小,bbb比ccc小,那么aaa比ccc小
- 非对称性:a<b→¬(b<a)a < b \rightarrow \lnot(b <a)a<b→¬(b<a),也就是如果aaa小于bbb为真了,那么bbb小于aaa一定为假
- 非可比的传递性:
- 简单说下可比性(a<b)∪(b<a)(a < b)\cup(b<a)(a<b)∪(b<a)为真,也就是两个元素至少有一个小于另外一个为真。
- 非可比传递性,也就是aaa跟bbb不可比较,bbb跟ccc不可比较,那么aaa跟ccc也不可比较
其中的非称性可以由非自反性和传递性推导出来,
因此可以直接省略掉。
而在C++ reference
中也正是这么做的。
这里的e(a,b)e(a,b)e(a,b)其实就是a,ba,ba,b之间不可比。
而不可比由于条件本身就满足自反和对称
aR̸a→e(a,a)e(a,b)↔e(b,a)a \not R \ a \rightarrow e(a,a)\\ e(a,b) \leftrightarrow e(b,a) aR a→e(a,a)e(a,b)↔e(b,a)
,而给出的第三条就是
传递性。因此这里定义的不可比性就是一个等价关系。
最后一句rrr在eee确定的等价类上诱导一个严格全序的意思是,我们把
这些元素根据不可比性质分类,比如e(a,b)e(a,b)e(a,b),就把a,ba,ba,b划分到一个等价
类[a][a][a]中去了,同样c,dc,dc,d不可比,划分到同一等价类[c][c][c]中去。对于不同
等价类中的元素的它们肯定是可比的,因此我们就可以选个代表进行
比较了,如b∈[a],d∈[c],b<d∨d<bb \in[a],d \in[c] , b < d \lor d <bb∈[a],d∈[c],b<d∨d<b。
而这些代表间肯定都有大小之分,因此就成了严格全序。
2.2 代码分析
错误的自定义代码如下
struct info {info(int fi_, int li_, int cnt_): fi(fi_), li(li_),cnt( cnt_ ) {}bool operator < (const info &f) const {if (f.fi == -1 || fi == -1)return fi == -1;if (f.cnt != cnt)return cnt < f.cnt;return li - fi > (f.li - f.fi);}int fi;int li;int cnt;
};
我由于用fi=−1fi=-1fi=−1来表示未输入的默认的情况,但是在两个默认值比较时
<<<返回的都是true
,也就不满足a<aa < aa<a为false
这一条了。
修正只需要去掉对fififi判断就可以了。由于两个默认值肯定是相
同的,所以最终两个默认值返回的都是false
。
3. 参考
wiki-weak-ordering
cppreference