C++ 位图及位图的实现原理

概念

位图就是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++ 位图及位图的实现原理的详细内容,更多关于C++ 位图的资料请关注我们其它相关文章!

(0)

相关推荐

  • C++实现位图排序实例

    在<编程珠玑>一书里提到了一种算法导论里没有提到过的位图排序方法,这种排序方法是通过牺牲空间效率来追求时间效率(线性时间)以达到时间-空间折中与双赢的目的.本文以实例形式简单讲一下位图排序思想. 一.问题描述 1.输入:一个至多包含1千万个非负整数的文件 2.特征:①每个数都是小于10000000的非负整数:②没有重复的数字:③数据之间不存在关联关系. 3.约束:①最多1MB的内存空间可用:②磁盘空间充足:③运行时间最多几分钟,最好是线性时间.           4.输出:按升序排列的整数序

  • CISBitmap派生的VC++位图透明类实例

    本文所述为一个由CISBitmap派生的VC++位图透明类,可以方便实现BMP图像的透明处理,主要包含两个文件,使用时主需要将其引入到你的C++工程中即可,具体的类代码如下: CISBitmap.cpp文件代码如下: #include <stdafx.h> #include "CISBitmap.h" #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[]=__FILE__; #define new DEBUG_NEW

  • C++保存HBITMAP为位图文件的实现方法

    本文使用C++将位图句柄HBITMAP保存为位图文件,配合C++抓图代码可以实现抓图保存文件(.bmp). 其步骤如下: 1.创建位图文件: 2.计算位图中每个像素所占字节数: 3. 获取位图结构BITMAP: 4.构造位图信息头BITMAPINFOHEADER: 5.构造位图文件头BITMAPFILEHEADER: 6.为位图内容分配内存: 7.处理调色板: 8.写入文件: 9.清除资源. 下面是C++源代码: ImageHelper.h #pragma once   #include <wi

  • 使用C++绘制GDI位图的基本编写实例

    1.加载位图 2.建立兼容DC 3.选择之前的位图对象 4.用贴图函数BitBlt() HBITMAP bitmap=(HBITMAP)LoadImage(NULL,L"Name.bmp",IMAGE_BITMAP,high,length,LR_LOADFROMFILE); HWND tmp=CreateCompatiable(g_hdc); SelectObject(tmp,bitmap); BitBlt(g_hdc,0,0,high,length,tmp,0,0,SRCCOPY);

  • 用位图排序无重复数据集实例代码(C++版)

    <Programming Pearls>(编程珠玑下载)第一章讲述了如何用位图排序无重复的数据集,整个思想很简洁,今天实践了下. 一.主要思想 位图排序的思想就是在内存中申请一块连续的空间作为位图,初始时将位图的每一位都置为0,然后依次读取待排序文件的整数,将整数所在的位设置为1,最后扫描位图,如果某一位为1,则说明这个数存在,输出到已排序文件.比如待排序的数据S={3,0,4,1,7,2,5},max(S)=7,我们可以设置一个八位的位图B,将位图的每一位初始为0,即B=[0,0,0,0,0

  • C++位图的实现原理与方法

    概念 位图就是bitmap的缩写,所谓bitmap,就是用每一位来存放某种状态,适用于大规模数据,该数据都是不重复的简单数据.通常是用来判断某个数据存不存在的 例如:给40亿个不重复的unsigned int的整数,没排过序的,然后再给一个数,如何快速判断这个数是否在那40亿个数当中 如果不看数据量,我们第一想到的肯定就是依次从头遍历,但是这个数据量是非常大的,有40亿,遍历40亿次消耗的时间和内存是非常多的.但是引入位图后,就可以专门解决这种大量数据查找是否存在的问题.查找这个数是否存在所消耗

  • C++ 位图及位图的实现原理

    概念 位图就是bitmap的缩写,所谓bitmap,就是用每一位来存放某种状态,适用于大规模数据,该数据都是不重复的简单数据.通常是用来判断某个数据存不存在的 例如:给40亿个不重复的unsigned int的整数,没排过序的,然后再给一个数,如何快速判断这个数是否在那40亿个数当中 如果不看数据量,我们第一想到的肯定就是依次从头遍历,但是这个数据量是非常大的,有40亿,遍历40亿次消耗的时间和内存是非常多的.但是引入位图后,就可以专门解决这种大量数据查找是否存在的问题.查找这个数是否存在所消耗

  • C语言位图及位图的实现

    本文实例为大家分享了C语言位图及位图的实现具体代码,供大家参考,具体内容如下 1.概念 位图(bitset)是一种常用的数据结构,常用在给一个很大范围的数,判断其中的一个数是不是在其中.在索引.数据压缩方面有很大的应用. 位图是用数组实现的,数组的每一个元素的每一个二进制位都表示一个数据,0表示该数据不存在,1表示该数据存在. 2.C++库中bitset的使用 3.bitset的简单实现 当我们存放一个数据时的思路是: 1)确定数据在哪个区间上,即_bitSet的第几个元素上,_bitSet是顺

  • 详解Linux下读取位图的注意事项

    详解Linux下读取位图的注意事项 在Linux下读取位图遇到的问题,很好地体现了linux与Windows操作系统的不同.按理说位图格式与操作系统无关,读取也应该无关,实际上在位图读到内存中时已经不同.下面主要介绍自己在Linux下操作位图遇到的问题. (一).位图结构 位图一开始是两个结构体,包括位图的详细信息,是读取后面数据的关键.所以读取位图首先要正确读取这两个结构体:BITMAPFILEHEADER和BITMAPINFOHEADER.其具体定义为: typedef struct tag

  • 如何通过UltraEdit解析BMP文件内部结构(BMP位图基础)

    目录 初见位图 位图文件的基本结构 1.文件头信息块 2.图像描述信息块 3.颜色表 4.图像数据区 具体例子 初见位图 我们先打开画图随便画一幅图并采用24位bmp图像格式保存,就得到了一张24位真彩色的位图 BMP位图一般由4部分组成:文件头信息块.图像描述信息块.颜色表(在真彩色模式无颜色表)和图像数据区组成,以BMP为扩展名保存. 打开Windows的画图程序,在保存图像时,可以看到三个选项:2色位图(黑白).16色位图.256色位图和24位位图.这是最普通的生成位图的工具,在这里讲解的

  • C++哈希应用的位图和布隆过滤器

    目录 C++哈希应用的位图和布隆过滤器 一.位图 1.位图的概念 2.位图的面试题 3.位图的实现 4.位图的应用 二.布隆过滤器 1.布隆过滤器的提出 2.布隆过滤器的概念 3.布隆过滤器的插入 4.布隆过滤器的查找 5.布隆过滤器的删除 6.布隆过滤器的优点和缺点 三.海量数据面试题 1.哈希切割 2.位图应用 3.布隆过滤器 C++哈希应用的位图和布隆过滤器 一.位图 1.位图的概念 所谓位图,就是用每一位来存放某种状态,适用于海量数据,数据无重复的场景.通常是用来判断某个数据存不存在的.

  • C++中的位运算和位图bitmap解析

    目录 位运算总结 移位运算 位运算应用举例 位图 位运算总结 移位运算 移位运算是双目运算符,两个运算分量都是整形,结果也是整形. “<<” 左移:右边空出的位上补0,左边的位将从首位挤掉,其值相当于乘2. ">>"右移:右边的位被挤掉.对于左边移出的空位,如果是正数则空位补0,若为负数,可能补0或补1,这取决于所用的计算机系统. 二进制补码运算公式: -x = ~x + 1 = ~(x-1) -(~x) = x+1 ~(-x) = x-1 x+y = x -

  • vue自定义加载指令v-loading占位图指令v-showimg

    目录 了解自定义指令的钩子函数 注册成为全局指令 需求描述 列表组件 ListCom.vue 加载动画组件 LoadingCom.vue 钩子函数 loading.js 分析上面的代码 main.js 中 注册成为全局指令 页面中使用加载动画指令 v-loading 占用图指令 v-showimg 占位图组件 ShowImgCom.vue 指令的书写 showimg.js main.js注册 指令的使用v-showimg指令 了解自定义指令的钩子函数 bind(){}:每当指令绑定到元素上的时候

  • 双缓冲解决VC++绘图时屏幕闪烁

    通常来说程序根据需要调用Invalidate(FALSE)使窗口客户区无效引起重绘,然后在窗口OnPaint函数(基于文档视图的程序则是OnDraw)中进行稳定绘图就行了.但是,我们在OnPaint中进行多重绘制(画背景.棋盘.棋子等),前后绘制的反差造成了闪烁现象.以前知道Java中解决屏幕闪烁问题是用双缓冲的方法,现在发现在vc++中也是可以这么做的.简单来说,双缓冲就是先把需要绘制的东西全部一口气画在内存中,最后把内存中的数据搬到屏幕上显示. 最近做中国象棋,绘制界面时遇到些问题,绘图过程

  • C++ 学习之旅三 我和超级玛丽有个约会

    首先,我说说对C++的最直观的感受吧!熟悉了.net 智能提示,开始一开始发现C++根本没有提示了.后来google了一下,下载了一个visual assist 这个插件,比vs自动提示强多了. 然后,就是习惯了在.net中,把所有的声明和方法实现写在同一文件中.可是C++不是这么回事. 他一个声明在头文件中,实现 在源文件中,说实在话,一开始并怎么习惯.后来渐渐就习惯了.然后,写C++的文件就是真他妈的痛苦,他不比.net,微软已经比你封装好了,在C++中,好多东西需要自己写.  首先,一个析

随机推荐