2009-10-30 25 views
1

是否存在Bob Jenkins散列函數的不區分大小寫的變體?不區分大小寫的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

對於Delphi 2010,使用「CompareText()」和「UpperCase()」是錯誤的 - 這些函數對Unicode字符串不起作用。請參閱https://forums.embarcadero。COM/thread.jspa?線程ID = 26949&TSTART = 0。 – mghie

+0

對於AnsiStrings,CompareText()和UpperCase()也是錯誤的,因爲它們只能對ASCII字符串進行操作。 –

回答

8

不,沒有散列函數的不變式版本。在將所有字符串傳遞給哈希函數之前,先將所有字符串縮小或大寫

+0

這就是我在我最後一段中寫的...... – jpfollenius

+2

是的,我確認它是一個解決方案。 –

3

它會稍微快一點,但它會傷害您的可維護性。這種微觀優化很少有很好的理由。只要將你的字符串轉換爲散列之前的低或大寫字母,就像你建議的那樣。

「我們應該忘記小 效率,講的 時間約97%:過早的優化是一切罪惡的 根然而,我們不 應在 關鍵的3%,通過了我們的機會。一個好的程序員將 不會被哄騙成這樣 推理自滿,他將是明智的,仔細看 在關鍵代碼;但 只有經過代碼已經確定 」 - 高德納

+1

+1爲Knuth的完整報價。所以我們經常只會得到「過早優化是萬惡之源」的部分。 –

+0

Knuth的報價很好,但你應該把它放在心上,尤其是「在代碼被識別出來之後」 - 你認爲它會稍微快一點嗎?我不這麼認爲。如果不分析代碼,我們的觀點本質上是毫無價值的。 – mghie

3

IMO整個問題都是錯誤的。引述Wikipedia article on hash functions

散列函數是大量的數據,可能是可變大小的量轉換成一個小基準,通常是一個整數,其可以充當任何定義明確的過程或數學函數數組的索引。

請注意「數據量」 - 沒有指定類型,事實上Bob Jenkins哈希函數有一個指向待散列數據的非類型化參數const Data。由於輸入數據不一定是一系列字符,因此無法計算「不區分大小寫」散列值。即使它是一系列字符 - 上限或下限將取決於字符集和編碼。所以你需要對ASCII字符串,UTF-8編碼的字符串,UTF-16 LE編碼的字符串......(你會明白)有不同的散列函數。

+0

嗯......這似乎是正確的...好吧,那麼,我會去的upperCase然後...或unicode版本的 – jpfollenius

0

我在項目中也需要這樣的功能。鮑勃·詹金的一個-AT-A-時間哈希:

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的字符串相同的哈希。

不要忘記禁用溢出檢查。