Bob Jenkins哈希函数是否存在不区分大小写的变体?
Generics.Defaults.BobJenkinsHash
提供快速哈希函数。不幸的是,它不能与不区分大小写的比较函数结合使用,如此
TCustomStringComparer = class (TEqualityComparer <String>)
function Equals(const Left, Right: String): Boolean; override;
function GetHashCode(const Value: String): Integer; override;
end;
function TCustomStringComparer.Equals (const Left, Right : String) : Boolean;
begin
Result := CompareText (Left, Right) = 0;
end;
function TCustomStringComparer.GetHashCode (const Value : String) : Integer;
begin
Result := Generics.Defaults.BobJenkinsHash (Value [1], Length (Value) * SizeOf (Char), 0);
end;
这是因为TDictionary首先比较哈希码,然后在检查相等时使用提供的比较器。
当然我可以在我的GetHashCode
函数中使用UpperCase,但我想知道如果我能以某种方式修改哈希函数本身会更快。
答案 0 :(得分:8)
不,哈希函数没有大小写不变的版本。在将所有字符串传递给哈希函数之前,将所有字符串置大小写。
答案 1 :(得分:3)
它会稍快一些,但会严重损害您的可维护性。这种微优化很少有充分的理由。只需像你建议的那样在散列之前将字符串转换为小写或大写。
“我们应该忘记小事 效率,约占97% 时间:过早优化是 万恶之源。但我们不应该 放弃我们的机会 至关重要3%。一个优秀的程序员会 不被这样的自满所哄骗 推理,他会明智地看 仔细阅读关键代码;但 只有在那段代码之后 确定“ - 唐纳德克努特
答案 2 :(得分:3)
IMO整个问题都是错误的。引用Wikipedia article on hash functions:
哈希函数是任何定义良好的过程或数学函数,它将大量可能可变大小的数据转换为小数据,通常是一个可作为索引的单个整数。一个数组。
注意“数据量” - 没有指定类型,实际上Bob Jenkins散列函数有一个无类型参数const Data
指向要散列的数据。由于输入数据不一定是字符序列,因此无法计算“不区分大小写”的散列值。即使它是一系列字符 - 上层或下层也依赖于字符集和编码。所以你需要为ASCII字符串,UTF-8编码字符串,UTF-16 LE编码字符串,...(你明白了)提供不同的哈希函数。
答案 3 :(得分:0)
我还需要在项目中使用这样的功能。 Bob Jenkin的一次性哈希:
function hash(const s: string): cardinal;
var
p, last: PByte;
begin
if s = '' then exit(1);
p := pbyte(pointer(s));
last := p + length(s);
result := 0;
while p < last do begin
if {$ifdef asciionly}p^ < 128{$else}true{$endif} then begin
result := result + p^;
if (p^ >= ord('a')) and (p^ <= ord('z')) then result := result - ord('a') + ord('A');
result := result + (result shl 10);
result := result xor (result shr 6);
end;
inc(p);
end;
result := result + (result shl 3);
result := result xor (result shr 11);
result := result + (result shl 15);
end;
如果设置了asciionly,它也应该为utf-8和latin1字符串提供相同的哈希值。
不要忘记禁用溢出检查。