位图概念
- 哈希是给一个类型的数据,进行单个映射。当面对40亿个海量数据时,内存就存不下了。
- 哈希桶一个 next 指针4个字节,单指针40亿个,160亿个字节。
- 换算:160亿个字节。
- 1个G 10亿多字节。40亿,4个G。16个G。
1 G = 1024MB = 1024*1024 KB = 1024*1024*1024Byte
2^30 1 000 000 000
1000 , 10000 , 10 0000 ,100 0000 ,1000 0000 ,1 0000 0000, 10 0000 0000
位图
- 数据是否在给定的整形数据中,结果是在或者不在,刚好是两种状态,
- 那么可以使用一个二进制比特位来代表数据是否存在的信息,如果二进制比特位为1,代表存在,为0代表不存在。
- 适用于海量数据,数据无重复的场景。通常是用来判断某个数据存不存在的。
- 字节序,即字节在电脑中存放时的序列与输入(输出)时的序列是先到的在前还是后到的在前。
位图的实现
- 2^32 个比特位 可表示一个无符号整型的最大值4,294,967,295,也就是 512MB。
2^32 / 2^3 2^29 = 2^30 / 2 = 1G /2 = 512MB
STL的容器:
size_t N
可变模板参数:根据数据范围,开多大的比特位。
- 常用功能:
- set,将一个数字设置成存在;
- reset,将一个存在的数据设置成不存在;
- test,看一个数字在不在。
- 一个数据
/ 8
就是 在哪个 数组 的下标里;% 8
,是在哪个比特位上。
#include<iostream>
#include<vector>
#include<time.h>
using namespace std;
namespace mybitset //处理整数 STL容器 bitset
{
//按位申请空间
template<size_t N>
class bitset
{
public:
bitset()
{
_vc.resize(N / 8 + 1,0);//多开一个字节,2/8 不给开
}
//该比特位设置成 1,在
void set(size_t x)
{
//在第几个char对象里
size_t i = x / 8;
//锁定在char对象里第几个比特位。
size_t j = x % 8;
_vc[i] |= (1 << j);
}
//将该数字设置成不存在
void reset(size_t x)
{
size_t i = x / 8;
size_t j = x % 8;
_vc[i] &= (~(1 << j));
}
//探测该数字在不在
bool test(size_t x)
{
size_t i = x / 8;
size_t j = x % 8;
return (_vc[i] & (1 << j)) == 0 ? false : true;
/*if ((_vc[i] & (1 << j)) == 0)
{
return false;
}
else
{
return true;
}*/
}
private:
vector<char> _vc;
};
位图应用
- 快速查找某个数据是否在一个集合中
- 排序
- 求两个集合的交集、并集等
- 操作系统中磁盘块标记
给定100亿个整数,设计算法找到只出现一次的整数?复用位图:给两个位图
template<size_t N>
class find_once_num
{
public:
find_once_num()
{}
void set(size_t x)
{
bool flag1=_bt1.test(x);
bool flag2 = _bt2.test(x);
if (flag1==false && flag2==false)//00--> 01
{
_bt2.set(x);
}
else if (flag1 == false && flag2 == true) // 01 已经出现一次;设置成10:代表出现两次
{
_bt1.set(x);
_bt2.reset(x);
}//10-->11出现多次
}
void prinf()
{
for (size_t i = 0; i < N; i++)
{
bool flag1 = _bt1.test(i);
bool flag2 = _bt2.test(i);
if (flag1 == false && flag2 == true)
{
cout << i << " ";
}
}
cout << endl;
}
private:
bitset<N> _bt1;
bitset<N> _bt2;
};
给两个文件,分别有100亿个整数,我们只有1G内存,如何找到两个文件交集?
- 位图应用变形:1个文件有100亿个int,1G内存,设计算法找到出现次数不超过2次的所有整数
哈希切分
给一个超过100G大小的log file, log中存着IP地址, 设计算法找到出现次数最多的IP地址? 与上题条件相同,如何找到top K的IP?
思路:
- 建立100个小文件,等于是100个哈希桶;100G文件依次获取ip地址,ip地址是字符串,算法转成int % 100 ,相同的,冲突的都到一个文件里面。
- 再依次读取每个小文件;
map<string,int> map[ ip ]++
,这里的ip地址就是大文件里该ip出现的总次数;给一个max,记录单个文件出现次数最多的那个pair. - 然后clear掉map,换下一个文件。
- 对所有小文件的max进行优先级队列按
pair<int,string>
插入,取top,K–。 - 若某个小文件过大,换个字符串转换算法,再切分。
测试用例
void test()
{
int a[] = { 5,6,6,7,8 };
find_once_num<10> f1;
/* srand(time(0));
for (size_t i = 0; i < 5; i++)
{
f1.set(rand()%100);
}*/
for (auto& i : a)
{
f1.set(i);
}
f1.prinf();
cout << endl;
}
void test1()
{
bitset<10> b1;
b1.set(9);
cout << b1.test(9)<<endl;
}