Почему словарь предпочтительнее Hashtable?

в большинстве языков программирования, словари предпочтительнее, чем хеш-таблицы. Каковы причины этого?

18 ответов


для чего это стоит, словарь и (концептуально) хэш-таблице.

если вы имели в виду " почему мы используем Dictionary<TKey, TValue> класс вместо Hashtable класса?- тогда ответ прост:Dictionary<TKey, TValue> универсального типа, Hashtable нет. Это означает, что вы получаете тип безопасности с Dictionary<TKey, TValue>, потому что вы не можете вставить в него случайный объект, и вам не нужно отбрасывать значения, которые вы берете.

интересно, что Dictionary<TKey, TValue> реализация в .NET Framework на основе Hashtable, как можно понять из этого комментария в исходном коде:

общий словарь был скопирован из источника Hashtable

источник


Dictionary >> Hashtable отличия:

  • Generic >> Non-Generic
  • должен собственная синхронизация потоков >> предлагает thread safe версия через Synchronized() метод
  • перечисляемого элемента: KeyValuePair >> перечисляемого элемента: DictionaryEntry
  • новее ( > .NET 2.0) >> старше (с .NET 1.0)
  • находится в .Коллекции.Generic >> находится в .Сборники
  • запрос на несуществующий ключ бросает исключение >> запрос на несуществующий ключ возвращает null
  • потенциально немного быстрее для типов значений >> чуть медленнее (требуется бокс/распаковка) для значения типы

Dictionary / Hashtable сходство:

  • как внутренне хеш-таблицы == быстрый доступ к данным много-деталя согласно ключу
  • как надо неизменяемые и уникальные ключи
  • ключи обоих нужно иметь GetHashCode() метод

как .NET коллекции (кандидаты для использования вместо словаря и Хеш-таблицы):

  • ConcurrentDictionary - thread safe (можно безопасно получить доступ из нескольких потоков одновременно)
  • HybridDictionary - оптимизация производительности (для немногих деталей и также для много деталей)
  • OrderedDictionary - значения могут быть доступ через int index (в порядке добавления элементов)
  • SortedDictionary - статьи автоматически сортируются
  • StringDictionary - со строгой типизацией и оптимизирован для строки

, потому что Dictionary является общим классом (Dictionary<TKey, TValue>), Так что доступ к его содержимому является типобезопасным (т. е. вам не нужно бросать из Object, а ты Hashtable).

сравнить

var customers = new Dictionary<string, Customer>();
...
Customer customer = customers["Ali G"];

to

var customers = new Hashtable();
...
Customer customer = customers["Ali G"] as Customer;
, Dictionary реализуется как Hashtable внутри, так что технически это работает точно так же.

к вашему сведению: во .Чистая, Hashtable является потокобезопасным для использования несколькими потоками чтения и одним потоком записи, в то время как в Dictionary открытые статические члены являются потокобезопасными, но любые члены экземпляров не гарантируется потокобезопасность.

нам пришлось изменить все наши словари на Hashtable из-за этого.


в .NET разница между Dictionary<,> и HashTable в первую очередь, что первый является общим типом, поэтому вы получаете все преимущества дженериков с точки зрения статической проверки типов (и уменьшенного бокса, но это не так велико, как люди склонны думать с точки зрения производительности - есть определенная стоимость памяти для бокса, хотя).


люди говорят, что словарь-это то же самое, что и хэш-таблица.

Это не обязательно так. Хэш-таблица-это реализация словаря. Типичный при этом, и он может быть по умолчанию в .NET, но он по определению не единственный.

вы также можете реализовать словарь со связанным списком или деревом поиска, он просто не будет таким эффективным (для некоторых показателей эффективности).


Collections & Generics полезны для обработки группы объектов. В .NET все объекты коллекций входят в интерфейс IEnumerable, который в свою очередь ArrayList(Index-Value)) & HashTable(Key-Value). После .NET framework 2.0,ArrayList & HashTable заменить List & Dictionary. Теперь Arraylist & HashTable больше не используются в современных проектах.

подходя к разнице между HashTable & Dictionary, Dictionary является общим, где as Hastable не является универсальным. Мы можем добавить любой тип возражаю HashTable, но при извлечении нам нужно привести его к требуемому типу. Таким образом, это не тип safe. Но ... --18-->, при объявлении себя мы можем указать тип ключа и значение, поэтому нет необходимости бросать при получении.

давайте рассмотрим пример:

HashTable

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);
        }
    }
}

словарь:

  • возвращает/бросает исключение, если мы пытаемся найти ключ, который не существует.

  • это быстрее, чем хэш-таблица, потому что нет бокса и распаковки.

  • только общедоступные статические члены являются потокобезопасными.

  • словарь является общим типом, что означает, что мы можем использовать его с любым типом данных (при создании необходимо указать типы данных для обоих ключей и значения.)

    пример: Dictionary<string, string> <NameOfDictionaryVar> = new Dictionary<string, string>();

  • - Диктивного тип-безопасная реализация Hashtable, Keys и Values строго типизированы.

Hashtable:

  • он возвращает null, если мы пытаемся найти ключ, который не существует.

  • Это медленнее, чем словарь, потому что он требует упаковки и распаковки.

  • все члены в хэш-таблице являются потокобезопасными,

  • Hashtable не является общим типом,

  • Hashtable-это слабо типизированная структура данных, мы можем добавлять ключи и значения любого типа.


начиная с .NET Framework 3.5 существует также HashSet<T>, который предоставляет все преимущества Dictionary<TKey, TValue> если вам нужны только ключи и никакого значения.

если вы используете Dictionary<MyType, object> и всегда устанавливайте значение null чтобы имитировать тип безопасной хэш-таблицы, вы должны, возможно, рассмотреть вопрос о переключении на HashSet<T>.


на обширное изучение структур данных с использованием C# в статье MSDN говорится, что существует также разница в стратегия разрешения столкновений:

класс Hashtable использует метод, называемый rehashing.

Rehashing работает следующим образом: существует набор хэш - функций, H1 ... Hn, и при вставке или извлечении элемента из хэш таблица, изначально H1 используется хэш-функция. Если это приводит к столкновение, H2 вместо этого пробуется и далее до Hn при необходимости.

словарь использует метод, называемый сцепление.

при повторном хэшировании в случае столкновения хэш пересчитывается, и пробуется новый слот, соответствующий хэшу. С цепями, однако,вторичная структура данных используется для хранения любые столкновения. В частности, каждый слот в словаре массив элементов, которые соответствуют этому ведру. В случае столкновения элемент colliding добавляется в список bucket.


на Hashtable - это слабо типизированная структура данных, поэтому вы можете добавлять ключи и значения любого типа в Hashtable. The Dictionary класс является типобезопасным Hashtable реализация, а ключи и значения строго типизированы. При создании Dictionary экземпляр, необходимо указать типы данных как для ключа, так и для значения.


обратите внимание, что MSDN говорит: "класс Dictionary)>) реализован как хэш-таблицы", не " словарь)>) класс реализован как HashTable"

словарь не реализован как хэш-таблица, но он реализован в соответствии с концепцией хэш-таблицы. Реализация не связана с классом HashTable из-за использования дженериков, хотя внутренне Microsoft могла бы использовать тот же код и заменить символы типа Object с TKey и TValue.

в .NET 1.0 дженерики не существовали; именно здесь изначально начинались хэш-таблица и ArrayList.


объект Hashtable состоит из ведер, содержащих элементы коллекции. Ведро-это виртуальная подгруппа элементов в хэш-таблице,что делает поиск и извлечение проще и быстрее, чем во многих коллекциях.

класс Dictionary имеет ту же функциональность, что и класс Hashtable. Словарь определенного типа (кроме Object) имеет лучшую производительность, чем Hashtable для типов значений, потому что элементы Hashtable имеют тип Object и, следовательно, бокс и распаковка обычно происходят при сохранении или получении типа значения.

для дальнейшего чтения: Hashtable и словарь типов коллекции


HashTable:

ключ / значение будет преобразован в тип объекта (бокса) при хранении в куче.

ключ / значение необходимо преобразовать в нужный тип при чтении из кучи.

эти операции очень дорогостоящие. Нам нужно избегать бокса / распаковки как можно больше.

словарь : общий вариант HashTable.

нет бокс/распаковка. Преобразование не требуется.


еще одно отличие, которое я могу понять:

мы не можем использовать словарь (generics) с веб-службами. Причина в том, что стандарт веб-службы не поддерживает стандарт generics.


Dictionary<> является общим типом,и поэтому он безопасен.

вы можете вставить любой тип значения в HashTable, и это иногда может вызвать исключение. Но!--1--> будет принимать только целочисленные значения, а так же Dictionary<string> принимает только строки.

Итак, лучше использовать Dictionary<> вместо HashTable.


другое важное различие заключается в том, что Hashtable является потокобезопасным. Hashtable имеет встроенную множественную безопасность потока читателя/одиночного писателя (MR/SW) которая значит что Hashtable позволяет одному писателю вместе с множественными читателями без фиксировать.

в случае словаря нет безопасности потоков; если вам нужна безопасность потоков, вы должны реализовать свою собственную синхронизацию.

уточнения:

Hashtable обеспечивает некоторую поток-безопасность через Synchronized свойство, которое возвращает потокобезопасную оболочку вокруг коллекции. Обертка работает путем блокировки всей коллекции при каждой операции добавления или удаления. Поэтому каждый поток, который пытается получить доступ к коллекции, должен дождаться своей очереди, чтобы взять одну блокировку. Это не масштабируется и может привести к значительному снижению производительности для больших коллекций. Кроме того, конструкция не полностью защищена от условий гонки.

классы коллекции .NET Framework 2.0 как List<T>, Dictionary<TKey, TValue>, etc. не предоставляйте синхронизацию потоков; код пользователя должен обеспечивать синхронизацию всех элементов при одновременном добавлении или удалении элементов в нескольких потоках

Если вам нужна безопасность типов, а также безопасность потоков, используйте параллельные классы коллекций в .NET Framework. Дальнейшее чтение здесь.

дополнительная разница заключается в том, что при добавлении нескольких записей в словаре сохраняется порядок добавления записей. Когда мы получим элементы из словаря, мы получим записи в том же порядке, в котором мы их вставили. В то время как Hashtable не сохраняет порядок вставки.


по тому что я вижу с помощью .Чистый отражатель:

[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 использует хэш-таблицу внутри.