Зачем кому-то использовать set вместо unordered_set? - PullRequest
126 голосов
/ 29 августа 2009

C ++ 0x представляет unordered_set, который доступен в boost и во многих других местах. Я понимаю, что unordered_set - это хеш-таблица со O(1) сложностью поиска. С другой стороны, set - это не что иное, как дерево с log(n) сложностью поиска. Зачем кому-то использовать set вместо unordered_set? т.е. есть ли необходимость в set больше?

Ответы [ 11 ]

291 голосов
/ 29 августа 2009

Неупорядоченные наборы должны платить за среднее время доступа O (1) несколькими способами:

  • set использует меньше памяти , чем unordered_set для хранения того же количества элементов.
  • Для небольшого числа элементов поиск в set может быть на быстрее , чем поиск в unordered_set.
  • Несмотря на то, что многие операции выполняются быстрее в среднем для unordered_set, они часто гарантированно имеют лучшие сложности в худшем случае для set (например, insert ).
  • То, что set сортирует элементы , полезно, если вы хотите получить к ним доступ по порядку.
  • Вы можете лексикографически сравнивать разные set s с <, <=, > и >=. unordered_set s не требуется для поддержки этих операций.

201 голосов
/ 29 августа 2009

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

25 голосов
/ 29 августа 2009

Всякий раз, когда вы предпочитаете дерево хеш-таблице.

Например, в худшем случае хеш-таблицы имеют значение "O (n)". O (1) - средний случай. Деревья в худшем случае "O ( log n)".

6 голосов
/ 06 сентября 2018

Использовать настройку, когда:

  1. Нам нужны упорядоченные данные (отдельные элементы).
  2. Мы должны были бы распечатать / получить доступ к данным (в отсортированном порядке).
  3. Нам нужен предшественник / преемник элементов.

Использовать unordered_set, когда:

  1. Нам нужно сохранить набор отдельных элементов, и упорядочение не требуется.
  2. Нам нужен одноэлементный доступ, т. Е. Обхода нет.

Примеры:

комплект:

Ввод: 1, 8, 2, 5, 3, 9

Выход: 1, 2, 3, 5, 8, 9

Unordered_set:

Ввод: 1, 8, 2, 5, 3, 9

Вывод: 9 3 1 8 2 5 (возможно, этот порядок зависит от хэш-функции)

В основном разница:

enter image description here

Примечание: (в некоторых случаях set более удобно), например, используя vector в качестве ключа

set<vector<int>> s;
s.insert({1, 2});
s.insert({1, 3});
s.insert({1, 2});

for(const auto& vec:s)
    cout<<vec<<endl;   // I have override << for vector
// 1 2
// 1 3 

Причина, по которой vector<int> может быть ключом set, потому что vector переопределить operator<.

Но если вы используете unordered_set<vector<int>>, вам нужно создать хеш-функцию для vector<int>, потому что вектор не имеет хеш-функции, поэтому вы должны определить такую ​​как:

struct VectorHash {
    size_t operator()(const std::vector<int>& v) const {
        std::hash<int> hasher;
        size_t seed = 0;
        for (int i : v) {
            seed ^= hasher(i) + 0x9e3779b9 + (seed<<6) + (seed>>2);
        }
        return seed;
    }
};

vector<vector<int>> two(){
    //unordered_set<vector<int>> s; // error vector<int> doesn't  have hash function
    unordered_set<vector<int>, VectorHash> s;
    s.insert({1, 2});
    s.insert({1, 3});
    s.insert({1, 2});

    for(const auto& vec:s)
        cout<<vec<<endl;
    // 1 2
    // 1 3
}

вы можете видеть, что в некоторых случаях unordered_set сложнее.

В основном цитируется из: https://www.geeksforgeeks.org/set-vs-unordered_set-c-stl/ https://stackoverflow.com/a/29855973/6329006

6 голосов
/ 02 сентября 2009

Рассмотрим алгоритмы стреловидности. Эти алгоритмы полностью потерпят неудачу с хеш-таблицами, но прекрасно работают со сбалансированными деревьями. Чтобы дать вам конкретный пример алгоритма разметки, рассмотрим алгоритм Fortune. http://en.wikipedia.org/wiki/Fortune%27s_algorithm

6 голосов
/ 29 августа 2009

Поскольку std :: set является частью стандарта C ++, а unordered_set - нет. C ++ 0x НЕ является стандартом и не является Boost. Для многих из нас мобильность важна, и это означает, что нужно придерживаться стандарта.

3 голосов
/ 03 февраля 2015

Прошу прощения, еще одна вещь, которую стоит отметить в отсортированном свойстве:

Если вы хотите диапазон данных в контейнере, например: вы сохранили время в , установите , и вам нужно время с 2013-01-01 по 2014-01-01 .

Для unordered_set это невозможно.

Конечно, этот пример будет более убедительным для случаев использования между map и unordered_map .

3 голосов
/ 14 марта 2011

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

Вставка в набор всегда занимает не более O (log n). Это может быть предпочтительнее в некоторых приложениях.

1 голос
/ 29 августа 2009

Если вы хотите отсортировать вещи, вы должны использовать set вместо unordered_set. unordered_set используется сверх установленного значения, когда сохраненный порядок не имеет значения.

1 голос
/ 29 августа 2009

От руки, я бы сказал, удобно иметь отношения в отношениях, если вы хотите преобразовать их в другой формат.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...