已知a.txt中有40亿个无符号整数,b.txt中有10000个无符号整数,求交集。可用内存:1G
定义
位图法是bitmap的缩写,其指用每一位来存放某种状态,适用于大规模数据,但数据状态不多的情况
举例说明:
|
|
在该数组成可存储N*sizeof(int)8个数据,但最大的数只能是Nsizeof(int)*8-1。若存数据范围0~15,则使N=1即可
数据为【5,12,1,0,4】存入后:
使用范围
使用bit数组来表示某些元素是否存在,如8位电话号码等
位图的操作
在C++中int类型由4个字节,即32位。当有1000万条不同数据时,我们只需1000万个位来表示,也就是10000000/(8*1024*1024)MB,约为1.25MB
1MB=1000KB=10^6B—–百万字节
1GB=1000MB=10^9B—–十亿字节
1000万条=10^7=(10/8)*10^6 B=1.25MB
使用一个unsigned int类型的数组或向量来表示位图,假定vector
i/32使用位移操作:i>>5,i%32使用:i&31
setZero置零操作
将位图中第i位置零1a[i>>5] &= ~(1<<(i&31));setOne置位操作
将位图中的第i位设置为1,即将a[i/32]的第(i%32)位设置为1。1a[i>>5] |= (1<<(i&31));getState获取状态操作
判断第i位是否为1,得到的值大于0,说明该位值为1,否则为01return a[i>>5] &(1<<(i&31));
实现代码
|
|
函数库实现
C++的STL中有bitmap类,它提供了很多方法,详见http://www.cplusplus.com/reference/stl/bitset/
- 使用C++的bitset:
|
|
注意:
bitset不能放在main内,否则stack overflow。若要放在main内,要放在main内,要加static或new一个。
位图应用
- 求字符的所有组合
思路:输入a、b、c,则它们的组合为a,b,c,ab,ac,bc,abc。
假设原有元素有n个,则最终组合为2^n-1个。利用位图思想,假设原有a、b、c三个元素,则1表示取元素,0表示不取。故取a则为001,取ab则为011,而000没有意义,所以共有2^n个结果。
这些位图值都是1,2,…,2^n,所以从值1到值2^n-1的输出结果为:
001,010,…,111
对应观察结果为:a,b,ab,c,ac,bc,abc。
因此,循环1~2^n-1,然后输出组合结果即可。
|
|
- bitmap求哈密尔顿距离
问题描述
给定N(1<=N<=100000)个五维的点(X1,X2,X3,X4,X5),求两点X(x1,x2,x3,x4,x5)和Y(y1,y2,y3,y4,y5)使得|x1-y1|+|x2-y2|+|x3-y3|+|x4-y4|+|x5-y5|最大
- 解题思路
对于任意两点(x1,x2)和(y1,y2)
|x1-y1|=max(x1-y1,y1-x1);
=>|x1-y1|+|x2-y2|=max{
(x1-y1)+(x2-y2)
(x1-y1)-(x2-y2)
(y1-x1)+(x2-y2)
(y1-x1)-(x2-y2)
};
=max{
(x1+x2)-(y1+y2)
(x1-x2)-(y1-y2)
(-x1+x2)-(-y1+y2)
(-x1-x2)-(-y1-y2)
};
通过观察,发现每一对相同元的符号必定相反,如:xi-yi,于是使用bitmap的思想来枚举这些二维的点的x轴和y轴前的正负号,这样可用一个0~3的二进制形式来表示:0表示+号,1表示-号。
对于每个点X和Y的符号,可用A[4]数组存储下来,那么对于点1(x1,y1)和2(x2,y2)两点就可表示为下式一:
A[1][0] - A[2][0]
A[1][1] - A[2][1]
A[1][2] - A[2][2]
A[1][3] - A[2][3]
约定X[ij]的下标数字(ij)是二进制,令
X00=x1+x2
X01=x1-x2
X10=-x1+x2
X11=-x1-x2
假设有A-Z共26个点,则
result=max{
(A00-B00), (A01-B01), (A10-B10), (A11-B11),
(A00-C00), (A01-C01), (A10-C10), (A11-C11),
……
(X00-Y00), (X01-Y01), (X10-Y10), (X11-Y11),
(Y00-Z00), (Y01-Z01), (Y10-Z10), (Y11-Z11),
}
很明显,对上面每一列应用max运算:
max(第一列)=
max(A00,B00,…,Z00) - min(A00,B00,…,Z00)
result=max{max(第一列),max(第二列) … };
对每个I(00,01,10,11),求A[*][I]的最大值max(I)和最小值min(I),然后再求max{max(I)-min(I)}
- 通俗的理解
先求A[i][I]-A[j][I](I=00,01,10,11),还原就是先求该等式xi+xj-(yi+yj)的最大值,分解后变成求max(xi+xj)和min(yi+yj)。再求这两个数相差后得到的集合中的最大值即可。