本文的的寫作是在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,每個表索引不要建太...