vlambda博客
学习文章列表

实现大量数据的快速排序、查找、去重——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提供的BitSetjava.util.BitSet


使用场景


对海量数据进行一些统计工作,比如日志分析、用户数统计等。