Bit-map就是用一个bit位来标记某个元素对应的Value, 而Key即是该元素。由于采用了Bit为单位来存储数据,因此在存储空间方面,可以大大节省。
1. Bit-map应用
1)可进行数据的快速查找,判重,删除,一般来说数据范围是int的10倍以下。
2)去重数据而达到压缩数据
2. Bit-map算法评价
优点:
1. 运算效率高,不进行比较和移位;
2. 占用内存少,比如最大的数MAX=10000000;只需占用内存为MAX/8=1250000Byte=1.25M。
缺点:
1. 所有的数据不能重复,即不可对重复的数据进行排序。(少量重复数据查找还是可以的,用2-bitmap)。
2. 当数据类似(1,1000,10万)只有3个数据的时候,用bitmap时间复杂度和空间复杂度相当大,只有当数据比较密集时才有优势。
3. Bit-map算法示例
3.1 只需要1个8bit空间的例子
假设要对0-7内的5个元素(4,7,2,5,3)排序(这里假设这些元素没有重复)。那么就可以采用Bit-map的方法来达到排序的目的。
用8个Bit(1Bytes)来表示0-7内的8个数,并将这些空间的所有Bit位都置为0(如下图):
然后遍历这5个元素,首先第一个元素是4,那么就把4对应的位置为1(可以这样操作 p+(i/8)|(0×01<<(i%8)) 当然了这里的操作涉及到Big-ending和Little-ending的情况,这里默认为Big-ending。不过计算机一般是小端存储的,如intel。小端的话就是将倒数第5位置1),因为是从零开始的,所以要把第五位置为一(如下图):
然后再处理第二个元素7,将第八位置为1,,接着再处理第三个元素,一直到最后处理完所有的元素,将相应的位置为1,这时候的内存的Bit位的状态如下:
最后遍历一遍Bit区域,将位置是1的对应的编号输出(2,3,4,5,7),这样就达到了排序的目的。
3.2 需要多个8bit空间的例子
假设需要排序或者查找的最大数MAX=10000000(这里MAX应该是最大的数而不是int数据的总数!),那么我们需要申请内存空间的大小为int a[1 + MAX/32],在内存中int占4个字节共32位。其中:a[0]在内存中占32为可以对应十进制数0-31,依次类推:
bitmap表为:
a[0]--------->0-31
a[1]--------->32-63
a[2]--------->64-95
a[3]--------->96-127
..........
要把一个整数N映射到Bit-Map中去,首先要确定把这个N Mapping到哪一个数组元素中去,即确定映射元素的index。我们用int类型的数组作为map的元素,这样我们就知道了一个元素能够表示的数字个数(这里是32)。于是N/32就可以知道我们需要映射的key了。所以余下来的那个N%32就是要映射到的位数。比如:N=65,65/32=2(-->对应在数组a中的下标为1,a[1]),65%32=1(--> 对应0-31的第1位),那么65的位置应该在a[1]的0-31中的第1位置。
4. 移位操作的实现
4.1 移位实现:求十进制数对应在数组a中的下标i
i = n>>K 等同于 n/(2^K)
int型数组,数组的每个元素都是int,int需要32bit的空间。所以先由十进制数n转换为与32的余可转化为对应在数组a中的下标。如十进制数0-31,都应该对应在a[0]中,比如n=24,那么 n/32=0,则24对应在数组a中的下标为0。又比如n=60,那么n/32=1,则60对应在数组a中的下标为1,同理可以计算0-N在数组a中的下标。
如果要求n在int型数组中的下标,那么就需要n/32,所以上面公式K=5。
Note: map的范围是[0, 原数组最大的数对应的2的整次方数-1]。
4.2 移位实现:求十进制数在数组元素a[i]中0-31的位置m
m = n & ((1 << K) - 1) 等同于 n%(2^K)
十进制数0-31就对应0-31,而32-63则对应也是0-31,即给定一个数n可以通过模32求得对应0-31中的数。如果要求n在a[i]中的0-31的具体位置,那么就需要n%32,所以上面公式K=5。
4.3 移位实现:设置int型a[i]的0-31中第m位的bit位为1
a[i] = a[i] | (1<<m)
利用移位0-31使得对应第m个bit位为1。如:将当前4对应的bit位置1的话,只需要1左移4位与B[0] | 即可。
Note: 1 p+(i/8)|(1<<(i%8))这样也可以?
4.4 移位实现:设置int型a[i]的0-31中第k位的bit位为0
a[i] = a[i] & ~(1<<k)