web-dev-qa-db-ja.com

HashMapの実装

Cでハッシュマップをゼロから作成するにはどうすればよいですか?考慮されるパラメーターは何ですか?また、ハッシュマップをどのようにテストするのですか?ハッシュマップが完成したと言う前に実行する必要があるベンチマークテストケースと同じように。

42
Thunderboltz

背後にある基本を知っていれば、それほど難しくないはずです。

通常、キーと値を含む「バケット」と呼ばれる配列を作成し、リンクリストを作成するためのオプションのポインターを使用します。

キーを使用してハッシュテーブルにアクセスする場合、整数を返すカスタムハッシュ関数を使用してキーを処理します。次に、結果のモジュラスを取得します。これは、配列インデックスまたは「バケット」の場所です。次に、ハッシュされていないキーと保存されているキーを確認し、一致する場合は適切な場所を見つけました。

それ以外の場合は、「衝突」が発生したため、リンクリストをクロールし、一致するまでキーを比較する必要があります。 (一部の実装では、衝突のためにリンクリストの代わりにバイナリツリーを使用します)。

この高速ハッシュテーブルの実装を確認してください。

https://attractivechaos.wordpress.com/2009/09/29/khash-h/

56
Unknown

最適なアプローチは、予想されるキーの分布と衝突の数に依存します。比較的少ない衝突が予想される場合、どの方法が使用されるかは実際には関係ありません。多数の衝突が予想される場合、どちらを使用するかは、再ハッシュまたはプローブのコストと拡張バケットデータ構造の操作に依存します。

しかし、これは Cでのハッシュマップの実装 のソースコード例です

5
TStamper

ハッシュマップの主な目的は、データセットを格納し、一意のキーを使用してほぼ一定の時間ルックアップを提供することです。ハッシュマップの実装には2つの一般的なスタイルがあります。

  • 個別のチェーン:バケットの配列を持つもの(リンクリスト)
  • オープンアドレッシング:エントリを隣接スロットに配置することでインデックスの衝突を解決できるように、余分なスペースが割り当てられた単一の配列。

ハッシュマップに不十分なハッシュ関数がある場合、潜在的に未使用のスロットにストレージを事前に割り当てることが望ましくない場合、またはエントリのサイズが可変である場合は、個別のチェーンが望ましいです。このタイプのハッシュマップは、負荷係数が1.0を超えても比較的効率的に機能し続ける場合があります。明らかに、リンクされたリストポインターを格納するために各エントリに追加のメモリが必要です。

負荷係数が特定のしきい値(一般に約0.7)未満に保たれ、合理的に優れたハッシュ関数が使用される場合、オープンアドレス指定を使用するハッシュマップには潜在的なパフォーマンス上の利点があります。これは、潜在的なキャッシュミスとリンクリストに関連付けられた多くの小さなメモリ割り当てを回避し、事前に割り当てられた連続した配列ですべての操作を実行するためです。すべての要素の反復処理も安価です。キャッチは、オープンアドレス指定を使用するハッシュマップをより大きなサイズに再割り当てし、理想的な負荷係数を維持するために再ハッシュする必要があります。そうしないと、パフォーマンスが大幅に低下します。それらの負荷係数が1.0を超えることは不可能です。

ハッシュマップの作成時に評価する主要なパフォーマンスメトリックには、次のものが含まれます。

  • 最大負荷率
  • 挿入時の平均衝突回数
  • 衝突の分布:不均一な分布(クラスタリング)は、ハッシュ関数が不十分であることを示している可能性があります。
  • さまざまな操作の相対的な時間:既存および存在しないエントリの書き込み、取得、削除。

これが、私が作成した柔軟なハッシュマップの実装です。衝突解決には、オープンアドレッシングと線形プローブを使用しました。

https://github.com/DavidLeeds/hashmap

3
Dave

オーバーフローエントリの単純なリンクリスト以外にも、オーバーフローを処理するメカニズムがあります。多くのメモリを無駄にします。

使用するメカニズムは、ハッシュ関数を選択し、複数を選択できるかどうかに依存します(たとえば、衝突を処理するためにダブルハッシュを実装するため)。頻繁にアイテムを追加する予定がある場合、またはマップが一度入力されると静的である場合。アイテムを削除するかどうか。 ...

これを実装する最良の方法は、最初にこれらすべてのパラメーターについて考えてから、自分でコーディングするのではなく、成熟した既存の実装を選択することです。 Googleにはいくつかの優れた実装があります。 http://code.google.com/p/google-sparsehash/

1
HD.