1、位圖(Bitmap)簡介
位圖是一種非常常見的結構,它使用每個二進制位來存放一個值的狀態,正因為這個性質,它經常被用在數據壓縮或者是索引等方面。
有這樣一道題:給40億個不重復的無符號整數,沒有經過排序,然后再給一個樹,如何快速判斷這個數是否在40億個數之中?在這里如果我們實打實的存放40億個數據在內存中,那會占據將近15個G的內存,普通電腦根本無法滿足,更不用說在對其進行查找操作了。 那么如果選擇位圖來存儲的話我們只需要差不多500M就夠了。大大的節省了內存的消耗。
如下圖,我們把1表示存在狀態,0表示不存在,那么該組數據中就標記了2和5兩個數存在

2、C++位圖實現
位圖結構需要自己實現,C++並沒有現成的數據結構可以用
一個int類型整數占4個字節,一共32位,可以標記32個數的狀態,因此,我們把一個整數占用的內存叫做一個單元,一個單元標記32個數據的狀態
我們對一個數據進行標記之前需要先確定在那個單元,N/32
在確定在該單元的第幾位上 N%32
確定位置之后改變狀態
(0-->1) ,采用或運算
(1-->0) ,采用與運算
#include<iostream> #include<string.h> #include<algorithm> #include <vector> #include<bitset> using namespace std; class BitMap { public: //初始化位圖的大小,range是要保存的數據個數,1個int數據可以標記32個狀態,因為位圖是不支持擴容操作的 //所以一開始要確定好位圖的大小 //比如要標記1000個數據的狀態,需要開int類型的數組大小為1000/32+1 BitMap(size_t range) { _bits.resize((range >> 5) + 1); } //在位圖中標記第N個數據 void Set(size_t N) { //先確定在那個單元 size_t index = N >> 5; //在確定在該單元的什么位置 size_t bitNum = N % 32; //或運算對原來為1的狀態沒有影響,方便我們改變第N個數的狀態 _bits[index] |= (1 << bitNum); } //在位圖中的第N個數據標記置零 void Reset(size_t N) { size_t index = N >> 5; size_t bitNum = N % 32; //假設bitNum=3,則1<<3 = 1000 // 取反操作 ~(1000) = 0111 _bits[index] &= (~(1 << bitNum)); } //判斷第N個數是否被標記 bool check(size_t N) { //假設N=9,9>>5相當於9/(2^5) size_t index = N >> 5; //bitNum=9 size_t bitNum = N % 32; //_bits[0]= 00000000 00000000 00000010 00000000 //_bits[0>>9=00000000 00000000 00000000 00000001 return (_bits[index] >> bitNum) & 1; } private: vector<int> _bits; }; int main() { BitMap bs(1001); bs.Set(5); bs.Set(63); bool ret = bs.check(33); if (ret) { cout << "它在" << endl; } else { cout << "它不在" << endl; } /*bitset<32>t1(~(9 >> 5)); bitset<32>t2(1 << 9); cout << t1<< endl; cout << t2 << endl;*/ system("pause"); return 0; }
