首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

尋找最小的 k 個數:八種算法的時間空間權衡全解析

     編輯:關於C語言

問題描述

輸入 n 個整數,輸出其中最小的 k 個。例:[1,2,3,4,5,6,7,8], k=4 → [1,2,3,4]。

八種方案複雜度對比

方案思路時間複雜度空間複雜度備註
1. 全量排序快排 + 取前 kO(n log n)O(1) 或 O(log n)最簡單,過度計算
2. 選擇/插入維護 k 元素維護大小 k 數組,每新元素與最大值比較O(n k)O(k)k 小時尚可
3. 最大堆(大小 k)建 k 最大堆,後續元素 < 堆頂則替換調整O(n log k)O(k)工程常用,流式處理友好
4. 快速選擇Partition 劃分,遞歸處理目標側平均 O(n),最壞 O(n²)O(1)原地操作,需隨機化 pivot
5. BFPRT (中位數的中位數)嚴格 O(n) 最壞情況O(n)O(1)理論優,工程常數大
6. 計數排序數據範圍小時線性O(n + range)O(range)受範圍限制
7. 最小堆(大小 n)+ 取 k 次建 n 最小堆,彈出 k 次O(n + k log n)O(n)空間換時間,k 很大時可考慮
8. 原地最小堆優化彈出建堆後,每次彈出只下沉 k 次O(n + k²)O(1)理論有爭議,實測接近方案 7

深度解析:方案 3 vs 方案 7

數學極限證明:當 k 為常數、n→∞ 時,O(n + k log n) < O(n log k)。但方案 7 需 O(n) 空間,方案 3 僅 O(k)。綜合考慮,方案 3(大小 k 最大堆)是工程首選:空間小、支持流式輸入、緩存友好。

C++ 實現:大小 k 最大堆(方案 3)

#include <vector>
#include <queue>
#include <algorithm>

vector<int> findKSmallest(const vector<int> &nums, int k) {
    if (k >= nums.size()) return nums;
    if (k <= 0) return {};

    // 大頂堆(預設 less<int> 即最大堆)
    priority_queue<int> maxHeap(nums.begin(), nums.begin() + k);

    for (size_t i = k; i < nums.size(); ++i) {
        if (nums[i] < maxHeap.top()) {
            maxHeap.pop();
            maxHeap.push(nums[i]);
        }
    }

    vector<int> result;
    while (!maxHeap.empty()) {
        result.push_back(maxHeap.top());
        maxHeap.pop();
    }
    // 如需有序輸出,可 reverse 或 sort
    return result;
}

快速選擇實現(方案 4,原地、平均 O(n))

int partition(vector<int> &a, int l, int r) {
    int pivot = a[r], i = l - 1;
    for (int j = l; j < r; ++j)
        if (a[j] <= pivot) swap(a[++i], a[j]);
    swap(a[i + 1], a[r]);
    return i + 1;
}

void quickSelect(vector<int> &a, int l, int r, int k) {
    if (l >= r) return;
    int p = partition(a, l, r);
    if (p == k) return;
    else if (p > k) quickSelect(a, l, p - 1, k);
    else quickSelect(a, p + 1, r, k);
}

// 調用:quickSelect(nums, 0, n-1, k-1); 前 k 個即為答案(無序)

選擇建議

  • k 很小、n 很大、流式數據 → 最大堆(方案 3)
  • 一次性內存數據、追求極致速度、可修改原數組 → 快速選擇(方案 4)
  • k 接近 n → 全量排序或最小堆(方案 7)
  • 數據範圍小(如 0~10^6) → 計數排序(方案 6)

總結

「最小 k 個」是經典 Top-K 問題縮影。無銀彈,只有權衡:理解各算法的時間/空間/穩定性/流式支持特性,根據具體約束選擇,才是編程藝術的體現。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved