web-dev-qa-db-ja.com

ハッシュテーブルとハッシュマップとは何ですか?

私は最近これらの用語に何度か出くわしましたが、それらがどのように機能し、いつそれらが通常実装されるのか、かなり混乱していますか?

36
Kamil Zadora

さて、このように考えてください。

単純なインデックスベースのデータ構造である配列を使用し、ランダムなもので埋める場合、基本的には検索を開始する必要があるため、特定のエントリを見つけることは、データを埋めるときにますますコストのかかる操作になります。必要なものが見つかるまで、一方をもう一方に向けます。

データへのアクセスを高速化したい場合は、通常、配列をソートしてバイナリ検索を使用します。ただし、これにより、既存の値を検索する速度が向上しますが、途中で要素を挿入する必要があるときに既存の要素を移動する必要があるため、新しい値の挿入が遅くなります。

一方、ハッシュテーブルには、エントリを取得し、それを数値、つまりハッシュキーに変換する関数が関連付けられています。この番号は、配列へのインデックスとして使用され、ここにエントリを格納します。

ハッシュテーブルは、最初は空で始まる配列を中心に展開します。空は長さがゼロを意味するのではなく、配列はサイズで始まりますが、配列内のすべての要素には何も含まれていません。

各要素には、2つのプロパティ、データ、およびデータを識別するキーがあります。たとえば、米国の郵便番号のリストは、郵便番号->名前タイプの関連付けになります。関数はキーを削減しますが、データは考慮しません。

したがって、ハッシュテーブルに何かを挿入すると、関数はキーを数値に減らします。これは、この(空の)配列へのインデックスとして使用されます。これは、データ、キー、および関連データの両方を格納する場所です。

次に、後で、キーがわかっている特定のエントリを見つけたいので、同じ関数でキーを実行し、そのハッシュキーを取得して、ハッシュテーブルの特定の場所に移動し、そこでデータを取得します。

理論によると、キーをハッシュキー(その数)に削減する関数は、線形検索よりも計算コストがはるかに安価です。

一般的なハッシュテーブルには、格納に使用できる要素の数が無限ではないため、通常、その数は、配列のサイズに適合するインデックスまでさらに削減されます。これを行う1つの方法は、配列のサイズと比較したインデックスの係数を単純に取得することです。サイズが10の配列の場合、インデックス0〜9は直接インデックスにマップされ、インデックス10〜19は再び0〜9にマップされます。

一部のキーは、ハッシュテーブルの既存のエントリと同じインデックスに削減されます。この時点で、実際のキーは直接比較され、すべてのルールはキーのデータ型の比較(つまり、通常の文字列比較など)に関連付けられています。完全に一致する場合は、新しいデータを無視する(既に存在する)か、上書きする(そのキーの古いデータを置き換える)か、それを追加する(多値ハッシュテーブル)。一致がない場合、つまり、ハッシュキーは同じでしたが、実際のキーは同じでなかった場合、通常、そのキーとデータを格納する新しい場所を見つけます。

衝突解決には多くの実装があり、最も簡単な方法は、配列内の次の空の要素に移動することです。ただし、この単純なソリューションには他の問題もあります。そのため、適切な解決アルゴリズムを見つけることも、ハッシュテーブルの良い練習になります。

ハッシュテーブルが完全に(または近くに)満杯になると、ハッシュテーブルも大きくなる可能性があります。これは通常、新しいサイズの新しい配列を作成し、すべてのインデックスをもう一度計算して、アイテムを新しい配列の新しい配列に配置することによって行われます場所。

キーを数値に変換する関数は、線形値を生成しません。 「AAA」が1になり、「AAB」が2になるため、ハッシュテーブルは通常の値で並べ替えられません。

この件に関するウィキペディアの優れた記事 here もあります。

70

lassevkの答えは非常に優れていますが、詳細が多すぎる可能性があります。エグゼクティブサマリーは次のとおりです。私は意図的に特定の関連を省略しています情報を99%無視しても安全です。

ハッシュテーブルとハッシュマップの間には、99%の時間で重要な違いはありませんがあります。

ハッシュテーブルは魔法です

真剣に。 つのことを保証する以外のすべての魔法のデータ構造。 (例外はあります。いつかそれらを学ぶことが役立つかもしれませんが、それらはほとんど無視できます。)

1)ハッシュテーブル内のすべてがペアの一部ですkeyvalueがあります。操作するキーを指定して、データを出し入れします。

2)ハッシュテーブルの単一のキーで何かをしている場合、それは非常に速いです。これは、put(key,value)get(key)contains(key)、およびremove(key)がすべて本当に高速であることを意味します。

3)一般的なハッシュテーブル#2にリストされていないものを実行すると失敗します! (「失敗」とは、非常に遅いことを意味します。)

ハッシュテーブルはいつ使用しますか?

私たちはハッシュテーブルを使用しますそれらの魔法が私たちの問題に合うとき

たとえば、cachingはしばしばハッシュテーブルを使用することになります-たとえば、大学に45,000人の学生がいて、すべてのレコードを保持する必要があるプロセスがあるとします。学生をID番号で定期的に参照する場合は、ID => studentキャッシュは非常に理にかなっています。このキャッシュに対して最適化している操作は高速検索です。

ハッシュは、データ間の関係を保存するにも非常に役立ちます。これは、完全に独り占めしてオブジェクト自体を変更したくない場合です。たとえば、コースの登録時に、受講者が受講しているクラスに学生を関連付けることができるとよいでしょう。ただし、何らかの理由で、Studentオブジェクト自体にそれを知らせたくない場合があります。 studentToClassRegistrationハッシュを使用して、必要なことを何でも行う間、それを保持します。

また、次のいずれかを実行する必要がある場合を除いて、データ構造のかなり良い最初の選択肢を作成します。

ハッシュテーブルを使用しない場合

要素を反復処理。ハッシュテーブルは通常、反復処理をあまりうまく行いません。 (一般的なもの、つまり、特定の実装にはリンクリストが含まれている場合があります。リンクリストを使用すると、リストの反復処理を減らすことができます。たとえば、Javaでは、LinkedHashMapを使用すると、キーまたは値をすばやく反復処理できます。)

並べ替え。反復できない場合、並べ替えも王の苦痛です。

値からキーへ2つのハッシュテーブルを使用します。私を信じて、私はあなたに多くの苦痛を救った。

54

javaの観点から話している場合、どちらもオブジェクトの追加、削除、更新を許可するコレクションであり、内部でHasingアルゴリズムを使用します。

ただし、Javaについて説明する場合の大きな違いは、ハッシュテーブルは本質的に同期されているため、スレッドセーフであり、ハッシュマップはスレッドセーフなコレクションではないということです。

同期とは別に、オブジェクトを保存および取得するための内部メカニズムは、どちらの場合もハッシュです。

ハッシュがどのように機能するかを確認する必要がある場合は、データ構造とハッシュ手法について少しグーグルすることをお勧めします。

4
Nrj