在海量數據中查找出重複出現的元素或者去除重複出現的元素是面試中常考的文圖。針對此類問題,可以使用位圖法來解決。例如:已知某個文件內包含若干個電話號碼,要求統計不同的號碼的個數,甚至在O(n)時間複雜度內對這些號碼進行排序。
位圖法需要的空間很少(依賴於數據分佈,但是我們也可以通過一些放啊發對數據進行處理,使得數據變得密集),在數據比較密集的時候效率非常高。例如:8位整數可以表示的最大十進制數值爲99999999,如果每個數組對應於一個bit位,那麼把所有的八進制整數存儲起來只需要:99Mbit = 12.375MB.
實際上,java jdk1.0已經提供了bitmap的實現BitSet類,不過其中的某些方法是jdk1.4之後纔有的。
下面我先自己實現一下bitmap 的原理,然後再直接調用jdk的BitSet類分別實現bitmap, 方便比較理解:
package swordoffer;
//去除重複並排序
import java.util.Arrays;
import java.util.BitSet;
import java.util.Random;
/**
* @author Gavenyeah
* @date Time: 2016年4月15日下午9:20:21
* @des:
*/
public class BitMap {
int ARRNUM = 800;
int LEN_INT = 32;
int mmax = 9999;
int mmin = 1000;
int N = mmax - mmin + 1;
public static void main(String args[]) {
new BitMap().findDuplicate();
new BitMap().findDup_jdk();
}
public void findDup_jdk() {
System.out.println("*******調用JDK中的庫方法--開始********");
BitSet bitArray = new BitSet(N);
int[] array = getArray(ARRNUM);
for (int i = 0; i < ARRNUM; i++) {
bitArray.set(array[i] - mmin);
}
int count = 0;
for (int j = 0; j < bitArray.length(); j++) {
if (bitArray.get(j)) {
System.out.print(j + mmin + " ");
count++;
}
}
System.out.println();
System.out.println("排序後的數組大小爲:" + count );
System.out.println("*******調用JDK中的庫方法--結束********");
}
public void findDuplicate() {
int[] array = getArray(ARRNUM);
int[] bitArray = setBit(array);
printBitArray(bitArray);
}
public void printBitArray(int[] bitArray) {
int count = 0;
for (int i = 0; i < N; i++) {
if (getBit(bitArray, i) != 0) {
count++;
System.out.print(i + mmin + "\t");
}
}
System.out.println();
System.out.println("去重排序後的數組大小爲:" + count);
}
public int getBit(int[] bitArray, int k) {// 1右移 k % 32位 與上 數組下標爲 k/32 位置的值
return bitArray[k / LEN_INT] & (1 << (k % LEN_INT));
}
public int[] setBit(int[] array) {// 首先取得數組位置下標 i/32, 然後 或上
// 在該位置int類型數值的bit位:i % 32
int m = array.length;
int bit_arr_len = N / LEN_INT + 1;
int[] bitArray = new int[bit_arr_len];
for (int i = 0; i < m; i++) {
int num = array[i] - mmin;
bitArray[num / LEN_INT] |= (1 << (num % LEN_INT));
}
return bitArray;
}
public int[] getArray(int ARRNUM) {
@SuppressWarnings("unused")
int array1[] = { 1000, 1002, 1032, 1033, 6543, 9999, 1033, 1000 };
int array[] = new int[ARRNUM];
System.out.println("數組大小:" + ARRNUM);
Random r = new Random();
for (int i = 0; i < ARRNUM; i++) {
array[i] = r.nextInt(N) + mmin;
}
System.out.println(Arrays.toString(array));
return array;
}
}