概念

位图就是bitmap的缩写,所谓bitmap,就是用每一位来存放某种状态,适用于大规模数据,该数据都是不重复的简单数据。通常是用来判断某个数据存不存在的

例如:给40亿个不重复的unsigned int的整数,没排过序的,然后再给一个数,如何快速判断这个数是否在那40亿个数当中
如果不看数据量,我们第一想到的肯定就是依次从头遍历,但是这个数据量是非常大的,有40亿,遍历40亿次消耗的时间和内存是非常多的。但是引入位图后,就可以专门解决这种大量数据查找是否存在的问题。查找这个数是否存在所消耗的时间复杂度为O(1),且节省了32倍的容量(下面有解释)。下面我们一起来看看位图的原理及代码实现

原理

查找一个数是否存在,其实答案就是存在或者不存在,这种只需要回答是与否的问题,我们都可以用二进制中的位来表示,1表示该数存在,反之0表示该数不存在。而位图中的每个数据单元都是一个bit位,这样子平时我们都要话32位4字节来存储数据,而现在我们只需要花1个字节就能“存储数据”,在空间上减少了约32倍的容量。例如40G的数据我们只要花1.3G来存储。但是我们平时操作的数据类型最小就是一个字节,我们不能直接对位进行操作,所以我们可以借助位运算来对数据进行操作。下面我们来看看数据在位图中是如何存储的
我们这里给出一个数组
int arr[] = {1,2,4,5,7,10,11,14,16,17,21,23,24,28,29,31};则我们只需要花1个字节来存这些数据

解释:我们目前很多的机器都是小端存储,也就是低地址存低位,一个整形数据中,第一个字节用来存储0-7的数字,第二个字节用来存储8-15的数字,第三个字节用来存储16-23的数字,第四个字节用来存储24-31的数字。我们来看看数字10是如何存储的。先通过模上32,取余还是10,然后再将4字节中第10个比特位置为1,则表示该数字出现过。由于我们的机器是小端存储,所以我们的每个比特位都是要从右边开始计算的,如下图

所以说我们只需要将对应的比特位置为1即可。但是如果我们要存储的数据很大呢?其实也很简单,我们可以定义一个数组,当做一个位图,如果该数字在0-31之间,我们就存储在0号下标的元素中进行操作,如果在32-63之间,则就在1号下标之间进行操作。计算下标我们可以通过模32来获得下标。

我们知道位图的原理后,我们在通过原理来用代码实现一个位图吧

实现

成员变量和构造函数:在实现位图中,我们的成员变量只需要一个数组就可以实现。而这个数组有多我们要开多大呢?数组多开一个整形空间,就能多存32个数字,所以我们可以让用户提供一个准确的数,这个数是一个数据量,也是数的最大范围。我们可以通过该数模上32,就可以获得该数组的大小,但是0~31模上32为0,我们开0个空间那显然不合适,所以我们要开range/32 + 1个空间大小的数组

存储数据:存储一个数字num需要3个步骤,第一是需要计算出该值对应的数组下标。计算数组下标方式为idx=num / 32;第二步是计算num在对应整数的比特位的位置bitIdx=num%32;第三步是要将计算出来的bite位置为1。我们之前说过,要操作位,我们可以通过位运算来操作,可以先将1左移bitIdx位后再和整数进行或运算
例如假设bitIdx=5,数据为10010011
1.将1进行左移5位==>100000
2.将数据和第一步计算出来的结果进行或运算
10010011 | 100000 =10110011,此时我们就将指定位置置位1了

查找数据:要判断一个数据是否存在,其实和存储数据是类似,也是需要计算出两个位置idx和bitIdx。然后通过这两个位置来判断对应位置是否为1,为1则表示该数字存在。如何判断呢?我们可以先将数组下标为idx的整数向右移bitIdx位,然后再和1进行与运算,如果为1则表示存在,否则不存在
例如假设bitIdx=5,数据为10110011
1.将数据进行右移5位00000101
2.将第一步计算出来的结果和1进行与运算
00000101 & 1 = 1,此时表示该数字存在,返回true

删除数据:删除数据和存储数据操作一样,唯一的区别就是将对应的bit位置为0。我们可以通过先将1进行左移bitIdx位,然后取反,将结果再和原来数据进行与运算
例如假设bitIdx=5,数据为10110011
1.将1进行左移5位后并取反011111
2.将第一步计算出来的结果和数据进行与运算
10110011 & 011111 = 10010011,删除成功

代码

class BitMap
{public://位图的内存大小和数据范围有关BitMap(size_t range):_bit(range / 32 + 1){}void set(const size_t num){//计算数组中的下标int idx = num / 32;//计算num在对应下标整数中的下标位置int bitIdx = num % 32;//将对应的比特位置1_bit[idx] |= 1 << bitIdx;}bool find(const size_t num){int idx = num / 32;int bitIdx = num % 32;return (_bit[idx] >> bitIdx) & 1;}void reset(const size_t num){int idx = num / 32;int bitIdx = num % 32;_bit[idx] &= ~(1 << bitIdx);}
private:vector<int> _bit;
};

测试截图:

C++ 位图及位图的实现相关推荐

  1. 八位图 16位图_了解位图

    八位图 16位图 几周前,我和Alistair正在研究用于对节点附加到Neo4j数据库中的标签进行建模的代码. 这种工作方式是将32个节点ID的块表示为每个标签的32位位图 ,其中1表示1表示节点具有 ...

  2. oracle 函数位图索引,位图索引

    常规的B树索引对包含每行记录的ROWID与索引键值.位图索引不会直接存储ROWID,每个不同的键值都有一个位图,这就是为什么创建位图索引的列要有较少的distinct值的原因.位图中的每一位映射到一个 ...

  3. 疯狂位图之——位图实现12GB无重复大整数集排序

    一.主要思想 位图排序的思想就是在内存中申请一块连续的空间作为位图,初始时将位图的每一位都置为0,然后依次读取待排序文件的整数,将整数所在的位设置为1,最后扫描位图,如果某一位为1,则说明这个数存在, ...

  4. Android官方开发文档Training系列课程中文版:高效显示位图之位图缓存

    原文地址:http://android.xsoftlab.net/training/displaying-bitmaps/cache-bitmap.html 往UI界面中加载单张图片的过程是很简单的, ...

  5. java位图_Java 位图法排序的使用方法

    java JDK里面容器类的排序算法使用的主要是插入排序和归并排序,可能不同版本的实现有所不同,关键代码如下: /** * Performs a sort on the section of the ...

  6. 为什么亿级数据量时要使用位图?位图和布隆过滤器有什么关系?

    文章目录 一.为什么要使用位图 二.什么是位图 三.布隆过滤器 四.位图的常见使用场景 4.1 生成看似无规律却呈趋势递增的号段式ID 4.2 搜索引擎爬虫网页去重 4.3 大型网站每天UV数量统计 ...

  7. java位图_位图Bitmap及其Java实现

    举个例子,如下图,如果我们想要存放 0,2,4,5,10,11,12,14,15这几个数字,如果采用普通存储方式,若4位表示一个数字,这9个数字需要4*9=36位,至少36位才能存储这些数据. 如果采 ...

  8. c语言建立位图坐标,位图(bitmap)—— C语言实现

    位图应当具备的置一,清零,以及判断三大功能: #define BITS_PER_WORD 32 #define MASK 0x1f #define SHIFT 5 // BITS_PER_WORD 与 ...

  9. java把字体转换成位图_位图字体生成工具Bitmap Font Generator的使用

    首先,说下为什么要使用这款工具作为cocos2d-x的字体生成工具.其实cocos2d-x能使用的字体生成工具也有好几个,当然了本人也没有全部使用过,就不一一说明了.Bitmap Font Gener ...

最新文章

  1. 信息系统开发平台OpenExpressApp:【OpenTest】 之 如何实现自动化测试框架
  2. Tensorflow【实战Google深度学习框架】使用 HDF5 处理大型数据集with TFLearn
  3. UIRecorder入门
  4. C语言中的标识符作用域
  5. 汇编语言(十六)之三数值求和
  6. python属性_深入理解python对象及属性
  7. 单片机c语言怎样添加自定义头文件,单片机C语言编程与或|头文件常见问题
  8. 做柱状图加数据标签_Origin绘图:如何优雅的绘制堆叠柱状图
  9. mysql统计信息表行数不准确_mysql SQL调优-统计信息不准的原因
  10. 使用C++模板判断两个类型是否一样
  11. 幼儿园编程机器人课程介绍
  12. oreilly免费电子书
  13. <C++>我用煮粽子的时间拿捏了类和对象中友元的全部形式
  14. 根式为什么是根式?(我可能疯了?)
  15. 必须掌握的八个dos命令
  16. rpm安装mysql odbc_如何以rpm方式安装mysql odbc驱动
  17. Win10——更改中文超级管理员的用户文件名(各系统版本通用)
  18. 用[记事本]查杀EXE病毒
  19. php eth erc20,【Ethereum】以太坊ERC20 Token标准完整说明
  20. 闻风丧胆系统角色权限五张表的设计

热门文章

  1. android接口调用超时,RCA:收单设备调用云端接口频繁超时排查总结
  2. 非命令行linux安装zip,如何在Ubuntu 18.04 Bionic Beaver Linux上使用命令行从ZIP文件安装Gnome Shell Extensions...
  3. oracle number长度转换,Oracle Number型数值存储与转换的实现详解
  4. php登录api,PHP登录REST API
  5. python单链表实现具体例子_python中单链表的实现
  6. PostgreSQL 字符串分隔函数(regexp_split_to_table、regexp_split_to_array)  发表于 2020-06-01 |  阅读次数: 394
  7. android静态动画,LayoutAnimation给ListView中的item设置动态出场效果(实例)
  8. 基于JAVA+SpringBoot+Mybatis+MYSQL的仿天猫商城
  9. 基于JAVA+SSH+MYSQL的社区医院远程挂号系统
  10. 基于JAVA+SpringMVC+Mybatis+MYSQL的学习资源交互系统