记录一个cpp的坑:cmp 排序自定义比较函数的问题

参考:http://biasee.com/2016/01/22/STL-sort-segmentation-fault/

C++ std的sort,compare函数写成下面这样,可能出现segmentation fault,因为写成a>=b是错误的,不符合stl的strict weak ordering关系。

bool cmp(int a,int b){
    return a>=b;
}

使用C++的标准模板库(Standard Template Library,STL)中的std::sort函数进行排序时,如果你的比较函数(这里是cmp)的实现是return a>=b;,可能会导致程序出现分段错误(Segmentation Fault)。

原因在于,这个比较函数并没有遵守STL所要求的严格弱序(Strict Weak Ordering)规则。这个规则可以用以下四个准则来描述:

  • 对于所有的x,cmp(x, x)必须返回false。也就是说,不应该存在任何一个元素,让比较函数判断它“小于或等于”自身。

  • 如果cmp(x, y)为true,那么cmp(y, x)必须为false。也就是说,如果x“小于”y,那么y不应该“小于或等于”x。

  • 如果cmp(x, y)和cmp(y, z)都为true,那么cmp(x, z)也必须为true。这个属性叫做传递性。

  • 对于所有的x和y,cmp(x, y)和cmp(y, x)至少有一个必须为false。这个属性叫做非对称性。

在函数

bool cmp(int a,int b){ return a>=b; }

中,违反了第一条和第二条规则,即自反性和反对称性。例如,当a和b相等时,cmp(a, b)和cmp(b, a)都会返回true,这违反了STL所要求的严格弱序关系。

正确的实现应该是return a < b;或return a > b;,取决于需要的是升序还是降序排序。这样的实现满足了STL的严格弱序要求。

也就是说,对于C++里面自定义的比较函数,如果想让它作为std::sort或其他STL算法的参数,那么函数应该遵守严格弱序(Strict Weak Ordering)规则。在这种情况下,不能返回a >= b,因为这样的定义违反了严格弱序的自反性和反对称性。

(但是,如果你的比较函数并不用于STL算法,那么严格弱序的规则就不是必须的。)

严格弱序典型实现

严格弱序规则的一个典型实现是return a < b(用于升序排序)或return a > b(用于降序排序)。如果比较函数cmp是用于std::sort或其他STL算法的,那么它应该返回a < b或a > b,而不是a >= b或a <= b。
例如:
std::sort:这是一个用于对容器进行排序的算法,可以接受一个比较函数来定义排序规则。

std::vector<int> v = {3, 2, 5, 1, 4};
auto cmp = [](int a, int b) { return a > b; };  // 按降序排序
std::sort(v.begin(), v.end(), cmp);

当自定义的比较函数(例如cmp)被用作std::sort或其他STL算法的参数时,需要遵循严格弱序(Strict Weak Ordering)规则。在这个例子中,cmp就是作为参数传递给std::sort的自定义比较函数,它满足严格弱序规则,std::sor才能正确地工作。

cmp的解释
auto cmp = [](int a, int b) { return a > b; };

这是定义了一个C++的lambda函数(也叫做匿名函数)并将它赋值给了一个名为cmp的变量。

[](int a, int b) { return a > b; }这部分就是一个lambda函数。具体来说:

[]:这是lambda函数的捕获列表,用于指定哪些在创建该lambda的作用域内的外部变量可以在lambda函数内部使用。在这个例子中,捕获列表为空,意味着这个lambda函数不使用任何外部变量。

(int a, int b):这是lambda函数的参数列表,类似于普通函数的参数列表。在这个例子中,这个lambda函数接受两个int类型的参数,分别命名为a和b。

{ return a > b; }:这是lambda函数的主体,也就是函数的实际执行代码。在这个例子中,这个lambda函数比较a和b的大小,并返回a > b的结果(也就是如果a大于b则返回true,否则返回false)。

std::sort(v.begin(), v.end(), cmp);

这是对v(一个std::vector容器)里的元素进行排序,排序规则由cmp这个函数对象(在这里就是lambda函数)来确定。在这个例子中,cmp是一个lambda函数,定义为[](int a, int b) { return a > b; },所以std::sort会按照降序(从大到小)来排序v中的元素。

作为STL算法中的参数传入的时候,比较函数的返回类型必须是bool,并且它们必须满足严格弱序规则

一些示例

  • 对一个std::vector中的元素进行降序排序:
std::vector<int> v = {3, 2, 5, 1, 4};
auto cmp = [](int a, int b) { return a > b; };
std::sort(v.begin(), v.end(), cmp);

  • 找出一个std::vector中最长的字符串:
std::vector<std::string> v = {"cat", "antelope", "dog", "elephant"};
auto cmp = [](const std::string& a, const std::string& b) { return a.size() < b.size(); };
auto longest = *std::max_element(v.begin(), v.end(), cmp);

  • 在一个已经按照长度排序的std::vector中查找一个指定长度的字符串:
std::vector<std::string> v = {"I", "am", "a", "list", "of", "words"};
auto cmp = [](const std::string& a, const std::string& b) { return a.size() < b.size(); };
std::sort(v.begin(), v.end(), cmp);
std::string to_find = "four";
bool found = std::binary_search(v.begin(), v.end(), to_find, cmp);

这些都是STL中可以接受比较函数作为参数的算法的例子。注意在这些例子中,比较函数的返回类型必须是bool,并且它们必须满足严格弱序规则,否则可能导致未定义的行为。

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值