如何在庞大的二进制数据中快速识别 1(索引)的连续范围?
Posted
技术标签:
【中文标题】如何在庞大的二进制数据中快速识别 1(索引)的连续范围?【英文标题】:How to fast identify contiguous range of 1’s(Index) in huge binary data? 【发布时间】:2015-02-01 18:02:57 【问题描述】:谁能建议更快的算法来识别大型二进制数据中 1 的连续范围?
遍历数据是唯一的解决方案吗?在我真的不想要的最坏情况下,遍历会给出O(n)
。
有人可以推荐更快的算法吗?
如下图所示。我需要找到索引 4000,它是 1 的连续范围的起始位置
index 0
|
00000000000000000000000000000000000000000011111100000
【问题讨论】:
如果某些东西比 O(n) 快,它不会查看某些位,而这些位可能是 1。将位 32 打包成一个 int,您可以一次跳过 0 的 32。 @brianbeuning 它仍然是 O(n),只是具有较低的常数因子 需要停在第一个范围还是创建地图?而且,只有两个“一”还可以称为一个范围? 一次检查大块会有所帮助,但最终,二进制数据将是0或1,要检查它是什么,您需要检查每个块[除非有一些外部信息可以告诉你什么更有可能,等等] 当然,在很多情况下,运行速度提高 64 或 128 倍确实是相当不错的性能提升。此外,使用多个处理器,可以将工作分成几个“大块”。 【参考方案1】:我想不出任何不是 O(n) 的东西,因为数据总是未排序的。
但是,我可以想到捷径,因为你想要一组至少 3 个,并且是二进制数据。
#include <iostream>
using namespace std;
int main()
unsigned int seed = 3758096384; //11100000000000000000000000000000
unsigned int testvar = 419307644; //00011000111111100010000001111100
int result = 0;
int continuous = 0;
while (seed != 7 && (continuous == 1 || result == 0))
if (seed == (testvar & seed))
result |= seed;
continuous = 1;
else
continuous = 0;
seed >>= 1;
// result = 16646144 or 00000000111111100000000000000000
cout << result << endl;
//the index, 8388608 or 00000000100000000000000000000000
cout << (int)((result ^ (result >> 1)) & ~(result >> 1)) << endl;
return 0;
它是如何工作的: 它是一个二进制过滤器,它创建一个 3 位的掩码,并在循环的每一步中连续左移 1。
所以你有这些数字作为过滤器:
3758096384 - 11100000000000000000000000000000
1879048192 - 01110000000000000000000000000000
939524096 - 00111000000000000000000000000000
...
14 - 00000000000000000000000000001110
7 - 00000000000000000000000000000111
然后它检查种子是否与测试的数字和种子本身之间的逻辑与结果匹配(这会过滤所有与过滤器不匹配的数字)。
如果种子和AND匹配,它使用逻辑或将种子移动到结果,并设置一个连续来控制序列的连续性。第一次结果不连续,就打破循环。
最后,你有结果,可以通过以下方式计算索引:
1110
0111 SHIFT TO LEFT by 1 and XOR
1001
0111 NOT (SHIFT TO LEFT by 1) and AND
------------
1000
您将需要以 32 位块扫描 50gb 数据(易于适应 64 位,甚至对其进行矢量化)。
【讨论】:
【参考方案2】:好吧,你不能避免至少检查一次整个数据(你必须至少查看所有内容!),但是如果你可以避免多次检查它,例如run-length encode 数据。
【讨论】:
以上是关于如何在庞大的二进制数据中快速识别 1(索引)的连续范围?的主要内容,如果未能解决你的问题,请参考以下文章