【问题标题】:What search algorithm fails fastest什么搜索算法失败最快
【发布时间】:2012-11-22 05:02:57
【问题描述】:

给定一个整数,我需要从一个小集合中找到一个匹配项。整数几乎总是不在集合中。对于大多数搜索算法,这是最坏的情况(花费时间最长)。但是对于这个应用程序,搜索时间将取决于搜索失败的速度。所以我想要一个最好的情况是“找不到”的算法。

这样的事情存在吗?

整数远不是随机的,它们是数组索引——比如 0..10k(15 位)。这些集合将包含 0..7 个整数,这对于简单的线性搜索来说是足够少的。但这在几乎所有情况下都是最坏的情况。

我唯一能想到的就是布隆过滤器。它会像这样工作:定义 F(int) = Set Bit (i AND 1Fh)(即,一个 32 位整数,一个位被设置)。对于每个集合,我会将 F(每个元素)的 OR'd 值存储在一起(一个 32 位整数,为 n 个元素设置最大 n 位)。然后搜索将是 IF (F(i) AND F(set))>0 然后执行线性搜索。

因此,除非至少一个集合元素具有与测试整数 i 相同的低 5 位,否则永远不会执行搜索。可以根据下一个最低 5 位添加第二个测试。

谁有更好的想法?

【问题讨论】:

  • 一组最多 7 个 16 位整数将整齐地放入单个缓存行中,因此在内存访问效率方面,朴素的方法可能已经是最佳的。是什么让您相信线性搜索值得优化?
  • 原则上布隆过滤器可能是一个好方法,但只有 7 个元素,你将很难击败线性搜索。您建议的哈希不是很好(想想当您有 4 个元素时应该设置多少位)。如果使用 SSE 指令,您或许可以在一条指令中使用 VCMPPS 进行比较。
  • @willglynn,Profiling 表明这是一个热点。此代码位于三重循环内,是跳过大多数内部情况的优化的一部分。所涉及的数据结构在设计时考虑了缓存效率。当我想到这可能毫无意义时,我正在考虑如何对集合元素进行排序,因为在大多数情况下我需要检查整个集合。因此问题。
  • @rlibby;同意,线性搜索将很难被击败。由于这些整数是连续的,因此 5-LSB 将均匀分布。是的,我考虑过位数。在本机整数中,我将有一个 32 位过滤器,我希望它们中的大多数保持为 0。过滤器 #2 和 3 可以分别是接下来的 5 位。在 3 个测试中,我可以确定是否存在测试整数——但不知道是哪一个。但平均而言,线性搜索将在等于平均集合占用率的多次比较中找到确切答案。
  • 我认为测试集合中的存在性已经接近最优,所以我会专注于寻找消除这种搜索的方法,而不是让它更快。这可能是多个集合的布隆过滤器,但如果不了解更多关于外部循环的信息,很难说。你能描述一下更广泛的问题吗?

标签: algorithm


【解决方案1】:

我能想象到的最快的算法,它会立即成功或失败,是一个巨大的数组 0..MaxInt 的布尔值,除了 Array[Set Member] 处的 True 之外都是 False。搜索将是一个简单的数组查找:

Found = Array[Test]  

但是内存占用是荒谬的。一个常见的优化是哈希数组。

作为测试,我使用 Set Members 的位实现了 Perfect Hash。函数 PHash(int) 返回一个整数 0..15,它是 如果存在匹配项,将在其中找到匹配项的数组索引。然后搜索是:

IF Array[PHash(Test)] = Test 
  THEN Found at Index PHash(Test) 
  ELSE Not Found  

分析表明这比线性搜索要慢,这可能不会让任何人感到惊讶。 (叹气)

当然,没有一个 Hash 可以将 15 位整数简化为不同的 4 位整数。我使用许多不同的哈希函数。为了生成集合,我找出哪个函数为该集合生成不同的 4 位哈希,然后将集合存储为哈希函数指针加上一个 16 元素数组。每个数组元素是 X 或一个集合成员,其中 X 不在集合范围内。 (找不到完美哈希会抛出一个异常,这还没有发生。)这些开销在分析中都不重要,因为它是在程序启动时完成的。

要在 Set 中查找 Test 整数,我调用 Set.HashFunction(Test),然后将 Test 与该 Set.Array 元素进行比较。最后的比较与线性搜索的每个步骤相同。为了更快,哈希函数必须比线性搜索的剩余比较更快。因此,这可能是一种更快的算法,但仅适用于足够大的集合大小。

我还没有尝试找到那个集合大小。无论如何,这取决于每个散列函数的速度。

【讨论】:

  • 更广泛的背景是什么?我坚持认为,比单个缓存行填充更快地评估这一点的唯一方法是扩大问题范围。合并或选择性地消除这些最里面的测试是可能的。即使不是,外部循环也可能保证显式预取未来 N 次迭代所需的数据——假设逻辑使得 CPU 无法猜测要预取什么。没有更多信息,这一切都只是猜测。
猜你喜欢
  • 2011-03-12
  • 1970-01-01
  • 1970-01-01
  • 2018-01-12
  • 1970-01-01
  • 2021-09-07
  • 1970-01-01
  • 2021-01-24
  • 1970-01-01
相关资源
最近更新 更多