【问题标题】:Confusion on quicksort that takes logarithmic space对占用对数空间的快速排序感到困惑
【发布时间】:2016-08-16 18:14:40
【问题描述】:

如果只调用较小的分区数组,如何对较大的分区数组进行排序?如果以递归方式完成,我只会看到更改 b 位置的代码(QSifelse 语句中调用)。

 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; 
     }
}

【问题讨论】:

  • 能否提供更多文档
  • 我从未见过这种编码方式。这段代码没有调用自身两次(如我之前所见),而是使用 while 循环代替第二次递归。

标签: java algorithm sorting big-o quicksort


【解决方案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 步之后,low..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,并再次更新范围。

每次迭代,未排序元素的数量越来越少,最终我们将只剩下一个未排序的元素。但是当然,一个元素本身排序的,所以此时我们知道我们已经对数组中的每个元素进行了排序。

【讨论】:

  • 感谢您的回复!我明白为什么只有一半的数组被调用到 QS 但我对 while 循环如何对较大的一半进行排序感到困惑
  • @stumped - 正如我在答案中发布的那样,每次 QS 调用自身时,h1 或 j1 都会更新。示例代码也有错误,在 if 之后第一次调用 QS 应该是 QS(b, h1, j-1); .
【解决方案2】:

注意在递归调用 QS 之后,如果 b[h1..] 小于 b[j+1..],则更新 h1,如果 b[h1..] 大于或等于,则更新 k1 b[j+1..]。

代码有个bug,if后第一次调用应该是QS(b, h1, j-1);

对数空间使用是指快速排序由于递归而使用的堆栈空间。在示例代码中,仅使用递归调用对较小的分区进行排序,然后代码循环返回以将较大的分区分成两部分,再次,仅对现在拆分的较大分区的较小部分使用递归调用.

文章链接:

http://en.wikipedia.org/wiki/Quicksort#Optimizations

http://blogs.msdn.microsoft.com/devdev/2006/01/18/efficient-selection-and-partial-sorting-based-on-quicksort

我不确定对尾递归的引用,因为代码包含一个实际循环而不是使用尾递归。尾递归看起来像是在函数中执行的最后一行的递归调用,编译器可以将其优化为循环。

【讨论】:

    猜你喜欢
    • 2015-06-25
    • 1970-01-01
    • 2011-12-14
    • 2011-07-17
    • 2010-09-29
    • 1970-01-01
    • 1970-01-01
    • 2021-12-31
    • 2012-06-29
    相关资源
    最近更新 更多