問題提出:M(如10億)個int整數,只有其中N個數重複出現過,讀取到內存中並將重複的整數刪除。java
問題分析:咱們確定會先想到在計算機內存中開闢M個int整型數據數組,來one bye one讀取M個int類型數組, 而後在一一比對數值,最後將重複數據的去掉。固然這在處理小規模數據是可行的。數組
咱們 考慮大數據的狀況:例如在Java語言下,對10億個int類型數據排重。緩存
java中一個 int 類型在內存中佔4 byte。那麼10億個int類型數據共須要開闢10 ^ 9次方 *4 byte ≈ 4GB 的連續內存空間。以 32 位操做系統電腦爲例,最大支持內存爲 4G, 可用內存更是小於4G。因此上述方法在處理大數據時根本行不通。dom
思惟轉化:既然咱們不能爲全部 int 類型的數據開闢 int 類型數組,那麼能夠採起更小的數據類型來讀取緩存 int 類型數據。考慮到計算機內部處理的數據都是 01 序列的bit,那麼咱們是否能夠用 1bit 來表示一個 int 類型數據。eclipse
位映射的引出:使用較小的數據類型指代較大的數據類型。如上所說的問題,咱們能夠用1個 bit jvm
來對應一個int 整數。假如對應的 int 類型的數據存在,就將其對應的 bit 賦值爲1,不然,賦值爲0(boolean類型)。java中 int 範圍爲 -2^31 到 2^31. 那麼全部可能的數值組成的長度爲2^32. 對應的 bit 長度也爲 2^32. 那麼能夠用這樣處理以後只須要開闢2^32 bit = 2^29 byte = 512M 大小的 內存空間 。顯然,這樣處理就能知足要求了。雖然對內存的消耗也不過小,暫時這樣處理吧。ide
問題解決方案: 首先定義以下圖的int - byte 映射關係,固然,映射關係能夠自定義。但前提要保證你的數組上下標不能越界。測試
但如上定義的bit[]數組顯然在計算機中是不存在的,所咱們須要將其轉化爲 java 中的一個基本數據類型存儲。顯然,byte[] 是最好的選擇。大數據
將其轉化爲byte[] 數組方案:this
自定義的映射關係表,每一個bit對應一個 int 數值,鄙人將 int 的最大值,最小值與數組的最大最小索引相對應。從上圖能夠看出來 int 數值與bit索引相差 2^31次方。固然,你也能夠定義其餘的映射關係,只是注意不要發生數組越界的狀況。因爲最大值多是2^32,故用long接收。
long bitIndex = num + (1l << 31);
計算在轉化爲byte[]數組的索引,因爲上面定義的bitIndex 索引是非負數,故無需引入位運算去符號。
int index = (int) (bitIndex / 8);
計算bitIndex 在byte[]數組索引index 中的具體位置。
int innerIndex = (int) (bitIndex % 8);
引入位運算將byte[]數組索引index 的各個位按權值相加
dataBytes[index] = (byte) (dataBytes[index] | (1 << innerIndex));
這樣就解決了整個大數據讀取排重的問題。
那麼怎麼將其讀取出來呢?怎麼對數據進行排序?
那就只須要按照byte[]數組進行一一對應到 int 類型數據上便可。
如下代碼升序輸出爲例。
遍歷數組,採起與以前映射關係的逆運算來還原數據。
for (int i = 0; i < bytes.length; i++) {
for (int j = 0; j < 8; j++) {
if (!(((bytes[i]) & (1 << j)) == 0)) {
int number = (int) ((((long) i * 8 + j) - (1l << 31)));
}
}
}
}
因爲編譯軟件默認設置的JVM內存是128—400M左右,測試此程序明顯是不夠的,因此須要調節一下分配給JVM的內存。不然,無論怎樣運行,都會出現Exception in thread "main" java.lang.OutOfMemoryError: Java heap space...
eclipse:選擇run->run configuration->arguments,輸入-Xms256M -Xmx1024M(-Xms表明jvm啓動時分配的內存大小,-Xmx表明可最大分配多少內存)
Intellij IDEA:修改安裝目錄/IntelliJ IDEA 7.0/bin下idea.exe.vmoption文件
-Xms256M
-Xmx1024M
源代碼:
1 package com.MassSort20131103; 2 3 import java.util.Random; 4 5 6 /** 7 * Created with IntelliJ IDEA. 8 * User: YangKang 9 * Date: 13-11-3 10 * Time:上午11:32 11 * To change this template use File | Settings | File Templates. 12 */ 13 public class BigDataSort { 14 15 private static final int CAPACITY = 1 000 000 000;//數據容量 16 17 // 定義一個byte數組緩存全部的數據 18 private byte[] dataBytes = new byte[1 << 29]; 19 20 public static void main(String[] args) { 21 BigDataSort ms = new BigDataSort(); 22 23 byte[] bytes = null; 24 25 Random random = new Random(); 26 for (int i = 0; i < CAPACITY; i++) { 27 int num = random.nextInt(); 28 System.out.println("讀取了第 " + (i + 1) + "\t個數: " + num); 29 bytes = ms.splitBigData(num); 30 } 31 System.out.println(""); 32 ms.output(bytes); 33 } 34 35 36 /** 37 * 讀取數據,並將對應數數據的 到對應的bit中,並返回byte數組 38 * @param num 讀取的數據 39 * @return byte數組 dataBytes 40 */ 41 private byte[] splitBigData(int num) { 42 43 long bitIndex = num + (1l << 31); //獲取num數據對應bit數組(虛擬)的索引 44 int index = (int) (bitIndex / 8); //bit數組(虛擬)在byte數組中的索引 45 int innerIndex = (int) (bitIndex % 8); //bitIndex 在byte[]數組索引index 中的具體位置 46 47 System.out.println("byte[" + index + "] 中的索引:" + innerIndex); 48 49 dataBytes[index] = (byte) (dataBytes[index] | (1 << innerIndex)); 50 return dataBytes; 51 } 52 53 /** 54 * 輸出數組中的數據 55 * @param bytes byte數組 56 */ 57 private void output(byte[] bytes) { 58 int count = 0; 59 for (int i = 0; i < bytes.length; i++) { 60 for (int j = 0; j < 8; j++) { 61 if (!(((bytes[i]) & (1 << j)) == 0)) { 62 count++; 63 int number = (int) ((((long) i * 8 + j) - (1l << 31))); 64 System.out.println("取出的第 " + count + "\t個數: " + number); 65 } 66 } 67 } 68 } 69 }