我们正在寻找计算上最简单的函数,该函数能够通过广泛分布的整数和整数范围的高频输入流来确定函数的索引查找。
如果散列/映射函数选择本身根据特定的整数和范围要求而变化,则可以,并且与选择此算法的代码部分相关联的性能并不重要。在大多数情况下,感兴趣的整数/范围的数量将很小(从零到几千)。性能关键部分是处理输入流并选择适当的功能。
举个简单的例子,请考虑以下伪代码:
switch (highFrequencyIntegerStream)
case(2) : func1();
case(3) : func2();
case(8) : func3();
case(33-122) : func4();
...
case(10,000) : func40();
在一个典型的例子中,上面只显示了几千个“案例”,其中可能包括全范围的32位整数值和范围。 (在33-122之上的伪代码中表示从33到122的所有整数。)将有大量包含这些“switch语句”的对象。
(注意实际的实现不包括switch语句。它将是一个跳转表(它是一个函数指针数组)或者可能是Command和Observer模式的组合等。实现细节与请求,但提供以帮助可视化。)
许多对象将包含只有少数条目的“switch语句”。感兴趣的值受实时变化的影响,但与管理这些变化相关的性能并不重要。基于特定的整数和感兴趣的范围(对于给定时间的给定对象),每次更新都可以缓慢地重新生成散列/映射算法。
我们在互联网上搜索,查看Bloom过滤器,维基百科“哈希函数”页面和其他地方列出的各种哈希函数,相当多的Stack Overflow问题,抽象代数(主要是Galois理论,对其计算简单的操作数很有吸引力) ),各种密码等,但没有找到似乎针对这个问题的解决方案。 (我们甚至找不到将这些类型的范围视为输入的哈希或地图函数,更不用说高效的范围。也许我们没有找到正确的位置或使用正确的白话。)
当前的计划是创建一个自定义算法,该算法预处理有趣的整数和范围列表(对于给定时间的给定对象),查找可应用于输入流的移位和掩码,以帮助描绘范围。请注意,大多数传入的整数都是不感兴趣的,并且尽可能快地决定流的那部分的大部分是非常重要的(这就是为什么Bloom过滤器最初看起来很有趣(在我们开始之前)认为他们的实现需要比其他解决方案更多的计算复杂性))。
因为第一个决定是如此重要,我们还在考虑使用多个表,其中第一个表是反向掩码(选择不感兴趣的数字的掩码),以便于查找不包含在给定“开关”中的大范围数据声明“,后面的表格将扩展较小的范围。我们认为,对于大多数输入流的情况,这将产生比范围边界上的二进制搜索快得多的东西。
请注意,可以认为输入流是随机分布的。
答案 0 :(得分:1)
我认为有一个非常广泛的最小完美哈希函数理论可以满足您的要求。最小完美散列的想法是以1-1方式将一组不同的输入映射到一组密集的整数。在你的情况下,一组N个32位整数和范围将被映射到一个大小范围内的唯一整数N.Gnu有一个称为gperf
的完美哈希函数生成器,用于字符串但可能会对您的数据起作用。我肯定会试一试。只需添加一个长度字节,使整数为5个字节的字符串,范围为9个字节。 the Wikipedia page有一些正式的参考资料。 ACM和IEEE文献中的文献搜索肯定会更多。
我刚刚遇到this library我以前从未见过的人。
<强>加成强>
我现在看到你试图将范围中的所有整数映射到相同的函数值。正如我在评论中所说,这与散列不是很相容,因为散列函数故意试图“擦除”位的位置中的幅度信息,因此具有相似幅度的值不可能映射到相同的散列值。
因此,我认为您不会比最佳二叉搜索树做得更好,或者等效地生成“if else”语句的最佳“树”的代码生成器。
如果我们想要构建您要求的类型的函数,我们可以尝试使用实数,其中各个域值映射到共域中的连续整数,范围映射到共域中的单位间隔。因此,简单的楼层操作将为您提供您正在寻找的跳转表索引。
在您提供的示例中,您将拥有以下映射:
2 -> 0.0
3 -> 1.0
8 -> 2.0
33 -> 3.0
122 -> 3.99999
...
10000 -> 42.0 (for example)
诀窍是找到一个单调增加的多项式,插入这些点。这当然是可能的,但是有数千个点我肯定你最终会得到比最佳搜索要慢得多的东西。
答案 1 :(得分:0)
也许我们的thoughts on hashing integers可以帮助一点点。你还会发现一个基于Bob Jenkins&#39;的散列库(hashlib.zip)。以智能方式处理整数的工作。 在单个案例被散列机制拒绝后,我建议处理更大的范围。