第一章主要讨论了一个对一个包含1000万条的整数文件排序问题, 很有baidu面试题的风格。
主要思想是hash来解决排序问题,但是hash的空间复杂度又相对比较大,所以用bitmap来减少hash算法所需的空间。
一般的hash,例如对数组[2, 3, 5, 10] 运用桶排序算法,需要声明10个整数的bucket,如下图所示:
0 | 1 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 1 |
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
但是如果用bitmap的话,只需一个整数,因为一个整数(32位机)的话有32bit,每个bit都能map一个整数,如下图所示:
1 | 1 | 1 | 1 | |||||||||||||
31 | 30 | … | 3 | 2 | 1 | 0 | 31 | … | 9 | … | 5 | 4 | 3 | 2 | 1 | 0 |
数组元素1 | 数组元素0 |
所以关键就是位操作set, clear, test:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
例如某公司面试题:
在一个文件中有 10G 个整数,乱序排列,要求找出中位数。内存限制为 2G。只写出思路即可。
10G整数做bitmap需要10G/32 = 0.3G 个整数(< 32位机器总共可以的2^31-1 = 2G个整数),0.3G个整数只需要0.3G*4=1.2G的存储空间,故可以只扫描一遍,就可以求出中位数。
public class BitMap {
private static byte[] bitMap = null;
public BitMap(int size) {
if (size % 8 == 0) {
bitMap = new byte[size / 8];
} else {
bitMap = new byte[size / 8 + 1];
}
}
public static void main(String[] args) {
BitMap map = new BitMap(10);
map.setTag(11);
map.printBitMap();
String string = "";
for (int i = 0; i < bitMap.length; i++) {
System.out.println(string + bitMap[i]);
}
}
public void setTag(int number) {
int index = 0;
int bit_index = 0;
if (number % 8 == 0) {
index = number / 8 - 1;
bit_index = 8;
} else {
index = number / 8;
bit_index = number % 8;
}
switch (bit_index) {
case 1:
bitMap[index] = (byte) (bitMap[index] | 0x01);
break;
case 2:
bitMap[index] = (byte) (bitMap[index] | 0x02);
break;
case 3:
bitMap[index] = (byte) (bitMap[index] | 0x04);
break;
case 4:
bitMap[index] = (byte) (bitMap[index] | 0x08);
break;
case 5:
bitMap[index] = (byte) (bitMap[index] | 0x10);
break;
case 6:
bitMap[index] = (byte) (bitMap[index] | 0x20);
break;
case 7:
bitMap[index] = (byte) (bitMap[index] | 0x40);
break;
case 8:
bitMap[index] = (byte) (bitMap[index] | 0x80);
break;
}
}
public void printBitMap() {
int size = bitMap.length;
for (int i = 0; i < size; i++) {
if ((bitMap[i] & 0x01) == 1) {
System.out.print(i * 8 + 1 + " ");
}
if ((bitMap[i] >> 1 & 0x01) == 1) {
System.out.print(i * 8 + 2 + " ");
}
if ((bitMap[i] >> 2 & 0x01) == 1) {
System.out.print(i * 8 + 3 + " ");
}
if ((bitMap[i] >> 3 & 0x01) == 1) {
System.out.print(i * 8 + 4 + " ");
}
if ((bitMap[i] >> 4 & 0x01) == 1) {
System.out.print(i * 8 + 5 + " ");
}
if ((bitMap[i] >> 5 & 0x01) == 1) {
System.out.print(i * 8 + 6 + " ");
}
if ((bitMap[i] >> 6 & 0x01) == 1) {
System.out.print(i * 8 + 7 + " ");
}
if ((bitMap[i] >> 7 & 0x01) == 1) {
System.out.print(i * 8 + 8 + " ");
}
}
System.out.println();
}
}