40億個32位整數求中位數

2021-10-10 21:19:37 字數 2671 閱讀 1101

40億個32位整數,想找到其中的中位數該怎麼辦?

按行讀取檔案,讀取操作不占用記憶體。

2^k = ? 應該都能夠熟記,達到反射性反應的程度。

位元組數對應計算機中的容量(t, g, m, k)

1k = 2^10 ≈ 10^3,一千

1m = 2^20 ≈ 10^6,一百萬

1g = 2^30 ≈ 10^9,十億

int型為有符號32位整數,佔4個位元組,取值範圍在-2,147,483,648~2,147,483,647之間。-21億到21億

uint型為無符號32位整數,佔4個位元組,取值範圍在0~4,294,967,295之間。0到42億

使用桶排序的思想,將全部整數按照固定的數值區間劃分到桶中,劃分區間的範圍取決於桶的數量和整數的數量,記錄每個桶中存放的整數個數,然後逐個獲取桶中存放的整數個數相加,一直得到結果超過20億,則中位數在當前該桶a中,記錄偏移量s,即在桶a的第s個整數為正好第20億個;

如果當前該桶a只是粗略估計某個數值區間的整數總數,則需要再對這個區間細分到每個桶儲存,然後再對所有整數全部遍歷一次,將所有原本落在桶a的整數再細分到每個桶中,然後再根據偏移量s來獲取更細化的桶,再看這個桶是否還是粗略估計區間,如果是,繼續劃分。。。。。。

32位整數有正有負,所以我們在記錄的時候可以全部加上21億,當成無符號整數來統計,最後取出中位數時再減去21億

40億個32位整數,所以乙個數最多出現40億次,可以用乙個uint32整數來記錄次數

有些題目問的是比如10g的32位整數,那麼每個佔4位元組,所以10g共有2.5g個整數,大概就是25億整數

允許的最大記憶體 / 記錄者所佔的記憶體大小 = 桶的數量

也可以理解為建立乙個元素為「記錄者數值型別」,數量為「桶的數量」的陣列

32位整數最大區間(42億)/桶的數量 = 桶的區間

桶的數量為2gb/4b = 512m,所以建立512m個桶,即記憶體允許我們建立大概是5億個桶

每個桶的區間為42億 / 5億 ≈ 8

所以我們在2gb記憶體下,可以將42億的大區間劃分成約5億個小區間,每個小區間大小為8

所以遍歷全部整數:

第乙個桶記錄取值為0到7的數的個數,第二個記錄取值為8到15的數的個數,以此類推。。。

如乙個數為0,則arr[0/8]++,乙個數為8,則arr[8/8]++

最終每個桶相加,找到相加後超出20億的桶,記錄偏移量,標記在該桶內的第幾個是中位數

比如是在第二個桶,記錄的取值範圍為8到15,偏移量為30

則釋放掉原來所有的桶,重新建立8個桶,第乙個桶記錄取值為8的數的個數,第二個桶記錄9。。。

再進行一次遍歷,只統計取值為8到15的數的個數,儲存到各個桶中

然後找到相加和超過30的桶,該桶記錄的值即為中位數

桶的數量為10mb/4b = 2.5m,大概是250萬個桶,即記憶體允許我們建立250萬個桶

每個桶的區間為42億 / 250萬 = 1680

所以我們在10mb記憶體下,可以將42億的大區間劃分成250萬個小區間,每個小區間大小為1680

第乙個桶記錄取值為0到1679的數的個數,第二個記錄取值為1680到3359的數的個數,以此類推。。。

第一次遍歷找到中位數所在桶後,第二次遍歷則重新建立1680個桶,每個桶精確到1個數

桶的數量為20kb/4b = 5k,即記憶體允許我們建立5000個桶

每個桶的區間為42億 / 5000 = 84萬

所以我們在20kb記憶體下,可以將42億的大區間劃分成5000個小區間,每個小區間大小為84萬

現在問題來了,第一次遍歷找到中位數所在桶後,第二次遍歷仍然建立不了84萬個桶,我們的記憶體只允許建立5000個,那就繼續創5000個唄。

新的桶區間為84萬 / 5000 = 168

重新建立5000個桶,再將84萬的大區間劃分成5000個小區間,每個小區間大小為168

仍然能通過上次的偏移量獲取新桶的位置,新桶仍然是模糊統計,再細分建立168個桶,這次每個桶精確到1個數

當記憶體開始逐漸變小的時候,第二次劃分桶就能精確到1個數的情況就不復存在,需要再劃分的次數就會逐漸增加

那麼極限情況在哪?

這是記憶體小到最極限的情況

桶的數量為8b/4b = 2,即記憶體允許我們建立2個桶

每個桶的區間為42億 / 2 = 21億

當只有兩個uint32變數來做桶時,桶排序的思想就變成了二分的思想。

還是一樣,遍歷全部整數:

對42億區間進行二分,將-21億到0的部分劃到第乙個桶,將1到21億的部分劃到第二個桶

如果第乙個桶統計的值超過20億,則說明中位數在第乙個桶中,繼續對範圍-21億到0的部分二分劃分到兩個桶,然後再二分,以此類推。。。

因此,極限情況是最多劃分32次,就能求出中位數

這是記憶體大到最極限的情況,如果記憶體足夠大,則桶的數量可以創很多,多到超過42億,

則每個桶的區間為42億/42億 = 1

每個桶可以直接精確到1個數,那麼桶排序直接轉化為計數排序,建立乙個42億大小的uint32陣列arr將int型整數的所有範圍都涵蓋,每遍歷乙個整數num就直接arr[num]++即可

遍歷所有桶的值進行相加,求出第20億個整數即可。

1、確定記錄者的數值型別

2、確定桶的數量

3、確定桶的區間

4、在記憶體不夠用的情況下,先模糊統計中位數所在區間,再對該區間放大,還不夠再放大,直到最後能精確統計某個數值的個數為止。

100億個整數,找出中位數

100億個整數,記憶體足夠,如何找到中位數?記憶體不足,如何找到中位數?1 當記憶體足夠時 採用快排,找到第n大的數。隨機選取乙個數,將比它小的元素放在它左邊,比它大的元素放在右邊 如果它恰好在中位數的位置,那麼它就是中位數,直接返回 如果小於它的數超過一半,那麼中位數一定在左半邊,遞迴到左邊處理 ...

5億個無序整數 找中位數

有5億個整數,沒有排序。找到他們的中位數 使用雙層桶劃分 分而治之 的策略。假設題目中指的是32位的無符號整數,共有2 32個數字。我們將2 32這個範圍劃分成2 10個區域。對資料進行第一次掃瞄,統計各個落到各個區域內的數字的個數。第一次掃瞄後,通過統計就可以知道,中位數在哪個區域內,以及它是這個...

求海量個無序整數的中位數

在乙個檔案中有 10g 個整數,亂序排列,要求找出中位數。記憶體限制為 2g。不妨假設10g個整數是64bit的。2g記憶體可以存放256m個64bit整數。我們可以將64bit的整數空間平均分成256m個取值範圍,用2g的記憶體對每個取值範圍內出現整數個數進行統計。這樣遍歷一邊10g整數後,我們便...