bitmap與2-bitmap使用總結

bitmap是一種簡單的數據結構。但在存儲空間壓縮方面卻使用普遍。css

bitmap就是用一個bit位來標記某個元素是否存在:1表示存在,0表示不存在;而2-bitmap就是用兩個bit爲來標記某個元素出現的次數:00出現0次,01出現1次。10出現2次及其以上。11無心義。html

2-bitmap在內存中的表演示樣例如如下:
          [0]                  [1]                [2]              ……    
|00 00 00 00|00 00 00 00|00 00 00 00|    ……
  3   2   1   0   7   6   5   4   11 10  9   8       ……

面試


不論什麼一個可採用數組做爲輔助標記來解決的問題都可以用bitmap來解決,因爲用數組的每個元素做爲標記的話,用bit相同可以做爲標記。當數據量比較小時,有時候爲了操做方便,可直接採用數組。但當數據量很是大的時候,因爲內存大小的緣由或題目限定了可用內存大小,數組就再無法解決咱們的問題。 而此時bitmap就顯示出其空間壓縮的威力了:假設用char型的數組,標記相同範圍內的數bitmap最多可以節省8倍空間,2-bitmap可節省4倍空間。若採用int型的數組。bitmap和2-bitmap可以分別最多節省32倍、16倍的空間。數組


bitmap能用來處理如下問題:數據結構

(1)、字符串方面函數

一、C語言str系列庫函數之strtok()、strspn()、strcspn()和strpbrk()函數都用到了bitmap。post

詳見C語言str系列庫函數之strtok()C語言str系列庫函數之strspn()、strcspn()和strpbrk()
大數據

二、推斷一個字符串B中的字符是否都在還有一個字符串A中出現(網上能搜到)。google

跟上面第1條博文連接裏的十分類似。spa

三、在一個字符串中找到第一個僅僅出現一次的字符(google面試題、網上能搜到)。

可以用26維的數組統計26個字母出現的次數。而後順序查找統計表直到查到到結果爲1的就是要查到的字符。

也可以採用2-bitmap,更節省空間。

(2)、大數據

一、在2.5億個整數找出不反覆的整數,內存不足以容納着2.5億個整數

二、騰訊面試題:給40億個不反覆的unsigned int的整數。沒排過序的,而後再給一個數,怎樣高速推斷這個數是否在那40億個數其中?


對於問題1。整數多是正數也多是負數,首先僅僅考慮正整數狀況,採用2Bitmap方法,用00表示不存在,01表示出現1次,10表示出現2次及以上,此方法總共需要的內存2^31*2bit = 1Gb = 128MB(32位的正整數有2^31個,每個存儲需要2bit,因此就是1Gb,換成字節就是128MB),這樣內存就應該可以容納了,最後在處理全然部的數後,僅僅要輸出相應位爲01的數就能夠。

假設這2.5億個數裏面既有正數又有負數那麼就用兩個2Bitmap分別存儲正數和負數(取絕對值存儲),零就隨便放。這是所需要的內存是256MB。

對於問題2,直接用Bitmap就能夠,0表示存在,1表示不存在。


不少其它關於用bitmap來解決這個問題的博文:十七道海量數據處理面試題與Bit-map具體解釋http://blog.csdn.net/v_july_v/article/details/7382693


2-bitmap的使用關鍵在於怎樣操縱位,如下是一個演示樣例代碼:

#include <stdio.h>
#include <memory.h>
#include <stdlib.h>

#define N 1024*1024*1024
unsigned char bitmap[1 + N / 4];  //2-bitmap

void set(int x,int num)
{  
	int m = x >> 2;		//x / 4;  
	int n = x & 0x3;	//x % 4; 

	//bitmap[m] &= ~((0x3<<(2*n)) & 0xff);  
	//bitmap[m] |= ((num&0x3)<<(2*n) & 0xff);
	bitmap[m] &= ~(0x3 << (2*n));
	bitmap[m] |= ((num & 0x3) << (2*n));
}

void clear(int x)
{
	int m = x >> 2;		//x / 4;  
	int n = x & 0x3;	//x % 4; 

	//bitmap[m] &= ~((0x3<<(2*n)) & 0xff);	 //0xff可以去掉
	bitmap[m] &= ~(0x3 << (2*n));
}

unsigned get(int x)
{
	int m = x >> 2;
	int n = x & 0x3;

	return  (bitmap[m] & (0x3 << (2*n))) >> (2*n);
}

void add(int x)
{
	set(x, get(x) + 1);
}

int main()
{
	int a[8] = {1, 3, 1, 4, 5, 5, 5, 5};  //找出數組a中不反覆的元素
	
	memset(bitmap, 0, sizeof(bitmap));	  //清空位圖

	for (int i = 0;i < 8; i++)
	{
		unsigned val = get(a[i]);		//00、0一、10
		if (val <= 1)                           //a[i]在bitmap的位序列爲10時表示出現最少2次
			set(a[i], val+1);
	}

	//現在可以查看每個元素出現的次數
	for (int i = 0;i < 8; i++)
		printf("%d %d\n", a[i], get(a[i]));
	putchar('\n');

	//假設要推斷某個數x是否存在於數組a中,直接推斷get(x)的值
	//get(x) > 0 ? 存在 : 不存在

	//如下的代碼輸出在a數組中僅出現1次的數
	for (int i = 0; i < 2;i++)			  //這裏實際上僅僅需要用到16bit
		for(int j = 0; j < 4; j++)
		{
			int x =	 (i << 2 | (j & 0x3));   //獲得存在這個位置的數是多大
			int val = get(x);
			if (val == 1)
				printf("%d ", x);
		}
	getchar();
	return 0;
}

參考: http://blog.csdn.net/acceptedxukai/article/details/9025493
相關文章
相關標籤/搜索