私はハッシュテーブルを理解しようとしています-誰かがそれを私に説明できますか?


25

PHPでのハッシュテーブルの正しい使用と実装を理解したい(申し訳ありません)。

私はどこかで、経験の浅いプログラマーがハッシュテーブルを作成し、それを反復処理したことを読みました。今、私はなぜそれが間違っているのか理解していますが、私の理解が正しいかどうかを知るための完全な知識はまだありません(あなたが私の意味を知っているなら)。

だから誰かが私にPHPでハッシュテーブル(おそらく連想配列)を実装する方法、そしておそらくもっと重要なことには、「ハッシュで」値にアクセスする方法とそれが実際に何を意味するかを説明できますか?

回答:


37

シンプルハッシュテーブルの概要

復習として、ハッシュテーブルは、データ構造内の特定のキーの下に値を格納する方法です。たとえば"a"、キーの下に値を格納1し、後で1ハッシュテーブルでキーを検索して値を取得できます。

私が頭の中で思いつくことができるハッシュテーブルの最も簡単な例は、整数のみを格納できるハッシュテーブルです。ハッシュテーブルエントリのキーは格納されている値でもあります。テーブルのサイズが8で、基本的にメモリ内の配列だとしましょう:

---------------------------------
|   |   |   |   |   |   |   |   |
---------------------------------
  0   1   2   3   4   5   6   7  

ハッシュ関数

ハッシュ関数は、値を保存する場所のインデックスを提供します。このテーブルの非常に単純なハッシュ関数は、保存したい値に1を追加し、することです国防省 8(テーブルサイズ)で、それを。言い換えると、ハッシュ関数は(n+1)%8であり、ここでnは保存したい整数です。

挿入物

このハッシュテーブルに値を挿入する場合は、挿入する値に対してハッシュ関数(この場合(n+1)%8)を呼び出して、インデックスを提供します。たとえば、14を挿入する場合、(14 + 1) % 8index を呼び出して取得する7ため、indexに値を挿入します7

---------------------------------
|   |   |   |   |   |   |   |14 |
---------------------------------
  0   1   2   3   4   5   6   7  

同様に、33、82、および191を次のように挿入できます。

---------------------------------
|191|   |33 |82 |   |   |   |14 |
---------------------------------
  0   1   2   3   4   5   6   7  

衝突

しかし、エントリと衝突するものを挿入しようとするとどうなりますか?2は、インデックスに行く必要があります3が、この問題を解決するために、複数の方法があります82により取得され、最も簡単なのは、我々が空きスペースを見つけるまで、繰り返し何度も何度も私たちのハッシュ関数を呼び出すことです。

したがって、ロジックは次のとおりです。

  1. (2 + 1)%8 = 3
  2. インデックス3がいっぱいです
  3. プラグ3当社のハッシュ関数に背中を。(3 + 1)%8 = 4、これは空です。
  4. 値をインデックス4に配置します。

ハッシュテーブルは次のようになり、値2がindexに格納されます4

---------------------------------
|191|   |33 |82 |2  |   |   |14 |
---------------------------------
  0   1   2   3   4   5   6   7  

このソリューションの欠点は、すぐにテーブルがいっぱいになることです!データサイズが制限されていることがわかっている場合、テーブルがすべての可能な値を保持するのに十分な大きさである限り、これは問題になりません。もっと保持できるようにしたい場合は、衝突を異なる方法で処理できます。2を挿入する前の場所に戻りましょう。

---------------------------------
|191|   |33 |82 |   |   |   |14 |
---------------------------------
  0   1   2   3   4   5   6   7  

思い出すと、(2+1)%8indexが与え3られます。ハッシュテーブルをいっぱいにしたくない場合は、各テーブルインデックスをリンクリストとして使用し、そのインデックスでリストに追加できます。したがって、再度ハッシュ関数を呼び出す代わりに、indexのリストに単純に追加します3

            -----
            | 2 |
---------------------------------
|191|   |33 |82 |   |   |   |14 |
---------------------------------
  0   1   2   3   4   5   6   7  

このリストは、メモリが許す限り大きくなる可能性があります。18を挿入でき、2に追加されます。

            -----
            |18 |
            -----
            | 2 |
---------------------------------
|191|   |33 |82 |   |   |   |14 |
---------------------------------
  0   1   2   3   4   5   6   7  

ルックアップ

ハッシュテーブルのサイズが非常に大きい場合、ハッシュテーブルでの値のルックアップは迅速です。単にハッシュ関数を呼び出して、インデックスを取得します。82がテーブルにあるかどうかを見たいとしましょう。ルックアップ関数は(82+1)%8= を呼び出し3、indexのアイテムを見て、3それを返します。16を検索した場合、検索関数はindexを検索し1、存在しないことを確認します。

ルックアップも衝突を処理する必要があります!

値2を検索しようとすると、ハッシュテーブルは、データの取得と同じ衝突ロジックを使用して、データを取得する必要があります。ハッシュテーブルの動作方法に応じて、探しているエントリが見つかるまで(または空白が見つかるまで)キーを何度もハッシュするか、アイテムが見つかるまでリンクリストを繰り返します(またはリストの最後に到達しました)

概要

したがって、ハッシュテーブルは、キーと値のペアをすばやく保存してアクセスするための優れた方法です。この例では、値と同じキーを使用しましたが、実際のハッシュテーブルではキーはそれほど制限されていません。ハッシュ関数はキーに対して機能してインデックスを生成し、キー/値をそのインデックスに保存できます。ハッシュテーブルは、実際に反復されることを意図していませんが、反復することは可能です。ご覧のとおり、ハッシュテーブルには多くの空白が含まれている可能性があり、ハッシュテーブルを反復処理するのは時間の無駄です。ハッシュテーブルにイテレータの空白検索をスキップするロジックがある場合でも、リンクリストなどのイテレータ用に設計されたデータ構造を使用する方が適しています。


2
アスキーアートFTW!
アント

2
素晴らしい答え。各インデックスがリンクリストであるメソッドは、チェーンと呼ばれることに言及する価値があるかもしれません。
アレクサン

+1素晴らしい答えで、私の頭からほとんど疑いが飛び出しました。もう1つ質問する必要があります。すべての実装はハッシュを使用して整数を格納しますか?またはこれは特定の場合に使用されますか?はいの場合、それらのケースは何ですか?
0decimal0

@PHIfounderあなたの質問を完全に理解したかどうかはわかりませんが、キーに対して実行されるハッシュ関数は、整数などの特定のデータ型に適用するだけでなく、汎用になるように設計されています。Cコードについて話している場合、ハッシュテーブルは、キーと値に対して(void *)を受け入れ、キーのポインター値でハッシュ計算を行うように設計できます。
ジェフ

@Jeffは実際にこれを尋ねるのはばかかもしれませんが、コンピューターの内部構造について話しているのです。すべてのコンピューターが整数を参照するストア参照を格納するためにハッシュテーブルのようなデータ構造を使用するかどうかは、内部的にですか?
-0decimal0

7

数千冊の本がある図書館を想像してください。書籍をタイトルごとにできるだけ早く見つけられるように整理する必要があります。

これを行う1つの(一般的な)方法は、本をアルファベット順に並べ替えることです。タイトルが「G」で始まる場合、「G」エリアを見つけてから、2番目の文字を探して「ö」、次に「d」、「e」、「l」、検索の絞り込みなどを検索します。 、本が見つかるまで。ただし、これには時間がかかる場合があります。また、新しい本が届くと、レイアウトを再編成して、新しい本のためのスペースを確保する必要がある場合があります。

それはバイナリ検索です。それは良いです。

ただし、これを行うにはより簡単な方法があります。すべての本棚と棚を列挙し、その後、各本について、本が見つかるはずの本棚/棚に対応する、特別な、できれば一意の番号を計算するとします。「キー」の計算方法は、ランダムに見える数値を提供する限り、重要ではありません。たとえば、タイトルのすべての文字の文字コードを追加し、それをある素数で除算することができます(おそらく最良の方法ではありませんが、とにかく動作します)。

それはハッシュです。書棚や棚全体を調べてタイトルの次の文字を調べる必要がないため、はるかに高速です。ハッシュは、通常、1回限りの操作です。ただし、2つ以上の本が同じキーに解決するときに「衝突」が発生する場合を除きます。しかし、それは問題ありません。それらは隣同士にあり、ハッシュ関数の品質に応じて、同じキーの下にあまり多くはないはずです。

ハッシュテーブルにはいくつかの制限と気まぐれ(リハッシュ/リサイズ)があり、実行可能な競合他社としてバイナリ検索を続けています。どちらの方法が優れているかに関しては、すべてが白黒ではありません。しかし、それは別の話です。

PS質問に直接答えないですみません(PHPでハッシュテーブルを作成します)が、それは詳細であり、「プログラミング」と呼ばれています;)


2
コンピューター関連の問題に対するコンピューター関連以外の説明が好きです。+1
ギャブリン

1

PHPのハッシュテーブルは、私の知る限り、次のように実装されています。

$my_hash = array(
    1 => "Bob",
    2 => "Alice",
    3 => "Jack"
);

次に、次のような呼び出しを介してデータにアクセスします。

echo $my_hash[2]; // Will echo "Alice"

foreach()関数を使用して、配列の内容を反復処理します。

ハッシュテーブルを理解する最善の方法は、http://en.wikipedia.org/wiki/Hash_tableのようなものを読むことですが、大まかに言ってこれに要約されます:そのarray()呼び出し内のすべての行の左側がキーです。これらのキーはハッシュ計算にかけられ、結果はハッシュになります。おそらくMD5またはSHAハッシュを以前に見たことがあるでしょう。これは非常によく似ています。このハッシュの特定の部分、通常は最初のX文字ですが、場合によっては完全なハッシュが、値の格納領域(右側)であるいわゆる「バケット」を識別するために使用されます。

次に、ハッシュテーブルにアクセスするたびに、キーを使用して値を取得します。キーは再びハッシュに対して計算され、ハッシュは関連する値をすばやく検索するために使用されます。そのため、ハッシュテーブルを使用すると、すべてが保存されている場合に直線的に検索するよりも高速に検索できます。唯一の欠点は、一部のハッシュ実装が衝突に悩まされることです。これは、2つの異なるキーに対して同じ計算ハッシュです。一般的に、それはあなたが多くを心配しなければならないものではありません。

これが背景を提供してくれることを願っていますが、興味があればこのテーマについてもっと読んでみてください。私の説明は非常に初歩的なものであり、そこに十分な穴があると確信していますが、簡単に説明するにはこれで十分でしょう。

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