用2GB 處理21億的資料的排序

2021-10-06 17:34:55 字數 3420 閱讀 2562

本文的的寫作是在csdn 看到了【漫畫+**】面試官讓我用 2gb 記憶體給 20億個整數(需要8gb記憶體)排序,我該咋整??這麼一篇文章,這篇文章說的外部排序的方法。

但是,基於愛研究的精神,考慮有沒有一種方法比外部排序更快。

c++的bitset,但此處並未使用bitset ,因為不熟悉。點陣圖每一位占用1bit ,只有0或者1兩種取值,有點抽象,用下面乙個使用案例來解釋。

比如有這麼乙個陣列,陣列有元素[0,5,3,1,2,7]6個,即使使用byte(unsigned char) 進行表示,需要占用位置 6 bytes = 42bits,使用位圖進行表示 11110101 = 245

111

1010

1// 通過遍歷位圖得到 排序 0,1,2,3,5,7 ,填充完後直接獲得排序順序01

2345

67

當第 i 位(i 從0 開始) 值為1 時,表示陣列內存在i,這樣的表示方法,把空間占用壓縮到乙個byte 裡面,8 bits。

使用c++ 描述將值加入位圖

int array;

int len = sizeof(array)/sizeof(int)

usigned char *bitset = new unsigned char[1]; //設定位圖

for(int i = 0; i< len; i++)

比如輸入到第四個值1

但如題目所言,並沒有宣告不重複,取值範圍為整型,也就是說會有取值空間為[0,2^31) (在不考慮負數的情況下)

初步解決方法

說完前言,開始進入主題使用點陣圖的難點在於: 元素可能發生重複。

那麼如何解決呢?

將位圖 11110101 表示為另一種形式

1 1 1 1 0 1 0 1  共 8 bits 表示為  0001 0001 0001 0001 0000 0001 0000 0001共64bits

0 1 2 3 4 5 6 7 含義: 0001個0 0001個1 。。。。

通過上面這種新的點陣圖表示,有個優勢,只要重複個數不高於15 個,就可以完全容納。

此時加入點陣圖的c++ **描述為:

int index =

(tmp)/2

;//tmp 為輸入值 ,將在位圖中的索引進行轉換成在byte 陣列中的

int pos =

(tmp - index *2)

;unsigned

char value = bitset[index]

;//bitset 為乙個byte 陣列

if(pos ==0)

else

解決重複個數 > 15 個的情況

當某一數值重複個數超過15個時,使用4 bits 表示已經無法容納乙個數出現次數,此時有兩種解決方法:

int index =

(tmp)/2

;int pos =

(tmp - index *2)

;unsigned

char value = bitset[index];if

(pos ==0)

//在位圖中使用bitset[index] 的前四位進行表示

else

考慮取值範圍為[0,2147483647],總數目為2147483648 的情況:

此處附上**:

#include

#include

//#include "build_test.h" //生成測試資料集

#include

#include

const

char

*res_file =

"reslut.txt"

;void

writetofile

(std:

:ofstream &o, std:

:map<

int,

int> data,

int value,

int count)

;int

main

(int argc,

char

**ar**)

default

: cout <<

"no ar**..."

<< endl;

return0;

} time_t begin =

clock()

;//記錄時間

unsigned

char

*bitset = new unsigned

char

[len]

; map<

int,

int> datamap;

ifstream file

(input_file)

; ofstream res

(res_file)

;int tmp =0;

int add =0;

//讀取未排序數字 來自檔案

file >> tmp;

while

(!file.

eof())

else

if(value ==

0x0f

) datamap[tmp]+=

1;else

bitset[index]

+= add;

file >> tmp;

}

file.

close()

; cout <<

"input and sort done ,cost :"

<<

clock()

- begin << endl;

//輸出結果

for(

int i =

0; i < len; i++

)

res.

close()

; delete[

] bitset;

datamap.

clear()

; cout <<

"this sort cost :"

<<

clock()

- begin << endl;

return0;

}void

writetofile

(std:

:ofstream &o, std:

:map<

int,

int> data,

int value,

int count)

for(

int i =

0; i < count; i++

)}

Linux C操作超過2GB大小的檔案

使用普通的open lseek操作檔案,當檔案達到2gb的時候寫資料就會失敗。這也是顯然的,lseek的原型是 long lseek int handle,long offset,int fromwhere long在32位作業系統上只有4個位元組,只能定址正負2gb的資料。lseek64是用於讀寫...

如何處理MySQL每月5億的資料

第一階段 1,一定要正確設計索引 2,一定要避免sql語句全表掃瞄,所以sql一定要走索引 如 一切的 等等之類的寫法都會導致全表掃瞄 3,一定要避免 limit 10000000,20 這樣的查詢 4,一定要避免 left join 之類的查詢,不把這樣的邏輯處理交給資料庫 5,每個表索引不要建太...

如何處理MySQL每月5億的資料

第一階段 1,一定要正確設計索引 2,一定要避免sql語句全表掃瞄,所以sql一定要走索引 如 一切的 等等之類的寫法都會導致全表掃瞄 3,一定要避免 limit 10000000,20 這樣的查詢 4,一定要避免 left join 之類的查詢,不把這樣的邏輯處理交給資料庫 5,每個表索引不要建太...