等価比較にショートカットとしてのハッシュコードを使用することは理にかなっている一つのケースがあります。
ハッシュテーブルまたはハッシュセットを構築する場合を考えてみましょう。実際、ハッシュセットを考えてみましょう(ハッシュテーブルは値を保持することでそれを拡張しますが、それは関係ありません)。
さまざまなアプローチがありますが、いずれもハッシュ値を入れることができるスロット数は少なく、オープンまたはクローズドアプローチをとっています。反対の専門用語を他者に使用する)。同じスロットに2つの異なるオブジェクトを衝突させた場合、同じスロットにオブジェクトを格納するか(実際にオブジェクトが格納されているリンクされたリストなど)、別のスロットを選択するために再プロービングすることができますこのための戦略)。
どちらのアプローチでも、私たちはハッシュテーブルでO(1)の複雑さからO(n)の複雑さに近づいています。このリスクは利用可能なスロットの数に反比例するので、あるサイズの後でハッシュテーブルのサイズを変更します(すべてが理想的だったとしても、格納されたアイテムの数がスロット)。
リサイズにアイテムを再挿入することは、明らかにハッシュコードに依存します。このため、オブジェクト内にGetHashCode()
をメモすることはめったにありませんが(ほとんどのオブジェクトでは頻繁に呼び出されることはありません)、ハッシュテーブル自体の中でメモを取ることは確かに意味があります(または、あなたが悪いGetHashCode()
の実装によって引き起こされた損害を減らすためにWang/Jenkinsハッシュで再ハッシュした場合など)。今
、我々はロジックのようなものになるだろう挿入するために来る:
- オブジェクトのハッシュコードを取得します。
- オブジェクトのスロットを取得します。
- スロットが空の場合は、オブジェクトを配置して戻ってください。
- スロットに等しいオブジェクトが含まれている場合は、ハッシュセットが完了し、ハッシュテーブルの値を置き換える位置になります。これを行い、帰ってください。
- 衝突の戦略に従って次のスロットを試して、アイテム3に戻ります(これをあまりにも頻繁に繰り返す場合はおそらくサイズ変更します)。
したがって、この場合、ハッシュコードを取得してから、同等かどうかを比較する必要があります。すでにサイズ変更が可能な既存のオブジェクトのハッシュコードも事前に計算されています。
private bool IsMatch(KeyType newItem, KeyType storedItem, int newHash, int oldHash)
{
return ReferenceEquals(newItem, storedItem) // fast, false negatives, no false positives (only applicable to reference types)
||
(
newHash == oldHash // fast, false positives, no fast negatives
&&
_cmp.Equals(newItem, storedItem) // slow for some types, but always correct result.
);
}
明らかに、これの利点は_cmp.Equals
の複雑さによって異なります。これら二つの事実の組み合わせは、それがのようにアイテム4のための私達の比較を実装することは理にかなっていることを意味します。私たちの鍵タイプがint
だった場合、これは完全に無駄になります。文字列と私たちが大文字と小文字を区別しないUnicodeで正規化された等価比較を使用していたキータイプ(長さに合わせてショートカットすることさえできない)なら、保存する価値があります。
一般的にmemoisingハッシュコードはパフォーマンス勝利には十分な頻度で使用されていないため意味がありませんが、ハッシュセットまたはハッシュテーブル自体に格納することは意味があります。
開発者として
GetHashCode
は、あなたが完全にハッシュが何であるかを理解するために自分自身にそれを借りてそれらはハッシュテーブルに関連して使用されます(DictionaryやHashSetなどで実装されています)。ハッシュテーブルのためのウィキペディアの記事は良いスタートです:http://en.wikipedia.org/wiki/Hash_table – spender@spender - これはまさにこの質問が私が最初に理解していた、または頭に浮かべるよりも詳細に説明したものです。 – Armbrat
等価チェックが間違っているだけでなく、コードが奇妙です。なぜゼロに397を掛けているのですか?私は今あなたに言うことができます、答えはゼロになるだろう、なぜマシンはそれを計算させる? xorに値が0の理由これはアイデンティティ操作です。 –