海量數據處理第二談-----位圖BitMap


位圖的概念:ios


    在C++中,位圖是以位來表示整數的結構,普通的整數一個數須要用4個字節來表示,咱們能夠換種思想,在整個整數的集合範圍內,某個整數存在與否,只有兩種狀況,在或者不在,那麼,咱們能夠考慮只用一個bit位,來表示該整數存在的狀態,從而達到節省內存的目的。算法


位圖實例分析:express


    給一個實際的例子,給40億個不重複的unsigned int的整數,沒排過序的,而後再給一個數,如何快速判斷這個數是否在那40億個數當中數組

    咱們能夠簡單計算一下,40億個整數所有放到內存,須要160億個字節,粗略計算,大體須要16G的內存,若是咱們把每一個整數是否出現,轉換成用一位來表示它存在的狀態,須要5億個字節,也就是大約500M的內存,對於計算機而言,對內存的節省亦常地重要,這就是位圖的一個重要應用。
數據結構


位圖模擬實現:less


    首先咱們考慮位圖的結構,實際上也是對數組的封裝,只不過咱們這裏須要的是以bit位爲單位進行存放,每一位的狀態只有0和1兩種,這裏用來表示該整數是否在位圖內。
ide

    咱們以一個×××爲例,在一個×××的空間,存儲【1 6 9 4 12 10】這些數,存儲結果應該以下:
函數

wKioL1gxAeXCyh6BAAAk9tpUtEc978.png

    這個只給出了兩個字節,全能夠表示上面的6個整數。
測試

    關於位圖的底層,這裏咱們使用vector來模擬實現。
ui

#include <vector>
#include<iostream>
using namespace std;
class BitMap
{
public:
    BitMap(const size_t& range)
    {
        int sz = (range >> 5) + 1;
        _vec.resize(sz);
    }
    void BitSet(const size_t& x)
    {
        int index = x >> 5; // index是x對應位所在的下標
        int num = x % 32; // num是x對應該×××的第多少位
        _vec[index] |= 1 << num;
    }
    void BitReSet(const size_t& x)
    {
        int index = x >> 5; // index是x對應位所在的下標
        int num = x % 32; // num是x對應該×××的第多少位
        _vec[index] &= (~(1 << num));
    }
    bool BitTest(const size_t& x)
    {
        int index = x >> 5; // index是x對應位所在的下標
        int num = x % 32; // num是x對應該×××的第多少位
        return _vec[index] & (1 << num);
    }
protected:
    vector<int> _vec;
};

    位圖的實現實際上就是進行一系列的位操做,經過位操做找到該×××對應的位,下面給出一組簡單的測試用例
    

void TestBitMap()
{
    BitMap  mp(100);
    mp.BitSet(1);
    mp.BitSet(2);
    mp.BitSet(11);
    mp.BitSet(22);
    cout << "test --<1>" << mp.BitTest(1) << endl;
    cout << "test --<2>" << mp.BitTest(2) << endl;
    cout << "test --<11>" << mp.BitTest(11) << endl;
    cout << "test --<22>" << mp.BitTest(22) << endl<<endl;
    mp.BitReSet(2);
    cout << "test --<1>" << mp.BitTest(1) << endl;
    cout << "test --<2>" << mp.BitTest(2) << endl;
    cout << "test --<11>" << mp.BitTest(11) << endl;
    cout << "test --<22>" << mp.BitTest(22) << endl << endl;
}

    

源碼庫中的位圖:


    在源碼庫中,有這樣一個容器 bitset,和咱們這裏的bitmap性質基本是同樣的,固然,功能要比上面實現的位圖大得多。


A bitset is a special container class that is designed to store bits (elements with only two possible values: 0 or 1, true or false, ...).

The class is very similar to a regular array, but optimizing for space allocation: each element occupies only one bit (which is eight times less than the smallest elemental type in C++: char).

Each element (each bit) can be accessed individually: for example, for a given bitset named mybitset, the expression mybitset[3] accesses its fourth bit, just like a regular array accesses its elements.

Because no such small elemental type exists in most C++ environments, the individual elements are accessed as special references which mimic bool elements:


    庫中提供了一系列的函數操做,除了set、reset、test以外,經常使用的還有filp<取反操做>,count<統計位爲1的個數>。關於bitset的操做,都包含在

#include <bitset>

的頭文件中。

    

位圖的分析與擴展:


    位圖的確用起來會很方便,但並非任何狀況下都須要使用到位圖的,位圖一般是爲了處理大量數據,內存中不足以存放全部的數字才使用的一種數據結構,由於位圖也有着必定的缺陷:

    1> 它的可讀性差

    2> 位圖在視圖節約空間的時候,也伴隨着必定的消耗,它要求給最大值和最小值之間的全部數都要佔用一個bit位,當數據過於分散而數據量又不至太大的狀況,位圖實際上是一種比較浪費空間的作法。若是最小值爲10000,位圖開闢出來的前10000個bit位其實就空了出來,沒有利用到,以前咱們舉得例子,40億個整數,由於無符號整數的最大值就到42.9億左右,大部分的整數值肯定都已經被取到,所以咱們採用了位圖來實現。

    3> 當位圖用來存儲有符號整數時,有兩種解決方案,一種是咱們約定好最小值再也不從0開始,全部的計算都須要減去有符號整數的最大值,另外一種是這裏採用兩位來存儲一個數,用兩位來表示正數、負數、不存在三種狀態。

    試想,若是咱們要求統計40億個無符號整數中,出現兩次以上的數該如何處理?

。。。。。。

    一樣,多加一位標誌位,用兩個bit位來進行處理,那這樣的話,就須要咱們本身來實現一個基本的兩位爲一個單元的位圖結構。

    除此以外,位圖還可用來排序,判重,固然這裏僅僅限於無符號整數,和上一節的哈希同樣,受限於整數範圍確實是個很差的地方,下一談會提到字符串哈希算法與布隆過濾器,正是因爲字符串哈希算法,才使得這些數據結構得以大範圍的使用。

關於哈希算法:
    http://muhuizz.blog.51cto.com/11321490/1870717

                            -----muhuizz整理

相關文章
相關標籤/搜索