Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/61.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 查找位数组中的第一个零_C_Linux_Bitmap_Bit Manipulation - Fatal编程技术网

C 查找位数组中的第一个零

C 查找位数组中的第一个零,c,linux,bitmap,bit-manipulation,C,Linux,Bitmap,Bit Manipulation,我有一个位图 uint64_t bitmap[10000] 跟踪系统中分配的资源。 现在的问题是如何有效地找到位图中的第一个未设置(零)位 我知道glibc中有ffsll(unsigned long-long)用于查找第一个设置位,我假设这是使用硬件指令完成的 为了在我的例子中使用这个函数,首先我需要初始化数组,将每一位设置为1,然后当我进行资源分配时,我必须在数组中线性搜索第一个非零字。然后使用ffsll()查找第一个设置位 我怎样才能做得更快 更新: 我使用的是x86-64 cpu。我不

我有一个位图

uint64_t bitmap[10000] 
跟踪系统中分配的资源。 现在的问题是如何有效地找到位图中的第一个未设置(零)位

我知道glibc中有
ffsll(unsigned long-long)
用于查找第一个设置位,我假设这是使用硬件指令完成的

为了在我的例子中使用这个函数,首先我需要初始化数组,将每一位设置为1,然后当我进行资源分配时,我必须在数组中线性搜索第一个非零字。然后使用ffsll()查找第一个设置位

我怎样才能做得更快

更新:
我使用的是x86-64 cpu。

我不确定您将如何获得比这快得多的速度,但我很容易被证明是错误的:

uint64_t bitmap[10000];
unsigned int i;
for (i = 0; i < (sizeof(bitmap) / sizeof(*bitmap)) && 0xFFFFFFFFFFFFFFFF == bitmap[i]; ++i);
const int bitInWord = ffsll(bitmap[i]);
const unsigned int firstZeroBit = bitInWord ? i * sizeof(*bitmap) * CHAR_BIT + bitInWord : 0;
uint64_t位图[10000];
无符号整数i;
对于(i=0;i<(sizeof(位图)/sizeof(*位图))&&0xFFFFFFFFFFFFFF==位图[i];+i);
常量int bitInWord=ffsll(位图[i]);
常量unsigned int firstZeroBit=bitInWord?i*sizeof(*位图)*字符位+二进制:0;

如果您使用的是32位cpu,则不希望这样做。而是使用32位整数的数组。阵列上的循环将更快

您还可以对1字节的每个值进行编码,然后预存储该字节中设置的第一位。因此,当您找到一个并非全部为0xFFFFFF的整数时,您可以简单地比较字节。如果第一个字节不是0xFF,则它位于该字节中,依此类推

因此,如果一个字节不是0xFF,则表示它是该字节255个可能值之一。每个值都有一个第一位集

另一种看待问题的方法是,如果可能的话,把问题分成几块。我不知道你的资源是什么,所以我不能说

还考虑在前一次扫描中,它向前循环的未设置位。如果您存储了上一个结果的索引,那么您可以在下一次搜索时从同一个索引开始。将此索引称为pos,并每次使用它

您还可以在每次将位设置为零时创建一个小的“空闲”索引数组,因此当“pos”到达数组末尾时,只需从保存的索引之一重新开始

换句话说,您真的不想每次都运行这么长的循环。这是您的问题,而不是获取位的最终指令。使用如上所述的索引跟踪,速度将提高数百倍。

您可以维护位图树,以高效地查找最低位集。在64位CPU上,跟踪4096个64位元素只需树深度为3,这意味着只需使用三个
ffsll
调用

基本上,这是通过将数组划分为64个单词块并为每个块分配一个64位索引来实现的。如果相应的位集字已设置所有位,则设置索引字的一位。更改位集中的位时,调整相应的索引字

然后可以在顶部构建另一个索引数组以形成树


每一个位的变化都需要一点额外的工作,但与需要空闲位时不必线性搜索位集所节省的成本相比,额外工作(和存储)的总量可以忽略不计。

谢谢,正如bobshacks在回答中提到的(分块)当您有要解除分配的资源索引,但需要找到与之对应的确切块,然后相应地更新位图树时,这会变得复杂。此外,位图树的动态增长必须使用平衡技术,否则此位图树将变得不平衡。@cmcdragokai:对于更新,它非常简单:将索引分成6位块,使用从最高有效到最低有效的块数搜索树。取消设置最低位;如果生成的64位字全部为零,则在父级中取消设置相应的值,依此类推。不需要平衡树:每个级别只是一个64路树。例如,索引0b001011_110000_001100_010101(0x2f0315)将解析为连续的位索引11、48、12和21。此位图树的设计与用于解析x86和其他体系结构上的地址的多级页表没有什么不同。我不是在处理与问题不同的固定大小的位数组。对于可以增长和收缩的可变大小的位数组,我希望这棵树在增长时需要平衡?在这种情况下,如何做到这一点?