Когда я должен использовать тип HashSet <T>?

public static string Reverse( string s )
{
    char[] charArray = s.ToCharArray();
    Array.Reverse( charArray );
    return new string( charArray );
}
128
задан GEOCHET 8 August 2009 в 14:02
поделиться

9 ответов

Самое важное в HashSet прямо в названии: это набор . Единственное, что вы можете сделать с одним набором, - это установить его элементы и проверить, является ли элемент членом.

Спросить, можете ли вы получить один элемент (например, set [45] ]) неверное понимание концепции множества. Нет такого понятия, как 45-й элемент набора. Предметы в наборе не имеют упорядочивания. Наборы {1, 2, 3} и {2, 3, 1} идентичны во всех отношениях, потому что они имеют одинаковое членство, и членство - это все, что имеет значение.

Несколько опасно перебирать HashSet , потому что это накладывает порядок на элементы в наборе. Этот порядок на самом деле не является свойством набора. Не стоит полагаться на это. Если для вас важен порядок элементов в коллекции, эта коллекция не является набором.

Наборы действительно ограничены и имеют уникальные элементы. С другой стороны, они действительно быстрые.

225
ответ дан 24 November 2019 в 00:34
поделиться

A HashSet реализует интерфейс ICollection :

public interface ICollection<T> : IEnumerable<T>, IEnumerable
{
    // Methods
    void Add(T item);
    void Clear();
    bool Contains(T item);
    void CopyTo(T[] array, int arrayIndex);
    bool Remove(T item);

    // Properties
   int Count { get; }
   bool IsReadOnly { get; }
}

A List реализует IList , который расширяет ICollection

public interface IList<T> : ICollection<T>
{
    // Methods
    int IndexOf(T item);
    void Insert(int index, T item);
    void RemoveAt(int index);

    // Properties
    T this[int index] { get; set; }
}

A HashSet имеет семантику набора, реализованную с помощью внутренней хэш-таблицы:

Набор - это коллекция, которая не содержит повторяющиеся элементы, и чьи элементы не находятся в определенном порядке.

Что получает HashSet, если он теряет поведение индекса / позиции / списка?

Добавление и извлечение элементов из HashSet всегда осуществляется самим объектом, а не через индексатор, и близко к операция O (1) (список - это O (1) добавить, O (1) получить по индексу, O (n) найти / удалить).

Поведение HashSet можно сравнить с использованием Dictionary только добавлением / удалением ключей как значений и игнорированием самих значений словаря. Можно было бы ожидать, что ключи в словаре не будут иметь повторяющихся значений, и в этом суть части «Установить».

23
ответ дан 24 November 2019 в 00:34
поделиться

Производительность была бы плохой причиной для выбора HashSet вместо List. Вместо этого, что лучше отражает ваше намерение? Если порядок важен, то Set (или HashSet) отсутствует. Аналогично, если разрешены дубликаты. Но есть множество обстоятельств, когда нас не волнует порядок, и мы не хотели бы иметь дубликатов - и именно тогда вам нужен набор.

14
ответ дан 24 November 2019 в 00:34
поделиться

HashSet - это набор , реализованный посредством хеширования. Набор - это набор значений, не содержащий повторяющихся элементов. Значения в наборе также обычно неупорядочены. Итак, нет, набор не может использоваться для замены списка (если только вы не должны использовать набор в первую очередь).

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

11
ответ дан 24 November 2019 в 00:34
поделиться

Вероятно, наиболее распространенное использование хэш-наборов - это увидеть, содержат ли они определенный элемент, что близко к операции O (1) для них (при условии достаточно сильной хеш-функции), в отличие от для списков, для которых проверка на включение составляет O (n) (и отсортированных наборов, для которых это O (log n)). Поэтому, если вы много проверяете, содержится ли элемент в каком-либо списке, hahssets может улучшить производительность. Если вы будете выполнять итерацию только по ним, особой разницы не будет (итерация по всему набору - O (n), так же, как со списками и хэш-наборами, при добавлении элементов немного больше накладных расходов).

И нет, вы можете 'не индексировать набор, что в любом случае не имеет смысла, потому что наборы не упорядочены. Если вы добавите какие-то элементы, набор не запомнит, какой из них был первым, а какой вторым и т. Д.

6
ответ дан 24 November 2019 в 00:34
поделиться

Список используется для хранения упорядоченных наборов информации. Если вы знаете относительный порядок элементов списка, вы можете получить к ним доступ в постоянное время. Однако, чтобы определить, где находится элемент в списке, или проверить, существует ли он в списке, время поиска является линейным. С другой стороны, HashedSet не гарантирует порядка хранимых данных и, следовательно, обеспечивает постоянное время доступа для своих элементов.

Как следует из названия, HashedSet - это структура данных, которая реализует семантику набора . Структура данных оптимизирована для реализации операций над наборами (например, Union, Difference, Intersect), что не может быть выполнено так эффективно с традиционной реализацией List.

Итак, выбор того, какой тип данных использовать, действительно зависит от того, что вы пытаетесь сделать с вашим приложением. Если вас не волнует, как ваши элементы упорядочены в коллекции, и вы хотите только перечислить или проверить наличие, используйте HashSet . В противном случае рассмотрите возможность использования List или другой подходящей структуры данных.

4
ответ дан 24 November 2019 в 00:34
поделиться

Вкратце - каждый раз, когда у вас возникает соблазн использовать Словарь (или Словарь, где S является свойством T), вам следует рассмотреть HashSet (или HashSet +, реализующий IEquatable на T, что приравнивается к S)

1
ответ дан 24 November 2019 в 00:34
поделиться

Здесь реальный пример того, где я использую HashSet :

Часть моей подсветки синтаксиса для файлов UnrealScript - это новая функция, которая выделяет комментарии в стиле Doxygen . Мне нужно знать, допустима ли команда @ или \ , чтобы определить, отображать ли ее серым (допустимый) или красным (недопустимый). У меня есть HashSet всех допустимых команд, поэтому всякий раз, когда я нажимаю токен @xxx в лексере, я использую validCommands.Contains (tokenText) ] в качестве проверки действительности O (1). Я действительно не Меня не волнует ничего, кроме существования команды в наборе допустимых команд. Давайте посмотрим на альтернативы, с которыми я столкнулся:

  • Dictionary : Какой тип использовать для значения? Значение не имеет смысла, поскольку я просто собираюсь использовать ContainsKey . Примечание. До .NET 3.0 это был единственный выбор для поиска O (1) - HashSet был добавлен для 3.0 и расширен для реализации ISet для 4.0. 1239] List : Если я сохраню список отсортированным, я могу использовать BinarySearch , который равен O (log n) (не видел этого факта, упомянутого выше). Однако, поскольку мой список допустимых команд - это фиксированный список, который никогда не изменяется, он никогда не будет более подходящим, чем просто ...
  • строка [] : Опять же, Массив. BinarySearch дает производительность O (log n). Если список короткий, это может быть лучший вариант. У него всегда меньше места, чем у HashSet , Dictionary или List . Даже с BinarySearch он не быстрее для больших наборов, но для небольших наборов стоит поэкспериментировать. У меня есть несколько сотен элементов, поэтому я передал это.
105
ответ дан 24 November 2019 в 00:34
поделиться

HashSet - это структура данных в платформе .NET, способная представлять математический набор в виде объекта. В этом случае он использует хэш-коды (результат GetHashCode для каждого элемента) для сравнения равенства элементов набора.

Набор отличается от списка тем, что допускает только одно вхождение одного и того же содержащегося элемента внутри. HashSet просто вернет false , если вы попытаетесь добавить второй идентичный элемент. Действительно, поиск элементов выполняется очень быстро ( O (1) раз), поскольку внутренняя структура данных представляет собой просто хеш-таблицу.

Если вам интересно, что использовать, обратите внимание, что использование ] List , где HashSet является подходящим, не является самой большой ошибкой, хотя это может потенциально позволить проблемы, когда у вас есть нежелательные повторяющиеся элементы в вашей коллекции. Более того, поиск (поиск элемента) намного эффективнее - в идеале O (1) (для идеального группирования) вместо O (n) времени, что очень важно во многих сценарии.

4
ответ дан 24 November 2019 в 00:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: