我想将长度最多为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;
}
答案 0 :(得分:40)
static UInt64 CalculateHash(string read)
{
UInt64 hashedValue = 3074457345618258791ul;
for(int i=0; i<read.Length; i++)
{
hashedValue += read[i];
hashedValue *= 3074457345618258799ul;
}
return hashedValue;
}
这是一个Knuth哈希。您也可以使用Jenkins。
答案 1 :(得分: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;
}
它避免了昂贵的浮点计算和ElementAt
的开销。
Btw (UInt64)Math.Pow(31, i)
对于较长的字符串不起作用。对于超过15左右的字符,浮点舍入将导致乘数为0。
答案 2 :(得分:1)
我玩过Paul Hsieh的实现,并且看起来很快就碰撞很少(对于我的场景无论如何)
答案 3 :(得分:1)
为了加快实施速度,(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];