快速選擇問題(top k問題)

2021-10-07 15:19:15 字數 1872 閱讀 4401

找到乙個陣列中第k大的資料;

使用分治法,參考快速排序的思想, 找原陣列中找到乙個樞紐元pivot, 將陣列分為s1, pivot, s2; s1中的資料都是小於pivot, s2中的資料都是大於pivot;

如果pivot 就是第k個陣列,直接返回;

如果s1中資料多於k, 第k個資料存在於s1, 遞迴呼叫s1;

如果k存在於s2, 第(k-pivot-s1)個資料就是解, 遞迴呼叫s2;

快速選擇問題的具體**如下;

該演算法時間複雜度是o(n), 因為每一次分治實際上只有一次遞迴呼叫;

#include

#include

intpartition

(int

* arr,

int i,

int j)

arr[i]

= pivot;

return i;

}void

quickselect

(int

* arr,

int low,

int high,

int k)

}int

main()

;int len =

sizeof

(arr)

/sizeof

(arr[0]

);quickselect

(arr,

0, len -1,

13);for

(int i =

0; i < len; i++

)printf

("a[%d]:%d\n"

, i+

1, arr[i]);

printf

("\n");

return0;

}

上述演算法的問題是會改變輸入陣列的資料,當輸入資料非常大的時候,這些海量資料存在磁碟上,不能一次性都讀入到記憶體中,而且改變這些海量資料是不允許的;

乙個o(nlogn)的演算法, 適用於處理海量資料;

演算法思路:

先建立乙個大小為k的容器,用來儲存最小的k個數字。然後每次從輸入的n個資料中讀入乙個資料;

如果容器沒滿, 直接將資料插入容器;

如果容器滿了, 直接將資料與容器中最大的資料比較,新資料更大進行下一次迴圈; 新資料更小, 刪除容器中最大資料, 插入新資料;

因此, 總的時間複雜度是o(nlogk);

可以使用大根堆實現容器, 也可以使用紅黑樹實現容器;

具體**實現如下, 使用c++的multiset容器(紅黑樹實現的);

#include

#include

#include

using namespace std;

typedef multiset<

int, greater<

int>> intset;

typedef multiset<

int, greater<

int>>

::iterator setiterator;

void

topknum

(const vector<

int>

& data, intset& kcontainer,

unsigned

int k)}}

}int

main()

; intset container;

topknum

(data, container, k)

; cout <<

*(container.

begin()

)<< endl;

return0;

}

topK問題(大頂堆 快速選擇演算法)

topk問題 有 n n 1000000 個數,求出其中的前k個最小的數。力扣原題 最小的k個數 輸入整數陣列 arr 找出其中最小的 k 個數。方法一 大頂堆 思路 維護乙個大小為k的大頂堆,遍歷一次陣列,初始插入k個數,然後每遍歷乙個數,將其與堆頂比較,若比堆頂小,則堆頂彈出,該數入堆。clas...

Top K問題 基於快速排序

p為待查詢陣列,l,r分別為陣列下標,k表示第k大數 public intfindkth int p,int l,int r,int k 一次快速排序 以p l 為比較物件,比p l 大或等於的在其左邊,否則在其右邊 public intquicksort int p int l,int r whi...

TopK問題 線性時間選擇

相信計算機專業的同學應該都對快速排序有或多或少的了解。設定此模組是因為,線性時間選擇topk與快速排序的思想有相通之處,可以輔助我們理解。快速排序的思路 設定乙個瞭望元素 劃分元素 以此元素為基礎,將工作區間 l,r 內的所有元素分割成兩部分。劃分元素以左均比其小,劃分元素以右均比其大。對分割元素左...