C#中字符串的快速散列函数
本文关键字:散列函数 字符串 | 更新日期: 2023-09-27 18:26:36
我想散列一个长度不超过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;
}
static UInt64 CalculateHash(string read)
{
UInt64 hashedValue = 3074457345618258791ul;
for(int i=0; i<read.Length; i++)
{
hashedValue += read[i];
hashedValue *= 3074457345618258799ul;
}
return hashedValue;
}
这是Knuth散列。你也可以使用詹金斯。
首先,考虑使用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;
}
它避免了昂贵的浮点计算和ElementAt
的开销。
顺便说一句,(UInt64)Math.Pow(31, i)
对较长的字符串不起作用。浮点舍入将导致超过15个字符的乘数为0。
为了加快实现速度,(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];