Randomized Quickselect

🔥 Vibe Prompt

"Find the median of 10M numbers using Quickselect. Show expected vs worst-case time."

import random

def quickselect(arr, k):
    """Return k-th smallest (0-indexed)"""
    if len(arr) == 1:
        return arr[0]
    
    pivot = random.choice(arr)
    left = [x for x in arr if x < pivot]
    mid = [x for x in arr if x == pivot]
    right = [x for x in arr if x > pivot]
    
    if k < len(left):
        return quickselect(left, k)
    elif k < len(left) + len(mid):
        return mid[0]
    else:
        return quickselect(right, k - len(left) - len(mid))

# Test
import time
data = [random.randint(0, 1000000) for _ in range(100000)]

# Random pivot
start = time.time()
med = quickselect(data, len(data)//2)
time_rand = time.time() - start

# Deterministic (min element for worst case)
def quickselect_worst(arr, k):
    pivot = min(arr)  # Always worst-case
    left = [x for x in arr if x < pivot]
    mid = [x for x in arr if x == pivot]
    right = [x for x in arr if x > pivot]
    if k < len(left): return quickselect_worst(left, k)
    elif k < len(left) + len(mid): return mid[0]
    else: return quickselect_worst(right, k - len(left) - len(mid))

print(f"Median: {med}")
print(f"Random pivot: {time_rand*1000:.2f}ms (expected O(n))")
print(f"\nRandomized avoids O(n²) worst-case!")

Why Randomize?

| Approach | Best | Average | Worst | |----------|------|---------|-------| | Deterministic | O(n) | O(n) | O(n²) | | Randomized | O(n) | O(n) | O(n) (prob.) |

Applications

  • Real-time median calculation
  • Order statistics in DB
  • Load balancing
  • Outlier detection

Key Points

  • Understand the core concepts thoroughly
  • Practice with hands-on code examples
  • Apply knowledge to real-world problems
  • Review and reinforce through exercises

Further Learning

  • Official documentation
  • Open source projects on GitHub
  • Community forums and discussions
  • Related courses and tutorials


為什麼你需要學會第 k 小元素的快速選擇?

想像你正在開發一個即時分析系統,每天從 1000 萬筆交易中找到中位數價格——不是全部排序,只要中位數。

  • 全部排序(O(n log n)):1000 萬 × log(1000 萬) ≈ 2.3 億次比較,約需 5 秒
  • Quickselect(期望 O(n)):約 1000 萬次比較,約需 0.02 秒——快 250 倍

不只是中位數——找第 95 百分位數(效能監控的 P95 延遲)、找前 10 名、找面試中的第 k 大元素——Quickselect 都是你該選的工具。

為什麼隨機化這麼重要?

如果不隨機化,選第一個元素作為 pivot,那在已排序的陣列上,Quickselect 會退化到 O(n²)——每次只能排除一個元素。

隨機 pivot 保證了期望 O(n)——不管輸入是什麼,演算法的平均表現都是一樣的。這就是隨機化演算法最強大的特性:不受對手(惡意輸入)影響

固定 pivot(第一個元素)
已排序輸入 [1,2,3,...,1000] → 每次排除 1 個 → O(n²)

隨機 pivot
任意輸入 → 每次期望排除 n/2 個 → O(n)

下一章預告:從選取到抽樣

Quickselect 解決的是「在已知的陣列中找到第 k 小的元素」。但如果你遇到的資料不是一個已知大小的陣列,而是一個不知道有多大的串流呢?

下一章 水庫抽樣 (Reservoir Sampling) 解決的正是這個問題——從一個未知大小的串流中,均勻隨機地抽出 k 個樣本。

解鎖完整教學內容

本章為付費內容。加入專案即可解鎖超過 5000 字的深度解析,包含 10 個以上神級 Prompt 與真實 Source Code 範例!