Quickselect的平均运行时间

时间:2011-05-10 04:35:11

标签: algorithm big-o

维基百科指出,quickselect算法(Link)的平均运行时间为O(n)。但是,我无法清楚地知道这是怎么回事。任何人都可以向我解释(通过递归关系+主方法使用)关于平均运行时间如何是O(n)?

4 个答案:

答案 0 :(得分:40)

由于

  

我们已经知道了所需元素所在的分区。

我们不需要对所有元素进行排序(通过分区),而只需对我们需要的分区进行操作。


在快速排序中,我们必须分成两半*,然后分成两半,但这次,我们只需要在一个单个分区中进行下一轮分区(预期元素所在的两个中的一半。

就像(不太准确)

  

n + 1/2 n + 1/4 n + 1/8 n + .....< 2 n

所以它是O(n)。

一半用于方便,实际分区不是精确的50%。

答案 1 :(得分:26)

要对quickselect进行平均案例分析,必须考虑在算法期间为每对元素和假设随机旋转比较两个元素的可能性。 >。由此我们可以得出平均比较数。不幸的是,我将展示的分析需要更长时间的计算,但这是一个干净的平均案例分析而不是当前的答案。

假设我们要从k - 最小元素中选择的字段是[1,...,n]的随机排列。我们在算法过程中选择的枢轴元素也可以看作给定的随机排列。在算法期间,我们总是从这个排列中选择下一个可行的枢轴,因此它们随机选择均匀,因为每个元素与随机排列中的下一个可行元素具有相同的发生概率。

有一个简单但非常重要的观察结果:我们只比较两个元素ij(带i<j)当且仅当其中一个被选为第一个支点时范围[min(k,i), max(k,j)]中的元素。如果首先选择此范围中的另一个元素,那么它们将永远不会被比较,因为我们继续在子字段中搜索,其中至少包含一个元素i,j

由于上述观察以及随机选择枢轴的事实,ij之间的比较概率为:

2/(max(k,j) - min(k,i) + 1)

max(k,j) - min(k,i) + 1种可能性中的两个事件。)

我们将分析分为三个部分:

  1. max(k,j) = k,因此i < j <= k
  2. min(k,i) = k,因此k <= i < j
  3. min(k,i) = imax(k,j) = j,因此i < k < j
  4. 在第三种情况下,省略了不太相等的符号,因为我们已经在前两种情况下考虑了这些情况。

    现在让我们的手在计算上有点脏。我们只是总结了所有的概率,因为这给出了预期的比较次数。

    案例1

    案例2

    与案例1类似,所以这仍然是一个练习。 ;)

    案例3

    我们使用H_r作为第r个谐波数,它大约像ln(r)那样增长。

    结论

    所有三种情况都需要线性数量的预期比较。这表明quickselect确实在O(n)中具有预期的运行时间。请注意 - 如前所述 - 最糟糕的情况是O(n^2)

    注意:这个证明的想法不是我的。我认为这大致是quickselect的标准平均案例分析。

    如果有任何错误,请告诉我。

答案 2 :(得分:5)

在quickselect中,如指定的那样,我们仅在分区的一半上应用递归。

平均案例分析:

  

第一步: T(n)= cn + T(n / 2)

其中,cn =执行分区的时间,其中c是任何常量(无关紧要)。
T(n / 2)=在分区的一半上应用递归。
由于它是一个平均情况,我们假设分区是中位数。

当我们继续进行递归时,我们得到以下等式:

  

T(n / 2)= cn / 2 + T(n / 4)
T(n / 4)= cn / 2 + T(n / 8)
。< br。> T。(2)= c.2 + T(1)
T(1)= c.1 + ...

求和方程式和交叉抵消类似的值会产生线性结果。

  

c(n + n / 2 + n / 4 + ... + 2 + 1)= c(2n) // GP的总和

因此,它是 O(n)

答案 3 :(得分:0)

当我读到 quickselect 的平均时间复杂度是 O(n) 而我们每次将列表分成两半(如二分搜索或快速排序)时,我也感到非常矛盾。事实证明,每次将搜索空间分成两半并不能保证 O(log n) 或 O(n log n) 运行时。使快速排序 O(n log n) 和快速选择 O(n) 的原因是我们总是需要为快速排序探索递归树的所有分支,而对于快速选择只需要探索一个分支。让我们比较quicksort和quickselect的时间复杂度递推关系来证明我的观点。

快速排序:

T(n) = n + 2T(n/2)
     = n + 2(n/2 + 2T(n/4))
     = n + 2(n/2) + 4T(n/4)
     = n + 2(n/2) + 4(n/4) + ... + n(n/n)
     = 2^0(n/2^0) + 2^1(n/2^1) + ... + 2^log2(n)(n/2^log2(n))
     = n (log2(n) + 1)      (since we are adding n to itself log2 + 1 times)

快速选择:

T(n) = n + T(n/2)
     = n + n/2 + T(n/4)
     = n + n/2 + n/4 + ... n/n
     = n(1 + 1/2 + 1/4 + ... + 1/2^log2(n))
     = n (1/(1-(1/2))) = 2n                           (by geometric series)

我希望这能说服你为什么 quickselect 的平均运行时间是 O(n)。