按大小選擇第K個數的問題(top-k選擇問題)

選擇問題(seletion problem)概述[1]

從N個數當中選出第k個最大者。
最簡單的兩種算法:html

  • 算法A1:排序-->返回k位置的數。時間複雜度O(N^2)java

  • 算法A2:先讀入前k個數-->排序-->逐個讀入其他-->插入/丟掉。時間複雜度O(KN)
    K=N/2 (上取整) 時,二者複雜度都是O(N^2)算法

新解法1、用優先隊列(堆)解決選擇問題

優先隊列基礎知識

- 優先隊列基本模型
url?sa=i&rct=j&q=&esrc=s&source=images&cd=&cad=rja&uact=8&ved=0ahUKEwjsq-GZq7jLAhXFbz4KHd9_BHUQjRwIBw&url=http%3A%2F%2Fblog.csdn.net%2Flcore%2Farticle%2Fdetails%2F9100073&psig=AFQjCNFKCTyxWXH7qzRPaiLITmP_ygVk3w&ust=1457775531777546數組

- 優先隊列的簡單實現數據結構

方法a,鏈表:表頭插入-->遍歷鏈表刪除最小元。時間複雜度O(1)+O(N)
方法b,二叉查找樹。時間複雜度O(logN)ui

- 優先隊列更好的實現方案:二叉堆(簡稱堆)url

a.二叉堆的結構性質
堆:徹底填滿的二叉樹。底層元素從左到右填入。(徹底二叉樹)
徹底二叉樹,高h與節點數N的關係spa

N = 2^h ~ 2^(h+1) - 1
h = O(logN)

徹底二叉樹很是規律-->能夠用數組表示徹底二叉樹
位置i的元素-->左兒子[2i],右兒子(2i+1),父親(i/2)下取整
b.堆序性質
堆序性質(heap-order property):讓操做快速執行的性質
在一個堆中,每個子節點X的父親中的關鍵字小於等於X的關鍵字,根節點除外。
c.基本的堆操做(見數據結構與算法分析P153).net

用優先隊列解決選擇問題

  • 算法A3
    將N個元素讀入數組,對數組應用buildHeap算法。執行k次deleteMin操做。code

buildHeap最壞狀況用時O(N)
每次deleteMin用時O(logN)
kdeleteMin-->用時O(klogN + N)

  • 算法A4
    用簡單方法A2,但用堆buildHeap來實現前k個數,耗時O(k)-->檢測新元素是否進入O(1)-->必要時刪除舊插入新O(logk)-->總時間O( k + (N - k)logk )=O( Nlogk )

新解法2、用快速排序解決選擇問題(快速選擇)

算法A5
選取S中一個元素做爲樞紐元v,將集合S-{v}分割成S1和S2,就像快速排序那樣
若是k <= |S1|,那麼第k個最小元素必然在S1中。在這種狀況下,返回QuickSelect(S1, k)
若是k = 1 + |S1|,那麼樞紐元素就是第k個最小元素,即找到,直接返回它。
不然,這第k個最小元素就在S2中,即S2中的第(k - |S1| - 1)個最小元素,咱們遞歸調用並返回QuickSelect(S2, k - |S1| - 1)
此算法的平均運行時間爲O(N)

複雜度比較

在我本身的項目中,k=1或2.因此採用算法a2或者a4比較好。a2代碼量小,果斷採用。

clipboard.png

參考文獻

[1]數據結構與算法分析 java語言描述
[2]尋找最小的k個數 http://taop.marchtea.com/02.01.html

相關文章
相關標籤/搜索