海量資料處理-----bitmap
【什麼是Bit-map】
所謂的Bit-map就是用一個bit位來標記某個元素對應的Value, 而Key即是該元素。由於採用了Bit為單位來儲存資料,因此在儲存空間方面,可以大大節省。
如果說了這麼多還沒明白什麼是Bit-map,那麼我們來看一個具體的例子,假設我們要對0-7內的5個元素(4,7,2,5,3)排序(這裡假設這些元素沒有重複)。那麼我們就可以採用Bit-map的方法來達到排序的目的。要表示8個數,我們就只需要8個Bit(1Bytes),首先我們開闢1Byte的空間,將這些空間的所有Bit位都置為0(如下圖:)
然後遍歷這5個元素,首先第一個元素是4,那麼就把4對應的位置為1(可以這樣操作 p+(i/8)|(0×01<<(i%8)) 當然了這裡的操作涉及到Big-ending和Little-ending的情況,這裡預設為Big-ending),因為是從零開始的,所以要把第五位置為一(如下圖):
然後再處理第二個元素7,將第八位置為1,,接著再處理第三個元素,一直到最後處理完所有的元素,將相應的位置為1,這時候的記憶體的Bit位的狀態如下:
然後我們現在遍歷一遍Bit區域,將該位是一的位的編號輸出(2,3,4,5,7),這樣就達到了排序的目的。下面的程式碼給出了一個BitMap的用法:排序。
//定義每個Byte中有8個Bit位
#include <memory.h>
#define BYTESIZE 8
void SetBit(char *p, int posi)
{
for(int i=0; i < (posi/BYTESIZE); i++)
{
p++;
}
*p = *p|(0x01<<(posi%BYTESIZE));//將該Bit位賦值1
return;
}
void BitMapSortDemo()
{
//為了簡單起見,我們不考慮負數
int num[] = {3,5,2,10,6,12,8,14,9};
//BufferLen這個值是根據待排序的資料中最大值確定的
//待排序中的最大值是14,因此只需要2個Bytes(16個Bit)
//就可以了。
const int BufferLen = 2;
char *pBuffer = new char[BufferLen];
//要將所有的Bit位置為0,否則結果不可預知。
memset(pBuffer,0,BufferLen);
for(int i=0;i<9;i++)
{
//首先將相應Bit位上置為1
SetBit(pBuffer,num[i]);
}
//輸出排序結果
for(int i=0;i<BufferLen;i++)//每次處理一個位元組(Byte)
{
for(int j=0;j<BYTESIZE;j++)//處理該位元組中的每個Bit位
{
//判斷該位上是否是1,進行輸出,這裡的判斷比較笨。
//首先得到該第j位的掩碼(0x01<<j),將記憶體區中的
//位和此掩碼作與操作。最後判斷掩碼是否和處理後的
//結果相同
if((*pBuffer&(0x01<<j)) == (0x01<<j))
{
printf("%d ",i*BYTESIZE + j);
}
}
pBuffer++;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
BitMapSortDemo();
return 0;
}
【適用範圍】
可進行資料的快速查詢,判重,刪除,一般來說資料範圍是int的10倍以下
【基本原理及要點】
使用bit陣列來表示某些元素是否存在,比如8位電話號碼
【擴充套件】
Bloom filter可以看做是對bit-map的擴充套件
【問題例項】
1)已知某個檔案內包含一些電話號碼,每個號碼為8位數字,統計不同號碼的個數。
8位最多99 999 999,大概需要99m個bit,大概10幾m位元組的記憶體即可。 (可以理解為從0-99 999 999的數字,每個數字對應一個Bit位,所以只需要99M個Bit==12.4MBytes,這樣,就用了小小的12.4M左右的記憶體表示了所有的8位數的電話)
2)2.5億個整數中找出不重複的整數的個數,記憶體空間不足以容納這2.5億個整數。
將bit-map擴充套件一下,用2bit表示一個數即可,0表示未出現,1表示出現一次,2表示出現2次及以上,在遍歷這些數的時候,如果對應位置的值是0,則將其置為1;如果是1,將其置為2;如果是2,則保持不變。或者我們不用2bit來進行表示,我們用兩個bit-map即可模擬實現這個2bit-map,都是一樣的道理。