BitMap算法和C++ STL里面的bitset

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Q1410136042/article/details/82119599

今天看到大数据处理的BitMap算法,可以有效地对空间进行压缩。

一、BitMap基本思想

在32位的机器上,一个int需要占据32位,而有时候这就是很大的空间浪费。比如没有重复数字的计数排序的时候,假设数据范围[0,1e8],则需要开辟数组int a[(int)1e8+1],a[i]表示i的出现的次数。这就需要大约400M的空间了。然而,由于数字不会重复,所以a[i]只会是0或1,那么32位的int必然对空间造成了很大的浪费。如果是以前,我会改成bool数组,空间下降为100M,然而接触BitMap算法后,我发现bool实际上是个不合理的存在——它用着1byte即8位的空间,却干着1位的事情(非0即1)。因为非0即1,所以完全可以用1位来表示一个数存在或者不存在,空间变为最初的1/32。用一位来表示一个数,这就是BitMap的基本思想

二、BitMap的基本实现

现在可以重新开一个数组int b[(int)1e8/32+1],b[]是a[]的1/32,但需要表达的内容却要和a[]一样多,那么则需要对b[]进行处理。因为一位表示一个数,那么对于任意b[i],自然都是表示32位数了。即:b[0]表示0~31,b[1]表示32~63,以此类推。现在给一个数399,怎么存到b[]数组里呢?首先判断它应该存到b[i]对应的哪个i,这简单,显然i=399/32,也就是i=12。那么再考虑399对应b[12]的哪一位,这也很显然,对应的自然是399%32=15位里。然后问题是怎么将b[12]的第15位变成1?我使用的方法是

b[12] |= (1<<15)。这很好理解~

代码:

const int maxn = 1e8/32 + 1;
int b[maxn];
inline void insert(const int& x)
{
    int i = x/32, j = x%32;
    b[i] |= (1<<j);
}

三、STL之bitset

我觉得bitset就是bitmap算法在C++里面被封装起来了,也是用位来表示一个数,bitset支持与(unsigned)(long long) int、bool、string之间的相互转化。

头文件:

#include<bitset>

声明bitset变量:

bitset<size> name<InitNum>

像上面那个数组直接就可以写成:

const int size = 1e8 + 1;
bitset<size> c(0);

这样开辟出来的bitset变量c和上面包含了(1e8/32+1)个int的b数组所占空间差不多。需要注意的是,这里的c是一个占据空间size bit的变量,而不是一个数组,所以后面括号里面的初始值是转化为size长度二进制后赋给c的所有位。额,好像说起来有点抽象,举个栗子:

由这个栗子可以知道bitset支持cout,那么我们可以猜到,bitset同样支持cin,需要注意的是输入必须是01串,否则从第一个非0/1的数字开始就不会读入了。

上面我们自己实现的bitmap插入一个数用insert(x),对于bitset却是可以直接用:

b[x] = 1

没错,bitset可以直接对某一位赋值,这里就有点像string了。不同的是bitset还可以进行&、|、~、^、<<、>>等位运算符。

接下来介绍一下bitset的一些方法:

c.size()      // 返回大小(位数)
c.count()     // 返回1的个数
c.any()       // 返回是否有1
c.none()      // 返回是否没有1
c.set()       // 全都变成1
c.set(p)      // 将第p + 1位变成1
c.set(p, x)   // 将第p + 1位变成x
c.reset()     // 全都变成0
c.reset(p)    // 将第p + 1位变成0
c.flip()      // 全都取反
c.flip(p)     // 将第p + 1位取反
c.to_ulong()  // 返回它转换为unsigned long的结果,如果超出范围则报错
c.to_ullong() // 返回它转换为unsigned long long的结果,如果超出范围则报错
c.to_string() // 返回它转换为string的结果

猜你喜欢

转载自blog.csdn.net/Q1410136042/article/details/82119599