web-dev-qa-db-ja.com

HashSet <T>(IEqualityComparer <T>)のルックアップ時間の複雑さはどれくらいですか?

C#.NETでは、ルックアップの時間計算量がO(1)と想定されるため、HashSetを使用するのが好きです。クエリされるデータのセットが大きい場合は、よく使用することをお勧めします。リストへのHashSetは、今回は複雑であるためです。

私を混乱させているのは、IEqualityComparerを引数として取るHashSetのコンストラクターです。

http://msdn.Microsoft.com/en-us/library/bb359100.aspx

上記のリンクでは、「コンストラクターはO(1)操作」である」と述べていますが、その場合、ルックアップがまだO(1)であるかどうかを知りたいと思います。

特に、HashSetのコンストラクターに渡すComparerを作成する場合、ルックアップを実行するたびに、すべてのキーでComparerコードを実行して、存在するかどうかを確認する必要があるように思われます。試合。これはO(1)ではなく、O(n)になります。

要素がコレクションに追加されると、実装は内部的にルックアップテーブルを構築しますか?

一般に、.NETデータ構造の複雑さに関する情報をどのように確認できますか?

19
Kirby

HashSetは、挿入したオブジェクトをハッシュ(IEqualityComparer.GetHashCodeを介して)して機能し、ハッシュごとにオブジェクトをバケットに入れます。バケット自体は配列に格納されるため、O(1)の部分です。

たとえば(これは必ずしもC#実装の動作とは異なり、フレーバーを与えるだけです)ハッシュの最初の文字を受け取り、1で始まるハッシュを含むすべてのものをバケット1にスローします。2のハッシュ、バケット2など。オン。そのバケットの中には、ハッシュの2番目の文字で分割されるバケットの別の配列があります。ハッシュ内のすべての文字についても同様です。

これで、何かを調べると、それがハッシュされ、適切なバケットをジャンプします。複数の配列ルックアップ(ハッシュ内の文字ごとに1つ)を実行する必要がありますが、追加したオブジェクトの数であるNの関数としては増加しないため、O(1)評価。

他の質問に対して、コレクションの操作の複雑さに関するブログ投稿があります: http://c-sharp-snippets.blogspot.com/2010/03/runtime-complexity-of-net -generic.html

20
Scott Stafford

hashSetのコンストラクターに渡すComparerを作成する場合、ルックアップを実行するたびに、すべてのキーでComparerコードを実行して、一致するものがあるかどうかを確認する必要があります。これはO(1)ではなく、O(n)になります。

検索している値を「クエリ」値と呼びましょう。

クエリに一致するかどうかを確認するために、すべてのキーで比較ツールを実行する必要があると考える理由を説明できますか?

この信念は誤りです。 (もちろん、比較者によって提供されるハッシュコードがすべてのキーで同じでない限り!)検索アルゴリズムは、すべてのキーで等式比較を実行しますハッシュコードは、バケットの数を法として、クエリのハッシュコードと一致しますハッシュテーブルで。これがハッシュテーブルがO(1)ルックアップ時間を取得する方法です。

要素がコレクションに追加されると、実装は内部的にルックアップテーブルを構築しますか?

はい。

一般に、.NETデータ構造の複雑さに関する情報をどのように確認できますか?

ドキュメントを読んでください。

14
Eric Lippert

IEqualityComparer実装が提供するハッシュ関数(GetHashCode())の品質によって異なります。理想的なハッシュ関数は、十分に分散されたランダムなハッシュコードのセットを提供する必要があります。これらのハッシュコードは、キーを値にマッピングできるインデックスとして使用されるため、特にキーが複雑なオブジェクト/構造である場合、キーによる値の検索がより効率的になります。

一致するものがあるかどうかを確認するには、すべてのキーでComparerコードを実行する必要があります。これはO(1)ではなく、O(n)になります。

これはハッシュテーブルの仕組みではなく、ある種の単純なブルートフォース検索です。ハッシュテーブルの場合、インデックスによる検索(ハッシュコード)を使用するよりインテリジェントなアプローチがあります。

1
sll

IEqualityComparerを渡した場合、ルックアップは引き続きO(1)です。ハッシュセットは、IEqualityComparerを渡した場合と同じロジックを使用しますしない IEqualityComparerを渡すだけです。 System.Objectのインスタンスメソッド(または問題のオブジェクトによって提供されるオーバーライド)の代わりに、IEqualityComparerによるGetHashCodeおよびEqualsの実装。

1
phoog

実際、_HashSet<T>_のルックアップ時間は必ずしもO(1)ではありません。

他の人がすでに述べたように、HashSetはIEqualityComparer<T>.GetHashCode()を使用します。
ここで、常に同じハッシュコードxを返す構造体またはオブジェクトについて考えてみましょう。

N個のアイテムをHashSetに追加すると、同じハッシュを持つn個のアイテムが存在します(オブジェクトが等しくない場合)。
したがって、ハッシュコードxの要素がHashSetに存在するかどうかを確認する場合、ハッシュコードxのすべてのオブジェクトに対して同等性チェックを実行して、 HashSetには要素が含まれています

1
nikstffrs