搜索已排序的静态数组

时间:2017-03-24 00:24:13

标签: c++ algorithm sorting optimization

我正在寻找以最快的方式搜索已排序的固定32位密钥数组。数组大小和数据是静态的,永远不会改变。该数组的大小约为1000-10000个唯一元素。搜索范围明显更广(~100000),因此无法找到大量搜索值。我只对完全匹配感兴趣。

以下是搜索的进展方式:

  1. 生成~100个键。这些键按相关性顺序排列,因此不能简单地排序
  2. 在静态数组集合中搜索~100个键的集合(通常介于50到300之间)
  3. 当我们找到足够的匹配结果时停止搜索(因此,不对键进行排序以获得最相关的结果的重要性)
  4. 密钥的一个潜在有趣的属性是,即使它们在整数值方面不接近,它们中的大多数只会与它们最近的邻居有几个不同的位(~1-4)。

    我发现大多数答案都指向二进制搜索但没有处理静态数组的情况,这可能会带来一些优化可能性。

    我完全可以控制数据结构,现在它是一个固定的排序数组,但如果它不是最优的,我可以改变它。我还可以添加预先计算的信息,因为如果不占用不合理的内存量,数据不会改变。

    目标是在CPU和内存方面都很高效,尽管CPU是这里的优先事项。

    使用C ++虽然这可能不会影响答案。

1 个答案:

答案 0 :(得分:3)

考虑到您的静态数组永远不会改变,并且您拥有无限的预处理能力,我认为最好的方法是为每个数组创建一个特定的哈希函数。

我的方法 - 定义参数化哈希函数(java中的代码):

private static Function<Long, Integer> createHashFunction(int sz) {
    int mvLeft = ThreadLocalRandom.current().nextInt(30);
    int mvRight = ThreadLocalRandom.current().nextInt(16);
    int mvLeft2 = ThreadLocalRandom.current().nextInt(10);
    int mvRight2 = ThreadLocalRandom.current().nextInt(16);
    int mvLeft3 = ThreadLocalRandom.current().nextInt(16);
    int mvRight3 = ThreadLocalRandom.current().nextInt(20);
    return (key) -> {
        // These operations are totally random, and has no mathematical background beneath them!
        key = ~key + (key << mvLeft);
        key = key ^ (key >>> mvRight);
        key = key + (key << mvLeft2);
        key = key ^ (key >>> mvRight2);
        key = key + (key << mvLeft3);
        key = key ^ (key >>> mvRight3);
        return (int) (Math.abs(key) % sz); // sz is the size of target array
    };
}

对于每个测试阵列找到这样的参数组合,即最大桶大小是最小的。

一些测试(输入数组的大小为10k,填充了随机元素):

  • 哈希映射到[0..262k]会产生最多2个项目的桶。测试了5k随机数组,单线程版本以~100阵列/秒速率查找散列函数。

考虑到最大桶大小为2,可以将两个值映射到一个64位整数,这种方法只会导致一次内存跳转,而最简单的CPU操作 - 散列是通过xor,plus和移位,这应该是非常快的以及位比较。

但是,您的数据可能不太好,并且可能要求存储桶大小为3,这会破坏存储桶项目long long使用的可能性。在这种情况下,您可以尝试找到一些不错的哈希函数,而不是我写的随机混乱。