C++ stl 的sort使用中的坑

    stl的sort函数是一个很有用且高效的排序方法。如果自行添加比较函数,可以很大程度上的扩展其功能,使之能灵活的适应各种场景。但是sort在使用过程中存在一些注意事项,如果不加注意,很容易发生bug满地跑,你却不知道bug的源头在哪里的情况。

   1.sort需要迭代器是随机访问迭代器。如果使用list容器,可以使用list容器自带的sort成员函数,而不要使用使用这个泛型算法的sort。

  2.sort的加比较函数的重载版本:sort(begin,end,comp),需要comp编译时不能被改变符号名。类成员函数无法作为比较函数,但是可以使用比较类或者重载类的比较运算符。一般采用的方法时定义comp为全局的函数,或者C++ 11可以使用lambda表达式。详情可以参考[1].

  3.comp函数的书写需要注意严格弱序规则。所谓严格弱序规则,简单来讲就是只用一个严格弱序就能区分两个关键字的大小。比如 x大于y可以用y

    推广到比较函数,严格弱序的规则可以表示为:

  1. 两个关键字不能同时“严格弱序”于对方
  2. 如果a“严格弱序”于b,且b“严格弱序”于c,则a必须“严格弱序”于c
  3. 如果存在两个关键字,任何一个都不“严格弱序”于另一个,则这两个关键字是相等的。(参考[2])

    举个例子:

#include 
#include 
#include 

bool comp(int x1, int x2) {
	return x1 > x2 ? true : false;
}

int main()
{
	vector vec(3);
	vec[0] = 5;
	vec[1] = 8;
	vec[2] = 5;
	sort(vec.begin(), vec.end(), comp);
	for (auto v : vec) cout << v << endl;
	return 0;
}

   为了清楚显示true和false,我在代码中写出了。这里可以验证一下这里的判断是否属于严格弱序。如果有数组vec[0]=5,vec[1]=8,vec[2]=5。

  1.  可以看出对于vec[1] > vec[0]成立 和vec[0] > vec[1]成立,显然只会有vec[1] > vec[0]成立(同理vec[1]和vec[2])。
  2.   第二个条件这个情况下不存在,但是一个5改为4,就可以发现是满足的。
  3. vec[0] > vec[2]不成立,vec[2] > vec[0] 不成立,所以vec[0] == vec[2]。

   但是 >=就不对了,因为不满足第一个种情况,5和5同时满足vec[0] >= vec[2]成立,vec[2] >= vec[0]成立。(注意这里成立为返回true,不成立为返回false,不理解这里,下文就无法理解)

  这时候仔细思考下,是不是>=就不能放在比较函数中用来判断了吗?看下修改后的例子:

bool comp(int x1, int x2) {
	return x1 >= x2 ? false : true;
}

这个时候修改 >为 >= ,同时置换false和true的位置,再上机编译,输入5,8 ,5又能通过了(只是这里排序方式颠倒了)。主要问题就在于上文中的成立和不成立的判断。true代表成立,false代表不成立。

对5,8,5不满足的上文的第1个条件,在这种情况下再分析(这里成功转变为上文中第3条):

  1.  可以看出对于vec[0] > =vec[2]返回false(不成立)的情况 和vec[0] > = vec[2]返回false(不成立)的情况,显然只会有vec[1] == vec[0]成立(返回ture)。

    最后,如果被成功绕晕了。这里经验性的结论就是,不要在相等的情况下时候返回true。在>号时,5,5比较返回false。

在>= 时候,5和5比较,5>= 5,但是还是返回false。

  最最后,如果在出现比较函数出错的情况,加上或者减去一个等号往往就会成功。

[1]http://www.wl566.com/biancheng/98907.html(原创地址,文章中为参考地址)

[2]https://blog.csdn.net/River_Lethe/article/details/78618788

你可能感兴趣的:(C++)