【算法與數據結構專場】BitMap算法基本操做代碼實現

上篇咱們講了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中添加一個數值

咱們先來講說如何在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中是有不少優化的,並不會像咱們上面實現的代碼同樣那麼浪費空間資源。有興趣的能夠研究下。

至於如何優化,我會在以後的文章講,盡情期待。

獲取更多原創文章,能夠關注下個人公衆號:苦逼的碼農,我會不按期分享一些資源和軟件等。後臺回覆禮包送你一份時下熱門的資源大禮包,同時也感謝把文章介紹給更多須要的人

相關文章
相關標籤/搜索