ほとんどのプログラミング言語では、ハッシュテーブルよりも辞書が優先されます。その背後にある理由は何ですか?
Dictionary
の実装だと思っていましたHashtable
。
HashTable
ます。言語にジェネリックを追加したとき、ジェネリックバージョンと呼ばれていましたDictionary
。どちらもハッシュテーブルです。
ほとんどのプログラミング言語では、ハッシュテーブルよりも辞書が優先されます。その背後にある理由は何ですか?
Dictionary
の実装だと思っていましたHashtable
。
HashTable
ます。言語にジェネリックを追加したとき、ジェネリックバージョンと呼ばれていましたDictionary
。どちらもハッシュテーブルです。
回答:
価値があるのは、辞書は(概念的には)ハッシュテーブルです。
「なぜDictionary<TKey, TValue>
クラスの代わりにクラスを使用するのか」という意味の場合Hashtable
、それは簡単な答えです。Dictionary<TKey, TValue>
ジェネリック型であり、そうでHashtable
はありません。つまりDictionary<TKey, TValue>
、ランダムオブジェクトをオブジェクトに挿入できず、取り出した値をキャストする必要がないため、でタイプセーフになります。
興味深いことに、Dictionary<TKey, TValue>
.NET Frameworkの実装は、Hashtable
ソースコードのこのコメントからわかるように、に基づいています。
一般的な辞書はHashtableのソースからコピーされました
HashTable
(クラス)とDictionary
(クラス)は、ハッシュテーブル(概念)ですが、HashTable
ではないDictionary
、またあるDictionary
A HashTable
。これらは、非常によく似た方法で使用されDictionary<Object,Object>
、aと同じ型なしの方法でHashTable
動作できますが、コードを直接共有しません(パーツは非常によく似た方法で実装される可能性があります)。
Dictionary
<<< >>>のHashtable
違い:
Synchronized()
KeyValuePair
<<< >>>列挙型アイテム:DictionaryEntry
Dictionary
/ Hashtable
類似点:
GetHashCode()
メソッドが必要です同様の .NETコレクション(辞書とハッシュテーブルの代わりに使用する候補):
ConcurrentDictionary
- スレッドセーフ(複数のスレッドから同時に安全にアクセスできます)HybridDictionary
- 最適化されたパフォーマンス(少数のアイテムと多くのアイテム)OrderedDictionary
-値はintインデックスを介してアクセスできます(アイテムが追加された順序で)SortedDictionary
-アイテムは自動的にソートされますStringDictionary
-強く型付けされ、文字列用に最適化されていますStringDictionary
... btwの+1は、デフォルトのコンストラクタを使用する場合StringDictionary
とは異なりDictionary<string, string>
ます。
のでDictionary
、一般的なクラスが(あるDictionary<TKey, TValue>
)、そのコンテンツにアクセスするようにすること(つまり、あなたがからキャストする必要はありません、タイプセーフであるObject
あなたがそうであるように、Hashtable
)。
比較する
var customers = new Dictionary<string, Customer>();
...
Customer customer = customers["Ali G"];
に
var customers = new Hashtable();
...
Customer customer = customers["Ali G"] as Customer;
ただし、Dictionary
内部的にはハッシュテーブルとして実装されるため、技術的には同じように機能します。
参考:.NETでは、Hashtable
複数のリーダースレッドと1つの書き込みスレッドで使用してDictionary
もスレッドセーフですが、パブリック静的メンバーではスレッドセーフですが、インスタンスメンバーはスレッドセーフであるとは限りません。
Hashtable
このため、すべての辞書を元に戻す必要がありました。
ConcurrentDictionary
は、すべてのpublic / protectedメソッドがスレッドセーフになるように実装されているクラスを追加しました。レガシープラットフォームをサポートする必要がない場合はHashtable
、マルチスレッドコードのmsdn.microsoft.com/en-us/library/dd287191.aspx
辞書はハッシュテーブルと同じだと人々は言っています。
これは必ずしも本当ではありません。ハッシュテーブルは、辞書を実装する1つの方法です。その典型的なものであり、それはDictionary
クラスの.NETのデフォルトの1つかもしれませんが、定義上、唯一のものではありません。
リンクされたリストまたは検索ツリーを使用して、同じように辞書を実装することもできますが、これはそれほど効率的ではありません(いくつかの測定基準では)。
Dictionary<K,V>
。IDictionary<K,V>
ただし、何でも
Collections
&Generics
は、オブジェクトのグループを処理するのに役立ちます。.NETでは、すべてのコレクションオブジェクトはインターフェイスの下にあり、インターフェイスIEnumerable
にはArrayList(Index-Value))
&がありHashTable(Key-Value)
ます。.NETフレームワーク2.0の後、ArrayList
&HashTable
に置き換えましたList
&Dictionary
。現在、Arraylist
&HashTable
は現在のプロジェクトでは使用されていません。
HashTable
&の違いはDictionary
、Dictionary
ジェネリックでHastable
はないジェネリックです。任意のタイプのオブジェクトをに追加できますHashTable
が、取得中に必要なタイプにキャストする必要があります。したがって、タイプセーフではありません。しかしdictionary
、それ自体を宣言するときに、キーと値のタイプを指定できるため、取得中にキャストする必要はありません。
例を見てみましょう:
ハッシュ表
class HashTableProgram
{
static void Main(string[] args)
{
Hashtable ht = new Hashtable();
ht.Add(1, "One");
ht.Add(2, "Two");
ht.Add(3, "Three");
foreach (DictionaryEntry de in ht)
{
int Key = (int)de.Key; //Casting
string value = de.Value.ToString(); //Casting
Console.WriteLine(Key + " " + value);
}
}
}
辞書、
class DictionaryProgram
{
static void Main(string[] args)
{
Dictionary<int, string> dt = new Dictionary<int, string>();
dt.Add(1, "One");
dt.Add(2, "Two");
dt.Add(3, "Three");
foreach (KeyValuePair<int, String> kv in dt)
{
Console.WriteLine(kv.Key + " " + kv.Value);
}
}
}
辞書:
存在しないキーを見つけようとすると例外を返す/スローします。
ボックス化とボックス化解除がないため、Hashtableより高速です。
パブリックスタティックメンバーのみがスレッドセーフです。
ディクショナリは一般的なタイプであり、任意のデータタイプで使用できます(作成時に、キーと値の両方のデータタイプを指定する必要があります)。
例: Dictionary<string, string> <NameOfDictionaryVar> =
new Dictionary<string, string>();
DictionayはHashtableのタイプセーフな実装でKeys
ありValues
、強く型付けされています。
ハッシュ表:
存在しないキーを見つけようとするとnullを返します。
ボクシングとアンボクシングが必要なため、ディクショナリよりも低速です。
Hashtableのすべてのメンバーはスレッドセーフであり、
ハッシュテーブルはジェネリック型ではありませんが、
ハッシュテーブルは緩やかに型付けされたデータ構造であり、任意の型のキーと値を追加できます。
Dictionary.TryGetValue
MSDNのC#を使用したデータ構造の広範な調査では、衝突解決戦略にも違いがあると述べています 。
ハッシュテーブルクラスは、と呼ばれる技術を使用して再ハッシュ。
再ハッシュは次のように機能します。ハッシュの異なる関数のセットH 1 ... H nがあり、ハッシュテーブルからアイテムを挿入または取得する場合、最初はH 1ハッシュ関数が使用されます。これが衝突につながる場合は、代わりにH 2が試行され、必要に応じてH nまで試行されます。
辞書は、チェーンと呼ばれる手法を使用します。
再ハッシュでは、衝突が発生した場合、ハッシュが再計算され、ハッシュに対応する新しいスロットが試行されます。ただし、連鎖では、衝突を保持するために2次データ構造が使用されます。具体的には、ディクショナリの各スロットには、そのバケットにマップする要素の配列があります。衝突が発生した場合、衝突要素がバケットのリストの先頭に追加されます。
.NET Framework 3.5以降には、キーのみが必要で値は必要ない場合のHashSet<T>
すべての長所を提供するもDictionary<TKey, TValue>
あります。
したがって、aを使用しDictionary<MyType, object>
、常に値をnull
に設定してタイプセーフハッシュテーブルをシミュレートする場合は、への切り替えを検討する必要がありHashSet<T>
ます。
MSDNによると、「Dictionary <(Of <(TKey、TValue>)>)クラスはHashTableとして実装されているのではなく、「Dictionary <(Of <(TKey、TValue>)>)クラスはハッシュテーブルとして実装されています」
辞書はHashTableとして実装されていませんが、ハッシュテーブルの概念に従って実装されています。Genericsを使用しているため、実装はHashTableクラスとは関係ありませんが、内部ではMicrosoftが同じコードを使用し、Object型のシンボルをTKeyおよびTValueに置き換えた可能性があります。
.NET 1.0 Genericsには存在しませんでした。これは、HashTableとArrayListが最初に始まった場所です。
ハッシュ表:
キー/値は、ヒープへの格納中にオブジェクト(ボックス化)タイプに変換されます。
ヒープから読み取るときに、キー/値を目的のタイプに変換する必要があります。
これらの操作は非常にコストがかかります。ボクシング/アンボクシングはできるだけ避ける必要があります。
辞書: HashTableの一般的なバリアント。
ボクシング/アンボクシングはありません。変換は必要ありません。
Hashtableオブジェクトは、コレクションの要素を含むバケットで構成されています。バケットはHashtable内の要素の仮想サブグループであり、ほとんどのコレクションよりも簡単かつ高速に検索および取得できます。
Dictionaryクラスは、Hashtableクラスと同じ機能を備えています。特定のタイプ(オブジェクト以外)のディクショナリは、値タイプのHashtableよりもパフォーマンスが優れています。これは、Hashtableの要素がオブジェクトタイプであるため、通常、値タイプを格納または取得するときにボックス化とボックス化解除が発生するためです。
もう1つの重要な違いは、Hashtableはスレッドセーフであることです。Hashtableには、複数のリーダー/シングルライター(MR / SW)のスレッドセーフティが組み込まれているため、1つのライターを複数のリーダーと一緒にロックせずに使用できます。
辞書の場合、スレッドセーフはありません。スレッドセーフが必要な場合は、独自の同期を実装する必要があります。
さらに詳しく説明するには:
Hashtableは、
Synchronized
プロパティを通じてスレッドセーフを提供します。プロパティは、コレクションのスレッドセーフラッパーを返します。ラッパーは、追加または削除操作のたびにコレクション全体をロックすることによって機能します。したがって、コレクションにアクセスしようとする各スレッドは、その順番が1つのロックを取得するまで待機する必要があります。これはスケーラブルではなく、大規模なコレクションのパフォーマンスを大幅に低下させる可能性があります。また、設計は競合状態から完全に保護されていません。などの.NET Framework 2.0コレクションクラスは
List<T>, Dictionary<TKey, TValue>
、スレッド同期を提供しません。複数のスレッドでアイテムが同時に追加または削除された場合、ユーザーコードはすべての同期を提供する必要があります
タイプセーフとスレッドセーフが必要な場合は、.NET Frameworkで並行コレクションクラスを使用します。詳細はこちら。
追加の違いは、ディクショナリに複数のエントリを追加するときに、エントリが追加される順序が維持されることです。辞書からアイテムを取得すると、レコードを挿入したときと同じ順序でレコードを取得します。一方、Hashtableは挿入順序を保持しません。
Hashset
使用シナリオで MR / SWスレッドの安全性が保証されます。MR / SWを完全に安全にすることを意図していたと思いますが、安全に削除を処理すると、MR / SWの安全性のコストが大幅に増加します。の設計はDictionary
MR / SWの安全性を削除なしのシナリオで最小限のコストで提供できたかもしれませんが、MSは削除なしのシナリオを「特別な」ものとして扱うことを避けたかったと思います。
私が理解できるもう1つの違いは次のとおりです。
Webサービスでは、Dictionary <KT、VT>(ジェネリック)は使用できません。その理由は、ジェネリック標準をサポートするWebサービス標準がないためです。
ほとんどのプログラミング言語では、ハッシュテーブルよりも辞書が優先されます
私はこれが必ずしも本当であるとは思いません、ほとんどの言語は、彼らが好む用語に応じて、どちらか一方を持っています。
ただし、C#では、明らかな理由(私にとって)は、C#HashTablesおよびSystem.Collections名前空間の他のメンバーがほとんど使用されていないことです。それらはc#V1.1に存在していました。それらはC#2.0からSystem.Collections.Generic名前空間のGenericクラスに置き換えられました。
.NET Reflectorを使用して私が見たものによると:
[Serializable, ComVisible(true)]
public abstract class DictionaryBase : IDictionary, ICollection, IEnumerable
{
// Fields
private Hashtable hashtable;
// Methods
protected DictionaryBase();
public void Clear();
.
.
.
}
Take note of these lines
// Fields
private Hashtable hashtable;
したがって、DictionaryBaseがHashTableを内部で使用していることを確認できます。