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