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データ構造の複雑さに関する情報をどのように確認できますか?
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
hashSetのコンストラクターに渡すComparerを作成する場合、ルックアップを実行するたびに、すべてのキーでComparerコードを実行して、一致するものがあるかどうかを確認する必要があります。これはO(1)ではなく、O(n)になります。
検索している値を「クエリ」値と呼びましょう。
クエリに一致するかどうかを確認するために、すべてのキーで比較ツールを実行する必要があると考える理由を説明できますか?
この信念は誤りです。 (もちろん、比較者によって提供されるハッシュコードがすべてのキーで同じでない限り!)検索アルゴリズムは、すべてのキーで等式比較を実行しますハッシュコードは、バケットの数を法として、クエリのハッシュコードと一致しますハッシュテーブルで。これがハッシュテーブルがO(1)ルックアップ時間を取得する方法です。
要素がコレクションに追加されると、実装は内部的にルックアップテーブルを構築しますか?
はい。
一般に、.NETデータ構造の複雑さに関する情報をどのように確認できますか?
ドキュメントを読んでください。
IEqualityComparer
実装が提供するハッシュ関数(GetHashCode()
)の品質によって異なります。理想的なハッシュ関数は、十分に分散されたランダムなハッシュコードのセットを提供する必要があります。これらのハッシュコードは、キーを値にマッピングできるインデックスとして使用されるため、特にキーが複雑なオブジェクト/構造である場合、キーによる値の検索がより効率的になります。
一致するものがあるかどうかを確認するには、すべてのキーでComparerコードを実行する必要があります。これはO(1)ではなく、O(n)になります。
これはハッシュテーブルの仕組みではなく、ある種の単純なブルートフォース検索です。ハッシュテーブルの場合、インデックスによる検索(ハッシュコード)を使用するよりインテリジェントなアプローチがあります。
IEqualityComparerを渡した場合、ルックアップは引き続きO(1)です。ハッシュセットは、IEqualityComparerを渡した場合と同じロジックを使用しますしない IEqualityComparerを渡すだけです。 System.Objectのインスタンスメソッド(または問題のオブジェクトによって提供されるオーバーライド)の代わりに、IEqualityComparerによるGetHashCodeおよびEqualsの実装。
実際、_HashSet<T>
_のルックアップ時間は必ずしもO(1)ではありません。
他の人がすでに述べたように、HashSetはIEqualityComparer<T>.GetHashCode()
を使用します。
ここで、常に同じハッシュコードx
を返す構造体またはオブジェクトについて考えてみましょう。
N個のアイテムをHashSetに追加すると、同じハッシュを持つn個のアイテムが存在します(オブジェクトが等しくない場合)。
したがって、ハッシュコードx
の要素がHashSetに存在するかどうかを確認する場合、ハッシュコードx
のすべてのオブジェクトに対して同等性チェックを実行して、 HashSetには要素が含まれています