一、概述
本文将讲述Bit-Map算法的相关原理,Bit-Map算法的一些利用场景,例如BitMap解决海量数据寻找重复、判断个别元素是否在海量数据当中等问题.最后说说BitMap的特点已经在各个场景的使用性。
二、Bit-Map算法
先看看这样的一个场景:给一台普通PC,2G内存,要求处理一个包含40亿个不重复并且没有排过序的无符号的int整数,给出一个整数,问如果快速地判断这个整数是否在文件40亿个数据当中?
问题思考:
40亿个int占(40亿*4)/1024/1024/1024 大概为14.9G左右,很明显内存只有2G,放不下,因此不可能将这40亿数据放到内存中计算。要快速的解决这个问题最好的方案就是将数据搁内存了,所以现在的问题就在如何在2G内存空间以内存储着40亿整数。一个int整数在java中是占4个字节的即要32bit位,如果能够用一个bit位来标识一个int整数那么存储空间将大大减少,算一下40亿个int需要的内存空间为40亿/8/1024/1024大概为476.83 mb,这样的话我们完全可以将这40亿个int数放到内存中进行处理。
具体思路:
1个int占4字节即4*8=32位,那么我们只需要申请一个int数组长度为 int tmp[1+N/32]即可存储完这些数据,其中N代表要进行查找的总数,tmp中的每个元素在内存在占32位可以对应表示十进制数0~31,所以可得到BitMap表:
tmp[0]:可表示0~31
tmp[1]:可表示32~63
tmp[2]可表示64~95
.......
那么接下来就看看十进制数如何转换为对应的bit位:
假设这40亿int数据为:6,3,8,32,36,......,那么具体的BitMap表示为:

那么怎么快速定位它的索引呢。如果找到它的索引号,又怎么定位它的位置呢。Index(N)代表N的索引号,Position(N)代表N的所在的位置号。

Index(N) = N/8 = N >> 3;

Position(N) = N%8 = N & 0x07;

add方法:

    public void add(int num){
// num/8得到byte[]的index
int arrayIndex = num >> 3; // num%8得到在byte[index]的位置
int position = num & 0x07; //将1左移position后,那个位置自然就是1,然后和以前的数据做|,这样,那个位置就替换成1了。
bits[arrayIndex] |= 1 << position;
}

code:

public class BitMap {
//保存数据的
private byte[] bits; //能够存储多少数据
private int capacity; public BitMap(int capacity){
this.capacity = capacity; //1bit能存储8个数据,那么capacity数据需要多少个bit呢,capacity/8+1,右移3位相当于除以8
bits = new byte[(capacity >>3 )+1];
} public void add(int num){
// num/8得到byte[]的index
int arrayIndex = num >> 3; // num%8得到在byte[index]的位置
int position = num & 0x07; //将1左移position后,那个位置自然就是1,然后和以前的数据做|,这样,那个位置就替换成1了。
bits[arrayIndex] |= 1 << position;
} public boolean contain(int num){
// num/8得到byte[]的index
int arrayIndex = num >> 3; // num%8得到在byte[index]的位置
int position = num & 0x07; //将1左移position后,那个位置自然就是1,然后和以前的数据做&,判断是否为0即可
return (bits[arrayIndex] & (1 << position)) !=0;
} public void clear(int num){
// num/8得到byte[]的index
int arrayIndex = num >> 3; // num%8得到在byte[index]的位置
int position = num & 0x07; //将1左移position后,那个位置自然就是1,然后对取反,再与当前值做&,即可清除当前的位置了.
bits[arrayIndex] &= ~(1 << position); } public static void main(String[] args) {
BitMap bitmap = new BitMap(100);
bitmap.add(7);
System.out.println("插入7成功"); boolean isexsit = bitmap.contain(7);
System.out.println("7是否存在:"+isexsit); bitmap.clear(7);
isexsit = bitmap.contain(7);
System.out.println("7是否存在:"+isexsit);
}
}

每个byte存8个数字,相对于int类型来说,节省了32倍的存储空间

存储数据范围,就上面的例子来说,上面bits数组的长度为13,那么总共可以存储(13*8)104个数字,分别是(0~103)

上面的代码并没有扩容方法,超出范围会报错,

使用bit数组来表示某些元素是否存在,比如8位电话号码.

缺点:

如果是比较特殊的数字,比如[1,100000000],那么就会浪费存储空间,比如这个就必须要(100000000>>3)个字节

针对上面的缺点,谷歌所实现的EWAHCompressedBitmap对bitmap存储空间做了一定的优化

相信的讲解:http://www.sohu.com/a/166661005_479559

问题实例

1、在2.5亿个整数中找出不重复的整数,注,内存不足以容纳这2.5亿个整数
解法一:采用2-Bitmap(每个数分配2bit,00表示不存在,01表示出现一次,10表示多次,11无意义)进行,共需内存2^32 * 2 bit=1 GB内存,还可以接受。然后扫描这2.5亿个整数,查看Bitmap中相对应位,如果是00变01,01变10,10保持不变。所描完事后,查看bitmap,把对应位是01的整数输出即可。

解法二:也可采用与第1题类似的方法,进行划分小文件的方法。然后在小文件中找出不重复的整数,并排序。然后再进行归并,注意去除重复的元素。”
2、给40亿个不重复的unsigned int的整数,没排过序的,然后再给一个数,如何快速判断这个数是否在那40亿个数当中?
解法一:可以用位图/Bitmap的方法,申请512M的内存,一个bit位代表一个unsigned int值。读入40亿个数,设置相应的bit位,读入要查询的数,查看相应bit位是否为1,为1表示存在,为0表示不存在。

https://www.jianshu.com/p/6082a2f7df8e

https://wizardforcel.gitbooks.io/the-art-of-programming-by-july/content/06.07.html

http://blog.51cto.com/zengzhaozheng/1404108

http://blog.csdn.net/h348592532/article/details/45362661

https://www.cnblogs.com/protected/p/6626447.html

http://mp.weixin.qq.com/s?__biz=MzIxMjE5MTE1Nw==&mid=2653191272&idx=1&sn=9bbcd172b611b455ebfc4b7fb9a6a55e&chksm=8c990eb2bbee87a486c55572a36c577a48df395e13e74314846d221cbcfd364d44c280250234&scene=21#wechat_redirect

海量数据处理-BitMap算法的更多相关文章

  1. (面试)Hash表算法十道海量数据处理面试题

    Hash表算法处理海量数据处理面试题 主要针对遇到的海量数据处理问题进行分析,参考互联网上的面试题及相关处理方法,归纳为三种问题 (1)数据量大,内存小情况处理方式(分而治之+Hash映射) (2)判 ...

  2. 海量数据处理算法—Bloom Filter

    海量数据处理算法—Bloom Filter 1. Bloom-Filter算法简介 Bloom-Filter,即布隆过滤器,1970年由Bloom中提出.它可以用于检索一个元素是否在一个集合中. Bl ...

  3. 从hadoop框架与MapReduce模式中谈海量数据处理

    http://blog.csdn.net/wind19/article/details/7716326 前言 几周前,当我最初听到,以致后来初次接触Hadoop与MapReduce这两个东西,我便稍显 ...

  4. 从Hadoop框架与MapReduce模式中谈海量数据处理(含淘宝技术架构) (转)

    转自:http://blog.csdn.net/v_july_v/article/details/6704077 从hadoop框架与MapReduce模式中谈海量数据处理 前言 几周前,当我最初听到 ...

  5. 从Hadoop骨架MapReduce在海量数据处理模式(包括淘宝技术架构)

    从hadoop框架与MapReduce模式中谈海量数据处理 前言 几周前,当我最初听到,以致后来初次接触Hadoop与MapReduce这两个东西,我便稍显兴奋,认为它们非常是神奇.而神奇的东西常能勾 ...

  6. july教你如何迅速秒杀掉:99%的海量数据处理面试题

    作者:July出处:结构之法算法之道blog 以下是原博客链接网址 http://blog.csdn.net/v_july_v/article/details/7382693 微软面试100题系列 h ...

  7. 海量数据处理面试题学习zz

    来吧骚年,看看海量数据处理方面的面试题吧. 原文:(Link, 其实引自这里 Link, 而这个又是 Link 的总结) 另外还有一个系列,挺好的:http://blog.csdn.net/v_jul ...

  8. 海量数据处理的 Top K 相关问题

    Top-k的最小堆解决方法 问题描述:有N(N>>10000)个整数,求出其中的前K个最大的数.(称作Top k或者Top 10) 问题分析:由于(1)输入的大量数据:(2)只要前K个,对 ...

  9. DBA_Oracle海量数据处理分析(方法论)

    2014-12-18 Created By BaoXinjian

随机推荐

  1. 2018/03/10 每日一个Linux命令 之 cksum

    每日一个Linux命令 2018-03-10 Linux 命令 cksum cksum [文件]  今天楼下的一个大妈去世了,不仅感叹,现如今,真的和以前不一样了,楼上楼下都不知道住的是谁? cksu ...

  2. 解决重启服务器以后Nginx无法启动

    今天重启服务器以后发现nginx服务器启动失败. 这应该是因为把nginx进程杀死后pid丢失了,下一次再开启nginx -s reload时无法启动,重装可以解决这个问题,但是太麻烦了. 然后这样就 ...

  3. mysql 内置功能 存储过程 创建无参存储过程

    操作哪个数据库,就把存储过程建到那个数据库 例如 现在use db2; 应该把存储过程 建立到db2数据库里 创建无参存储过程 delimiter // # 设置mysql结束符合为// create ...

  4. MySQL完全卸载方法

    1.在控制面板里把Mysql正常卸载 2.C:\Documents and Settings\All Users\Application Data\MySQL 这里还有MySQL的文件,必须要删除 注 ...

  5. 扩展的friend语法

    Java中没有定义friend. friend用于声明类的友元,可以无视类中成员的属性.无论成员3p中的哪一种,友元类或友元函数都可以访问,破坏了封装性,此关键字备受争议.专家会建议程序员使用get/ ...

  6. LVS + Keepalived 实现高可用、负载均衡 Web 集群

    简介: LVS 是 Linux Virtual Server 的简写,Linux 虚拟服务器的意思,是一个虚拟的服务器集群系统,此项目由章文嵩博士于 1998 年 5 月成立,是中国最早出现的自由软件 ...

  7. Centos 设置zookeeper开机自启动

    把zookeeper做成服务 1.进入到/etc/rc.d/init.d目录下,新建一个zookeeper脚本 [root@zookeeper ~]# cd /etc/rc.d/init.d/ [ro ...

  8. Outlier Detection

    1)正态分布数据,飘出95%的可能是异常值.变量var正态标准化,|var|<=1.96的可能是异常值,further chk needed!large sample better. 对于偏态分 ...

  9. [LeetCode] 200. Number of Islands_ Medium tag: BFS

    Given a 2d grid map of '1's (land) and '0's (water), count the number of islands. An island is surro ...

  10. Haproxy启动故障:Starting proxy:cannot bind socke

    Haproxy启动时提示失败: [ALERT] 146/132210 (3443) : Starting frontend Redis: cannot bind socket [0.0.0.0:637 ...