В большинстве языков программирования словари предпочтительнее хэш-таблиц. Каковы причины этого?
@Promit Я всегда думал, что Dictionary - это реализация Hashtable.
Я думаю, причина в том, что в словаре вы можете определить тип ключа и значение для себя. Hashtable может принимать только объекты и сохранять пары на основе хэша (из object.GetHashCode ()).
@Dan Ваше утверждение совершенно ошибочно ... хеш-таблица содержит только один экземпляр каждого ключа, и поиск никогда не дает нескольких записей; если вы хотите связать несколько значений с каждым ключом, сделайте значение хэш-таблицы списком значений. Нет такой структуры данных, как «Словарь» ... Словарь - это просто имя, которое некоторые библиотеки используют для своей хеш-таблицы. например, неуниверсальная хеш-таблица C# называется HashTable. Когда они добавили в язык универсальные шаблоны, они назвали универсальную версию Dictionary. Оба являются хеш-таблицами.
@Dan Ваше утверждение ошибочно ... хеш-таблица (en.wikipedia.org/wiki/Hash_table) - это конкретная реализация словаря, также известного как ассоциативный массив (en.wikipedia.org/wiki/Associative_array), и, будучи словарем, содержит только один экземпляр каждого ключа, и поиск никогда не дает множественные записи; если вы хотите связать несколько значений с каждым ключом, сделайте значение хэш-таблицы списком значений. И классы .NET Dictionary и Hashtable являются хэш-таблицами.
Первоначальное название вопроса было специфичным для C#. Я восстановил "на C#" в заголовке.
Не путать с HashSet <T>, который, в отличие от HashTable, является общим.





Поскольку 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 разница между Dictionary<,> и HashTable заключается в первую очередь в том, что первый является универсальным типом, поэтому вы получаете все преимущества универсальных типов с точки зрения проверки статического типа (и уменьшенного бокса, но это не так велико, как люди склонны. думаю с точки зрения производительности - правда, там боксу определенная стоимость памяти).
Hashtable представляет собой свободно типизированную структуру данных, поэтому вы можете добавлять в Hashtable ключи и значения любого типа. Класс Dictionary является типобезопасной реализацией Hashtable, а ключи и значения строго типизированы. При создании экземпляра Dictionary необходимо указать типы данных как для ключа, так и для значения.
Для чего это стоит, Dictionary является (концептуально) - хеш-таблица.
Если вы имели в виду «почему мы используем класс Dictionary<TKey, TValue> вместо класса Hashtable?», То это простой ответ: Dictionary<TKey, TValue> - это общий тип, а Hashtable - нет. Это означает, что вы получаете безопасность типов с Dictionary<TKey, TValue>, потому что вы не можете вставлять в него какой-либо случайный объект, и вам не нужно приводить значения, которые вы извлекаете.
Интересно, что реализация Dictionary<TKey, TValue> в .NET Framework основана на Hashtable, как вы можете видеть из этого комментария в его исходном коде:
The generic Dictionary was copied from Hashtable's source
А также общие коллекции намного быстрее, поскольку нет упаковки / распаковки
Не уверен в Hashtable с указанным выше утверждением, но для ArrayList vs List <t> это правда
Hashtable использует Object для внутреннего хранения вещей (только не общий способ сделать это), поэтому ему также придется упаковывать / распаковывать.
Если Dictionary является универсальным, не было бы правильнее сказать, что хеш-таблица - это словарь? Все, что «квадраты - это прямоугольники, но не все прямоугольники - квадраты»?
@BrianJ: «Хеш-таблица» (два слова) - это компьютерный термин для обозначения такого рода структур; Словарь - это конкретная реализация. HashTable примерно соответствует Dictionary <object, object> (хотя и с немного разными интерфейсами), но оба являются реализациями концепции хеш-таблицы. И, конечно, чтобы еще больше запутать ситуацию, некоторые языки называют свои хэш-таблицы «словарями» (например, Python), но правильный термин CS по-прежнему остается хеш-таблицей.
@MichaelMadsen Итак, чтобы я вас правильно понял, структура данных HashTable - это словарь, который представляет собой хеш-таблицу (концепцию), верно?
@BrianJ: И HashTable (класс), и Dictionary (класс) являются хэш-таблицами (концепция), но HashTable не является Dictionary, а Dictionary не является HashTable. Они используются очень похожим образом, и Dictionary<Object,Object> может действовать таким же нетипизированным образом, что и HashTable, но они не используют напрямую какой-либо код (хотя части, вероятно, будут реализованы очень похожим образом).
@BrianJ "Если словарь является общим, не было бы правильнее сказать, что хеш-таблица - это словарь?" - Нет, потому что «общий» имеет особое значение в языках программирования, которое имеет мало общего с термином английского языка. «Универсальный» класс или метод - это класс или метод, который имеет один или несколько параметров типа.
@MichealMadsen, я думаю, что путаница возникает из-за того, что за пределами C# термин Словарь также используется как абстрактный тип данных, для которого Hash Table является решением с определенным временем работы. Кроме того, общий также имеет значение вне C#, поэтому, если вы не знаете C#, «общий словарь» можно интерпретировать как абстрактную структуру данных.
Только общедоступные статические члены являются потокобезопасными в Dictionary, тогда как все члены являются потокобезопасными в Hashtable.
Словарь поддерживает больше операторов linq, чем Hashtable
К вашему сведению: в .NET Hashtable является потокобезопасным для использования несколькими потоками чтения и одним потоком записи, в то время как в Dictionary общедоступные статические члены являются потокобезопасными, но не гарантируется, что любые члены экземпляра будут потокобезопасными.
Из-за этого нам пришлось поменять все наши словари обратно на Hashtable.
Веселье. Исходный код Dictionary <T> выглядит намного чище и быстрее. Возможно, лучше использовать Словарь и реализовать собственную синхронизацию. Если чтение словаря абсолютно необходимо, чтобы он был актуальным, вам просто нужно синхронизировать доступ к методам чтения / записи словаря. Было бы много блокировок, но это было бы правильно.
В качестве альтернативы, если ваши чтения не обязательно должны быть абсолютно актуальными, вы можете рассматривать словарь как неизменяемый. Затем вы можете получить ссылку на Словарь и повысить производительность, вообще не синхронизируя чтение (поскольку он неизменяемый и по своей сути потокобезопасный). Чтобы обновить его, вы создаете полную обновленную копию словаря в фоновом режиме, а затем просто меняете ссылку на Interlocked.CompareExchange (при условии, что один поток записи; несколько потоков записи потребуют синхронизации обновлений).
.Net 4.0 добавил класс ConcurrentDictionary, в котором все общедоступные / защищенные методы реализованы для обеспечения потоковой безопасности. Если вам не нужна поддержка устаревших платформ, это позволит вам заменить Hashtable в многопоточном коде: msdn.microsoft.com/en-us/library/dd287191.aspx
Я помню, как читал, что HashTable является потокобезопасным только для чтения и записи в сценарии, когда информация никогда не удаляется из таблицы. Если читатель запрашивает элемент, который находится в таблице, в то время как другой элемент удаляется, и читатель будет искать элемент более чем в одном месте, возможно, что пока читатель ищет, писатель может переместить элемент из места, которое не было исследовано, в место, которое было проверено, что приводит к ложному сообщению о том, что предмет не существует.
Люди говорят, что словарь - это то же самое, что и хеш-таблица.
Это не обязательно правда. Хеш-таблица - это один из способов воплощать в жизнь словаря. При этом типичный, и он может быть по умолчанию в .NET в классе Dictionary, но по определению не единственный.
Вы могли бы с тем же успехом реализовать словарь, используя связанный список или дерево поиска, но это было бы не так эффективно (для некоторых показателей эффективности).
Документы MS говорят: «Получение значения с использованием его ключа происходит очень быстро, близко к O (1), потому что класс Dictionary <(Of <(TKey, TValue>)>) реализован как хеш-таблица». - поэтому вам должна быть гарантирована хеш-таблица при работе с Dictionary<K,V>. Хотя IDictionary<K,V> может быть чем угодно :)
@ rix0rrr - Думаю, у вас все наоборот, Dictionary использует HashTable, а HashTable - Dictionary.
@JosephHamilton - rix0rrr правильно понял: «Хэш-таблица является представляет собой реализацию толковый словарь». Он имеет в виду понятие «словарь», а не класс (обратите внимание на нижний регистр). Концептуально хеш-таблица реализует интерфейс словаря. В .NET Dictionary использует хеш-таблицу для реализации IDictionary. Это грязно;)
Я говорил о .NET, поскольку именно на это он ссылался в своем ответе.
@JosephHamilton: орудия (или реализация) даже отдаленно не означает то же самое, что использует. Наоборот. Возможно, было бы яснее, если бы он сказал это немного иначе (но с тем же смыслом): «хеш-таблица - это один из способов реализовать словарь». То есть, если вам нужна функциональность словаря, один из способов сделать это (для словаря воплощать в жизнь) - использовать хеш-таблицу.
@JosephHamilton: «Я говорил о .NET, поскольку именно на это он ссылался в своем ответе». - Вы ошибаетесь в любом случае; класс .NET Dictionary не использует и не ссылается каким-либо иным образом на класс .NET Hashtable (и нет класса .NET HashTable). Ответ rix0rrr совершенно правильный и ни в коем случае не обратный.
@JimBalter .Net HashTable -> docs.microsoft.com/en-us/dotnet/api/…
@JimBalter "Универсальный класс Dictionary <TKey, TValue> обеспечивает сопоставление набора ключей с набором значений. Каждое добавление в словарь состоит из значения и связанного с ним ключа. Получение значения с помощью его ключа выполняется очень быстро , близко к O (1), потому что класс Dictionary <TKey, TValue> реализован как хэш-таблица ". docs.microsoft.com/en-us/dotnet/api/…
@JosephHamilton И какое это имеет отношение к этому? Во-первых, «Hashtable»! = «HashTable». Во-вторых, «хеш-таблица»! = «Класс .NET Hashtable». Все это здесь неоднократно обсуждалось ... прочтите, пожалуйста, внимательнее. Я не буду больше отвечать на ваши неточности.
Еще одно различие, которое я могу понять:
Мы не можем использовать Dictionary <KT, VT> (generics) с веб-сервисами. Причина в том, что стандарт веб-сервисов не поддерживает стандарт универсальных шаблонов.
Мы можем использовать общие списки (List <string>) в веб-сервисе на основе мыла. Но мы не можем использовать словарь (или хеш-таблицу) в веб-сервисе. Я думаю, что причина этого в том, что .net xmlserializer не может обрабатывать объект словаря.
Обратите внимание, что документация говорит: «Класс Dictionary <(Of <(TKey, TValue>)>) реализован как хеш-таблица», а не «класс Dictionary <(Of <(TKey, TValue>)>) реализован как Хеш-таблица. "
Словарь НЕ реализован как HashTable, но реализован в соответствии с концепцией хеш-таблицы. Реализация не связана с классом HashTable из-за использования Generics, хотя внутри Microsoft могла бы использовать тот же код и заменить символы типа Object на TKey и TValue.
В .NET 1.0 Generics не существовало; здесь изначально начинались HashTable и ArrayList.
Согласно тому, что я вижу, используя .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.
System.Collections.Generic.Dictionary <TKey, TValue> не является производным от DictionaryBase.
«Так что мы можем быть уверены, что DictionaryBase внутренне использует HashTable». - Хорошо, но это не имеет отношения к вопросу.
Dictionary <<< >>> Hashtable отличия:
Synchronized()KeyValuePair <<< >>> Пронумерованный элемент: DictionaryEntryDictionary / Hashtable сходства:
GetHashCode()Коллекции Похожий .NET (кандидаты для использования вместо Dictionary и Hashtable):
ConcurrentDictionary - потокобезопасный (может быть безопасно доступен из нескольких потоков одновременно)HybridDictionary - оптимизированная производительность (для нескольких предметов, а также для многих предметов)OrderedDictionary - значения могут быть доступ через int index (по порядку добавления элементов)SortedDictionary - предметы автоматически сортируетсяStringDictionary - строго типизированный и оптимизирован для струнных@ Guillaume86, вот почему вы используете TryGetValue вместо msdn.microsoft.com/en-us/library/bb347013.aspx
+1 для StringDictionary ... кстати, StringDictionary - это не то же самое, что Dictionary<string, string>, когда вы используете конструктор по умолчанию.
ParallelExtensionsExtras @ code.msdn.microsoft.com/windowsdesktop/… содержит ObservableConcurrentDictionary, который отлично подходит для связывания, а также для параллелизма.
отличное объяснение, очень приятно, что вы также перечислили сходства, чтобы уменьшить количество вопросов, которые могут прийти в голову
StringDictionary теперь считается устаревшим в пользу Dictionary<string,string> * с подходящим экземпляром StringComparer.
Dictionary<> - это универсальный тип, поэтому он безопасен по типу.
Вы можете вставить любой тип значения в HashTable, и это может иногда вызывать исключение. Но Dictionary<int> принимает только целочисленные значения, и аналогично Dictionary<string> принимает только строки.
Так что лучше использовать Dictionary<> вместо HashTable.
Collections и Generics полезны для обработки группы объектов. В .NET все объекты коллекций находятся под интерфейсом IEnumerable, который, в свою очередь, имеет ArrayList(Index-Value)) и HashTable(Key-Value). После .NET framework 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);
}
}
}
вместо того, чтобы явно назначать тип данных для KeyValuePair, мы могли бы использовать var. Таким образом, это уменьшило бы набор текста - foreach (var kv in dt) ... просто предложение.
Начиная с .NET Framework 3.5, существует также HashSet<T>, который предоставляет все преимущества Dictionary<TKey, TValue>, если вам нужны только ключи, а не значения.
Поэтому, если вы используете Dictionary<MyType, object> и всегда устанавливаете значение null для имитации типобезопасной хэш-таблицы, вам, возможно, следует подумать о переходе на HashSet<T>.
Объект Hashtable состоит из сегментов, содержащих элементы коллекции. Корзина - это виртуальная подгруппа элементов внутри хэш-таблицы, что делает поиск и извлечение проще и быстрее, чем в большинстве коллекций.
Класс Dictionary имеет ту же функциональность, что и класс Hashtable. Словарь определенного типа (кроме Object) имеет лучшую производительность, чем Hashtable для типов значений, поскольку элементы Hashtable относятся к типу Object, и, следовательно, упаковка и распаковка обычно происходят при сохранении или извлечении типа значения.
Для дальнейшего чтения: Типы коллекций хеш-таблиц и словарей
Словарь:
Он возвращает / выдает исключение, если мы пытаемся найти несуществующий ключ.
Это быстрее, чем Hashtable, потому что нет упаковки и распаковки.
Только общедоступные статические члены являются потокобезопасными.
Словарь - это общий тип, что означает, что мы можем использовать его с любым типом данных (при создании необходимо указать типы данных как для ключей, так и для значений).
Пример: Dictionary<string, string> <NameOfDictionaryVar> =
new Dictionary<string, string>();
Dictionay - это типобезопасная реализация Hashtable, Keys и Values строго типизированы.
Хеш-таблица:
Он возвращает ноль, если мы пытаемся найти несуществующий ключ.
Он медленнее, чем словарь, потому что требует упаковки и распаковки.
Все члены в Hashtable являются потокобезопасными,
Hashtable не является универсальным типом,
Hashtable - это слабо типизированная структура данных, мы можем добавлять ключи и значения любого типа.
«Он возвращает / выдает исключение, если мы пытаемся найти несуществующий ключ». Нет, если вы используете Dictionary.TryGetValue
В статье Обширное изучение структур данных с использованием C# на MSDN говорится, что есть разница в стратегия разрешения столкновений:
Класс Hashtable использует метод, называемый перефразирование.
Rehashing works as follows: there is a set of hash different functions, H1 ... Hn, and when inserting or retrieving an item from the hash table, initially the H1 hash function is used. If this leads to a collision, H2 is tried instead, and onwards up to Hn if needed.
Словарь использует метод, называемый цепочка.
With rehashing, in the event of a collision the hash is recomputed, and the new slot corresponding to a hash is tried. With chaining, however, a secondary data structure is utilized to hold any collisions. Specifically, each slot in the Dictionary has an array of elements that map to that bucket. In the event of a collision, the colliding element is prepended to the bucket's list.
Еще одно важное отличие состоит в том, что Hashtable является потокобезопасным. Hashtable имеет встроенную безопасность потоков с несколькими читателями / одиночными записями (MR / SW), что означает, что Hashtable позволяет ОДИН писатель вместе с несколькими считывателями без блокировки.
В случае со словарем потокобезопасность отсутствует; если вам нужна потокобезопасность, вы должны реализовать свою собственную синхронизацию.
Для дальнейшего уточнения:
Hashtable provides some thread-safety through the
Synchronizedproperty, which returns a thread-safe wrapper around the collection. The wrapper works by locking the entire collection on every add or remove operation. Therefore, each thread that is attempting to access the collection must wait for its turn to take the one lock. This is not scalable and can cause significant performance degradation for large collections. Also, the design is not completely protected from race conditions.The .NET Framework 2.0 collection classes like
List<T>, Dictionary<TKey, TValue>, etc. do not provide any thread synchronization; user code must provide all synchronization when items are added or removed on multiple threads concurrently
Если вам нужна безопасность типов, а также безопасность потоков, используйте классы параллельных коллекций в .NET Framework. Дальнейшее чтение здесь.
Дополнительное отличие состоит в том, что при добавлении нескольких записей в словарь порядок, в котором они добавляются, сохраняется. Когда мы извлекаем элементы из Dictionary, мы получим записи в том же порядке, в котором мы их вставляли. В то время как Hashtable не сохраняет порядок вставки.
Насколько я понимаю, Hashset гарантирует безопасность потоков MR / SW в сценариях использования которые не связаны с удалениями. Я думаю, что это могло быть предназначено для полной безопасности MR / SW, но безопасная обработка удалений значительно увеличивает расходы на безопасность MR / SW. Хотя дизайн Dictionary мог обеспечить безопасность MR / SW при минимальных затратах в сценариях без удаления, я думаю, что MS хотела избежать обработки сценариев без удаления как «особых».
Хеш-таблица:
Ключ / значение будут преобразованы в тип объекта (бокса) при сохранении в куче.
Ключ / значение необходимо преобразовать в нужный тип при чтении из кучи.
Эти операции очень дороги. Нам нужно по возможности избегать упаковки / распаковки.
Словарь : Общий вариант HashTable.
Никакого бокса / распаковки. Никаких преобразований не требуется.
In most programming languages, dictionaries are preferred over hashtables
Я не думаю, что это обязательно так, в большинстве языков есть один или другой, в зависимости от терминология, которую они предпочитают.
Однако в C# очевидная причина (для меня) заключается в том, что C# HashTables и другие члены пространства имен System.Collections в значительной степени устарели. Они присутствовали в C# V1.1. В C# 2.0 они были заменены классами Generic в пространстве имен System.Collections.Generic.
Одно из преимуществ хеш-таблицы перед словарем заключается в том, что если ключ не существует в словаре, это вызовет ошибку. Если ключ не существует в хеш-таблице, он просто возвращает ноль.
В C# я бы по-прежнему избегал использования System.Collections.Hashtable, поскольку у них нет преимуществ дженериков. Вы можете использовать Dictionary TryGetValue или HasKey, если не знаете, будет ли существовать ключ.
Упс, не HasKey, это должен быть ContainsKey.
> Это не обязательно так. Хеш-таблица - это реализация словаря. При этом типичный, и он может быть по умолчанию в .NET, но по определению не единственный. Я не уверен, что это требуется стандартом ECMA, но Документация MSDN очень четко называет это реализованным в виде хеш-таблицы. Они даже предоставляют класс SortedList для тех случаев, когда альтернатива более разумна.