所謂的BitMap就是用一個bit位來標記某個元素所對應的value,而key便是該元素,因爲BitMap使用了bit位來存儲數據,所以能夠大大節省存儲空間。
java
首先用一個簡單的例子來詳細介紹BitMap算法的原理。假設咱們要對0-7內的5個元素(4,7,2,5,3)進行排序(這裏假設元素沒有重複)。咱們可使用BitMap算法達到排序目的。要表示8個數,咱們須要8個byte。算法
首先咱們開闢一個字節(8byte)的空間,將這些空間的全部的byte位都設置爲0數組
而後便利這5個元素,第一個元素是4,由於下邊從0開始,所以咱們把第五個字節的值設置爲1code
而後再處理剩下的四個元素,最終8個字節的狀態以下圖blog
從上面的例子能夠看出,BitMap算法的思想仍是比較簡單的,關鍵的問題是如何肯定10進制數到二進制的轉換排序
MAP映射:內存
假設須要排序或則查找的數的總數N=100000000,BitMap中1bit表明一個數字,1個int = 4Bytes = 4*8bit = 32 bit,那麼N個數須要N/32 int空間。因此咱們須要申請內存空間的大小爲int a[1 + N/32],其中:a[0]在內存中佔32爲能夠對應十進制數0-31,依次類推:數學
a[0]-----------------------------> 0-31it
a[1]------------------------------> 32-63class
a[2]-------------------------------> 64-95
a[3]--------------------------------> 96-127
......................................................
那麼十進制數如何轉換爲對應的bit位,下面介紹用位移將十進制數轉換爲對應的bit位:
1.求十進制數在對應數組a中的下標
十進制數0-31,對應在數組a[0]中,32-63對應在數組a[1]中,64-95對應在數組a[2]中………,使用數學概括分析得出結論:對於一個十進制數n,其在數組a中的下標爲:a[n/32]
2.求出十進制數在對應數a[i]中的下標
例如十進制數1在a[0]的下標爲1,十進制數31在a[0]中下標爲31,十進制數32在a[1]中下標爲0。 在十進制0-31就對應0-31,而32-63則對應也是0-31,即給定一個數n能夠經過模32求得在對應數組a[i]中的下標。
3.位移
對於一個十進制數n,對應在數組a[n/32][n%32]中,但數組a畢竟不是一個二維數組,咱們經過移位操做實現置1
a[n/32] |= 1 << n % 32
移位操做:
a[n>>5] |= 1 << (n & 0x1F)
n & 0x1F 保留n的後五位 至關於 n % 32 求十進制數在數組a[i]中的下標
public class BitMap { private static final int N = 10000000; private int[] a = new int[N/32 + 1]; /** * 設置所在的bit位爲1 * @param n */ public void addValue(int n){ //row = n / 32 求十進制數在數組a中的下標 int row = n >> 5; //至關於 n % 32 求十進制數在數組a[i]中的下標 a[row] |= 1 << (n & 0x1F); } // 判斷所在的bit爲是否爲0 public boolean exits(int n){ int row = n >> 5; return (a[row] & ( 1 << (n & 0x1F))) != 0; } public void display(int row){ System.out.println("BitMap位圖展現"); for(int i=0;i<row;i++){ List<Integer> list = new ArrayList<Integer>(); int temp = a[i]; for(int j=0;j<32;j++){ list.add(temp & 1); temp >>= 1; } System.out.println("a["+i+"]" + list); } } public static void main(String[] args){ //int num[] = {1,5,30,32,64,56,159,120,21,17,35,45}; int num[] = {4,7} BitMap map = new BitMap(); for(int i=0;i<num.length;i++){ map.addValue(num[i]); } int temp = 4; if(map.exits(temp)){ System.out.println("value:[" + temp + "] has already exists"); } map.display(3); } }
運行結果:
value:[4] has already exists BitMap位圖展現 a[0][0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] a[1][0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] a[2][0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
解析代碼:
若是將 0,1,2 ,3 這些10進制位的數字 分別 經過 & 0X1F (至關於取模32) 經過移位 << N
其實就是 將其 變爲 :
0 ---> 0001 即2的0次方 1
1 ---> 0010 即2的1次方 2
2 ---> 0100 即2的2次方 4
再而後 | 運算 因爲 都是經過直接左移 得出(不會有重合的值 )
此時的 | 運算 能夠理解爲相加 那麼 若是 a[row] |= 1 << (n & 0x1F) 得出結果爲 7
那麼確定是由 0111 構成,那麼 無論是 0001 (1) 、 0010 (2)、0100(4) 與 0111 & 運算
其結果確定有相同位置 同1 也就是必定不爲0
應用範圍: 能夠運用在快速查找、去重、排序、壓縮數據等。