1. 程式人生 > >Bit-Map實現查詢陣列中的重複數字

Bit-Map實現查詢陣列中的重複數字

Bit-Map中文翻譯為點陣圖,其實和本文所謂的Bit-Map是有出入的。

所謂的Bit-Map就是用一個bit位來標記某個元素對應的Value, 而Key即是該元素。由於採用了Bit為單位來儲存資料,因此在儲存空間方面,可以大大節省。

查詢一個數組中的重複數字,假設陣列時從0開始的,且陣列是亂序的,不用Bit-Map的方法就是申請一個boolean陣列,陣列的長度等於要去重陣列的長度 。然後遍歷要去重的陣列,得到每個數字,在boolean陣列的相應索引位置判斷,如果為false,則更新為true,如果為true,則這個索引位置所對應的陣列是重複數字。

例如:要去重的陣列為 {2, 3, 2, 1, 5, 4},初始化boolean陣列 {false, false, false, false, false, false}

對陣列進行遍歷,第一個元素為 2 ,則boolean索引為 2 的位置進行更新操作。

更新後的beelean陣列為 {false, false, true, false, false, false}

下一個元素為 3 ,索引為 3 的元素為 false,說明 3 還沒有出現過,則更新為true。

更新後的boolean陣列為 {false, false, true, true, false, false}

下一個元素為 2 ,索引為 2 的元素為 true,說明 2 已經出現過,則元素 2 為第一個重複的元素。

程式碼實現:

public boolean duplicate(int[] numbers) {
    if(numbers == null && numbers.length == 0) return false;
    boolean[] b = new boolean[numbers.length];
    for(int i = 0; i < numbers.length; i++) {
        if(b[numbers[i] == false) {
            b[numbers[i]] = true;
        } else {
            return false         //說明陣列有重複元素
        }    
    }
    return true                //陣列無重複元素
}

程式碼實現非常簡單,但是有一個問題,boolean型別在java中所佔的位元組,可以參考:        https://blog.csdn.net/YuanMxy/article/details/74170745

從網上查閱資料瞭解到,boolean的大小JVM規範並沒有指定。那boolean的大小就取決於JVM是如何實現的了。但是大多數實踐發現,一個boolean所佔大小為 1byte 。 http://blog.51cto.com/mb1069/1077652 

1byte = 8bit,虛擬機器的實現可能是用 0000 0001 表示 true,用 0000 0000 表示false,有 8 個位,但是隻用到了 1 個位,在如今大資料的時代下,這是非常嚴重的記憶體浪費。在記憶體相同的情況下,如果 8個位 全部利用起來,可能使一次處理資料的數量提升 8倍。所以我們就要考慮把另外的七個位利用起來。

Bit-Map用byte簡單實現方法:

用byte陣列,一個byte所佔記憶體空間為 1位元組 ,也就是 8bit,但是卻可以表示8種狀態。還拿上面的去重陣列舉例

去重陣列 {2, 3, 0, 1, 3, 4},初始化一個byte,值為 0, 二進位制位 0000 0000。

一個byte可以表示 0 ~ 7。對陣列進行遍歷,第一個元素為 2,則把第三位也就是 2 的位置置為 1。

現在byte表示有一個元素 2 。

下一個元素為 3,則把第三位置為 1。

下一個為 0 。

下一個為1 。

再下一個為 3 ,但是此時 3 的位置已經被置為 1 了,所以 3 是第一個重複的元素。

Bit-Map大致原理就是這樣,本來用 6 byte 才能搞定的事情,現在用 1 byte就能搞定。

實現程式碼如下:

private static byte[] bitmap;

public static void initBitMap(int capacity) {
    int length = numbers.length % 8 == 0 ? numbers.length / 8 : numbers.length / 8 + 1;
    bitmap = new byte[length];    //如果numbers.length % 8 == 0,就不用 + 1

}
    
public static boolean setBit(int index) {
    int bIndex = index % 8;
    index = index / 8;
    byte b = (byte) (bitmap[index] >> bIndex);
    //以下程式碼有很大的改進空間,留給小夥伴們了
    if((b & 0x01) == 1) return false;
    byte temp = (byte) (0x01 << bIndex);
    bitmap[index] = (byte) (bitmap[index] | temp);
    return true;
}

public static boolean duplicate(int[] numbers) {
    if(numbers == null || numbers.length == 0) return false;
    initBitMap(numbers.length);
    for(int i = 0; i < numbers.length; ++i) {
        if(!setBit(numbers[i]) return false;
    }
    return true;
}

以上