为什么赋予qsort()的比较函数需要返回三个不同的值?

时间:2018-12-15 11:06:21

标签: c algorithm sorting

我已经了解到qsort()所需的比较函数需要具有3个结果:

  • 如果val1 < val2
  • 为否定结果
  • 0,如果val1 == val2
  • 如果val1 > val2
  • 为肯定结果

据我所知,对数组进行排序仅需要返回true或false的谓词。以气泡排序为例:

int compare(int a, int b)
{
    if(a>b) return 1;
    return 0;
}
void bubbleSort(int arr[], int n) 
{
    int i, j;
    for (i = 0; i < n-1; i++)  
        for (j = 0; j < n-i-1; j++)  
            if ( compare(arr[j],arr[j+1]) ) 
                swap(&arr[j], &arr[j+1]);
}

那为什么qsort()比较函数需要有3个可能的结果而不是2个?

5 个答案:

答案 0 :(得分:4)

<div id="main"> </div> <button onclick="myFunction(1)">Test </button> <button onclick="myFunction(2)">Test 1</button> <button onclick="myFunction(4)">Test 2</button> <button onclick="myFunction(6)">Test 3</button>可以使用布尔比较函数而不是三路比较来编写,但是规范说它需要三路比较函数,并且某些(并非全部)实现利用了三种可能的情况。如果您的比较函数不符合规范,则将导致未定义行为。在这种情况下,“未定义的行为”可能包括无法正确分类或在极少数情况下触发缓冲区溢出,直到航天飞机从轨道返回时您才可能注意到。所以不要那样。

为什么实现可能需要三向比较,这是一种可能性:对于具有很多重复值的输入,通过使用三向分区可以大大加快quicksort的速度。可以通过在相反方向上进行两次比较来进行双向比较来完成,但是实现者知道需要三向比较器时,很可能会在他们想知道的情况下测试是否相等。

答案 1 :(得分:3)

如果元素A ==元素B但比较器函数告诉qsort B > A,则qsort会认为在{{1}之间应该还有其他元素}和A(不是这种情况),因此请执行不必要的检查。

答案 2 :(得分:2)

从技术上讲,您可以使用小于号,因为a == b等效于!(a < b) && !(b < a)

答案 3 :(得分:1)

根据@Matteo Italia的评论,比较次数中存在效率问题,您可以使用等号减​​少比较次数,因为在某些情况下a == b!(a < b) && !(b < a)是等效的(例如,当值为整数时)。

此外,在更一般的情况下(注释中没有特别提到在qsort中),您需要它来保持排序功能的稳定性。在相等的情况下,如果排序要稳定,则应该在比较中了解相等。您可以进一步了解排序here的稳定性。 因此,稳定的排序方法需要返回三个值

答案 4 :(得分:1)

如果将quicksort内循环写成与此等效:

while(x[i] < pivot) i++;  // less-than
while(pivot < x[j]) j--;  // less-than

然后您仅需实现<就可以摆脱困境。

在任何情况下,只要使比较清楚调用者应该执行的操作即可坚持使用principle of least astonishment -如果您的比较函数指针命名为compare并且该函数的行为不应像通常的stdlib qsort比较委托,那么这是一个坏主意。

另一方面,如果您的参数被命名为less_thanisLessThan之类的东西,则对调用者来说应该更清楚比较功能所期望的结果:

 void sort(
     const void * arr,
     size_t num_items,
     size_t element_size, 
     bool (*is_less_than)(const void*, const void*)
 );