为什么以递归方式调用快速排序的不同方式?

时间:2014-07-23 00:46:44

标签: algorithm quicksort

我注意到以递归方式调用quicksort的方式存在差异。

一种方法是

quicksort(Array, left, right)
  x = partition(Array, left, right)
  quicksort(Array, left, x-1)
  quicksort(Array, x+1, right)



  partition(array, left, right)
     pivotIndex := choose-pivot(array, left, right)
     pivotValue := array[pivotIndex]
     swap array[pivotIndex] and array[right]
     storeIndex := left
     for i from left to right - 1
         if array[i] ≤ pivotValue
             swap array[i] and array[storeIndex]
             storeIndex := storeIndex + 1
     swap array[storeIndex] and array[right]  // Move pivot to its final place
     return storeIndex

[EXAMPLE]

这是有道理的,因为quicksort通过在枢轴周围划分其他元素来工作,因此元素Array [x]应该处于其最终位置。因此,[left,partion-1]和[partition + 1,right]的范围仍然存在。

另一种方式

quicksort(Array, left, right)
  x = partition(Array, left, right)
  quicksort(Array, left, x)
  quicksort(Array, x+1, right)

PARTITION(A,p,r)

x  A[p]    
i  p - 1    
j  r + 1   
while TRUE  
   do repeat j  j - 1   
        until A[j]  x   
      repeat i  i + 1    
        until A[i]  x    
      if i < j    
          then exchange A[i]  A[j]
          else return j

[EXAMPLE]

注意缺少-1。这些似乎表明数组已正确分区,但没有一个元素处于最终位置。这两种方式是不可互换的,如果我以第二种方式输入-1,则输入数组被不正确地排序。

造成差异的原因是什么?显然它在分区方法中的某个地方,是否与Hoare或Lumuto的算法有关?

4 个答案:

答案 0 :(得分:0)

除了在最小的阵列上运行外,两个版本之间的效率实际上没有太大差异。大部分工作是在分离一个大的 n 大数组时完成的,这些大小的数组可以在多个 n 空间远离它们的正确位置,分成两个较小的数组。即使在最坏的情况下,即使是较小的,也不能有远离其正确位置的价值。单向&#34;单向&#34;本质上在每一步创建三个分区 - 但由于第三个分区只有一个空间大,所以它只对算法的进展做出O(1)贡献。

话虽这么说,实现最终切换非常容易,所以我不确定为什么你的代码以及其他方式&#34;例子没有采取这一步骤。他们甚至指出了一个陷阱(如果为枢轴选择了最后一个而不是第一个元素,递归永远不会结束),这将完全通过实现消除末端的枢轴元素的开关来完全避免。我能想象的唯一情况是使用的优选代码是代码空间绝对溢价。

答案 1 :(得分:0)

如果没有别的,排除或传递分区索引可能是封闭和半开放间隔之间的差异:右边可能是第一个不触摸的索引 - 没有引用的不完整片段没有告诉。

答案 2 :(得分:0)

造成差异是因为partition()的返回值意味着不同的事情。

  • One way中,partition()的返回值是用于分区的数据透视最终位于Array[x]之后parition()是使用的数据透视的位置在partition()
  • Other way中,partition()的返回值不是用于分区的数据透视最终位于Array[x]之后的partition()的元素。少于partition()中使用的支点,但除此之外我们不太了解。实际的枢轴可以位于阵列上半部分的任何位置。

由此可见,x-1中使用x而不是Other way的第一次递归调用可能很容易给出不正确的结果,例如pivot = 8Array[x] = 5Array[x-1] = 7

答案 3 :(得分:-1)

如果您考虑一下,其他方式不会对算法产生任何影响。如果分区算法第一个中的相同,那么在其中一个子数组中包含枢轴将不会产生任何影响,因为在这种情况下没有其他元素会将其位置与子数组中的枢轴交换。

最多会增加一些数字的比较次数。虽然我不确定它是否会对大型阵列的排序时间产生不利影响。