设为首页 加入收藏

TOP

Bit-map法处理大数据问题(一)
2015-08-31 21:23:23 来源: 作者: 【 】 浏览:55
Tags:Bit-map 处理 数据 问题

问题引入:


1.给40亿个不重复的unsigned int的整数,没排过序的,然后再给一个数,如何快速判断这个数是否在那40亿个数当中?
2.给定一个千万级别数据量的整数集合,判断哪些是重复元素。
3.给定一个千万级别数据量的整形数组,对其进行排序。
4.在5亿个整数中找出不重复的整数(注意,内存不足以容纳这5亿个整数)。


从数据量上看,使用常规的解法(普通排序算法,逐个比较等)明显不合适,所以这里我们引入一个新的解法,就是Bitmap。


Bitmap就是用一个bit位来标记某个元素对应的Value, 而Key即是该bit的位序。由于采用了Bit为单位来存储数据,因此可以大大节省存储空间。 bitmap通过1个位表示一个状态,比如:int类型有2^32个数字,即4G个数字,那么每个数字一个状态,就是2^32个bit,即512 MB(也就是说,用512兆存储空间就可以处理4G个数据,即40+亿数据)。


下面是我用C++写的一个bitmap类,可以通过构造对象时传入数据规模,动态申请所需的内存,然后处理用户的大量数据:


#include
#include
#include
using namespace std;
const unsigned SIZE = 512000000;//512兆静态存储区可处理40.96亿数据


class Bitmap {
? ? typedef struct Byte {
? ? ? ? unsigned char bit8;
? ? ? ? static const unsigned char mask[9];//用来取得一个字节每一位的辅助数组
? ? ? ? Byte()
? ? ? ? {
? ? ? ? ? ? bit8 = 0;
? ? ? ? }
? ? ? ? //设置该位,就是存储该数
? ? ? ? void set1(unsigned at)
? ? ? ? {
? ? ? ? ? ? bit8 |= mask[at];
? ? ? ? }
? ? ? ? //读取该位是否有数
? ? ? ? bool get1(unsigned at)
? ? ? ? {
? ? ? ? ? ? return bit8 & mask[at];
? ? ? ? }
? ? } Byte;
? ? Byte *m_byte;
? ? unsigned m_size;
public:
? ? Bitmap(unsigned _size)
? ? {
? ? ? ? m_byte = new Byte[(_size+7)/8];
? ? ? ? m_size = _size;
? ? }
? ? virtual ~Bitmap()
? ? {
? ? ? ? delete[] m_byte;
? ? ? ? m_size = 0;
? ? }
? ? //存储一个数据
? ? bool push(unsigned data)
? ? {
? ? ? ? if(data>=m_size)
? ? ? ? ? ? return false;
? ? ? ? m_byte[data/8].set1(data%8);
? ? ? ? return true;
? ? }
? ? //读取一个数据是否存在
? ? bool find(unsigned data)
? ? {
? ? ? ? return data>=m_size ? 0 : m_byte[data/8].get1(data%8);
? ? }
? ? //返回能存储的数据个数
? ? unsigned size()
? ? {
? ? ? ? return m_size;
? ? }
? ? //重载运算符实现常用功能
? ? //存储一个数据
? ? bool operator>>(unsigned data)
? ? {
? ? ? ? return push(data);
? ? }
? ? //读取一个数据是否存在
? ? bool operator<<(unsigned data)
? ? {
? ? ? ? return find(data);
? ? }
? ? //访问到某个数据块
? ? Byte& operator[](unsigned i)
? ? {
? ? ? ? if(i>=m_size/8)
? ? ? ? ? ? throw "index out of range";
? ? ? ? return m_byte[i];
? ? }
};
const unsigned char Bitmap::Byte::mask[9] = {0x80,0x40,0x20,0x10,0x8,0x4,0x2,0x1};//用来取得一个字节每一位的辅助数组


int main()
{
? ? Bitmap bitmap(8*SIZE);//可以存储40+亿数据
? ? ifstream file("in.txt");//从文件内录入一些整数
? ? unsigned read, i=0, t1 = clock();
? ? for(i=0; i? ? ? ? if(file>>read)
? ? ? ? ? ? bitmap>>read;
? ? ? ? else
? ? ? ? ? ? break;
? ? file.close();
? ? cout<<"共存储"<? ? t1 = clock();
? ? for(i=0; i<1000000; ++i)
? ? ? ? if(bitmap<? ? ? ? ? ? ;
? ? cout<<"访问"<? ? cout<<"请输入需要检索的数据:"<? ? while(cin>>read) {
? ? ? ? if(bitmap<? ? ? ? ? ? cout<<"已存储"<? ? ? ? else
? ? ? ? ? ? cout<<"Error: 未存储"<? ? }
? ? return 0;
}


运行结果如下:



在程序中,先读取一个文本文件中随机产生的6W个整数,存到这个bitmap中,然后测试了一下从这个建立好的bitmap中查找100W数据耗时情况(11ms左右),接下来的部分是用户可以手动输入一些整数,程序会自动检索bitmap中是否已存储该数据。


这样就可以解决引入话题中的第一个问题了,把输入的文本数据改为已知的40亿数据就可以了(40亿数据的录入可能需要一会儿,大概1300秒)。


下面给出引入的剩余三个问题的解题思路。


问题2:先建立一个足够大的Bitmap对象,然后依次录入这些数据,如果录入某数据前发现该位已经为1,则该数据重复,依次得到重复的数据即可。


问题3:先建立一个足够大的Bitmap对象,然后依次录入这些数据,从Bitmap开始位置起遍历,如果某位不为0,则表示有该数据,依次输出不为0的位的位序就是排序好的数组(输出太多没意义,可以将输出转换到写入文件,那么新文件中数据就是排序好的)。


问题4:方法1,建立2个足够大的Bitmap对象,依次录入数据,录入前先判断该数据在bitmap1中是否存在(即对应位是否为1),不存在则录入到bitmap1中,存在就录入到bitmap2中;全部录入完后,依次遍历bitmap1中每一位,如果某一位为1但是bitmap2中对应位不为1,则表示该数据只出现过一次,依次输出即可。


方法2,建立一个足够大的Bitmap对象,不过用两位表示一个数据,00表示数据不存在,01数据出现一次,10表示数据出现多次。11呢?一边凉快去吧,不要你了,哈哈。这样依次录入数据时,如果该对应位(其实是两位)为00则改为01,01就改为10,10就不管了。录入完成后,遍历整个bitmap,找到01位就输出。


  好了,常见的大数据题目就通过bitmap这个神奇的结构给解决了,不过bitmap也不是万能的,很明显,它暂时只适合存储整形数据,当然这里只考虑了unsigned类型数据,如果是int类型的话,对应映射一下就可以了也是没问题的。不过即使如此,也只能处理10亿级别的数据,如果数据量更大、类型不只是整形呢?


  比如:需要写一个网络蜘蛛(web crawler)。由于网络间的链接错综复杂,蜘蛛在网络间爬行很可能会形成“环”。为了避免形成“环”,就需要知道蜘蛛已经访问过哪那些URL。给一个URL,怎样知道蜘蛛是否已经访问过?


  不难想到如下几种方案:


  1. 将访问过的URL全部保存到数据库


  2. 用HashSet将访问过的URL保存起来。

首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇二分查找真的有你想象中那么简单.. 下一篇for(int a:i)在Java 编程中的使用

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: