[算法系列之十八]海量数据处理之BitMap

一:简介

所谓的BitMap就是用一个bit位来标记某个元素对应的Value, 而Key即是该元素。由于采用了bit为单位来存储数据,因此在存储空间方面,可以大大节省。

二:基本思想

我们用一个具体的例子来讲解,假设我们要对0-7内的5个元素(4,7,2,5,3)排序(这里假设这些元素没有重复)。那么我们就可以采用BitMap的方法来达到排序的目的。要表示8个数,我们就只需要8个bit(1Bytes)。

(1)首先我们开辟1字节(8bit)的空间,将这些空间的所有bit位都置为0,如下图:

(2)然后遍历这5个元素,首先第1个元素是4,那么就把4对应的位置为1,因为是从零开始的,所以要把第5个位置为1(如下图):

然后再处理第2个元素7,将第8个位置为1,,接着再处理第3个元素,一直到处理完所有元素,将相应的位置为1,这时候的内存的bit位的状态如下:

(3)然后我们现在遍历一遍bit区域,将该位是1的位的编号输出(2,3,4,5,7),这样就达到了排序的目的。

算法思想比较简单,但关键是如何确定十进制的数映射到二进制bit位的map图。

三:Map映射

假设需要排序或者查找的总数N=10000000。

BitMap中1bit代表一个数字

1个int = 4Bytes = 4*8bit = 32 bit,那么N个数需要N/32 int空间。所以我们需要申请内存空间的大小为int a[1 + N/32],其中:a[0]在内存中占32为可以对应十进制数0-31,依次类推:

BitMap表为:

    a[0]  --------->  0-31
    a[1]  --------->  32-63
    a[2]  --------->  64-95
    a[3]  --------->  96-127
    ..........

那么十进制数如何转换为对应的bit位,下面介绍用位移将十进制数转换为对应的bit位。

申请一个int一维数组,那么可以当作为列为32位的二维数组。

a[0]

a[1]

a[2]

a[3]

a[i] ……………………………….

a[n]

例如:

十进制1 在a[0]中,位置如下图:

十进制31 在a[0]中,位置如下图:

十进制32 在a[1]中,位置如下图:

十进制33 在a[1]中,位置如下图:

通过上图分析得出通过以下几步将十进制数如何转换为对应的bit位:

(1)求十进制数在对应数组a中的下标

十进制数0-31,对应在数组a[0]中,32-63对应在数组a[1]中,64-95对应在数组a[2]中………

分析得出:对于一个十进制数n,对应在数组a[n/32]中

例如n=11,那么 n/32=0,则11对应在数组a中的下标为0,n=32,那么n/32=1,则32对应在数组a中的下标为1,n = 106,那么n/32 = 3,则106对应数组a中的下标为3。

(2)求十进制数在对应数组a[i]中的下标

例如十进制数1在a[0]的下标为1,十进制数31在a[0]中下标为31,十进制数32在a[1]中下标为0。

在十进制0-31就对应0-31,而32-63则对应也是0-31,即给定一个数n可以通过模32求得在对应数组a[i]中的下标。

分析得出:对于一个十进制数n,对应在数组a[n/32][n%32]中

(3)移位

对于一个十进制数n,对应在数组a[n/32][n%32]中,但数组a毕竟不是一个二维数组,我们通过移位操作实现置1。

a[n/32] |= 1 << n % 32

移位操作:

a[n>>5] |= 1 << (n & 0x1F)

n & 0x1F 保留n的后五位 相当于 n % 32 求十进制数在数组a[i]中的下标

/*--------------------------------
*   日期:2015-02-07
*   作者:SJF0115
*   题目: BitMap
*   博客:
------------------------------------*/
#include <iostream>
#include <vector>
using namespace std;

#define N 1000000000

//申请内存的大小
int a[1 + N/32];

// 设置所在的bit位为1
void BitMap(int n){
    // row = n / 32 求十进制数在数组a中的下标
    int row = n >> 5;
    // n & 0x1F 保留n的后五位
    // 相当于 n % 32 求十进制数在数组a[i]中的下标
    a[row] |= 1 << (n & 0x1F);
}
// 判断所在的bit为是否为1
bool Exits(int n){
    int row = n >> 5;
    return a[row] & ( 1 << (n & 0x1F));
}

void Show(int row){
    cout<<"BitMap位图展示:"<<endl;
    for(int i = 0;i < row;++i){
        vector<int> vec;
        int tmp = a[i];
        for(int i = 0;i < 32;++i){
            vec.push_back(tmp & 1);
            tmp >>= 1;
        }//for
        cout<<"a["<<i<<"]"<<"->";
        for(int i = vec.size()-1;i >= 0;--i){
            cout<<vec[i]<<" ";
        }//for
        cout<<endl;
    }//for
}

int main(){
    int num[] = {1,5,30,32,64,56,159,120,21,17,35,45};
    for(int i = 0;i < 12;++i){
        BitMap(num[i]);
    }//for
    int row = 5;
    Show(5);
    /*if(Exits(n)){
        cout<<"该数字已经存在"<<endl;
    }//if
    else{
        cout<<"该数字不存在"<<endl;
    }//else*/
    return 0;
}

应用范围

可以运用在快速查找、去重、排序、压缩数据等。

扩展

Bloom filter可以看做是对BitMap的扩展

布隆过滤器具体参考:[算法系列之十]大数据量处理利器:布隆过滤器

具体应用

待完善…….

引用:

http://blog.csdn.net/hguisu/article/details/7880288

http://blog.csdn.net/v_july_v/article/details/6685962

http://www.tuicool.com/articles/mUb2Qnn

http://nemogu.iteye.com/blog/1522332

http://blog.csdn.net/v_july_v/article/details/7382693

时间: 2024-10-20 09:10:58

[算法系列之十八]海量数据处理之BitMap的相关文章

转 十道海量数据处理面试题与十个方法大总结

作者:July.youwang.yanxionglu. 时间:二零一一年三月二十六日本文之总结:教你如何迅速秒杀掉:99%的海量数据处理面试题.有任何问题,欢迎随时交流.指正.出处:http://blog.csdn.net/v_JULY_v. 第一部分.十道海量数据处理面试题 1.海量日志数据,提取出某日访问百度次数最多的那个IP. 首先是这一天,并且是访问百度的日志中的IP取出来,逐个写入到一个大文件中.注意到IP是32位的,最多有个2^32个IP.同样可以采用映射的方法,比如模1000,把整

每日算法之二十八:Longest Valid Parentheses

Given a string containing just the characters '(' and ')', find the length of the longest valid (well-formed) parentheses substring. For "(()", the longest valid parentheses substring is "()", which has length = 2. Another example is &

Cocos2d-x 3.x 图形学渲染系列二十八

笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,国家专利发明人;已出版书籍:<手把手教你架构3D游戏引擎>电子工业出版社和<Unity3D实战核心技术详解>电子工业出版社等. CSDN视频网址:http://edu.csdn.net/lecturer/144 昨天,刚从丈母娘家回来,继续博客的更新,接着Cocos2d-x 3.x图形学渲染系列二十七继续系列二十八的编写. 接下来读取FBX模型文件信息,首先要做的是把读取的模型信息进行归类并

C++语言笔记系列之十八——虚函数(1)

1.C++中的多态 (1)多态性:同一个函数的调用可以进行不同的操作,函数重载是实现多态的一种手段. (2)联编:在编译阶段进行联接,即是在编译阶段将一个函数的调用点和函数的定义点联接起来. A.静态联编:在编译阶段就完成的函数联编--函数重载. B.动态联编:在程序的运行阶段由系统自动选择具体的函数--虚函数. 注:C++的多态主要指的就是动态联编. 2.虚函数 (1)虚函数是在函数的定义时将其声明为虚函数即可. (2)说明:virtual 数据类型 函数名(参数表) {函数体} A.目的:当

[算法系列之十四]字符串匹配之Morris-Pratt字符串搜索算法

前言 我们前面已经看到,蛮力字符串匹配算法和Rabin-Karp字符串匹配算法均非有效算法.不过,为了改进某种算法,首先需要详细理解其基本原理.我们已经知道,暴力字符串匹配的速度缓慢,并已尝试使用Rabin-Karp中的一个散列函数对其进行改进.问题是,Rabin-Karp的复杂度与强力字符串匹配相同,均为O(mn). 我们显然需要采用一种不同方法,但为了提出这种不同方法,先来看看暴力字符串匹配有什么不妥之处.事实上,再深入地研究一下它的基本原理,就能找到问题的答案了. 在暴力匹配算法中,需要检

ComicEnhancerPro 系列教程十八:JPG文件长度与质量

作者:马健邮箱:[email protected] 主页:http://www.comicer.com/stronghorse/ 发布:2017.07.23 教程十八:JPG文件长度与质量 众所周知,JPG是一种"有损"压缩格式,与PNG等无损压缩格式相比,最大的问题是:如果反复压缩,会造成图像质量逐渐退化.所以在对JPG文件进行处理,并且输出仍然选择JPG格式的情况下,很多人都会问同样的一个问题:如何才能在尽情享受有损压缩带来的较小文件长度的便利前提下,尽量避免图像质量退化? 为了解

[算法系列之十九]最长公共子序列

题目 最长公共子序列 分析 有两个字符串S1和S2,求一个最长公共子串,即求字符串S3,它们同时是S1和S2的子串,且要求它们的长度最长,并确定这个长度.这个问题我们称之为最长公共子序列问题. 与求最长递增子序列一样,我们首先将原问题分割成一些子问题,我们用dp[i][j]表示S1中前i个字符和S2中前j个字符分别组成的两个前缀字符串的最长公共子串长度.显然的,当i,j较小时我们可以直接给出答案,如dp[0][j] 必等于0.那么,假设我们已经求的dp[i][j](0 <= i < x,0 &

算法系列(十)堆实现优先队列

在算法系列(九)平衡二叉查找树AVL树中介绍了AVL树.这篇文章主要讲解优先队列. 一般都使用二叉堆来实现优先队列.暂时之说这种实现. 堆的定义和性质 堆实际上是一棵完全二叉树,其任何一非叶节点满足性质: Key[i]<=key[2i+1]&&Key[i]<=key[2i+2]或者Key[i]>=Key[2i+1]&&key>=key[2i+2] 即任何一非叶节点的关键字不大于或者不小于其左右孩子节点的关键字. 堆分为大顶堆和小顶堆,满足Key[i]

[算法系列之十]大数据量处理利器:布隆过滤器

[引言] 在日常生活中,包括在设计计算机软件时,我们经常要判断一个元素是否在一个集合中.比如在字处理软件中,需要检查一个英语单词是否拼写正确(也就是要判断 它是否在已知的字典中):在 FBI,一个嫌疑人的名字是否已经在嫌疑名单上:在网络爬虫里,一个网址是否被访问过等等.最直接的方法就是将集合中全部的元素存在计算机中,遇到一个新 元素时,将它和集合中的元素直接比较即可.一般来讲,计算机中的集合是用哈希表(hash table)来存储的.它的好处是快速准确,缺点是费存储空间.当集合比较小时,这个问题