個別の連鎖にバイナリ検索ツリーを使用してハッシュテーブルを高速化することは可能ですか?


11

バイナリ検索ツリーを使用してハッシュテーブルを実装し、O(n)(リンクリストを使用)からO(log n)(BSTを使用)への個別チェーンプロセスの検索の複雑さを軽減します。これを行うことはできますか?ソリューションが段階的なロジックの実装であれば、理解しやすくなります。

ハッシュテーブル(個別のチェーンを使用してビルド)の検索時間を短縮したいのですが、同時に挿入時間を増やしたくありません。私のプロジェクトでは、ハッシュ関数を変更して衝突を減らすことはできません。しかし、スケーラビリティのために、衝突が発生しています。私は回避策を見つけようとしていますので、衝突が発生した場合に何らかの方法で最高のアクセスと時間を挿入できるようにしています...つまり、アルゴリズム全体を再構築するよりも物の現在の状態を管理します。パンアウトしない場合は、再構築する必要があります。アイデアはありますか?


4
ハッシュテーブルとバイナリ検索ツリーは異なるコンテナです。そのため、提案したことを実行できません(または用語の間違いを犯しています)。
バジルスタリンケビッチ

ツリーの各ノードにハッシュ/値のペアを置くことができると思います...しかし、それは悪いハッシュテーブルか悪いバイナリツリーのどちらかになります。どうしてこれをやりたいのか、最終結果に何ができるようにするのかについての明確な説明がなければ、これが本当に答えられるとは思いません。
Ixrec

1
@AK_:そうですね、あなたが言ったように。バイナリ検索ツリーを使用して衝突を処理したい。質問を少し修正して、わかりやすくしました。
アウイルス

1
この場合、挿入ごとにO(n log n)のペナルティが伴うことに注意してください。一般に、ハッシュテーブルが一杯になり始めた(そして、許容できるよりも長いチェーンを持っている)場合、ハッシュを再構築します。3または4よりも長いチェーンに定期的に遭遇する場合は、何かが間違っています。

3
あるバリエーション無数のアドレス指定衝突低減のハッシュテーブルに、オープン、およびテーブルの動的サイズ変更は。どちらが要件に合うかは、検討する必要があるものです。現在のアプローチは、他の構造との個別のチェーン

回答:


11

あなたが求めていることは、あなたの制約を考えると可能です。

分析

ハッシュテーブルの強みは、検索と挿入の速度が速いことです。その速度を得るには、テーブル内の順序の類似性を放棄する必要があります。つまり、エントリがすべて乱雑になります。リストはテーブルエントリとして使用できます。トラバーサルはO(n)ですが、ハッシュテーブルが十分に大きく、テーブルに格納されているオブジェクトが良質のハッシュアルゴリズムを使用してハッシュされると、リストは短くなる傾向があります。

二分探索木(BST)には、O(log 2 n)での高速挿入と検索があります。また、格納する要素に制限を課します。要素を順序付ける方法が必要です。ツリーに2つの要素ABが格納されている場合、ABの前に来るか、または同等の順序を持​​っているかを判断できる必要があります。

ハッシュテーブルにはそのような制限はありません。ハッシュテーブルの要素には2つのプロパティが必要です。まず、それらが同等であるかどうかを判断する方法が必要です。次に、決定論的なハッシュコードを計算する方法が必要です。注文は必須ではありません。

ハッシュテーブル要素に順序がある場合、BSTをハッシュテーブルエントリとして使用して、同じハッシュコード(衝突)を持つオブジェクトを保持できます。ただし、O(log 2 n)ルックアップおよび挿入を行うBSTにより、構造全体(ハッシュテーブルとBST)の最悪のケースは、テーブルエントリとしてリストを使用するよりも技術的に優れていることを意味します。BSTの実装に応じて、リストより多くのストレージが必要になりますが、それほど多くは必要ありません。

通常、BSTのオーバーヘッドと動作は、実際の状況ではハッシュテーブルバケットとしてテーブル何ももたらさないことに注意してください。これが、リストの理論的なパフォーマンスの低下を許容する理由です。つまり、ハッシュテーブルは、各リスト(バケット)に配置するアイテムを少なくすることで、リストの弱点を補います。ただし、この問題は、ハッシュテーブルのサイズを大きくすることはできず、ハッシュテーブルでの典型的な衝突よりも頻繁に衝突が発生することを具体的に述べています。

実装

正直なところ、それは本当に必要ではなく、とにかく言語を与えなかったので、ここにコードを入れるつもりはありません。

言語の標準ライブラリに含まれる標準ハッシュテーブルを新しいクラスにコピーし、テーブルバケットタイプをリストからツリーに変更するだけです。言語とその標準ライブラリによっては、これは非常に簡単なことです。

通常、私はこのようなコピーと貼り付けのコーディングを推奨しません。ただし、これは非常に迅速に戦闘テスト済みのデータ構造を取得する簡単な方法です。


漸近的な用語で言えば、衝突処理にバイナリツリーを使用しても、ハッシュテーブルが既にO(1)のパフォーマンスを達成するための通常のトリックをすでに行っていれば、ハッシュテーブルの期待されるパフォーマンスは変わりません。良好なパフォーマンスを確保するためにハッシュテーブルのサイズを変更すると、バケットごとの予想アイテム(バイナリツリーのサイズ)も小さくなると予想されるため、どちらの方法でも同じ予想償却O(1)になります。最悪の場合でも-バランシング制約が指定されていない場合、バイナリツリーの最悪の場合のパフォーマンスは、とにかくリンクリストのように動作することです。
スティーブ314

@ Steve314問題は衝突が多いことであることに留意してください。したがって、彼はバケットに通常ハッシュテーブルよりも多くのアイテムが含まれることを期待しています。

良い点-たとえば、無制限のデータを含む一定サイズのハッシュテーブルの場合、ハッシュテーブルの漸近的なパフォーマンスは衝突処理の漸近的なパフォーマンスと同じです-ハッシュテーブルは定数係数のみを変更します。
Steve314

@ Steve314正しい。基本的に、ハッシュテーブルが各バケットの要素数を効果的に制限できない場合、漸近的なパフォーマンスは各バケットで使用されるサブデータ構造に低下します。これを明確にするために、回答に段落を追加しました。

7

ハッシュテーブルでの衝突処理にバイナリツリーを使用することは、単に可能であるだけではありません-それは行われました。

Walter BrightDプログラミング言語の発明者として最もよく知られていますが、DMDScriptと呼ばれるECMAScriptバリアントも作成しました。過去において、DMDScript(または祖先-私はDScriptという名前を覚えているようです)の見出しの主張は、そのハッシュテーブルが多くの同様の言語のものよりも優れている傾向があるということでした。理由-バイナリツリーを使用した衝突処理。

私はこれがどこから来たのか正確には覚えていませんが、使用されたツリーは、ハッシュテーブル自体がいっぱいになり、ハッシュ衝突のばかげた確率は得られないので、バイナリツリーは常に小さくなければなりません。基本的に、最悪の場合は衝突処理にリンクリストを使用する場合と同じです(ただし、ノードごとに1つではなく2つのポインターの価格を支払うことを除きます)が、平均的な場合は各ハッシュバケット内の検索量が減少します。

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