C++ 用于在位数组中搜索连续设置/清除位的快速代码?
是否有一些相当快的代码可以帮助我快速搜索大位图(几兆字节)中连续的零位或一位的运行 我所说的“相当快”是指可以利用机器字的大小,一次比较整个字,而不是进行极其缓慢的逐位分析(例如使用C++ 用于在位数组中搜索连续设置/清除位的快速代码?,c++,c,bitarray,bitvector,C++,C,Bitarray,Bitvector,是否有一些相当快的代码可以帮助我快速搜索大位图(几兆字节)中连续的零位或一位的运行 我所说的“相当快”是指可以利用机器字的大小,一次比较整个字,而不是进行极其缓慢的逐位分析(例如使用vector) 它非常有用,例如,在卷的位图中搜索可用空间(用于碎片整理等)。Windows有一个可以与其API一起使用的数据结构 但是我在前一段时间需要这方面的代码,所以我在这里写了它(警告,它有点难看): 我只对它进行了部分测试,所以它可能仍然有bug(特别是在反向测试时)。但是最近的一个版本(与这个版本略有不
vector
)
它非常有用,例如,在卷的位图中搜索可用空间(用于碎片整理等)。Windows有一个可以与其API一起使用的数据结构
但是我在前一段时间需要这方面的代码,所以我在这里写了它(警告,它有点难看):我只对它进行了部分测试,所以它可能仍然有bug(特别是在
反向测试时)。但是最近的一个版本(与这个版本略有不同)似乎对我有用,所以值得一试
整个过程的基本操作是能够快速找到一段位的长度:
long long GetRunLength(
const void *const pBitmap, unsigned long long nBitmapBits,
long long startInclusive, long long endExclusive,
const bool reverse, /*out*/ bool *pBit);
考虑到它的多功能性,其他一切都应该很容易在此基础上构建
我试图包含一些SSE代码,但没有显著提高性能。但是,一般来说,代码比逐位分析快很多倍,因此我认为它可能有用
如果你能在某种程度上掌握<代码> vector < /COD>缓冲区,那么如果你在Visual C++上,那么就可以很容易地测试它了。如果你发现了bug,请随时告诉我。我不知道如何直接在内存单词上做得很好,所以我制定了一个快速解决方案,就是在字节上工作;为了方便起见,让我们绘制一个计算连续数的算法:
构造两个大小为256的表,其中您将为0到255之间的每个数字写入,即字节开头和结尾的尾随1的数量。例如,对于数字167(二进制为10100111),将1放在第一个表中,将3放在第二个表中。让我们将第一张桌子命名为BBeg,第二张桌子命名为BEnd。然后,对于每个字节b,有两种情况:如果是255,则在当前连续的一组字节的当前和中加上8,即在一个1区域中。否则,用BBeg[b]位结束一个区域,用BEnd[b]位开始一个新区域。
根据您想要的信息,您可以调整此算法(这就是为什么我不在这里放任何代码的原因,我不知道您想要什么输出)
一个缺陷是它不计算一个字节内的(小的)连续的一组
除了这个算法之外,一位朋友告诉我,如果是用于磁盘压缩,只需查找不同于0(空磁盘区域)和255(满磁盘区域)的字节。这是一种快速的启发式方法,可以构建一个映射,以确定要压缩的块。也许这超出了本主题的范围…听起来这可能很有用:
和
你不会说你是否想做某种RLE,或者只是简单地计算字节的0和1位(比如0b1001应该返回1x1 2x0 1x1)
查找表加上用于快速检查的SWAR算法可能会很容易地为您提供这些信息。
有点像这样:
byte lut[0x10000] = { /* see below */ };
for (uint * word = words; word < words + bitmapSize; word++) {
if (word == 0 || word == (uint)-1) // Fast bailout
{
// Do what you want if all 0 or all 1
}
byte hiVal = lut[*word >> 16], loVal = lut[*word & 0xFFFF];
// Do what you want with hiVal and loVal
for (int i = 0; i < sizeof(lut); i++)
lut[i] = countContiguousZero(i); // Or countContiguousOne(i)
// The implementation of countContiguousZero can be slow, you don't care
// The result of the function should return the largest number of contiguous zero (0 to 15, using the 4 low bits of the byte, and might return the position of the run in the 4 high bits of the byte
// Since you've already dismissed word = 0, you don't need the 16 contiguous zero case.
字节lut[0x10000]={/*见下文*/};
用于(uint*word=words;word>16],loVal=lut[*word&0xFFFF];
//对hiVal和loVal做你想做的事
LUT必须根据预期的算法进行构造。如果要计算字中连续的0和1的数量,可以这样构造:
byte lut[0x10000] = { /* see below */ };
for (uint * word = words; word < words + bitmapSize; word++) {
if (word == 0 || word == (uint)-1) // Fast bailout
{
// Do what you want if all 0 or all 1
}
byte hiVal = lut[*word >> 16], loVal = lut[*word & 0xFFFF];
// Do what you want with hiVal and loVal
for (int i = 0; i < sizeof(lut); i++)
lut[i] = countContiguousZero(i); // Or countContiguousOne(i)
// The implementation of countContiguousZero can be slow, you don't care
// The result of the function should return the largest number of contiguous zero (0 to 15, using the 4 low bits of the byte, and might return the position of the run in the 4 high bits of the byte
// Since you've already dismissed word = 0, you don't need the 16 contiguous zero case.
for(int i=0;i
难道你不能把你的数组当作一个整数数组,并将整数与零进行比较吗?@Andrew:这取决于你试图实现的目标……这些位可能不会一次对齐8位。你可以比较6个字节(如果bmp是彩色图像文件:6个字节是两个连续的像素)使用6个零的数组。@eharvest:我不是说图片!这与光栅图像完全无关。我是说位数组,即位数组。对不起,我读你的问题太快了。。。