Java中Bitmap的實現(xiàn)

說bitmap之前漆撞,我們要明白數(shù)字在內(nèi)存中的表示圣贸,如果說byte用8個二進制位表示挚歧,即可以表示2^8 = 256個數(shù),每個byte占8位吁峻,即每個byte占8行滑负,在內(nèi)存中這樣形象的表示:


要說明的一點是,上面框里只是說這個數(shù)是怎樣表示的用含,并沒有說那是內(nèi)存地址矮慕,不要搞混了。
而bitmap結(jié)構(gòu)啄骇,充分利用了每一行所有的位數(shù)痴鳄,它將每個位置作為一個數(shù),那么一行就可以模擬表示出8個數(shù)缸夹。

Bitmap介紹

bitmap是很有用的結(jié)構(gòu)痪寻。所謂的bitmap就是用一個bit位來標記某個元素,而數(shù)組下標是該元素明未。

bitmap優(yōu)勢

bitmap經(jīng)常用在大數(shù)據(jù)的題中槽华,比如10億個int類型的數(shù),如果用int數(shù)組存儲的話趟妥,那么需要大約4G內(nèi)存猫态,浪費內(nèi)存。如果用bitmap解決披摄,就比較方便亲雪。bitmap可以用int來模擬,也可以用byte來模擬疚膊,它只是邏輯上的概念义辕,在java語言中寫不出來,我們采用byte寓盗。一個byte占8個bit灌砖,如果每一個bit的值是有或者沒有璧函,即1或0,則如下圖所示:


比如基显,當我們用 int 類型來模擬 Bitmap 時蘸吓,一個 int 4個字節(jié)共 4*8 = 32位,可以表示32個數(shù)撩幽。原來10億個 int 類型的數(shù)用 int 數(shù)組需要 4G 的內(nèi)存库继,但是我用 bitmap 只需要 4GB / 32 = 128 MB 的內(nèi)存,是不是少多了窜醉。

bitmap代碼實現(xiàn)

第一步:構(gòu)建特定長度的byte數(shù)組(new byte[capacity/8 + 1])宪萄,其中capacity為整數(shù)數(shù)組長度(如:10億個數(shù)字等)

byte[] bits = new byte[getIndex(n) + 1];

第二步:計算數(shù)字num在byte[]中的位置(num/8和num >> 3一樣),也就是說num在byte[k]榨惰,算這個k是幾

    /**
     * num/8得到byte[]的index
     * @param num
     * @return
     */
    public int getIndex(int num){
        return num >> 3;
    }

第三步:計算數(shù)字num在byte[index]中的位置拜英,就是在byte[index]的第幾位,每個byte有8位(num % 8)

    /**
     * num%8得到在byte[index]的位置
     * @param num
     * @return
     */
    public int getPosition(int num){
        return num & 0x07;
    }

第四步:將所在位置從0變成1琅催,其它位置不變

    /**
     * 標記指定數(shù)字(num)在bitmap中的值聊记,標記其已經(jīng)出現(xiàn)過
     * 將1左移position后,那個位置自然就是1恢暖,然后和以前的數(shù)據(jù)做|排监,這樣,那個位置就替換成1了
     * @param bits
     * @param num
     */
    public void add(byte[] bits, int num){
        bits[getIndex(num)] |= 1 << getPosition(num);
    }

解釋如下圖:


第五步:判斷指定數(shù)字num是否存在

    /**
     * 判斷指定數(shù)字num是否存在<br/>
     * 將1左移position后杰捂,那個位置自然就是1舆床,然后和以前的數(shù)據(jù)做&,判斷是否為0即可
     * @param bits
     * @param num
     * @return
     */
    public boolean contains(byte[] bits, int num){
        return (bits[getIndex(num)] & 1 << getPosition(num)) != 0;
    }

第六步:重置某一數(shù)字對應(yīng)在bitmap中的值

    /**
     * 重置某一數(shù)字對應(yīng)在bitmap中的值<br/>
     * 對1進行左移嫁佳,然后取反挨队,最后與byte[index]作與操作。
     * @param bits
     * @param num
     */
    public void clear(byte[] bits, int num){
        bits[getIndex(num)] &= ~(1 << getPosition(num));
    }

全部代碼如下:

public class Test {

    /**
     * 創(chuàng)建bitmap數(shù)組
     */
    public byte[] create(int n){
        byte[] bits = new byte[getIndex(n) + 1];
        
        for(int i = 0; i < n; i++){
            add(bits, i);
        }
        
        System.out.println(contains(bits, 11));
        
        int index = 1;
        for(byte bit : bits){
            System.out.println("-------" + index++ + "-------");
            showByte(bit);

        }
        
        return bits;
    }
    
    /**
     * 標記指定數(shù)字(num)在bitmap中的值蒿往,標記其已經(jīng)出現(xiàn)過<br/>
     * 將1左移position后盛垦,那個位置自然就是1,然后和以前的數(shù)據(jù)做|瓤漏,這樣腾夯,那個位置就替換成1了
     * @param bits
     * @param num
     */
    public void add(byte[] bits, int num){
        bits[getIndex(num)] |= 1 << getPosition(num);
    }
    
    /**
     * 判斷指定數(shù)字num是否存在<br/>
     * 將1左移position后,那個位置自然就是1蔬充,然后和以前的數(shù)據(jù)做&蝶俱,判斷是否為0即可
     * @param bits
     * @param num
     * @return
     */
    public boolean contains(byte[] bits, int num){
        return (bits[getIndex(num)] & 1 << getPosition(num)) != 0;
    }
    
    /**
     * num/8得到byte[]的index
     * @param num
     * @return
     */
    public int getIndex(int num){
        return num >> 3;
    }
    
    /**
     * num%8得到在byte[index]的位置
     * @param num
     * @return
     */
    public int getPosition(int num){
        return num & 0x07;
    }
    
    /**
     * 重置某一數(shù)字對應(yīng)在bitmap中的值<br/>
     * 對1進行左移,然后取反饥漫,最后與byte[index]作與操作榨呆。
     * @param bits
     * @param num
     */
    public void clear(byte[] bits, int num){
        bits[getIndex(num)] &= ~(1 << getPosition(num));
    }
    
    /**
     * 打印byte類型的變量<br/>
     * 將byte轉(zhuǎn)換為一個長度為8的byte數(shù)組,數(shù)組每個值代表bit
     */
    
    public void showByte(byte b){
        byte[] array = new byte[8];
        for(int i = 7; i >= 0; i--){
            array[i] = (byte)(b & 1);
            b = (byte)(b >> 1);
        }
        
        for (byte b1 : array) {
            System.out.print(b1);
            System.out.print(" ");
        }
        
        System.out.println();
    }
    
    public static void main(String[] args) {
        int n = 100;
        new Test().create(n);
    }
}

結(jié)果如圖庸队,一共100個數(shù):


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末积蜻,一起剝皮案震驚了整個濱河市闯割,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌竿拆,老刑警劉巖纽谒,帶你破解...
    沈念sama閱讀 221,430評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異如输,居然都是意外死亡,警方通過查閱死者的電腦和手機央勒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,406評論 3 398
  • 文/潘曉璐 我一進店門不见,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人崔步,你說我怎么就攤上這事稳吮。” “怎么了井濒?”我有些...
    開封第一講書人閱讀 167,834評論 0 360
  • 文/不壞的土叔 我叫張陵灶似,是天一觀的道長。 經(jīng)常有香客問我瑞你,道長酪惭,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,543評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上贺拣,老公的妹妹穿的比我還像新娘璃岳。我一直安慰自己,他們只是感情好因悲,可當我...
    茶點故事閱讀 68,547評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般窥岩。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上宰缤,一...
    開封第一講書人閱讀 52,196評論 1 308
  • 那天颂翼,我揣著相機與錄音,去河邊找鬼慨灭。 笑死疚鲤,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的缘挑。 我是一名探鬼主播集歇,決...
    沈念sama閱讀 40,776評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼语淘!你這毒婦竟也來了诲宇?” 一聲冷哼從身側(cè)響起际歼,我...
    開封第一講書人閱讀 39,671評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎姑蓝,沒想到半個月后鹅心,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,221評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡纺荧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,303評論 3 340
  • 正文 我和宋清朗相戀三年旭愧,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片宙暇。...
    茶點故事閱讀 40,444評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡输枯,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出占贫,到底是詐尸還是另有隱情桃熄,我是刑警寧澤,帶...
    沈念sama閱讀 36,134評論 5 350
  • 正文 年R本政府宣布型奥,位于F島的核電站瞳收,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏厢汹。R本人自食惡果不足惜螟深,卻給世界環(huán)境...
    茶點故事閱讀 41,810評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望烫葬。 院中可真熱鬧血崭,春花似錦、人聲如沸厘灼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,285評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽设凹。三九已至舰讹,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間闪朱,已是汗流浹背月匣。 一陣腳步聲響...
    開封第一講書人閱讀 33,399評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留奋姿,地道東北人锄开。 一個月前我還...
    沈念sama閱讀 48,837評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像称诗,于是被迫代替她去往敵國和親萍悴。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,455評論 2 359

推薦閱讀更多精彩內(nèi)容