前言
今天遇到一个求未排序数组中重复数的算法题,要求时间复杂度O(n),本来使用的是map实现的,但是波波说有更好的bitmap算法,并给了我他的博客链接,看完之后豁然开朗。
bitmap算法的定义
Bitmap就是用一个bit位来标记某个元素对应的Value, 而Key即是该bit的位序。由于采用了Bit为单位来存储数据,因此可以大大节省存储空间。 bitmap通过1个位表示一个状态,比如:int类型有2^32个数字,即4G个数字,那么每个数字一个状态,就是2^32个bit,即512 MB(也就是说,用512兆存储空间就可以处理4G个数据,即40+亿数据)。
优点与缺点
- 优点:
- 排序查询效率高,时间复杂度:O(n)
- 占用内存少,比如N=10000000;只需占用内存为N/8=1250000Byte=1.25M。
- 缺点:所有的数据不能重复。即不可对重复的数据进行排序和查找。
存储结构
首先存入一个数字5,则放入第5位
00000000000000000000000000100000
而存入2的时候
00000000000000000000000000100100
输入3时候
00000000000000000000000000101100
输入10的时候
00000000000000000000010000101100
下面是我用java实现的一个bitmap类
public class BitMap {
public static final byte B = 1;
public static final byte KB = 2;
public static final byte MB = 3;
private static final byte[] bit = new byte[] { -128, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1 };
private final int mMemory;
private int mAvailableSize;
private byte mArray[];
private BitMap() {
mMemory = 0;
}
// 指定bitmap的内存大小
BitMap(int memory, int units) {
switch (units) {
case B:
mMemory = memory;
break;
case KB:
mMemory = memory * 1024;
break;
case MB:
mMemory = memory * 1048576;
break;
default:
throw new IllegalArgumentException("参数units必须在1~3之间");
}
mArray = new byte[mMemory];
mAvailableSize = mMemory * 8;
}
// 添加元素
public boolean add(int num) {
if (num >= mMemory * 8) {
return false;
}
mArray[num / 8] |= bit[num % 8];
mAvailableSize--;
return true;
}
// 检查此元素是否存在
public boolean isInMap(int num, boolean flag) {
if (num >= mMemory * 8) {
return false;
}
return ((mArray[num / 8] & bit[num % 8]) != 0);
}
// 返回能存储的数据个数
public int getMemory() {
return mAvailableSize;
}
}