目录
一,位图的概念
在C++编程中,位图是一种常用的数据结构,用于高效地表示大量的布尔值。它通过使用一个二进制位来表示每个元素的存在与否,从而节省了大量的内存空间。
所谓位图,就是用每一位来存放某种状态,适用于海量数据,数据无重复的场景。通常是用 来判断某个数据存不存在的。
具体来说,位图由一组二进制位(0或1)组成,其中每个位代表一个元素的存在状态。
如果该位为1,则表示对应的元素存在;
如果该位为0,则表示对应的元素不存在。
通过这种方式,位图可以将大量的元素用较少的内存空间表示出来,从而提高了数据的处理效率。
在C++中,位图通常使用一个字符数组来表示。假设我们需要表示 n 个元素的存在状态,那么我们可以使用一个长度为 ( n / 8 + 1 ) 的整数数组来表示位图。其中,每个整数表示8个元素的存在状态。例如,如果第 i 个元素存在,则我们可以将第 i 个二进制位设置为1,并将其所在的整数存储在位图数组的第 i / 8 个位置上。
通过这种方式,我们可以快速地进行元素的插入、删除和查找操作。在插入一个元素时,我们只需要将相应的二进制位设置为1即可;在删除一个元素时,我们只需要将相应的二进制位设置为0即可;在查找一个元素时,我们只需要检查相应的二进制位是否为1即可。
问题:
给定一个包含40亿个数的数据集合,我们需要快速判断一个特定的数是否存在于其中。如何有效地解决这个问题呢?
在海量数据里面快速判断一个特定的树是否存在其中,传统的线性搜索算法需要遍历整个数据集合,时间复杂度较高,无法满足实时性和高效性的要求。而位图算法则提供了一种更加优雅和高效的解决方案。通过将每个数映射到位图中的相应位置上,我们可以利用位运算来快速判断一个数是否存在。
二,位图的实现
1,插入
1,计算索引:首先,需要确定要插入的元素在位图中对应的索引位置。通常情况下,位图使用字符数组来表示,每个整数可以表示8个元素的存在状态。因此,我们可以通过将元素的值除以8来计算它在整数数组中的索引。
int index= n / 8;
2,计算偏移量:接下来,需要确定要插入的元素在位图中对应的二进制位的偏移量。偏移量是指元素在整数中的二进制位的位置。我们可以通过将元素的值模8来计算偏移量。
int pos = n % 8;
3,设置二进制位:最后,通过使用位运算和按位或操作,将对应的二进制位设置为1,即将元素插入位图。
_bit[index] |= (1 << pos);
这里,(1 << pos)
表示将1左移pos位,得到一个只有第pos位为1的二进制数。然后,使用按位或操作符|=
将这个二进制数与位图中对应索引的整数进行按位或运算,将对应的二进制位设置为1。
2,删除
1,计算索引:首先,需要确定要插入的元素在位图中对应的索引位置。通常情况下,位图使用字符数组来表示,每个整数可以表示8个元素的存在状态。因此,我们可以通过将元素的值除以8来计算它在整数数组中的索引。
int index= n / 8;
2,计算偏移量:接下来,需要确定要插入的元素在位图中对应的二进制位的偏移量。偏移量是指元素在整数中的二进制位的位置。我们可以通过将元素的值模8来计算偏移量。
int pos = n % 8;
3,清除二进制位:最后,通过使用位运算和按位与操作,将对应的二进制位设置为0,即将元素从位图中删除。
_bit[index] &= ~(1 << pos);
这里,~(1 << pos)
表示将1左移pos位,得到一个只有第pos位为0的二进制数,然后使用按位与操作符&=将这个二进制数与位图中对应索引的整数进行按位与运算,将对应的二进制位设置为0。
3,查找
1,计算索引:首先,需要确定要插入的元素在位图中对应的索引位置。通常情况下,位图使用字符数组来表示,每个整数可以表示8个元素的存在状态。因此,我们可以通过将元素的值除以8来计算它在整数数组中的索引。
int index= n / 8;
2,计算偏移量:接下来,需要确定要插入的元素在位图中对应的二进制位的偏移量。偏移量是指元素在整数中的二进制位的位置。我们可以通过将元素的值模8来计算偏移量。
int pos = n % 8;
3,检查二进制位:使用按位与操作符&
将对应的二进制位提取出来,并检查其值是否为1。
int bit = _bit[index] & (1 << pos);
这里,(1 << pos)
表示将1左移pos位,得到一个只有第pos位为1的二进制数。然后,使用按位与操作符&
将这个二进制数与位图中对应索引的char变量进行按位与运算,提取出对应的二进制位。
如果结果为0,则表示元素不存在于位图中。
如果结果不为0,则表示元素存在于位图中。
三,模拟实现
class bitset
{
public:
bitset(size_t bitCount)
: _bit((bitCount >> 5) + 1), _bitCount(bitCount)
{}
// 将which比特位置1
void set(size_t which)
{
if (which > _bitCount)
return;
size_t index = (which >> 5);
size_t pos = which % 32;
_bit[index] |= (1 << pos);
}
// 将which比特位置0
void reset(size_t which)
{
if (which > _bitCount)
return;
size_t index = (which >> 5);
size_t pos = which % 32;
_bit[index] &= ~(1 << pos);
}
// 检测位图中which是否为1
bool test(size_t which)
{
if (which > _bitCount)
return false;
size_t index = (which >> 5);
size_t pos = which % 32;
return _bit[index] & (1 << pos);
}
private:
vector<int> _bit;
size_t _bitCount;
}