实现大量数据的快速排序、查找、去重——BitMap(位图法)
问题引子
有1千万个随机数,随机数的范围在1到1亿之间。现在要求写出一种算法,将1到1亿之间没有在随机数中的数求出来。
BitMap(位图法)原理
用1位来标记一个数据是否出现过,0表示没有出现过,1表示出现过。使用的时候根据此位是否为0来判断此数是否存在。
用一个位(bit)来标记某个数据的存放状态,由于采用了位为单位来存放数据,所以节省了大量的空间。
一个1G的空间,有 8*1024*1024*1024bit,也就是大约可以表示85亿个不同的数。
BitMap(位图法)实现
public class BitMap {
/**
* 定义标记数据是否存在的数组
*/
private long[] words;
/**
* 定义需要标记数据的个数
*/
private int capacity;
public BitMap(int capacity) {
this.capacity = capacity;
/* 1byte(字节)能存储8bit(位)数据,1long(长整型)占8个byte,那么capacity数据需要多少个long呢?
* (capacity-1)/64+1,右移6位相当于除以64
*/
int length = ((this.capacity - 1) >> 6) + 1;
words = new long[length];
}
// 标记数据
public void set(int bitIndex) {
// bitIndex/64得到long[] words的wordIndex
int wordIndex = bitIndex >> 6;
// // bitIndex%64得到在byte[index]的位置
// int position = bitIndex & 0x3F;
// // 将1左移position后,那个位置自然就是1,然后和以前的数据做|,这样,那个位置就替换成1了。
// words[wordIndex] |= 1 << position;
// 此步操作等价于上述注释的两步操作
words[wordIndex] |= 1L << bitIndex;
}
// 判断数据是否存在
public boolean contain(int bitIndex) {
// bitIndex/64得到long[] words的wordIndex
int wordIndex = bitIndex >> 6;
// bitIndex%64得到在byte[index]的位置
int position = bitIndex & 0x3F;
// 将1左移position后,那个位置自然就是1,然后和以前的数据做&,判断是否为0即可
return (words[wordIndex] & (1 << position)) != 0;
}
// 清除数据
public void clear(int bitIndex) {
// bitIndex/64得到long[] words的wordIndex
int wordIndex = bitIndex >> 6;
// bitIndex%64得到在byte[index]的位置
int position = bitIndex & 0x3F;
// 将1左移position后,那个位置自然就是1,然后对取反,再与当前值做&,即可清除当前的位置了.
words[wordIndex] &= ~(1 << position);
}
}
问题解决:
public static void main(String[] args) {
int oneBillion = 1000000000;
int tenMillion = 100000000;
BitMap bitmap = new BitMap(oneBillion);
Random random = new Random();
// 放入随机数
for (int i = 0; i < tenMillion; i++) {
bitmap.set(random.nextInt(oneBillion));
}
// 输出没有在随机数中的数字
for (int i = 0; i < oneBillion; i++) {
if (!bitmap.contain(i)) {
System.out.println(i);
}
}
}
JDK提供的BitMap(位图法)实现类
// 不需要自己实现,可以直接使用jdk提供的BitSet类
java.util.BitSet
使用场景
对海量数据进行一些统计工作,比如日志分析、用户数统计等。