上篇咱們講了BitMap是如何對數據進行存儲的,沒看過的能夠看一下【算法與數據結構專場】BitMap算法介紹java
這篇咱們來說一下BitMap這個數據結構的代碼實現。算法
一個二進制位對應一個非負數n,若是n存在,則對應的二進制位的值爲1,不然爲0。數組
這個時候,咱們的第一個問題:數據結構
咱們在使用byte,int,short,long等這些數據類型在存儲數據的時候,他們最小的都要佔用一個字節的內存,也就是8個bit,也就是說,最小的操做單位是8個bit。根本就沒有能夠一個一個bit位操做的數據類型啊。優化
在Java的bitMaP實現中,它採用的是用一個long數據來進行存儲的。一個long佔用8個字節,即64bit,因此一個long能夠存儲64個數。例如 arr 是一個long 類型的數組,則 arr[0]能夠存 0 ~ 63,arr[1]能夠存64 ~127,以此類推。this
不過,咱們就採用byte數組的來存吧。一個byte佔用一個字節,即8bit,能夠存8個數字。spa
固然,你要採用long數組來存也能夠。在實現上能夠說是同樣的。code
例如咱們要存儲(1,3,5,7,8,10)時,他們的內存以下所示。cdn
下面咱們就來說講如何對一個一個位進行操做的。blog
咱們先來講說如何在bitmap中如何添加一個數值的問題,例如咱們咱們要添加n=14。
這個其實很簡單,咱們先找到n在arr數組中的下標index,顯然index = 1。而後再找到n在arr[index]中的位置position,顯然這裏position = 6。
這裏仍是能夠很容易找出index和position的公式的。即
index = n / 8 = n >> 3。
position = n % 8 = n & 0x07。
接下來咱們把1向右移動position個二進制位,而後把所得的結果和arr[index]作「或(or)」操做就能夠了。以下圖
這裏有個須要注意的地方,在畫圖的時候,爲了方便,咱們是把左邊的位看成低位,右邊的位看成高位來算了。不過在實際的存儲中,左邊的纔是存高位,而右邊的存的是低位。因此在咱們的代碼實現中,咱們所說的右移對應代碼的左移。
代碼實現
//添加數據的操做
public void add(int n){
//用>>的操做是,運算會比較快
int index = n >> 3;
int position = n & 0x07;
//把1右移和作or操做兩步一塊兒
//即 << 對應上圖的右移,實際上<<是左移符。
arr[index] |= 1 << position;
}
複製代碼
知道了add操做,其餘的操做差很少相似。
固然,咱們實現的add操做只是簡單的實現一下,假如你要嚴謹地實現的話,仍是須要不少異常的判斷的。例如判斷這個數是不是非負數,判斷arr數組是否下標越界,進行容量的擴充等等。有興趣的能夠嚴謹去實現一下。
咱們只須要把對應的二進制的1變成0就能夠了。
咱們能夠把1右移(代碼中對應左移)後的結果取反,而後與arr[index]作「與」操做就能夠了。代碼以下:
public void delete(int n){
int index = n >> 3;
int position = n & 0x07;
arr[index] &= ~(1 << position);
}
複製代碼
咱們把1右移以後,把結果和arr[index]作「與」操做,如何結果不爲0,則證實存在,不然就不存在。
public boolean contain(int n){
int index = n >> 3;
int position = n & 0x07;
return (arr[index] & (1 << position)) != 0;
}
複製代碼
三個最基本的操做代碼基本實現了。
但願你們可以去實踐一下。
所有代碼:
public class BitMap {
private byte[] arr;
//容量,即最多可以存多少個數據
private int capacity;
public BitMap(int capacity) {
this.capacity = capacity;
//一個byte能夠存8個數據,capacity實際上指的是多少個bit
arr = new byte[(capacity / 8 + 1)];
}
//添加數據的操做
public void add(int n){
//用>>的操做是,運算會比較快
int index = n >> 3;
int position = n & 0x07;
//把1右移和作or操做兩步一塊兒
//即 << 對應上圖的右移,實際上<<是左移符。
arr[index] |= 1 << position;
}
public void delete(int n){
int index = n >> 3;
int position = n & 0x07;
arr[index] &= ~(1 << position);
}
public boolean contain(int n){
int index = n >> 3;
int position = n & 0x07;
return (arr[index] & (1 << position)) != 0;
}
}
複製代碼
你們看了以上的代碼,有沒發現一些問題呢?
例如咱們只在bitmap存儲1個數,而且存的數值是2000000000,咱們就會在第2000000000個二進制把0改成1。也就是說arr數組的大小至少爲2000000000/8+1。但是這時候前面的二進制位並無存數據,那不是超級超級浪費資源?
因此說,像咱們上面的那種寫法能夠說是暴力寫法,沒有通過任何優化,實際上,在Java自帶的bitMap中是有不少優化的,並不會像咱們上面實現的代碼同樣那麼浪費空間資源。有興趣的能夠研究下。
至於如何優化,我會在以後的文章講,盡情期待。
獲取更多原創文章,能夠關注下個人公衆號:苦逼的碼農,我會不按期分享一些資源和軟件等。後臺回覆禮包送你一份時下熱門的資源大禮包,同時也感謝把文章介紹給更多須要的人