ハッシュテーブルとハッシュアルゴリズム

ハッシュテーブル

ハッシュテーブル(HashTable、ハッシュテーブルとも呼ばれます)は、キーに従ってメモリの格納場所に直接アクセスするデータ構造です。

その実装原理は
、ハッシュ関数(ハッシュ関数とも呼ばれます)を介して要素のキーを配列インデックスにマップし(変換された値はハッシュ値またはハッシュ値と呼ばれます)、記録された値を対応するインデックス位置に格納します。キー値に従って要素をクエリする場合、同じハッシュ関数を使用してキー値を配列添え字に変換し、対応する配列添え字位置からデータを取得します。

ハッシュテーブルは、配列の特性を使用して、添え字に従ってデータへのランダムアクセスをサポートします。そのため、ハッシュテーブルは、実際には配列から発展した配列の拡張です。配列がないとハッシュテーブルがないと言えます。PHPの連想配列は単にハッシュテーブルに基づいています。

ハッシュ技術は、保存方法と検索方法の両方です。以前の検索方法との違いは、ハッシュ技術のレコード間に論理的な関係がないため、主に検索指向のデータ構造であるということです。解決する最も適切な問題は、指定された値が等しいレコードを見つけることです。

PHPerの場合、毎日使用する配列はハッシュテーブルに基づいているため、ハッシュテーブルに精通している必要があります。例えば、$arr['test'] = 123このコードは、PHPは、キーの下にあるであろうtestハッシュコードでは、ハッシュ関数に変換され、その後、123ハッシュコードにマッピングされました。ハッシュの衝突を考慮しない場合、ハッシュテーブルの検索、削除、挿入の時間の複雑さはすべてO(1)であり、非常に効率的です。

ハッシュテーブルには2つの重要な概念があります。1つはハッシュ関数(またはハッシュ関数)であり、もう1つはハッシュ衝突(またはハッシュ衝突)です。

ハッシュ関数

ハッシュ関数は、処理後にキー値をハッシュ値に変換するために使用されます。次の特性があります。

ハッシュ関数は、ハッシュ値が非負整数で計算
場合、key1 == key2次いで、hash(key1) == hash(key2)
場合に、key1 != key2その後、hash(key1) != hash(key2)

ハッシュ衝突

いわゆるハッシュ衝突は、簡単な言葉で、手段があることkey1 != key2の状況下で、ハッシュ関数の処理によりhash(key1) == hash(key2)、今回、我々は、ハッシュ衝突が発生したことを言います。適切に設計されたハッシュ関数でも、ハッシュ値は負でない整数であり、合計量が制限されているため、ハッシュの競合を回避できませんが、現実の世界で処理されるキー値は無制限であり、無制限のデータは制限付きにマッピングされますコレクションは、確かに競合を回避することはできません。

実際、ハッシュの競合が考慮されない場合、ハッシュテーブルの検索効率は非常に高く、時間の複雑さはO(1)です。これは、バイナリ検索よりも効率的ですが、ハッシュの競合は避けられないため、ハッシュテーブルの検索は時間の複雑さはハッシュの競合に依存します。最悪のケースはO(n)で、順次検索に退化します。ハッシュ関数が適切に設計されていない場合、この状況はさらに悪化します。

ハッシュ関数設計

ハッシュの競合を減らし、ハッシュテーブル操作の効率を向上させるには、優れたハッシュ関数を設計することが重要です。通常使用するmd5関数はハッシュ関数ですが、実際には他にも多くのカスタム設計実装があります。さまざまなシナリオ、さまざまなハッシュ関数を設計してハッシュの競合を減らし、ハッシュ関数自体も非常に単純でなければなりません。そうでなければ、ハッシュ関数自体の実行がハッシュテーブルのボトルネックになります。ハッシュ関数を自分で設計することはめったにありませんが、それでも簡単な理解を行う必要があります。

ハッシュ関数を作成するには、通常、次の方法があります。

  • 直接アドレス指定方法:つまりf(key) = a*key + b、fはハッシュ関数を表し、aおよびbは定数、keyはキー値です
  • デジタル分析方法:数値を左シフト、右シフト、逆演算してハッシュ値を取得します
  • 除数剰余法:つまりf(key) = key % p、pはコンテナーの数を表します。このメソッドは通常、指定されたコンテナーにデータを格納するために使用されます。テーブルを分割した後にデータを挿入する方法など、どのコンテナーにどのデータを入れるかを決定する方法(pは分割されます)データテーブルの数)、分散Redisがデータを格納する方法(この場合、pは複数のRedisサーバーを表します)
  • 乱数方式:つまりf(key) = random(key)、負荷分散などのランダムなメカニズム

上記は比較シナリオのハッシュ関数の設計アイデアのほんの一部であり、ここに記載されていない他の多くの設計方法があります。

ハッシュ衝突処理

適切に設計されたハッシュ関数でも、ハッシュの競合を完全に回避することはできません。ハッシュの競合の発生を最小限に抑えるために実装を最適化することしかできません。ハッシュの競合が発生した場合、どうすればよいですか?ここにいくつかのアイデアがあります:

  • オープンアドレッシング方式:この方式は、線形アドレッシング、2次検出、およびランダム検出の3つのタイプに分類できます。線形アドレス指定とは、ハッシュ競合が発生した後、次の空のハッシュアドレスが検索されることを意味します。線形アドレス指定のステップサイズは1で、2番目の検出ステップサイズは線形アドレス指定のステップサイズの2乗であり、他のロジックは同じです。各ステップをランダムにランダムに検出することは合理的です。検出方法に関係なく、ハッシュテーブルに多くの空き位置がない場合、ハッシュの衝突の確率が増加します。運用効率を確保するために、ハッシュテーブルに一定の割合の空きスロットがあることを確認しようとします。負荷係数を使用します。空室の数を示すには、負荷係数=フィルインエレメント/ハッシュテーブルの長さ。負荷係数が大きいほど、空き位置が少なくなり、競合が増え、ハッシュテーブルのパフォーマンスが低下します。
  • 再ハッシュ関数方法:ハッシュの競合が発生した後、ハッシュ関数を変更してハッシュ値を計算します
  • チェーンアドレス方式:ハッシュの競合が発生した後、対応するデータをハッシュ値によってマッピングされた以前の値にリンクした後、同じハッシュ値を持つ要素が同じスロットに対応するリンクリストに配置されます。チェーンアドレス方式では、多くのハッシュの競合がある場合でもすべてのデータがハッシュテーブルに確実に格納されますが、単一のリンクリストをたどることによりパフォーマンスが低下します。

まとめ

上記を紹介した後、産業レベルのハッシュテーブルを構築する方法を知っている必要があります。主な考慮事項は次のとおりです。

  • ハッシュ関数は合理的に設定され、複雑すぎず、パフォーマンスのボトルネックになります。
  • 動的拡張をサポートするように負荷率のしきい値を設定します。負荷率のしきい値の設定は、時間とスペースの複雑さを完全にバランスさせる必要があります。
  • 1回限りの容量拡張に時間がかかる場合は、バッチ拡張戦略を採用できます。しきい値に達した後は、スペースのみが適用され、データは移動されません。後でデータが挿入されるたびに、古いデータが移動され、最終的に徐々に移行が完了します。 、最初に新しいテーブルをチェックしてから、古いテーブルをチェックできます。
  • ハッシュ競合解決方法:データの量が少なく、負荷係数が小さい(1未満)場合に、オープンアドレス指定方法が選択されます。リンクリストの方法は、1より大きな負荷係数を許容できるため、大きなオブジェクト、大きなデータボリュームのハッシュテーブル、および柔軟で、より多くの最適化戦略をサポートします。

ハッシュ(ハッシュ)競合に対処するためにチェーンアドレスメソッドの画像を追加します。

ハッシュアルゴリズムの概念と特徴

以前にハッシュテーブル、ハッシュ関数、ハッシュの競合を共有しましたが、ハッシュテーブル、ハッシュ関数、ハッシュの競合に変換することもできます。ハッシュアルゴリズムの簡単な理解は、前述のハッシュ関数を実装するアルゴリズムであり、任意の長さのバイナリ値文字列を固定長のバイナリ値文字列にマップするために使用されます。マッピング後に取得されるバイナリ値はハッシュ値(ハッシュ値)です。

私たちの日常的な開発で最も一般的なハッシュアルゴリズムアプリケーションは、md5関数を介してデータを暗号化することです。md5はハッシュ関数です。md5と組み合わせると、ハッシュアルゴリズムの一般的な特性を要約できます。

  • 元のデータは、ハッシュ値から逆引きで導出することはできません(そのため、ハッシュアルゴリズムは一方向アルゴリズムとも呼ばれ、元に戻すことはできません)。
  • 入力データの影響を非常に受けやすく、元のデータが1ビットだけ変更されても、結果のハッシュ値も大きく異なります。
  • ハッシュの衝突の確率は非常に小さく、元のデータが異なる場合、同じハッシュ値の確率は非常に小さくなります。
  • ハッシュアルゴリズムの実行効率は可能な限り効率的である必要があります。長いテキストの場合、ハッシュ値もすばやく計算できます

ハッシュアルゴリズムの適用

1.シナリオ1:安全な暗号化

日常のユーザーパスワードの暗号化では、通常、md5、sha、その他のハッシュ関数を使用します。これは、元に戻すことができず、暗号化された結果の差が非常に大きいため、セキュリティが向上するためです。

2.シナリオ2:一意の識別

たとえば、URLフィールドや画像フィールドの要件を繰り返すことはできません。現時点では、対応するフィールド値に対してmd5処理を実行して、データを32ビット長に統一できます。データベースインデックスの構築とクエリの観点から、効果はより優れています。さらに、クラスのバイナリデータはmd5によって一意の識別子として処理されるため、重複ファイルを特定するときに高速になります。

3.シナリオ3:データ検証

たとえば、インターネットからダウンロードする多くのファイル(特にP2Pサイトのリソース)にはMD5値が含まれています。これは、ダウンロードされたデータの整合性を検証して、データがハイジャックされ、途中で改ざんされないようにするために使用されます。

4.シーン5:ハッシュ関数

前述のように、PHPのmd5、sha1、ハッシュおよびその他の関数は、ハッシュアルゴリズムに基づいてハッシュ値を計算します。

5.シナリオ5:負荷分散

同じクライアント上のリクエスト、特にログインしているユーザーのリクエストの場合、セッションのリクエストを同じマシンにルーティングして、データの一貫性を確保する必要があります。これは、ハッシュアルゴリズムを使用して、ユーザーIDの末尾を介して実現できます。数値は、総機械番号のモジュラス(機械番号に応じて何桁を取ることができるか)を取り、結果の値は機械番号と見なされます。

6.シナリオ6:分散キャッシュ

分散キャッシュは、各マシンによって格納されたキャッシュデータに一貫性がないため、他のマシンまたはデータベースの分散とは異なります。キャッシュマシンが拡張されると、キャッシュストレージマシンのインデックスを再作成(または部分的に再インデックス)する必要があります。これはハッシュアルゴリズムの概念でもあります。

おすすめ

転載: www.cnblogs.com/stringarray/p/12717110.html