引子

首先通过一道题来理解什么是bitmap。

题目:我有40亿个整数,再给一个新的整数,我需要判断新的整数是否在40亿个整数中,你会怎么做?

分析:

假设一个int占4个字节(32位),40个亿个整数就是160亿个字节,大概相当于16GB,假设一台计算机只有2GB内存,则16GB一次加载不完,需要分8次加载,从磁盘加载数据是磁盘io操作,是非常慢的(比内存中的操作要慢100倍),每次加载这么大的数据,并且要8次,那么查找的时间可以达到分钟甚至小时级。

还有一个办法是把数据分散在8台计算机上,然后来一个新数据,8台计算机同时找,然后再汇总结果。这样每台计算机都可以一次性把数据读入内存中,查找就不用来回加载数据,省去了加载数据的开销,是个好方法。

但是否还有其他更好的方法呢?那就是bitmap。bitmap存值的思路:每一个int有32位,int整数的范围是-2147483648 ~ 2147483647。为简化理解,这里先假设每一个整数位均为正整数(如果存在负整数需分开处理),2147483647/32 = 67108863,即只需要67108863个int型整数就可以表示 [0,2147483647] 范围的数字,即需要67108863*4 = 268,435,452‬个字节的内存,相当于0.2GB,即使加上负整数部分也才需要0.4GB的内存,一台计算机完全足够。这里将开辟67108863int型数组,数组中的每一位代表依次代表 [0,2147483647]。而且而且判断新的整数也只需要O(1)的时间复杂度,性能非常高。

bitmap定义

位图是一个数组的每一个数据的每一个二进制位表示一个数据,0表示数据不存在,1表示数据存在。

例如存储136这个数:

  1. 确定136在整个数据的那个区间,136/32 = 4,即在第四个区间;
  2. 确定136在这个区间的第几位(bit),136%32 = 25,即在第四区间的第25位上;
  3. 将这个位置置为1,表示存在这个数。

由于bitmap的数据存储方式,具有升序排序的性质。

代码实现

#include <iostream>
#include <vector> using namespace std; class Bitmap {
public:
Bitmap() {
bitVec_.resize((INT_MAX >> ) + ); //多开辟一个空间,原因是数组只能表示区间[0,size)
}
void BitmapSet(int val) {
int index = val >> ; //相当于除以32,用移位操作可提高性能
int offset = val % ;
bitVec_[index] |= ( << offset);
int capacity = bitVec_.capacity();
}
bool BitmapGet(int val) {
int index = val >> ;
int offset = val % ;
return bitVec_[index] & ( << offset);
}
private:
vector<unsigned int> bitVec_;
}; int main() {
Bitmap bm;
//这里只存[0,1000000]的数,
for (int i = ; i <= ; ++i) {
bm.BitmapSet(i);
}
bool exist1 = bm.BitmapGet(); // 100是否存在,返回true
bool exist2 = bm.BitmapGet(); // 10000000是否存在,返回false system("pause");
return ;
}

上面实现只是针对开篇题目写的简单bitmap,下一篇文章会探讨Bloom Filter的原理,会对用到的bitmap进行优化修改。

bitmap位图原理和实现的更多相关文章

  1. BitMap的原理以及运用

    位图(Bitmap),即位(Bit)的集合,是一种数据结构,可用于记录大量的0-1状态,在很多地方都会用到,比如Linux内核(如inode,磁盘块).Bloom Filter算法等,其优势是可以在一 ...

  2. BitMap的原理和实现

    相关概念 基础类型 在java中: byte -> 8 bits -->1字节 char -> 16 bit -->2字节 short -> 16 bits --> ...

  3. 重温delphi之:如何将Bitmap位图与base64字符串相互转换

    先引用delphi自带的单元 uses EncdDecd; 然后就可以使用下面二个函数了: by 菩提树下的杨过 http://yjmyzz.cnblogs.com/ ///将Bitmap位图转化为b ...

  4. delphi中Bitmap位图与base64字符串相互转换

    uses EncdDecd; ///将Bitmap位图转化为base64字符串 function BitmapToString(img:TBitmap):string ; var ms:TMemory ...

  5. bittorrent 学习(一) 种子文件分析与bitmap位图

    终于抽出时间来进行 BITTORRENT的学习了 BT想必大家都很熟悉了,是一种文件分发协议.每个下载者在下载的同时也在向其他下载者分享文件. 相对于FTP HTTP协议,BT并不是从某一个或者几个指 ...

  6. 【Bitmap Index】B-Tree索引与Bitmap位图索引的锁代价比较研究

    通过以下实验,来验证Bitmap位图索引较之普通的B-Tree索引锁的“高昂代价”.位图索引会带来“位图段级锁”,实际使用过程一定要充分了解不同索引带来的锁代价情况. 1.为比较区别,创建两种索引类型 ...

  7. Bitmap 位图

    转自: http://dongxicheng.org/structure/bitmap/ 1.  概述 位图(bitmap)是一种非常常用的结构,在索引,数据压缩等方面有广泛应用.本文介绍了位图的实现 ...

  8. 使用不安全代码将 Bitmap 位图转为 WPF 的 ImageSource 以获得高性能和持续小的内存占用

    在 WPF 中将一个现成的 Bitmap 位图转换成 ImageSource 用于显示一个麻烦的事儿,因为 WPF 并没有提供多少可以转过来的方法.不过产生 Bitmap 来源却非常多,比如屏幕截图. ...

  9. ( 转 ) 数据库BTree索引、Hash索引、Bitmap位图索引的优缺点

    测试于:MySQL 5.5.25 当前测试的版本是Mysql 5.5.25只有BTree和Hash两种索引类型,默认为BTree.Oracle或其他类型数据库中会有Bitmap索引(位图索引),这里作 ...

随机推荐

  1. paramiko多线程远程执行命令

    import paramiko import sys import getpass import threading import os def rcmd(host=None, port=22, us ...

  2. 010_Linux驱动之_DECLARE_WAIT_QUEUE_HEAD函数

    1. 功能:创建以个等待队列头 2. 函数原型 #define DECLARE_WAIT_QUEUE_HEAD (name)                            /     wait ...

  3. 彻底搞清楚setState

    setState最常见的问题是,是异步的还是同步的? setState在React.Component中的函数,是同步函数.但是我们调用的时候,不同的传参和不同的调用位置都会导致不同的结果. 从页面看 ...

  4. learning express step(八)

    To skip the rest of the middleware functions from a router middleware stack, call next('route') to p ...

  5. [Luogu] 广义斐波那契数列

    https://www.luogu.org/problemnew/show/P1349 题解:https://www.zybuluo.com/wsndy-xx/note/1152988

  6. Codeforces 1180E Serge and Dining Room

    题意: 有\(n\)个菜肴,有\(m\)个小朋友,每个菜肴的价格为\(a_i\),每个小朋友有\(b_i\)元钱,小朋友从\(1 \rightarrow m\)依次购买菜肴,当第\(i\)个小朋友轮到 ...

  7. 【概率论】4-2:期望的性质(Properties of Expectation)

    title: [概率论]4-2:期望的性质(Properties of Expectation) categories: - Mathematic - Probability keywords: - ...

  8. Jumbled String (Kattis - jumbledstring)(思维题)

    Problem Recall that a subsequence of a string is any string obtained by removing some subset of char ...

  9. jvm方法栈

    调用栈 先入后出 栈是一个只有一个口的容器,先进入栈的会落到栈底,出栈的时候最后出.最后进入栈的,在栈顶,出栈时先出. 方法调用时,需要在内存中开辟一块存储空间做为线程栈空间 每个线程都由自己的栈 调 ...

  10. Python 学习 —— 进阶篇(装饰器、类的特殊方法)

    Python基础部分学完之后,在进入其OOP部分前,先理解一下其装饰器这种结构,其功能可类比于Java中的面向切面编程,下面参见具体实例: def log(f): def fn(x): print ' ...