位映射對大數據的排重

問題提出: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 }  

 

 

轉自:http://blog.csdn.net/xqy_zyl/article/details/14456041

相關文章
相關標籤/搜索