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;
}
以上