ここには良いアイデアがたくさんありますが、散らばっているので、問題が解決されたとしても、より良いレイアウトの答えを作成しようと思います。
まず、辞書には順序が保証されていないため、キーをすばやく検索して対応する値を見つけるためにのみ使用するか、順序を気にせずにすべてのキーと値のペアを列挙します。
注文が必要な場合はOrderedDictionaryを使用しますが、トレードオフとしてルックアップが遅くなるため、注文が必要ない場合は要求しないでください。
辞書(およびJavaのHashMap)はハッシュを使用します。これは、テーブルのサイズに関係なく、O(1)時間です。順序付けられた辞書は通常、O(log2(n))であるある種のバランスの取れたツリーを使用するため、データが大きくなるにつれてアクセスが遅くなります。比較するには、100万個の要素の場合、これは2 ^ 20のオーダーであるため、ツリーのルックアップは20のオーダーで行う必要がありますが、ハッシュマップのルックアップは1です。それはかなり速いです。
ハッシュは決定論的です。非決定論とは、最初にhash(5)を実行し、次にhash(5)を実行すると、別の場所を取得することを意味します。それは完全に役に立たないでしょう。
人々が言うことは、辞書に物事を追加する場合、順序は複雑であり、要素を追加する(または削除する可能性がある)たびに変更される可能性があるということです。たとえば、ハッシュテーブルに500kの要素があり、400kの値があるとします。もう1つ追加すると、効率を上げるために約20%の空きスペースが必要になるため、重要なしきい値に到達します。そのため、より大きなテーブル(たとえば、100万エントリ)が割り当てられ、すべての値が再ハッシュされます。今では、それらはすべて以前とは異なる場所にあります。
同じ辞書を2回作成すると(私のステートメントを注意深く読んでください、同じです)、同じ順序になります。しかし、ジョンが正しく言っているように、それを当てにしないでください。最初に割り当てられたサイズであっても、物が多すぎると同じではなくなる可能性があります。
これは優れた点をもたらします。ハッシュマップのサイズを変更しなければならないのは、本当に本当に費用がかかります。つまり、より大きなテーブルを割り当て、すべてのキーと値のペアを再挿入する必要があります。したがって、1回の拡張でも発生するのではなく、必要なメモリの10倍を割り当てる価値があります。ハッシュマップのサイズを把握し、可能な場合は十分に事前に割り当てておくと、パフォーマンスが大幅に向上します。また、サイズ変更されない不適切な実装がある場合、小さすぎるサイズを選択すると、問題が発生する可能性があります。
ジョンが彼の答えの私のコメントで私と議論したのは、2つの異なる実行で辞書にオブジェクトを追加すると、2つの異なる順序が得られるということでした。本当ですが、それは辞書のせいではありません。
あなたが言う時:
new Foo();
メモリ内の新しい場所に新しいオブジェクトを作成しています。
値Fooを辞書のキーとして使用し、他の情報がない場合、それらが実行できるのは、オブジェクトのアドレスをキーとして使用することだけです。
つまり、
var f1 = new Foo(1);
var f2 = new Foo(1);
f1とf2は、同じ値であっても同じオブジェクトではありません。
したがって、それらを辞書に入れる場合:
var test = new Dictionary<Foo, string>();
test.Add(f1, "zero");
それが次のものと同じであると期待しないでください:
var test = new Dictionary<Foo, string>();
test.Add(f2, "zero");
f1とf2の両方が同じ値であっても。これは、辞書の決定論的な動作とは何の関係もありません。
ハッシュはコンピュータサイエンスの素晴らしいトピックであり、データ構造で教えるのが私のお気に入りです。
赤黒木とハッシュに関するハイエンドの本については、Cormen and Leisersonをチェックしてください。Bobという名前のこの男は、ハッシュと最適なハッシュに関するすばらしいサイトを持っています:http: //burtleburtle.net/bob