數據結構精講:從原理到實戰–學習筆記02

數據結構精講:從原理到實戰–學習筆記02

本筆記是記錄學習 《數據結構精講:從原理到實戰》,作者是:蔡元楠,Google Brain資深工程師。

如有侵權,聯繫刪除!

位數組

位數組 (bit array) 也稱爲 位圖 (bit map)
如果我們需要用一種數據類型來記錄布爾值的數組,通常定義數組如下:

int[] d = new int[2];

這樣的特點是:每個int型變量來儲存一個布爾型變量,但是記錄單個布爾值只需要1位(bit),而32和64位中,java的int型變量都是4字節(byte)= 8 * 4 = 32 位。因此,我們浪費了31/32的內存空間。

倘若我們把每個int型變量的32位來表示32個布爾值的數組,這種將每個元素中的每一個比特位都作爲狀態信息存儲的數組稱之爲位數組(Bit Array)或者位圖(Bit Map)

上述定義的數組d在內存中如圖所示:
在這裏插入圖片描述
上述可以表示64個狀態位的數組。

當我們要操作位數組中在位置爲“i”這個比特位的時候,應該如何定位它呢?很簡單,可以按照下面的公式來定位。

所在數組中的元素爲: i / data_size
比特位在元素中的位置爲:i % data_size

那我們以定位索引爲 35 這個比特位爲例子來說明一下,套用上面的公式,可以得出:

所在數組中的元素爲: 35 / 32 = 1
比特位在元素中的位置爲:35 % 32 = 3

所以這個比特位是位於 d[1] 這個元素上索引爲 3 的位置

位數組的實現

一般來說因爲位數組的元素只保存“0”或者“1”兩種狀態,所以對於位數組的操作有以下幾種:

  1. 獲取某個位置的比特位狀態;

  2. 設置某個位置的比特位,也就是將那個位置的比特位設置爲“1”;

  3. 清除某個位置的比特位,也就是將那個位置的比特位設置爲“0”。

GetBit()

public boolean GetBit(int[] array, int index) {
        int elementIndex = index / 32;
        int position = index % 32;
        long flag = 1;
        flag = flag << position;
        if((array[elementIndex] & flag) != 0) {
            return true;
        } else {
            return false;
        }
    }

這裏 & 運算可以這樣理解:
偏移後的flag1的位置即爲所求位置,1array[elementIndex] 經過 & 運算後,flag中那個1所在的位置對應array[elementIndex] 中的位置的值如果爲1則返回真。如果覺得難以理解,可以參考下圖:
在這裏插入圖片描述
elementIndex爲1時,flag偏移3位後(flag末尾幾位爲:00001000),能夠檢驗圖中第35位的值是否爲1;若爲1則返回true,反之返回false。

SetBit()

public void SetBit(int[] array, int index) {
        int elementIndex = index / 32;
        int position = index % 32;
        long flag = 1;
        flag = flag << position;
        array[elementIndex] = (int) (array[elementIndex] | flag);
    }

ClearBit()

public void ClearBit(int[] array, int index) {
        int elementIndex = index / 32;
        int position = index % 32;
        long flag = 1;
        flag = ~flag << position;
        array[elementIndex] = (int) (array[elementIndex] & flag);
    }

Redis中的Bitmap數據結構

Redis 是一個開源的並且使用內存來作爲存儲空間的高效數據庫,感興趣的可以到官網 https://redis.io 上查看相關文檔。

Redis 裏面的一個數據結構——Bitmap在這裏插入圖片描述Bitmap 的本質其實是在 Redis 裏面通過一個 Strings 類型來表示的。在 Redis 中,Strings 的最大長度可以是 512MB。

在 Redis 裏面對 Bitmap 的操作命令有以下幾種:BITCOUNT、BITFIELD、BITOP、GETBIT、SETBIT。其中,GETBIT 和 SETBIT 命令和前面我們自己所實現的 GetBit 和 SetBit 操作原理是一樣的,感興趣的同學可以前往 GitHub 鏈接來查看 Redis 中 Bitmap 的源碼。

可以用 Redis 裏的 BITCOUNT、SETBIT 和 BITOP 來完成。BITCOUNT 這個命令其實是可以計算一個位數組裏有多少比特位是爲“1”的,而 BITOP 可以針對位數組進行“與”、“或”、“非”、“異或”這樣的操作。

Redis 的 Bitmap 操作之所以強大,是因爲所有操作都是位運算以及發生在內存中,所以速度極快。

位數組這種數據結構可以極大地優化內存空間,當我們要表達的狀態只有true和false時,便可以考慮使用這種數據結構。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章