qsort()vs std :: sort,比较函数的哲学差异

时间:2013-08-01 18:44:58

标签: c++ c std

我想知道为什么在qsort() {C版}与std::sort()中指定比较函数有两种完全不同的方法。

qsort需要比较函数如下:我不知道它需要三种返回值-1,0,+ 1的原因。

int comp(int *x, int *y){   
   return *x - *y; 
}

std::sort()的比较函数,看起来更加一致,因为它是按照函数来编写的,以遵循不变量。即如果x小于y函数返回true,则x相对于y

处于正确位置
bool comp(int x, int y){   
       return x < y; 
}

为什么我们在返回bool时需要三个值-1,0,+ 1(或两个值为0的int)更简单干净?

5 个答案:

答案 0 :(得分:6)

其他人指出了两种比较方式的等价性;这就是为什么遵循这两种方法的原因。

在C中,比较需要是一个函数指针。这意味着你总是得到函数调用和指针间接开销。当qsort在20世纪70年代在PDP-11计算机上设计时,必须减少开销量,因此strcmp等比较函数在单个函数调用中进行了三向比较。 (请注意,qsort通常是一种不稳定的排序,因此相等的情况可能看起来毫无用处,但可以通过适当的指针比较使其稳定。)

在C ++中,比较可以在模板实例化时间内联,因此大部分开销都消失了(甚至不需要函数调用),并且可以使用更简单的约定。这也意味着std::sort默认情况下可以使用operator<重载。

答案 1 :(得分:2)

我想知道同样的事情,并提出了一个基于strcmpstd::string::compare的理论。即,进行比较可能需要相对大量的时间。要确定对象A是否小于,等于或大于另一个对象B,您可以使用:

if (A < B) {
    //do stuff where A is less
} else if (B < A) {
    //do stuff where A is greater
} else {
    //do stuff where A is equal
}

通常需要对A和B进行两次迭代,一次为A<B,一次为B<A。如果同时检查所有三种可能性,则只需迭代字符串一次。因此使用了-1, 0, 1约定。

然而,C ++似乎已经放弃了这个约定。我听到的一个论点是计算机已经发生变化,并且由于进行三向比较的代码的复杂性,进行一次三向比较更慢且更容易出错,并且大多数时候我们并不关心平等的情况。实际上,所有标准排序算法都是按照这样的方式工作的,尽管单个实现可能会做一些更有趣的事情。

if (A < B) {
    //do stuff where A is less
} else {
    //do stuff where A is greater or equal
}

根据MSVC在this test上的时间安排,string::operator<的速度几乎是strcmp的两倍,而调用string::operator<两次只比执行一次稍慢。 (我猜是缓存和更简单的代码?)。海湾合作委员会的结果是相似的。

答案 2 :(得分:2)

对于任何两个x和y,x&lt; y或x == y或x&gt; y持有,那么给出比较函数的两种方式是等价的。可以定义==和&gt;运营商的&lt;如下:

  • x == y相当于!(x
  • x&gt; y等于y&lt; X

您可能已经意识到,实施&lt;,&lt; =,==,&gt; =和&gt;通常更有效(也更简单)。就三向比较操作而言,然后根据&lt;如上所示。我认为这应该是C(以及许多其他语言实际上)选择三向比较函数的原因,即使快速排序可能无法利用这些额外信息。

C ++有运算符重载,但没有三向比较运算符(既没有C),所以从三向比较转换到'less'运算符(尽管存在上述潜在的缺点)允许利用运算符重载。

答案 3 :(得分:2)

qsort比较函数在strcmp和memcmp之后建模,它返回&lt; 0,0或者&gt; 0 ...这不仅仅是返回&lt;或&gt; =指示符...它需要两次这样的调用来确定两个元素是否相等。 “不变量”的概念在这里不适用:显然a [i]&lt;的不变量。 a [i + 1]不适用于原始数组...实际上它不适用于最终数组,因为[i] == a [i + 1]是可能的。术语“一致”也不适用......两种类型的比较函数的结果都必须一致。 “更清洁”是旁观者的眼睛,“更简单”是一种夸大其词。

答案 4 :(得分:2)

相关问题