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

C# C语言中字符串的快速哈希函数#,c#,string,performance,hash,C#,String,Performance,Hash,我想散列一个长度不超过30的字符串。如果时间是我关心的问题,那最好的办法是什么呢。该函数的调用次数将超过1亿次。目前我正在使用以下代码 static UInt64 CalculateHash(string read, bool lowTolerance) { UInt64 hashedValue = 0; int i = 0; while (i < read.Length) { hashedValue += read.ElementAt(i)

我想散列一个长度不超过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;
}
静态UInt64计算哈希(字符串读取,布尔低容差)
{
UInt64哈希值=0;
int i=0;
而(i
为了加快实现速度,应将
(UInt64)Math.Pow(31,i)
调用替换为查找:预先计算
31
的前30次幂的表,并在运行时使用它。由于长度限制为30,因此只需要31个元素:

private static unsigned long[] Pow31 = new unsigned long[31];

static HashCalc() {
    Pow31[0] = 1;
    for (int i = 1 ; i != Pow31.Length ; i++) {
        Pow31[i] = 31*Pow31[i-1];
    }
}

// In your hash function...
hashedValue += read.ElementAt(i) * Pow31[i];
静态UInt64计算哈希(字符串读取)
{
UInt64哈希值=3074457345618258791ul;

对于(int i=0;i首先,考虑使用<代码> GethAsHeCudie())< /C> > /P> 对现有实现的简单改进:

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;
}
静态UInt64计算哈希(字符串读取,布尔低容差)
{
UInt64哈希值=0;
int i=0;
ulong乘数=1;
而(i
它避免了昂贵的浮点计算和
ElementAt
的开销


顺便说一句,Math.Pow(31,i)
对较长的字符串不起作用。浮点舍入将导致超过15个左右的字符的乘数为0。

是否有原因导致
对象.GetHashCode()
方法对您不起作用?看起来您几乎是在重新实现相同的概念。任何不使用浮点数学的方法都会更快。GetHashCode是不可持久的,因此如果他需要将哈希代码存储到数据库中,它就没有用了。再说一次,这也没有用。您的用途是什么?您只需要对字符串进行哈希吗在运行时,或者您需要如何处理散列?如果您需要存储它,并且不会遇到太多冲突,Adler-32可能是一个选项。@Pbasak然后将其强制转换为
uint
或使用
0x7FFFFF
屏蔽它。运行探查器。这将告诉您慢的部分是什么。然后修复慢的部分。乘法器必须从素数开始大于256或者如果第一个字节很小,则会严重中断。@DavidSchwartz较大的素数当然更好,但严重中断有点言过其实。如果64位哈希函数有多个2字节的输入发生冲突,我认为它会严重中断。(但考虑到OP开始时的函数有多糟糕,可能我的标准太高。)即使素数>256,我也不能确定查表是否比整数乘法快。@CodeInChaos它肯定比
Math.Pow(31,I)快
。另外,当
I
在一个条件内增加2时,我需要一个额外的乘法,所以我会先尝试查找。根据我自己的测试,这个函数没有实现avalanche.YMMV。它更糟糕。但我应该量化我的原始语句。切换输入上的一个位会导致约49.40%的输出位切换到gling(使用原始常量),这比基于Bernstein的函数要好得多。对于大多数用途来说,这可能已经足够了。但是,例如,SuperFastHash()在同一页上,Murruld2给了我50.02%,而Murruld2给了我50.04%。它不适用于您关心的应用程序。它只是用于在哈希表中分配字符串。您能为这个算法提供引用吗?我搜索了TAOCP第3卷,但找不到您拥有的这些常量。@ShitalShah我很确定它是这是TAOCP的,但我不确定是哪一卷。
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;
}