为什么在快速排序中选择随机枢轴

Why choose a random pivot in quicksort

因此,在最坏的情况下,随机选择一个枢轴的时间复杂度为 O(n2) 运行,但当枢轴被选为最小值和最大值的平均值时列表的最坏情况 O(n log n).

当然,由于找到最小值和最大值而不是随机生成器具有的常数 O(1),因此每次递归都会增加 2*O(n)。将其实现为枢轴时,您会在递归树的叶子上对列表进行排序,而不是在标准算法中元素从根到叶进行排序。

在实施而不是将主元作为列表中的值时,它只是一个数字,因此这不是标准的快速排序,但我的问题仍然适用。

下面是我写得不好的伪代码:

func sort(List n):
    if n.length < 2
     return n;
    min = n.minValue
    max = n.maxValue
    avg = (min+max) /2 
    List left = list of elements in n less than avg
    List right = list of elements in n greater than avg
    sort(left)
    sort(right)

当列表包含以下元素时,如果您选择最小值和最大值的平均值作为基准,您的算法会受到 O(n2) 的影响:

1, 3, 7, 15, 31, 63, ..., 2n-1

您会发现,对于您的算法的每一次传递,right 部分总是只有 1 个元素。

三件事:

  1. 你可以在列表的一次传递中获得最大值和最小值,所以实际上我们为每次传递添加 1*O(n)。然而...

  2. 最大值和最小值的平均值不保证O(nlog(n)),因为最大值和最小值的平均值不一定是中值。如果你有一个已经排序的列表 (1,10,100,1000,10000),这实际上会给出一个 O(n^2) 的解决方案,这对于一个已经排序的列表来说真的很糟糕(而且很可能会发生)。

  3. 从统计角度来看,随机选择一个基准点很可能会给您带来接近中位数的结果。从列表中取一个随机数,50% 的时间这个数字位于列表的中间 50%,这意味着在最坏的情况下它有 75% 的列表在一侧,25% 在另一侧。显然,当我们选择更接近真实中位数时,性能会更好。