簡體   English   中英

在位數組中找到第一個零

[英]Find the first zero in a bitarray

我有位圖

uint64_t bitmap[10000] 

跟蹤系統中分配的資源。 現在的問題是,如何有效地找到此位圖中的第一個未設置(零)位?

我知道glibc中有ffsll(unsigned long long)用於查找第一個設置位,我假設它使用硬件指令來完成。

要在我的情況下使用此功能,首先我需要初始化數組以將每個位設置為1,然后在進行資源分配時,我必須在數組中線性搜索第一個非零字。 然后使用ffsll()查找第一個設置位。

我怎樣才能更快地完成?

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

您可以維護一個位圖以有效地找到最低位集。 在64位CPU上,您僅需具有3的樹深即可跟蹤4096個64位元素-這意味着僅使用三個ffsll調用。

基本上,這是通過將數組划分為64個字的塊並為每個塊分配一個64位索引來實現的。 如果相應的位集字已設置所有位,則設置索引字的一位。 當您更改位集中的某個位時,您將調整相應的索引字。

然后,您可以在頂部構建另一個索引數組以形成樹。

每次更改位都需要一點額外的工作,但是與不需要線性搜索位集而需要的空閑位相比,節省的總開銷(和存儲空間)可以忽略不計。

我不確定您會比這快得多,但是我很容易被證明是錯誤的:

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;

如果您使用的是32位cpu,則您不想這樣做。 而是使用32位整數數組。 陣列上的循環會更快。

您還可以將每個值編碼為1個字節,然后進行預存儲,這是該字節中設置的第一位。 因此,當您找到一個不全為0xFFFFFFFF的整數時,可以簡單地比較字節。 如果第一個字節不是0xFF,則它在該字節中,依此類推。

因此,如果字節不是0xFF,則表示它是該字節的255個可能值之一。 每個值都有一個第一位設置。

解決問題的另一種方法是,如果可能的話,將其分成多個部分。 我不知道您的資源是什么,所以我不能說。

還要考慮在前一次掃描中循環返回的未設置位。 如果存儲上一個結果的索引,則只需在下一個搜索中從相同的索引開始。 將此索引稱為pos並每次使用。

您還可以在每次將位設置為零時創建一個小的“空閑”索引數組,因此,當“ pos”到達數組末尾時,只需從已保存的索引之一開始即可。

換句話說,您確實不想每次都運行這么長的循環。 那是你的問題,而不是最后的指示。 使用上面概述的索引跟蹤,它將快數百倍。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM