长字符串密钥的快速哈希函数

时间:2015-12-18 09:58:39

标签: c++ hash-function

我使用的是可扩展的哈希,我希望将字符串作为键。问题是我正在使用的当前哈希函数遍历整个字符串/键,我认为这对于程序的性能非常糟糕,因为哈希函数被多次调用,特别是当我分割存储桶时。

当前哈希函数

int hash(const string& key)
{
    int seed = 131;
    unsigned long hash = 0;
    for(unsigned i = 0; i < key.length(); i++)
    {
        hash = (hash * seed) + key[i];
    }
    return hash;
}

密钥长度可达40个字符。

字符串/键的示例

string key = "from-to condition"

我在互联网上搜索了一个更好的,但我找不到任何与我的情况相符的内容。有什么建议吗?

3 个答案:

答案 0 :(得分:3)

您应该更喜欢使用std::hash,除非测量显示您可以做得更好。要限制它使用的字符数,请使用以下内容:

    const auto limit = min(key.length(), 16);
    for(unsigned i = 0; i < limit; i++)

您需要尝试找到要使用的16的最佳值。

我实际上会期望性能变差(因为你会有更多的碰撞)。如果你的字符串是几k,那么限制到前64个字节可能是值得的。

根据您的字符串,可能值得在一开始就开始。例如,散列文件名你最好使用20到5之间的字符(忽略常常的路径名前缀和文件扩展名)。但是你还需要衡量。

答案 1 :(得分:2)

  

我使用的是可扩展的哈希,我希望将字符串作为键。

如前所述,使用std::hash直到有充分的理由不这样做。

  

问题是我正在使用的当前哈希函数迭代整个字符串/键,我认为这很糟糕......

这是一个可以理解的想法,但实际上不太可能是一个真正的问题。

  

(期待)为什么?

快速扫描堆栈溢出将揭示许多有经验的开发人员谈论缓存和缓存行。

(如果我教我的祖母吃鸡蛋,请原谅我)

现代CPU在处理指令和执行(非常复杂)算术方面非常快。几乎在所有情况下,限制其性能的是必须通过总线与内存通信,相比之下,速度非常慢。

因此芯片设计人员可以构建内存缓存 - 位于CPU中的极快内存(因此无需通过慢速总线进行通信)。不幸的是,这个缓存内存只有很多可用的空间[加上热量限制 - 另一天的主题],因此CPU必须将其视为操作系统执行磁盘缓存,刷新内存并在需要时将内存读取

如上所述,通过总线进行通信很慢 - (简单地说)它需要主板上的所有电子组件停止并彼此同步。这浪费了大量的时间[这将是一个很好的观点,讨论电子信号在主板上的传播受到大约一半光速的限制 - 这很有吸引力但是这里只有很多空间而且我有只有这么多时间]。因此,不是一次传输一个字节,字或长字,而是以块的形式访问内存 - 称为缓存行

事实证明,这是芯片设计人员的一个好决定,因为他们了解大多数内存是按顺序访问的 - 因为大多数程序大部分时间都是线性访问内存(例如在计算哈希值时,比较字符串或对象,转换序列,复制和初始化序列等等。

这一切的结果是什么?

嗯,奇怪的是,如果你的字符串还没有在缓存中,那么读取它的一个字节几乎与读取所有第一个(比如说)128个字节中的字节一样昂贵它的。

另外,因为缓存电路假定存储器访问是线性的,所以一旦获取了第一个缓存线,它就会开始提取。它会在CPU执行哈希计算时执行此操作。

我希望你能看到,在这种情况下,即使你的字符串长达数千字节,并且你选择仅每隔128字节哈希(比方说),你所做的只是计算一个非常低劣的仍然导致内存缓存在获取大块未使用内存时暂停处理器的哈希值。 这需要同样长的时间 - 更糟糕的结果!

  

话虽如此,有什么理由不使用标准实施?

仅限于:

  1. 用户抱怨您的软件太慢而无法使用,

  2. 该程序可以验证CPU限制(使用100%的CPU时间),

  3. 该程序不会通过旋转浪费任何周期,

  4. 仔细分析显示该程序最大的瓶颈是哈希函数,

  5. 另一位经验丰富的开发人员进行的独立分析证实,无法改进算法(例如通过不经常调用哈希)。

  6. 简而言之,几乎从不。

答案 2 :(得分:1)

您可以直接使用std::hash link,而不是实现自己的功能。

#include <iostream>
#include <functional>
#include <string>

size_t hash(const std::string& key)
{
    std::hash<std::string> hasher;
    return hasher(key);
}

int main() {
    std::cout << hash("abc") << std::endl;
    return 0;
}

请在此处查看此代码:https://ideone.com/4U89aU