bitmap位圖原理和實現


引子

首先通過一道題來理解什么是bitmap。

題目:我有40億個整數,再給一個新的整數,我需要判斷新的整數是否在40億個整數中,你會怎么做?

分析:

假設一個int占4個字節(32位),40個億個整數就是160億個字節,大概相當於16GB,假設一台計算機只有2GB內存,則16GB一次加載不完,需要分8次加載,從磁盤加載數據是磁盤io操作,是非常慢的(比內存中的操作要慢100倍),每次加載這么大的數據,並且要8次,那么查找的時間可以達到分鍾甚至小時級。

還有一個辦法是把數據分散在8台計算機上,然后來一個新數據,8台計算機同時找,然后再匯總結果。這樣每台計算機都可以一次性把數據讀入內存中,查找就不用來回加載數據,省去了加載數據的開銷,是個好方法。

但是否還有其他更好的方法呢?那就是bitmap。bitmap存值的思路:每一個int有32位,int整數的范圍是-2147483648 ~ 2147483647。為簡化理解,這里先假設每一個整數位均為正整數(如果存在負整數需分開處理),2147483647/32 = 67108863,即只需要67108863個int型整數就可以表示 [0,2147483647] 范圍的數字,即需要67108863*4 = 268,435,452‬個字節的內存,相當於0.2GB,即使加上負整數部分也才需要0.4GB的內存,一台計算機完全足夠。這里將開辟67108863int型數組,數組中的每一位代表依次代表 [0,2147483647]。而且而且判斷新的整數也只需要O(1)的時間復雜度,性能非常高。

bitmap定義

位圖是一個數組的每一個數據的每一個二進制位表示一個數據,0表示數據不存在,1表示數據存在。

例如存儲136這個數:

  1. 確定136在整個數據的那個區間,136/32 = 4,即在第四個區間;
  2. 確定136在這個區間的第幾位(bit),136%32 = 25,即在第四區間的第25位上;
  3. 將這個位置置為1,表示存在這個數。

由於bitmap的數據存儲方式,具有升序排序的性質。

代碼實現

#include <iostream>
#include <vector>

using namespace std;

class Bitmap {
public:
    Bitmap() {
        bitVec_.resize((INT_MAX >> 5) + 1);  //多開辟一個空間,原因是數組只能表示區間[0,size)
    }
    void BitmapSet(int val) {
        int index = val >> 5;  //相當於除以32,用移位操作可提高性能
        int offset = val % 32;
        bitVec_[index] |= (1 << offset);
        int capacity = bitVec_.capacity();
    }
    bool BitmapGet(int val) {
        int index = val >> 5;
        int offset = val % 32;
        return bitVec_[index] & (1 << offset);
    }
private:
    vector<unsigned int> bitVec_;
};

int main() {
    Bitmap bm;
    //這里只存[0,1000000]的數,
    for (int i = 0; i <= 1000000; ++i) {
        bm.BitmapSet(i);
    }
    bool exist1 = bm.BitmapGet(100);       // 100是否存在,返回true
    bool exist2 = bm.BitmapGet(10000000);  // 10000000是否存在,返回false

    system("pause");
    return 0;
}

上面實現只是針對開篇題目寫的簡單bitmap,下一篇文章會探討Bloom Filter的原理,會對用到的bitmap進行優化修改。

 


免責聲明!

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



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