算法系列-bitmap算法详解和实现

69 篇文章 2 订阅
69 篇文章 0 订阅

算法系列-bitmap算法详解和实现

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/tiankong_/article/details/77651076

1.什么是bitmap?

我们可以将bitmap看成是一种数据结构,所谓的Bit-map就是用一个(或几个)bit位来标记某个元素对应的state(value)。最基本的情况,使用1bit标示一个关键字的状态(可标示两种状态),但根据需要也可以使用2bit(标示4种状态),3bit(标示8种状态),当一个状态标示需要的位数达到32bit时,就演变成来一个整型数组了。

 

2.优点和缺点

优点:

由于采用了Bit为单位来存储数据并建立映射关系来查找位置,因此可以大大减少存储空间,加快在大量数据中查询的时间。(有点哈希表的意思,但哈希中的value值数据类型可以丰富多样,而bitmap最终查到的value只能表示简单的几种状态)

缺点:bitmap中的查询结果(value)能表达的状态有限,且所有的数据不能重复。即不可对重复的数据进行排序和查找。

 

3.bitmap实现

在真实项目中,我们是反感重复造轮子的,能使用稳定现成且开源的是最好,在一般情况下(不用笔试面试的时候),c++库中已经提供了bitmap容器(是一种位集合的容器,和普通数组一样使用即可,本质是一个模板类),以下是利用bitset容器实现简单的位图法排序

 

 
  1. #include <iostream>

  2. #include <bitset>

  3. #include <vector>

  4. using namespace std;

  5.  
  6. const unsigned int max_num = 20000; //最大数字

  7.  
  8. void BitmapSort(vector<unsigned int>& R)

  9. {

  10. bitset<max_num + 1> bit;

  11. //遍历元素,将对应位置为1

  12. for (auto x : R)

  13. bit.set(x); //bit.set(n)表示将第n位设为1

  14. int j = 0;

  15. //输出排序结果

  16. for (int i = 0; i <= max_num; i++)

  17. if (bit.test(i)) //bit.test(n)判断第n位是否为1

  18. R[j++] = i;

  19. }

  20.  
  21. int main()

  22. {

  23. vector<unsigned int> R = { 3, 6, 2, 4, 7, 1 };

  24. BitmapSort(R);

  25. for (auto x : R)

  26. cout << x << " ";

  27. cout << endl;

  28. }

 

或者在笔试或者面试中我们可以自己实现一个简易版的bitmap类

 

 
  1. #include<iostream>

  2. #include<vector>

  3. #pragma once

  4. using namespace std;

  5. class BitMap

  6. {

  7. public:

  8. //位图的构造

  9. BitMap(size_t N = 1024) //

  10. {

  11. _bm.resize((N/32)+1); //注意此处的运算符优先级

  12. }

  13. //按照位图的方式进行数值的置位

  14. void SetMap(size_t v)

  15. {

  16. //通过除得到此数在哪一个下标中存储中

  17. size_t index = v>>5;

  18. //通过模得到此数的具体位置

  19. size_t num = v%32;

  20. //将此数存在的位置置为1

  21. _bm[index] |= (1<<num);

  22.  
  23. }

  24. //进行数值的复位

  25. void RetsetMap(size_t v)

  26. {

  27. size_t index = v>>5;

  28. size_t num = v%32;

  29.  
  30. _bm[index] &= ~(1<<num);

  31. }

  32. //给定一个数,测试这个数是否在

  33. bool TestMap(size_t v)

  34. {

  35. size_t index = v>>5;

  36. size_t num = v%32;

  37.  
  38. return _bm[index] & (1<<num);

  39. }

  40. protected:

  41. vector<size_t> _bm;

  42. };

 

 

4.实际问题讲解

问题1:给40亿个不重复的unsigned int的整数,没有排过序,然后再给一个数,如果快速判断这个数是否在那40亿个数当中。(解决海量数据中的查询问题)

此题解法:建立一个位集合,全部初始化为0。遍历40亿个不重复的整数,通过上述提供的一种映射(每个不重复的整数映射到给定的位)找到其位的位置,标记为1。判断这个数是否在大整数集合中,即通过映射关系计算此整数的位位置,检查是否为1,若为1,则存在,若为0,则不存在

 

问题2:数据库里存了很多800电话号码,数量特别大,以至于内存放不下,如何排序,时间比空间更重要?电话号码类似于800-810-5555。(高效排序)

此题解法:其实就是不重复的任意7位数及其之内的排序问题。我们用1位来表示电话是否出现,遍历整个电话号序列,设置相应的位,遍历位图收集位被设置的号码即可。查看上述的实现代码

 

5.扩展:对于上述问题,每个电话号码最多出现一次,如果关键字可能多次重复出现,但关键字范围比较确定且很集中的情况下,也可使用位图(要求的条件比较苛刻)(根据关键字最多可能出现的次数确定每个关键字需要的位数),但此时的位图通常会是一个整型数组,数组内容为对应位置关键字出现的次数,在执行收集过程时,对于每个关键字要收集多次(根据数组的值确定)。如有一大批职工的年龄信息,需要对这些职工按照年龄信息进行排序,则只需要建立一个长度为100的数组,每个数组为对应年龄人的个数,扫描一遍数组,收集年龄信息即可。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值