一、結構思想
以 bit 作為存儲單位進行 0、1存取的數據結構。
可用作布爾值存取,比如給定第i位,該bit為1則表示true,為0則表示false。
二、使用場景及優點
適用於對布爾或0、1值進行(大量)存取的場景。
如:記錄一個用戶365天的簽到記錄,簽了為true,沒簽為false。若是以普通key/value數據結構,每個用戶都需要記錄365條,當用戶量很大時會造成巨大的空間開銷。
因此運用位圖的話,每天簽到記錄只占1個位(bit),一共就365位,則只需48個字節就能容納一個用戶一年的簽到記錄。
優點:
低空間開銷且高效的0、1存取方案
三、具體實現
實現源碼:https://github.com/SimpleIto/data_structure/blob/master/src/bitmap/Bitmap.java
主要考慮以下問題:
- 用什么物理結構存儲一系列bit?
- 如何通過位操作高效的實現對指定bit的獲取、修改操作?(而不是通過字符串轉去轉來臃腫的實現)
解決思路:
- Java中,使用 byte[] 字節數組來存儲bit。 1 byte = 8 bit
- 對於獲取操作
思路:拿到目標bit所在的byte后,將其向右位移(並將高位置0),使目標bit在第一位,這樣結果值就是目標bit值。
- 通過 byte[index >> 3] (等價於byte[index/8])取到目標bit所在的byte。
- 令 i = index&7(等價於index%8)得到目標bit在該byte中所在的位置。
- 為了將目標bit前面的高位置0(這樣位移后的值才等於目標bit本身):需要構建到目標bit為止的低位掩碼,即 0b11111111 >>>(7 - i),再與原byte做&運算。
- 最后將結果向右位移 i 位,使目標bit處在第一位,結果值即為所求。
- 對於修改操作
思路:根據設定值true或false的不同,分為兩種操作邏輯
- 如果value為true,則目標位應與1做“或”運算。需構建“目標位為1,其他為0”的操作數(因為實際操作的是byte,為了只修改目標bit,而不影響其他位)
- 如果value為false,則目標位應與0做“與”運算。則需構建“目標位為0,其他為1”的操作數。
- 構建目標位為1其他位為0的操作數:1 << (index & 7)