C#辞書の効率


13

C#辞書は、何かが存在するかどうかなどを見つける簡単な方法です。どのように機能するかについては質問があります。辞書の代わりにArrayListを使用するとしましょう。ContainsKey(または別の言語の同等のメソッド)を使用する代わりに、ArrayListをループして、そこに何かが存在するかどうかを確認します(または、データが並べ替えられているか、類似のものであればバイナリ検索を実行します)。効率の違いは何ですか?ContainsKeyメソッドは、キーをループして検索しているものが存在するかどうかをチェックするのではなく、より効率的な方法を使用していますか?

私が持っているデータの種類に対応する特定のハッシュ関数を作成し、そのデータのセット用に特別に設計されている場合、そのハッシュ関数はデータをループするよりも実際に高速です。しかし、辞書は一般的です。ContainsKeyメソッドは、取得するデータに固有ではなく、一般的な検索メソッドです。

基本的に私が求めているのは。辞書はプログラマーに役立ちます。それらには、多くのことを支援するメソッドが含まれており、文字列を整数(キーと値)などと組み合わせています。しかし、効率については、彼らは何を提供していますか?持つに違い何dictionaryArrayListのをstructs(string,int)


ここでは、実際にリンゴとオレンジを比較しています。私は、あなたが探しているキーワードがあると思いますData Structures 。このウィキリンクはあなたに多くの助けになることも
AMPT

回答:


20

あなたはどのように確認するためにビットを掘るために持っている辞書は、そのないように明らかと- C#で実装されたHashMap(ハッシュテーブル)またはTreeMapの(ソートされたツリー)(またはConcurrentSkipListMapの - スキップ・リスト)。

「備考」セクションを掘り下げる場合:

Dictionaryジェネリッククラスは、キーのセットから値のセットへのマッピングを提供します。辞書への各追加は、値とそれに関連付けられたキーで構成されます。Dictionaryクラスはハッシュテーブルとして実装されているため、キーを使用して値を取得するのは非常に高速で、O(1)に近いです。

そして、それがあります。それはハッシュテーブルです。そこにウィキペディアの記事をリンクしていることに注意してください-それはかなり良い読み物です。衝突の解決に関するセクションを読むことをお勧めします。ルックアップがO(N)に委ねられる病理学的データセットを取得することが可能です(たとえば、何らかの理由で、挿入するものはすべて同じハッシュ値またはハッシュテーブルのインデックスに該当し、リニアプローブが残ります)。

ディクショナリは汎用ソリューションですが、具象型(ディクショナリなど)を渡すべきではありません-インターフェイスを渡すべきです。この場合、そのインターフェースはIDictionarydocs)です。これに対して、あなたはあなたが持っているデータに対して最適なことをするあなた自身の辞書実装を書くことができます。

さまざまなルックアップ/包含の効率については?

  • ソートされていないリストを歩く:O(N)
  • ソートされた配列のバイナリ検索:O(log N)
  • ソートされたツリー:O(log N)
  • ハッシュテーブル:O(1)

ほとんどの人にとって、ハッシュテーブルは必要なものです。

代わりに、SortedDictionaryが必要なものであることがわかります。

SortedDictionary<TKey, TValue>ジェネリッククラスは、辞書内の要素の数であるnはO(Nログ)検索とバイナリ検索ツリーです。この点で、SortedList<TKey, TValue>ジェネリッククラスに似ています。2つのクラスには類似したオブジェクトモデルがあり、両方ともO(log n)を取得します。

ただし、データ構造がデータで理想的に機能するものでない場合は、データに最適なものを作成できるツール(インターフェイス)が提供されます。

辞書自体は抽象データ型です。あなたは私に辞書を与えて、私はそれで何ができるか、そして辞書であるという性質からそこに私が使用するすべてのツールを知っています。ArrayListを提供してくれた場合、リストから項目を検索、挿入、または削除するための独自のコードを記述していることに気付くでしょう。これは私の時間を無駄にし、スポットからスポットへコードを何度も何度もコピーするため、バグの可能性が高いことを意味します。


5
O(1)は必ずしも「高速」ではありません。リストをループすることは、アプリケーションが処理しているコレクションサイズのハッシュテーブルよりも速くなる可能性があります。
whatsisname

5
@whatsisnameは、O(1)が高速であることを主張しません。それは確かに最速になる可能性があります。ハッシュテーブルのキーの繰り返し処理は、ArrayListのそれよりも低速です(Javaが提供するLinkedHashMapのようなものを使用している場合を除く)。データとその動作を把握し、適切なコレクションを選択することが重要です。データが存在しない場合は、それを記述します。もちろん、そのような努力は実際に時間の価値があると仮定します(プロファイルを最初に!)。

あなたの引用は、「Dictionaryクラスはハッシュテーブルとして実装されているため、そのキーを使用して値を取得するのは非常に高速で、O(1)に近い」と述べています。言い換えれば、大きなOが「速度」に関する全体像を語っていないことを明確にしたかったのです。
whatsisname 14

3
@whatsisnameは、Microsoftから直接送信されたものです。キーを使用して値を検索する場合、病理学的なハッシュテーブル(他のメカニズムとのハッシュの衝突を解決する)がない限り、ツリーまたはソートリスト(またはソートされていないリスト)で検索するよりも高速です。たとえば、Javaは、衝突解決に線形プローブ(ステップ1)を使用します。これは、テーブルがいっぱいになりすぎたり、衝突するハッシュが多すぎる場合には遅くなる可能性があります。しかし、一般的な場合には、それで十分です。

関連する例として、最近、約20エントリのデータセットにハッシュテーブルを使用し、完了までに約400ミリ秒かかっていたc ++のコードを最近最適化しました。ツリーへのアクセスがより簡単なため、バイナリツリーに切り替えると200ミリ秒になりました。しかし、名前と値のペアの配列と、過去のアクセスパターンに基づいてどこから検索を開始するかを推測するヒューリスティックなルックアップ関数を使用することで、これをさらに削減できました。したがって、すべてのデータの量と、アクセスに含まれるパターンの種類(例えば、局所性)の問題です。
ジュール14
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.