32

一部のライブラリコードには、50,000個以上のアイテムを含むことができるリストがあります。

ライブラリの呼び出し元は、文字列がリストに追加される結果となるメソッドを呼び出すことができます。追加される文字列の一意性を効率的に確認するにはどうすればよいですか?

現在、文字列を追加する直前に、リスト全体をスキャンして、各文字列を追加する文字列と比較しています。これにより、10,000アイテムを超えるスケールの問題が表示され始めます。

これをベンチマークしますが、洞察に興味があります。

  • List<>をDictionary<>に置き換えると、リストが10,​​000アイテム以上に増えるので、ContainsKey()はかなり速くなりますか?
  • すべてのアイテムが追加されるまで一意性チェックを延期すると、より速くなりますか?その時点で、すべての要素を他のすべての要素と照合する必要がありますが、それでもn^^2操作です。

編集

いくつかの基本的なベンチマーク結果。FillとScanの2つのメソッドを公開する抽象クラスを作成しました。塗りつぶしは、コレクションをn個のアイテムで埋めるだけです(私は50,000を使用しました)。スキャンはリストをm回スキャンし(私は5000を使用しました)、指定された値が存在するかどうかを確認します。次に、そのクラスの実装をList用に、別のクラスをHashSet用に構築しました。

使用された文字列は、長さが均一に11文字であり、抽象クラスのメソッドを介してランダムに生成されました。

非常に基本的なマイクロベンチマーク。

Hello from Cheeso.Tests.ListTester
filling 50000 items...
scanning 5000 items...
Time to fill: 00:00:00.4428266
Time to scan: 00:00:13.0291180

Hello from Cheeso.Tests.HashSetTester
filling 50000 items...
scanning 5000 items...
Time to fill: 00:00:00.3797751
Time to scan: 00:00:00.4364431

したがって、その長さの文字列の場合、一意性をスキャンするとき、HashSetはListよりも約25倍高速です。また、このサイズのコレクションの場合、コレクションにアイテムを追加するときに、HashSetはリストに対してペナルティをゼロにします。

結果は興味深いものであり、有効ではありません。有効な結果を得るには、実装をランダムに選択して、ウォームアップ間隔、複数の試行を行う必要があります。しかし、それではバーが少ししか動かないだろうと私は確信しています。

みんな、ありがとう。

EDIT2

ランダム化と複数の試行を追加した後、この場合、HashSetは一貫してリストを約20倍上回っています。

これらの結果は、可変長の文字列、より複雑なオブジェクト、または異なるコレクションサイズには必ずしも当てはまりません。

4

6 に答える 6

60

HashSet<T>自分がしていることのために特別に設計されたクラスを使用する必要があります。

于 2009-12-07T14:30:04.827 に答える
19

HashSet<string> の代わりに使用するとList<string>、非常に適切にスケーリングされます。

于 2009-12-07T14:30:38.273 に答える
5

私のテストから、:)HashSet<string>と比較して時間はかかりませんList<string>

于 2009-12-07T14:37:09.030 に答える
3

トピックから外れている可能性がありますが、言語に依存しない方法で非常に大きな一意の文字列セット(数百万以上)をスケーリングする場合は、ブルームフィルターを確認してください。

于 2009-12-07T15:28:39.037 に答える
0

辞書<>が連想配列として実装されていることを読みました。一部の言語(必ずしも.NETに関連するものではありません)では、文字列インデックスは、ノード内の文字に基づいて各ノードで分岐するツリー構造として格納されます。http://en.wikipedia.org/wiki/Associative_arraysを参照してください。

同様のデータ構造は、1973年にAhoとCorasickによって考案されました(私は思います)。このような構造に50,000個の文字列を格納する場合、格納する文字列の数は重要ではありません。長さがもっと重要です文字列の。それらがほぼ同じ長さである場合、検索アルゴリズムは検索する文字列の長さに対して実行時に線形であるため、ルックアップの速度が低下することはほとんどありません。赤黒木またはAVLツリーの場合でも、検索の実行時間は、インデックス内の要素の数ではなく、検索する文字列の長さに依存します。ただし、ハッシュ関数を使用してインデックスキーを実装することを選択した場合、文字列のハッシュ(O(m)、m =文字列の長さ)のコストと、インデックス内の文字列のルックアップが発生します。 O(log(n))のオーダーになる可能性があります。n=インデックス内の要素の数。

編集:私は.NETの第一人者ではありません。他のより経験豊富な人々は別の構造を提案します。私は彼らの言葉を私に引き継ぐでしょう。

edit2:独自性を比較するための分析は少しずれています。ハッシュ構造または辞書を使用する場合、上記の理由により、O(n ^ 2)操作にはなりません。リストを引き続き使用する場合は、リスト内の各要素を毎回調べる必要があるため、O(n ^ 2)*(セット内の文字列の最大長)であることが正しいです。

于 2009-12-07T14:34:15.073 に答える
0

機能しませContains(T)んか?

于 2009-12-07T14:42:24.527 に答える