O n 時間找到中位數

2022-09-13 02:36:12 字數 2477 閱讀 8951

最直觀的方法是先排序再取中位數, 時間複雜度 \(o(n\log n)\). 然而最近才得知中位數有時間複雜度 \(o(n)\) 的演算法, 事實上任意順序統計量都可以用 \(o(n)\) 時間找出.

記待排序的數列 \(a = [a_0, \dots, a_]\), 其子列 \(a[p, \dots, r] = [a_p, \dots, a_r]\). 類似快排的方法, 找第 \(i\) 小的元素.

def partition(a, p, r):

pivot = a[r]

i = p - 1

for j in range(p, r):

if a[j] <= pivot:

i += 1

a[i], a[j] = a[j], a[i]

i += 1

a[i], a[r] = a[r], a[i]

return i

def randomized_partition(a, p, r):

i = random.randint(p, r)

a[i], a[r] = a[r], a[i]

return partition(a, p, r)

def randomized_select(a, p, r, i):

if p == r:

return a[p]

q = randomized_partition(a, p, r)

k = q - p + 1

if i == k:

# the pivot value is the answer

return a[q]

elif i < k:

return randomized_select(a, p, q-1, i)

else:

return randomized_select(a, q+1, r, i-k)

記時間複雜度為 \(t(n)\), 以及 \(y = \#a[p, \dots, r]\) 為子列的元素個數.

\[\begin

\mathbb e t(n) &\le \mathbb e\left[t\left(\max(y-1,n-y)\right) + o(n)\right]\\

& = \sum_^n \frac1n\mathbb e\left[ t\left(\max(k-1,n-k)\right) \right] + o(n)\\

& \le \frac2n\sum_^\mathbb et(k) + o(n).

\end

\]之後易證 (substitution method) \(\mathbb et(n) = o(n)\). 不過 worst-case 是 \(o(n^2)\).

依然是從 \(n\) 個元素的數列中找第 \(i\) 小的元素. 不妨約定, 當偶數個元素時, 中位數取中間兩個數中較小的那個.

演算法記為select演算法, 總體和前乙個演算法一樣, 關鍵是找到乙個好的 pivot. 記時間複雜度為 \(t(n)\).

把數列分成 \(\lceil n/5\rceil\) 組, 每組 5 個, 最後一組可能不足 5 個. 用時 \(o(n)\).

找到每組 5 個元素的中位數. 用時 \(o(n)\).

(遞迴地) 用select演算法找到 \(\lceil n/5\rceil\) 個中位數的中位數 \(x\). 用時 \(t(\lceil n/5\rceil)\).

以 \(x\) 為 pivot 進行劃分 (partition), 記 \(x\) 為第 \(k\) 小的元素. 用時 \(o(n)\).

若 \(i = k\), 返回 \(x\); 若 \(i < k\), (遞迴地) 用 select 演算法在較小的 partition 中找第 \(i\) 小的元素; 若 \(i > k\), 則在較大的 partition 中找第 \(i - k\) 小的元素.

下面考慮第 5 步的用時. 考慮比 \(x\) 大的元素個數, 有一半的組, 每組 3 個元素比 \(x\) 大 (除了 \(x\) 所在的組和最後乙個不滿 5 個元素的組以外). 故比 \(x\) 大的元素個數至少有

\[3\left( \left\lceil \frac12 \left\lceil\frac\right\rceil \right\rceil -2 \right) \ge \frac - 6.

\]故第 5 步最多用時 \(t(7n/10 + 6)\). 因此

\[t(n) \le t(\lceil n/5\rceil) + t(7n/10 + 6) + o(n).

\]易證 \(t(n) = o(n)\).

注意到若分為每組 3 個, 則不能如上證明 \(t(n) = o(n)\).

leiserson, c. e., rivest, r. l., cormen, t. h., & stein, c. (2009). introduction to algorithms (3rd ed.) (pp. 215-222). cambridge, ma: mit press.

海量資料找到中位數 大堆 小堆

我們分別定義a max,a count,b min,b count a max 表示位元組流較小的那一半數字所組成的大頂堆 記為堆a 的堆頂 a count 表示上述大頂堆元素個數 b min 表示位元組流較大的那一半數字所組成的小頂堆 記為堆b 的堆頂 b count 表示上述小頂堆元素的個數 其...

中位數的中位數

參照王曉東的演算法設計 中位數的中位數,即將一串數分成n段,求其排好序了的中間那個數,再把這些所有中位數再求一次中位數。for int i 0 i r p 4 5 i 找中位數的中位數,r p 4即上面所說的n 5 int x lineselect a,p,p r p 4 5,r p 4 10 線性...

隨時找到資料流的中位數

題目 有乙個源源不斷地吐出整數的資料流,假設你有足夠的空間來儲存吐出的數。請設計乙個名叫medianholder的結構,medianholder可以隨時取得之前吐出所有數的中位數。要求 1 如果medianholder已經儲存了吐出的n個數,那麼任意時刻將乙個新數加入到medianholder的過程...