45

要找到未排序数组的中位数,我们可以在n 元素的时间内进行最小堆操作,然后可以以n / 2个元素中的一个来提取一个中值。但是这种方法将花费O n log n 时间。O(nlogn)nn/2O(nlogn)

我们可以在时间内通过某种方法执行相同操作吗?如果可以,那怎么办?O(n)



1
@JukkaSuomela为什么不做一个快速,简单的答案(理想情况下,简短地解释一个这样的算法)?
拉斐尔

2
注意相关的元讨论 ; 事实证明,简单的Web搜索可以找到该问题的答案。
拉斐尔

Answers:


45

这是选择算法的一种特殊情况,它可以找到一个数组的第个最小元素,其中k是数组大小的一半。在最坏的情况下,有一个线性的实现。kk

通用选择算法

首先,让我们看find-kth一下找到数组第个最小元素的算法:k

find-kth(A, k)
  pivot = random element of A
  (L, R) = split(A, pivot)
  if k = |L|+1, return pivot
  if k ≤ |L|  , return find-kth(L, k)
  if k > |L|+1, return find-kth(R, k-(|L|+1))

该函数split(A, pivot)返回L,R,使得in R中的所有元素都大于pivotL所有其他元素(减去的一个出现pivot)。然后,所有操作都以递归方式完成。

O(n)O(n2)

线性最坏情况:中位数中值算法

更好的枢轴是A通过调用这些中位数数组上的过程来对大小为5 的子数组的所有中位数进行中位数调整。

find-kth(A, k)
  B = [median(A[1], .., A[5]), median(A[6], .., A[10]), ..]
  pivot = find-kth(B, |B|/2)
  ...

O(n)

请注意,大多数情况下使用随机数据透视会更快。


这是5标准尺寸吗?如果A的大小小于5怎么办?
Jayesh

对于任何固定的n,复杂度都是常数,除非它是无限的。因此,对于这种特殊情况,即使是O(2 ^ n),也可以使用任何复杂度有限的有效算法。对于固定的n(即,最多4个in out情况),复杂度最多为O(2 ^ 4)= O(1)。
v6ak '16

3
在第一个算法上:return A[k]不正确(除非A进行排序会使算法无意义)。如果split碰巧发生分裂A,以至于k = |L| + 1您仍然不知道kth元素在哪里。您的基本情况是,当|A| = 1您仍然需要进行两个递归调用之一时。
wcochran

2
@NickCaplinger使用web.archive.org修复
Jmad

1
通用选择算法O(NlogN)难道不是最坏的情况吗?即使递归调用在每次调用后仅离开数组的10%,也仍然是10的对数
。– octavian

6

n1/4O(n)

该算法的主要思想是使用采样。我们必须找到两个元素,它们按数组的排序顺序靠在一起,并且中间值位于它们之间。有关完整的讨论,请参见参考文献[MU2017]。


[MU2017] Michael Mitzenmacher和Eli Upfal。“概率和计算:算法和数据分析中的随机化和概率技术”,第3章,第57-62页。剑桥大学出版社,第二版,2017年。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.