找到乙個陣列中第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 內的所有元素分割成兩部分。劃分元素以左均比其小,劃分元素以右均比其大。對分割元素左...