你不知道的std::sort()



上周,刚上线的项目中,发现推荐结果排序不稳定,如果用stable_sort()性能会比降低,然后我就修改了比较函数,如果评分相等,比较上架时间

auto cmp = [](const GidScore& a, const GidScore& b) {
    if (a.score == b.score) {
        return a.create_time >= b.create_time;  //!!!
    }
    return a.score > b.score;
}

上面代码看起来没啥问题,但是测试时发现遇到特定的数据会导致出core文件,通过gdb查看core文件不能直接看不来具体的原因,打log发现,排序后有个元素内容被修改了。然后我试着把>=改为>好了。后来google发现,也有其他人也会遇到这个问题,是因为cmp函数导致的。函数原型:void sort (RandomAccessIterator first, RandomAccessIterator last, Compare comp);

对于参数comp的描述里有几个斜体:strict weak ordering严格的弱序列google后发现strict weak ordering具有以下性质:

  1. f(x, x) must be false.

  2. f(x, y) implies !f(y, x)

  3. f(x, y) and f(y, z) imply f(x, z).

  4. if x is equivalent to y and y is equivalent to z, then x is equivalent to z.如果我们的cmp函数里使用了>=则违反了1和2。所以比较时只能用>或<. 再看下为什么会导致出core呢。 sort代码:

inline void sort(_RandomAccessIter __first, _RandomAccessIter __last,
                 _Compare __comp) {
  if (__first != __last) {
    __introsort_loop(__first, __last,
                     __VALUE_TYPE(__first),
                     __lg(__last - __first) * 2,
                     __comp);
    __final_insertion_sort(__first, __last, __comp);
  }
}

sort先是调用了__introsort_loop然后是__final_insertion_sort

__introsort_loop 函数中运用了快速排序,但是快速排序存在一问题是,如果一个本来基本有序,则性能会很差,所以函数中加入了递归深度判断,如果深度大于lg(n)+1则采用堆排序,以提高性能,同时在选取中间值时用了三点中值(该算法在绝大多数数据中表现较好),经历多次调用最后会调用到__unguarded_linear_insert:
void __unguarded_insertion_sort_aux(_RandomAccessIter __first, 
                                    _RandomAccessIter __last,
                                    _Tp*, _Compare __comp) {
  for (_RandomAccessIter __i = __first; __i != __last; ++__i)
    __unguarded_linear_insert(__i, _Tp(*__i), __comp);
}

void __unguarded_linear_insert(_RandomAccessIter __last, _Tp __val, 
                               _Compare __comp) {
  _RandomAccessIter __next = __last;
  --__next;  
  while (__comp(__val, *__next)) {
    *__last = *__next;
    __last = __next;
    --__next;
  }
  *__last = __val;
}

该函数中用cmp去从后往前挨个比较,如果_comp一直返回true,则一直__next--,如果使用>=,数组元素全部为相等,则返回的next指针一直递减,除非访问到非法地址才会停下来。所以在数组全部相同时,>=会导致崩溃。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值