Java数据结构之位图
之前寫過一篇涂鴉之作,使用redis位圖統計日活,位圖是常見的基于數組的數據結構,可以把數組中的每個字節的每一位都有效利用起來,這樣就可以大大節省空間,一個字節就可以記錄8個0或1的值,這就是位圖的基本思想,使用位圖可以輕松記錄日活,判斷某個數據是否存在,實現布隆過濾器等。
位圖在內部維護一個數組,數組中的每個字節占8位,所以要表示0~999這1000個數字只需要125個字節,對比我們通常使用的一個整數4字節而言,極大地節省了空間。
| 1 | 1 | … | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 |
當我們要存儲數據時,只需將目標位設置為1,即表示該數據存在,例如我們要記錄用戶號1,2,5,7當日活躍,可以使用1個字節表示。
| 1 | 0 | 1 | 0 | 0 | 1 | 1 | 0 |
下面使用Java模擬一下Bitmap。
在Java中使用byte來聲明一個字節,1byte = 8bit,使用一個字節數組即可,另外需要記錄字節數組的長度length,方便起見記錄下活躍數1的個數active。
public class Bitmap {private byte[] bytes;private int length;private int active;public Bitmap(int length) {length = length;bytes = new byte[length % 8 == 0 ? length / 8 : length / 8 + 1];} }有了基本的數據結構,我們將要設置的數據映射到目標bit位,這里根據value值true或false設置,其他值0或1均可。
當value值為true時,使用目標位所在的字節與1(左移目標位個位置,與目標位對齊)做或運算,目的就是把原字節中目標位設置為1。
當value值為false時,使用目標位所在的字節與1(左移目標位個位置,與目標位對齊,并取反) 做與運算,目的就是把原字節中目標位置設置為0,當然這里是兼顧修改操作,如果忽略修改操作,此步可省略。
設置true的時候順手記錄一下活躍個數,方便統計活躍數。
public void set(int index, boolean value) {int i = index % 8;if (value) {active++;bytes[index / 8] |= (1 << i);} else {bytes[index / 8] &= ~(1 << i);} }有了set操作,繼續實現一下get操作。
只需找到目標位 i 所在的字節,然后將目標位置為最高位,即將目標位左邊的位全部置為0,也即將目標位右移(7-i)個位置。
然后將獲得的值再次右移 i 位,就得到了目標位上的值,值為0則為false,值為1則為true。
public boolean get(int index) {int i = index % 8;if ((bytes[index / 8] & (0b11111111 >>> (7 - i))) >> i == 0) {return false;}return true; }獲取活躍數可以直接返回active的值。
public int getActive(){return active; }這樣就簡單實現了一個Java位圖,覺得有用,點個關注,如有錯誤,歡迎批評指正。同名公眾號「碼農小麥」。
總結
以上是生活随笔為你收集整理的Java数据结构之位图的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: php strtok函数,strtok函
- 下一篇: Java的随机数原理