如果只调用较小的分区数组,那么较大的分区数组是如何排序的?我只看到代码在递归完成时更改b
的位置(QS
和if
语句中调用else
。
public static void QS(int[] b, int h, int k) {
int h1= h; int k1= k;
// invariant b[h..k] is sorted if b[h1..k1] is sorted
while (b[h1..k1] has more than 1 element) {
int j= partition(b, h1, k1);
// b[h1..j-1] <= b[j] <= b[j+1..k1]
if (b[h1..j-1] smaller than b[j+1..k1])
QS(b, h, j-1); h1= j+1;
else
QS(b, j+1, k1); k1= j-1;
}
}
答案 0 :(得分:1)
注意在递归调用QS后,如果b [h1 ..]小于b [j + 1 ..]则更新h1,如果b [h1 ..]大于或等于b,则更新k1 b [j + 1 ..]。
代码中有一个错误,if之后的第一个调用应该是QS(b,h1,j-1);
对数空间使用是指由于递归而由quicksort使用的堆栈空间。在示例代码中,只有较小的分区使用递归调用进行排序,然后代码循环返回以将较大的分区分成两部分,并且再次仅对现在拆分的较大分区的较小部分使用递归调用
文章链接:
http://en.wikipedia.org/wiki/Quicksort#Optimizations
我不确定对尾递归的引用,因为代码包含一个实际的循环而不是尾递归。尾递归看起来像是在函数中执行的最后一行的递归调用,编译器可以将其优化为循环。
答案 1 :(得分:1)
这是一些难以阅读的伪代码。这可能更容易理解:
QuickSort(b[], low, hi)
while the range low..hi contains more than 1 element
1: Pick a random pivot 'j' from the array
2: Re-order the array so that all elements less than the pivot are in
b[low..j-1], and all elements greater than the pivot are in b[j+1..hi]
3: Call quicksort on the side with less elements, and update the range to
exclude the sorted side
大约一半的值将小于数据透视表,并且一半的值将大于数据透视表。这意味着在步骤3之后,范围低 .. hi 的大小大致减半。因此,它需要log | N |范围之前的迭代只包含一个元素。
很难解释这一点,但是看看第3步如何仅在阵列的一半上调用QuickSort?这是因为while循环的其余部分对另一半进行排序。该功能可以轻松地重写为以下内容:
QuickSort(b[], low, hi)
if the range low..hi contains more than 1 element
1: Pick a random pivot 'j' from the array
2: Re-order the array so that all elements less than the pivot are in
b[low..j-1], and all elements greater than the pivot are in b[j+1..hi]
3: Call quicksort on both sides
while循环已被if语句和第二个递归调用替换。我希望从这里你可以看到复杂性大致为N log | N |。
修改强>
那么while循环如何对其余元素进行排序?在步骤3之后,范围已更新以排除较小的一半,因为我们只是通过调用QuickSort对其进行排序。这意味着该范围现在只包含较大的一半 - 未排序的元素。因此,我们对这些未排序的元素重复步骤1 - 3,然后再次更新范围。
每次迭代时,未排序元素的数量越来越小,最终我们只剩下一个未排序元素。但是,当然,其中的一个元素是排序的,所以此时我们知道我们已经对数组中的每个元素进行了排序。