我已经了解到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个?
答案 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_than
或isLessThan
之类的东西,则对调用者来说应该更清楚比较功能所期望的结果:
void sort(
const void * arr,
size_t num_items,
size_t element_size,
bool (*is_less_than)(const void*, const void*)
);