ハッシュテーブルとトライ(プレフィックスツリー)のどちらを選択するのですか?


134

したがって、ハッシュテーブルとプレフィックスツリーのどちらかを選択する必要がある場合、どちらを選択するかを決定する要因は何ですか。私自身の素朴な観点から、それは配列として保存されていないのでトライを使用するといくつかの余分なオーバーヘッドがあるように見えますが、実行時間の観点から(最長のキーが最長の英語の単語であると仮定)、それは本質的にOである可能性があります(1)(上限に関して)。多分最長の英語の単語は50文字ですか?

ハッシュテーブルは、インデックスを取得するとすぐに参照されます。ただし、インデックスを取得するためにキーをハッシュすると、簡単に50ステップ近くかかる可能性があります。

誰かがこれについてより経験豊富な視点を教えてくれますか?ありがとう!


1
文字列バイトごとに新しいブランチを必要としないため、redixツリーはプレーントライよりも効率的です。また、パスをたどるときに個々のビットを見ているので、redixツリーはハッシュテーブルよりも「ファジー」検索をサポートします。たとえば00110010、入力バイトである可能性がありますが、001110101ビットだけが削除された一致を含める必要があります。
Xeoncross

回答:


116

試行の利点:

基礎:

  • 予測可能なO(k)ルックアップ時間(kはキーのサイズ)
  • ルックアップがない場合、k時間未満かかることがあります
  • 順序付きトラバーサルをサポート
  • ハッシュ関数は不要
  • 削除は簡単です

新しい操作:

  • キーのプレフィックスをすばやく検索したり、特定のプレフィックスを持つすべてのエントリを列挙したりできます。

リンク構造の利点:

  • 共通のプレフィックスが多数ある場合は、それらに必要なスペースが共有されます。
  • 不変の試行は構造を共有できます。トライを適切に更新する代わりに、1つのブランチのみが異なる新しいトライを作成し、他の場所で古いトライをポイントすることができます。これは、同時実行性、テーブルの複数の同時バージョンなどに役立ちます。
  • 不変のトライは圧縮可能です。つまり、ハッシュコンスティングによって、サフィックスの構造も共有できます。

ハッシュテーブルの利点:

  • 誰もがハッシュテーブルを知っていますよね?お使いのシステムには、十分に最適化された実装がすでにあり、ほとんどの目的で試行するよりも高速です。
  • キーは特別な構造を持つ必要はありません。
  • 明らかにリンクされたトライ構造よりもスペース効率が良い(以下のコメントを参照

25
「明白なリンクトライ構造よりもスペース効率が良い」に完全に同意することはできません。一般的なハッシュテーブルの実装では、キーを含めるためにはるかに大きなスペースを占有しますが、試行では、各ノードが単語を表します。この意味で、試行はスペース効率が高くなります。
ギャラクティカ

1
1つの構造と他の構造のデータにアクセスするのはどうですか?キャッシュと場所を考えています
Horia Toma

8
@galactica、それは私の経験と矛盾します。たとえば、私が宇宙について測定したすべての構造のこの回答では、トライが最悪でした。ポインタはバイトよりはるかに大きいため、これは理にかなっています。はい、プレフィックスの共有は役立ちますが、パリティに到達するには多くのオーバーヘッドを克服する必要があります。よりスペース効率の良い表現は多くの場合に役立ちますが、その場合、明らかにリンクされた構造については説明しなくなります。
ダライアスベーコン2014年

1
電話番号計画を処理する@DariusBaconは、試してみるのに合理的なシナリオのようです。サンプルシナリオ:電話番号とキャリアマッチングを含む あるキャリアから別のキャリアに移植された番号。通常の辞書の場合、それは言語に依存する可能性があります(マンダリンvs英語)、n-gramやその他の統計データが必要になります。韻の本では、接尾辞の木も良いオプションのようです。
mbx 2015年

検索するデータの多様性は非常に重要です。データ値の大部分が一意である場合、追加のnullポインターを使用するため、ハッシュよりもスペースの複雑さが増します。
例による統計の学習

45

それはすべて、解決しようとしている問題に依存します。挿入と検索のみを行う必要がある場合は、ハッシュテーブルを使用してください。プレフィックス関連のクエリなどのより複雑な問題を解決する必要がある場合は、トライがより良い解決策になる可能性があります。


8
ハッシュテーブルとトライがクエリで同じ複雑さを持つ場合、k(長さ)文字列のO(k)はなぜハッシュに行く必要があるのでしょうか。説明していただけますか
Sazzad Hissain Khan、2018

29

誰もがハッシュテーブルとその使用法を知っていますが、ルックアップタイムが正確に一定ではありません。ハッシュテーブルの大きさ、ハッシュ関数の計算の複雑さによって異なります。

効率的なルックアップのために巨大なハッシュテーブルを作成することは、わずかなレイテンシ/スケーラビリティさえ重要な産業シナリオのほとんど(例えば、高頻度取引)ではエレガントなソリューションではありません。キャッシュミスを減らすために、メモリ内で使用するスペースについても最適化されるデータ構造に注意する必要があります。

Trieが要件に適している非常に良い例は、メッセージングミドルウェアです。さまざまなカテゴリ(JMS用語-トピックまたはエクスチェンジ)のメッセージのサブスクライバーとパブリッシャーが100万人いる場合、トピック(実際には文字列)に基づいてメッセージをフィルターで除外する場合は、ハッシュテーブルを作成しないでください。 100万のトピックを持つ100万のサブスクリプション。より良い方法は、トピックをtrieに格納することです。そのため、トピックの一致に基づいてフィルタリングを行う場合、その複雑さはトピック/サブスクリプション/パブリッシャーの数に依存しません(文字列の長さにのみ依存します)。スペース要件を最適化するためにこのデータ構造を創造的に使用できるため、キャッシュミスが少ないので、気に入っています。


10

木を使う:

  1. オートコンプリート機能が必要な場合
  2. 「a」または「axe」で始まるすべての単語を検索します。
  3. サフィックスツリーは、ツリーの特殊な形式です。接尾辞ツリーには、ハッシュではカバーできない利点の完全なリストがあります。

4

覚えておくことが重要だと私が誰かが明確に述べているのを見たことがありません。通常、ハッシュテーブルとさまざまな種類の試行の両方にO(k)操作があります。ここkで、はビット単位の文字列(または同等の文字単位)の長さです。

これは、優れたハッシュ関数があることを前提としています。「農場」と「農場の動物」を同じ値にハッシュしたくない場合、ハッシュ関数はキーのすべてのビットを使用する必要があるため、「農場の動物」のハッシュには約2倍の時間がかかります。 "ファーム"(ある種のローリングハッシュシナリオを使用している場合を除きますが、操作を節約するための類似のシナリオがいくつかあります)。そして、バニラトライを使用すると、「農場の動物」の挿入に「農場」の2倍の時間がかかるのは明らかです。長期的には、圧縮試行でも同様です。


3

トライの挿入と検索は、入力文字列O(s)の長さと線形です。

ハッシュは、ルックアップと挿入のO(1)を提供しますが、最初に、再びO(s)である入力文字列に基づいてハッシュを計算する必要があります。

結論として、漸近時間の複雑さはどちらの場合も線形です。

トライはデータの観点から多少オーバーヘッドが多くなりますが、ハッシュテーブルとの関係で多かれ少なかれ、圧縮トライを選択できます。

ネクタイを破るには、次の質問を自問してください。完全な単語のみを検索する必要がありますか?または、プレフィックスに一致するすべての単語を返す必要がありますか?(予測テキスト入力システムの場合と同様)。最初のケースでは、ハッシュを求めます。シンプルでクリーンなコードです。テストと保守が簡単です。接頭辞または接尾辞が重要である、より詳細な使用例については、トライしてください。

そして、もしあなたが単に楽しみのためにそれをするなら、トライを実装することは、日曜日の午後を有効に使うでしょう。


「ハッシュは、ルックアップと挿入のO(1)を提供しますが、最初に、再びO(s)である入力文字列に基づいてハッシュを計算する必要があります。」説明してくれてありがとう!
アバダウィ

2

HashTableの実装は、基本的なTrieの実装と比較してスペース効率に優れています。しかし、文字列では、ほとんどの実用的なアプリケーションで順序付けが必要です。しかし、HashTableは完全に辞書的順序を乱します。ここで、アプリケーションが辞書式順序(部分検索、指定されたプレフィックスを持つすべての文字列、並べ替えられたすべての単語など)に基づいて操作を実行している場合は、トライを使用する必要があります。ルックアップのみの場合は、HashTableを使用する必要があります(間違いなく、ルックアップ時間は最小になります)。

PS:これら以外に、Ternary Search Trees(TST)は優れた選択です。そのルックアップ時間はHashTableよりも長くなりますが、他のすべての操作では時間効率が良くなります。また、試行錯誤よりもスペース効率が高くなります。


-2

一部の(通常は組み込みのリアルタイム)アプリケーションでは、処理時間がデータから独立している必要があります。その場合、ハッシュテーブルは既知の実行時間を保証できますが、トライはデータに基づいて異なります。


6
ほとんどのハッシュテーブルは、既知の実行時間を保証していません。すべての要素が衝突して連鎖する場合、最悪のケースはO(n)です
Adam Rosenfield '29

2
どのデータセットでも、そのデータのO(1)ルックアップを保証する完全なハッシュ関数を計算できます。もちろん、完璧なハッシュの計算は無料ではありません。
ジョージV.ライリー、

5
また、衝突は衝突を処理する唯一の方法ではありません。これを処理するには、あらゆる種類の興味深い巧妙な方法があります。1 つにはカッコウハッシュ(en.wikipedia.org/wiki/Cuckoo_hashing)があり、最適な選択はクライアントコードのニーズによって異なります。
ハンクゲイ

カッコウハッシュとブルームフィルターとの関係を知りませんでした。
Horia Toma

キャッシュと分散に優れたロビンフッドハッシュを忘れないでください。sebastiansylvan.com/2013/05/08/...は codecapsule.com/2013/11/11/robin-hood-hashing
瓶詰めニコルズ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.