(衝突のない)ハッシュテーブル検索は本当にO(1)なのですか?


10

免責事項:私はこことStackoverflowで同様の聞こえる質問があることを知っています。しかし、それらはすべて衝突についてであり、それは私が求めているものではありません。

私の質問は次のとおりです。なぜそもそも衝突のないルックアップなのO(1)ですか?

私がこのハッシュテーブルを持っているとしましょう:

Hash  Content
-------------
ghdjg Data1
hgdzs Data2
eruit Data3
xcnvb Data4
mkwer Data5
rtzww Data6

今、私はkハッシュ関数h(k)が与えるキーを探していますh(k) = mkwer。しかし、ルックアップはハッシュmkwerが5の位置にあることをどのように「知っている」のでしょうか。それO(n)を見つけるためにすべてのキーをスクロールする必要がないのはなぜですか?ハッシュは、実際のハードウェアアドレスではあり得ません。データを移動する能力を失うからです。そして、私の知る限りでは、ハッシュテーブルはハッシュでソートされていません(そうであったとしても、検索にも時間がかかりますO(log n))?

ハッシュを知ることは、テーブル内の正しい場所を見つけるのにどのように役立ちますか?

回答:


24

ハッシュ関数は、などの文字列を返しませんmkwer。配列内のアイテムの位置を直接返します。たとえば、ハッシュテーブルに10個のエントリがある場合、ハッシュ関数は0〜9の範囲の整数を返します。


1
ありがとう。:)私の間違いは、MD5やSHAのようなハッシュテーブルハッシュ関数について考えていました。しかし、もちろん、ハッシュは整数の位置にすることもできますが、私は考えていませんでした。何を探すべきかわかったので、すぐに良い例を見つけました。PHPの
Fooバー

13
@FooBar:MD5とSHAは、入力から単一の数値も計算します。16進形式でハッシュについて話すことは非常に一般的です。メモリアドレスが10進数で考慮されることはほとんどありません。
nperson325681

4
さらに、MD5などは、配列のインデックスとして直接使用するには長すぎます。下位nビットなど、ハッシュの一部を使用することが可能です。
chirlu 2016年

6

ハッシュ関数は、与えられた文字列から配列の位置を計算します。これが完全なハッシュである場合、それは確かに衝突がないことを意味します。最も可能性の高い配列は、要素の数よりも少なくとも2倍大きいです。


バツ=0;
バツ=バツメートルod52

この非常に単純なハッシュ(制限があり、衝突しやすい)は、ハッシュのメカニズムが他のハッシュとは異なり、与えられた入力を考慮しません。より高度なスキームでは、ハッシュは要素の数に合わせて調整された、より大きな数です。衝突がないことを保証するために、すべての入力に対して完全なハッシュが生成されます。

O1

hk

thszeofeleメートルet


1
そして、ルックアップはどのようにしてテーブルのどこにハッシュがあるかを知っていますか?順序付けされたアドレスでも、ハードウェアアドレスでもありません。
Foo Bar

hバツcvb=8

ただし、すべてのインデックスが入力されるわけではありません。ハッシュ1、4、8、90、および223にデータを入力した場合、ルックアップはどのようにして正しい場所を見つけますか?この場合、他のほとんどのインデックスが存在しないため、インデックス「90」は4の位置にあります。そして、空のハッシュテーブルはすべての可能な位置を持つ無限のサイズではありません!?
Foo Bar

HaHahバツcvb=Ha[90]

ハッシュ関数は、配列へのインデックスを返しません。代わりに、配列にマッピングできる予測可能な数を返します。これは通常、他のオペランドとしてハッシュテーブルバケットの数を指定したモジュラス演算子を使用して行われます。
クリストファーシュルツ2016

3

David Richerbyの答えを拡張すると、「ハッシュ関数」という用語は少し過負荷になります。多くの場合、ハッシュ関数について話すとき、MD5、SHA-1、または.hashCode()いくつかの入力を単一の数値に変換するJavaのメソッドのようなものを思い浮かべます。しかし、この数のドメインを使用すると、中にデータを格納しようとしているハッシュテーブルと同じサイズになるように非常に低い(すなわち、最大値である。)(MD5は、SHA-1は20バイトで、16バイトであり、。.hashCode()であるint- 4バイト)。

だからあなたの質問はその次のステップについてです-任意の入力を数値にマッピングできるハッシュ関数を作成したら、それらを特定のサイズのデータ​​構造にどのように入れるのですか?「ハッシュ関数」とも呼ばれる別の関数を使用して!

そのような関数の自明な例はmoduloです。モジュロを使用して、配列内の特定のインデックスに任意のサイズの数を簡単にマッピングできます。これは「分割方法」としてCLRSに導入されています。

kメートルkメートル

hk=kメートル

...

メートルメートルメートル=2phkpk

〜アルゴリズムの紹介、§11.3.1-CLRS

メートル

Java HashMapは、.hashCode()2のべき乗のサイズの配列を使用できるように、弱い実装を説明する前処理ステップを実行する除算メソッドの変更バージョンを使用します。あなたは.getEntry()メソッドで何が起こっているのか正確に見ることができます(コメントは私のものです):

 // hash() transforms key.hashCode() to protect against bad hash functions
 int hash = (key == null) ? 0 : hash(key.hashCode());
 // indexOf() converts the resulting hash to a value between 0 and table.length-1
 for (Entry<K,V> e = table[indexFor(hash, table.length)];
     ...

Java 8は、書き換えHashMapがさらに高速になりましたが、少し読みにくくなっています。ただし、インデックスの検索には同じ一般的な原則を使用します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.