本文源于三篇文章:
http://blog.chinaunix.net/uid-22663647-id-1771837.html
http://www.wikieno.com/2012/03/data-structure-bitmap/
http://blog.csdn.net/zhoubl668/article/details/6781587
在此,感谢三位作者的分享。
这三篇文章,我费了一段时间才理解,其中隐去了部分过程细节,所以,对于初学者不太容易理解。在此,我简介下我的理解过程,希望对于初学bitmap的道友有所帮助,文中可能存在部分错误,欢迎留言指出。
1 对数组array[4,7,2,5,3]排序
bitmap采用的是以空间换时间的思想,数组中最大元素值为7,所以在内存中开辟8位的存储空间,存储空间大小的确定方法是(元素最大值/8+1),之所以除以8,是因为开辟空间的时候以byte为单位,1byte=8bit。
开辟8位的空间后,每位初始化为0,如下表:
0号位 | 1号位 | 2号位 | 3号位 | 4号位 | 5号位 | 6号位 | 7号位 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
开始遍历array数组,array[0]=4时,则将4号位’置1,变为下表:
0号位 | 1号位 | 2号位 | 3号位 | 4号位 | 5号位 | 6号位 | 7号位 |
0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
array[1]=7时,则将7号位置1,变为下表:
0号位 | 1号位 | 2号位 | 3号位 | 4号位 | 5号位 | 6号位 | 7号位 |
0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 |
直至遍历完array数组,空间各位如下表:
0号位 | 1号位 | 2号位 | 3号位 | 4号位 | 5号位 | 6号位 | 7号位 |
0 | 0 | 1 | 1 | 1 | 1 | 0 | 1 |
从头开始遍历空间中各位,不为0的输出其为号,得:2,3,4,5,7,其效率为O(n)=8
2 8位电话号码问题
初始化空间如下表:
0号位 | 1号位 | ... | ... | 9999 9999号位 |
0 | 0 | 0 | 0 | 0 |
读到一个号码时,将该号码对应的号位置1,最后遍历存储空间的各位,其消耗的空间为(10^8b)/(8*10^6)=12.5MByte,除以8是把位转换为字节,除以10^6是转换为M,(篇头三篇文章的结果为1.25MByte,不知道怎么计算的,知道的朋友请留意,先谢了),效率为O(n)=10^8
3 开辟空间及数据存储的方式
以array[1,2,5,8,10]为例:
初始化空间如下表:
0号位 | 1号位 | 2号位 | 7号位 | 8号位 | 15号位 | 15号位 | |||||||||
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
申请时以字节申请空间:g_bitmap = (char *)malloc((size/8+1)*sizeof(char));
此时将上表从7号位处分开(即2个字节的空间,定义字节数组byte[]):
0号位 | 1号位 | ... | 7号位 |
0 | 0 | ... | 0 |
0号位 | 1号位 | ... | 7号位 |
0 | 0 | ... | 0 |
读取array[0]=1时,
array[0]/8=0——>byte[0]
array[0]%8=1——>1号位,即将byte[0]中的1号位置1,
读取array[4]=10时,
array[0]/8=1——>byte[1]
array[0]%8=2——>2号位,即将byte[1]中的2号位置1,
最后,空间变为:
0号位 | 1号位 | 2号位 | 3号位 | 4号位 | 5号位 | 6号位 | 7号位 |
0 | 1 | 1 | 0 | 0 | 1 | 0 | 0 |
0号位 | 1号位 | 2号位 | 3号位 | 4号位 | 5号位 | 6号位 | 7号位 |
1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
遍历每个byte[]下的每位,为1的输出(逆运算得到该位在array[]中的值),
上面的两个例子在编程时,也经过这样的处理,详细可参考篇头biti-leaf的程序,
将他的代码全都放在同一.cpp文件中,稍作修改即可在VC6.0中运行。