海量數據處理-BitMap算法


一、概述
本文將講述Bit-Map算法的相關原理,Bit-Map算法的一些利用場景,例如BitMap解決海量數據尋找重復、判斷個別元素是否在海量數據當中等問題.最后說說BitMap的特點已經在各個場景的使用性。
二、Bit-Map算法
先看看這樣的一個場景:給一台普通PC,2G內存,要求處理一個包含40億個不重復並且沒有排過序的無符號的int整數,給出一個整數,問如果快速地判斷這個整數是否在文件40億個數據當中?
問題思考:
40億個int占(40億*4)/1024/1024/1024 大概為14.9G左右,很明顯內存只有2G,放不下,因此不可能將這40億數據放到內存中計算。要快速的解決這個問題最好的方案就是將數據擱內存了,所以現在的問題就在如何在2G內存空間以內存儲着40億整數。一個int整數在java中是占4個字節的即要32bit位,如果能夠用一個bit位來標識一個int整數那么存儲空間將大大減少,算一下40億個int需要的內存空間為40億/8/1024/1024大概為476.83 mb,這樣的話我們完全可以將這40億個int數放到內存中進行處理。
具體思路:
1個int占4字節即4*8=32位,那么我們只需要申請一個int數組長度為 int tmp[1+N/32]即可存儲完這些數據,其中N代表要進行查找的總數,tmp中的每個元素在內存在占32位可以對應表示十進制數0~31,所以可得到BitMap表:
tmp[0]:可表示0~31
tmp[1]:可表示32~63
tmp[2]可表示64~95
.......
那么接下來就看看十進制數如何轉換為對應的bit位:
假設這40億int數據為:6,3,8,32,36,......,那么具體的BitMap表示為:

那么怎么快速定位它的索引呢。如果找到它的索引號,又怎么定位它的位置呢。Index(N)代表N的索引號,Position(N)代表N的所在的位置號。

Index(N) = N/8 = N >> 3;

Position(N) = N%8 = N & 0x07;

add方法:

    public void add(int num){
        // num/8得到byte[]的index
        int arrayIndex = num >> 3; 
        
        // num%8得到在byte[index]的位置
        int position = num & 0x07; 
        
        //將1左移position后,那個位置自然就是1,然后和以前的數據做|,這樣,那個位置就替換成1了。
        bits[arrayIndex] |= 1 << position; 
    }

code:

public class BitMap {
    //保存數據的
    private byte[] bits;
    
    //能夠存儲多少數據
    private int capacity;
    
    
    public BitMap(int capacity){
        this.capacity = capacity;
        
        //1bit能存儲8個數據,那么capacity數據需要多少個bit呢,capacity/8+1,右移3位相當於除以8
        bits = new byte[(capacity >>3 )+1];
    }
    
    public void add(int num){
        // num/8得到byte[]的index
        int arrayIndex = num >> 3; 
        
        // num%8得到在byte[index]的位置
        int position = num & 0x07; 
        
        //將1左移position后,那個位置自然就是1,然后和以前的數據做|,這樣,那個位置就替換成1了。
        bits[arrayIndex] |= 1 << position; 
    }
    
    public boolean contain(int num){
        // num/8得到byte[]的index
        int arrayIndex = num >> 3; 
        
        // num%8得到在byte[index]的位置
        int position = num & 0x07; 
        
        //將1左移position后,那個位置自然就是1,然后和以前的數據做&,判斷是否為0即可
        return (bits[arrayIndex] & (1 << position)) !=0; 
    }
    
    public void clear(int num){
        // num/8得到byte[]的index
        int arrayIndex = num >> 3; 
        
        // num%8得到在byte[index]的位置
        int position = num & 0x07; 
        
        //將1左移position后,那個位置自然就是1,然后對取反,再與當前值做&,即可清除當前的位置了.
        bits[arrayIndex] &= ~(1 << position); 

    }
    
    public static void main(String[] args) {
        BitMap bitmap = new BitMap(100);
        bitmap.add(7);
        System.out.println("插入7成功");
        
        boolean isexsit = bitmap.contain(7);
        System.out.println("7是否存在:"+isexsit);
        
        bitmap.clear(7);
        isexsit = bitmap.contain(7);
        System.out.println("7是否存在:"+isexsit);
    }
}

每個byte存8個數字,相對於int類型來說,節省了32倍的存儲空間

存儲數據范圍,就上面的例子來說,上面bits數組的長度為13,那么總共可以存儲(13*8)104個數字,分別是(0~103)

上面的代碼並沒有擴容方法,超出范圍會報錯,

使用bit數組來表示某些元素是否存在,比如8位電話號碼.

缺點:

如果是比較特殊的數字,比如[1,100000000],那么就會浪費存儲空間,比如這個就必須要(100000000>>3)個字節

 

針對上面的缺點,谷歌所實現的EWAHCompressedBitmap對bitmap存儲空間做了一定的優化

相信的講解:http://www.sohu.com/a/166661005_479559


問題實例

1、在2.5億個整數中找出不重復的整數,注,內存不足以容納這2.5億個整數
解法一:采用2-Bitmap(每個數分配2bit,00表示不存在,01表示出現一次,10表示多次,11無意義)進行,共需內存2^32 * 2 bit=1 GB內存,還可以接受。然后掃描這2.5億個整數,查看Bitmap中相對應位,如果是00變01,01變10,10保持不變。所描完事后,查看bitmap,把對應位是01的整數輸出即可。

解法二:也可采用與第1題類似的方法,進行划分小文件的方法。然后在小文件中找出不重復的整數,並排序。然后再進行歸並,注意去除重復的元素。”
2、給40億個不重復的unsigned int的整數,沒排過序的,然后再給一個數,如何快速判斷這個數是否在那40億個數當中?
解法一:可以用位圖/Bitmap的方法,申請512M的內存,一個bit位代表一個unsigned int值。讀入40億個數,設置相應的bit位,讀入要查詢的數,查看相應bit位是否為1,為1表示存在,為0表示不存在。

 

https://www.jianshu.com/p/6082a2f7df8e

https://wizardforcel.gitbooks.io/the-art-of-programming-by-july/content/06.07.html

http://blog.51cto.com/zengzhaozheng/1404108

http://blog.csdn.net/h348592532/article/details/45362661

https://www.cnblogs.com/protected/p/6626447.html

http://mp.weixin.qq.com/s?__biz=MzIxMjE5MTE1Nw==&mid=2653191272&idx=1&sn=9bbcd172b611b455ebfc4b7fb9a6a55e&chksm=8c990eb2bbee87a486c55572a36c577a48df395e13e74314846d221cbcfd364d44c280250234&scene=21#wechat_redirect


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM