C#中字符串的快速哈希函数

P b*_*sak 25 c# string hash performance

我想要将长度最多为30的字符串哈希.如果时间紧迫,那么最好的做法是什么.该功能将被调用超过1亿次.目前我使用以下代码,

static UInt64 CalculateHash(string read, bool lowTolerance)
{
    UInt64 hashedValue = 0;
    int i = 0;
    while (i < read.Length)
    {
        hashedValue += read.ElementAt(i) * (UInt64)Math.Pow(31, i);
        if (lowTolerance) i += 2;
        else i++;
    }
    return hashedValue;
}
Run Code Online (Sandbox Code Playgroud)

Dav*_*rtz 43

static UInt64 CalculateHash(string read)
{
    UInt64 hashedValue = 3074457345618258791ul;
    for(int i=0; i<read.Length; i++)
    {
        hashedValue += read[i];
        hashedValue *= 3074457345618258799ul;
    }
    return hashedValue;
}
Run Code Online (Sandbox Code Playgroud)

这是一个Knuth哈希.你也可以使用Jenkins.

  • 根据我自己的测试,此功能无法实现雪崩。YMMV。 (2认同)
  • 情况更糟.但我应该量化我原来的陈述.在输入上切换单个位会导致大约49.40%的输出位切换(使用原始常量),这比基于Bernstein的函数要好得多.对于大多数用途来说,这可能已经足够了.但是,例如,SuperFastHash(http://landman-code.blogspot.com/2009/02/c-superfasthash-and-murmurhash2.html)给了我50.02%.和Murmur2在同一页面给我50.04%. (2认同)
  • 它不适用于您关心的应用程序.它只是用于在哈希表中分发字符串. (2认同)

Cod*_*aos 6

首先,考虑使用GetHashCode().

对现有实施的简单改进:

static UInt64 CalculateHash(string read, bool lowTolerance)
{
    UInt64 hashedValue = 0;
    int i = 0;
    ulong multiplier = 1;
    while (i < read.Length)
    {
        hashedValue += read[i] * multiplier;
        multiplier *= 37;
        if (lowTolerance) i += 2;
        else i++;
    }
    return hashedValue;
}
Run Code Online (Sandbox Code Playgroud)

它避免了昂贵的浮点计算和开销ElementAt.

顺便说一下(UInt64)Math.Pow(31, i),对于较长的琴弦不适用.对于超过15左右的字符,浮点舍入将导致乘数为0.

  • 只是对 .NET Core 上的每个人发出警告:在 .NET Core 中,“GetHashCode”在应用程序重新启动之间是随机的!这意味着每次应用程序重新启动/回收时,您都会为同一字符串获得不同的哈希值 (2认同)