Является ли unordered_map действительно неупорядоченным? - PullRequest
13 голосов
/ 05 июля 2010

Меня очень смущает название "unordered_map".Название предполагает, что ключи не упорядочены вообще.Но я всегда думал, что они упорядочены по их хэш-значению.Или это неправильно (поскольку название подразумевает, что они не упорядочены)?

Или, если выразиться иначе: это

typedef map<K, V, HashComp<K> > HashMap;

с

template<typename T>
struct HashComp {
    bool operator<(const T& v1, const T& v2) const {
        return hash<T>()(v1) < hash<T>()(v2);
    }
};

такой же как

typedef unordered_map<K, V> HashMap;

?(Хорошо, не совсем, STL будет жаловаться здесь, потому что могут быть ключи k1, k2 и ни k1 multimap и перезаписать проверку на равенство.)

Или еще раз: когда я их перебираю, могу ли я предположить, что список ключей упорядочен по их хэш-значению?

Ответы [ 5 ]

22 голосов
/ 05 июля 2010

В ответ на ваш отредактированный вопрос, никакие эти два фрагмента не эквивалентны вообще. std::map хранит узлы в древовидной структуре, unordered_map сохраняет их в хеш-таблице *.

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

function add_value(object key, object value) {
   int hash = key.getHash();

   int bucket_index = hash % NUM_BUCKETS;
   if (buckets[bucket_index] == null) {
       buckets[bucket_index] = new linked_list();
   }
   buckets[bucket_index].add(new key_value(key, value));
}

function get_value(object key) {
   int hash = key.getHash();

   int bucket_index = hash % NUM_BUCKETS;
   if (buckets[bucket_index] == null) {
       return null;
   }

   foreach(key_value kv in buckets[bucket_index]) {
       if (kv.key == key) {
           return kv.value;
       }
   }
}

Очевидно, что это серьезное упрощение, и реальная реализация будет намного более продвинутой (например, поддержка изменения размера массива buckets, возможно, использование древовидной структуры вместо связанного списка для сегментов и т. Д.), Но это должно дать идея о том, как вы не можете вернуть значения в любом конкретном порядке. См. wikipedia для получения дополнительной информации.


* Технически, внутренняя реализация std::map и unordered_map определяется реализацией, но стандарт требует определенной сложности Big-O для операций, которые подразумевают этих внутренних реализаций

6 голосов
/ 05 июля 2010

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

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

Что касается "упорядоченного по их значению хеша": значения хеш-функции обычно берутся из полного диапазона целых чисел, но в картах хеша нет 2 ** 32 слотов вих.Диапазон значения хеш-функции будет уменьшен до количества слотов, если принять его по модулю количества слотов.Кроме того, когда вы добавляете записи в хэш-карту, она может изменить размер для соответствия новым значениям.Это может привести к тому, что все предыдущие записи будут переставлены, изменив их порядок.

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

2 голосов
/ 05 июля 2010

Как следует из названия unordered_map, в стандарте C ++ 0x порядок не указан. Очевидный порядок unordered_map будет зависеть от того, что удобно для фактической реализации.

1 голос
/ 05 июля 2010

Вы правы, unordered_map на самом деле заказано хешем.Обратите внимание, что большинство современных реализаций (до TR1) называют его hash_map.

Компилятор IBM C / C ++ Документация отмечает, что , если у вас есть оптимальная хеш-функция, числооперации, выполняемые во время поиска, вставки и удаления произвольного элемента, не зависят от количества элементов в последовательности , поэтому это означает, что порядок не настолько неупорядочен ...

Теперь, чтоэто означает, что это упорядоченный хэш ?Поскольку хеш должен быть непредсказуемым, по определению вы не можете принимать какие-либо предположения о порядке элементов на карте.По этой причине он был переименован в TR1: старое имя подсказывало порядок.Теперь мы знаем, что заказ действительно используется, но вы можете игнорировать его, так как он непредсказуем.

1 голос
/ 05 июля 2010

Если вы хотите провести аналогию, посмотрите на СУБД по вашему выбору.

Если вы не укажете предложение ORDER BY при выполнении запроса, результаты будут возвращены «неупорядоченными», то есть в любом порядке, в котором база данных выглядит. Порядок не указан, и система может свободно «заказывать» их, как пожелает, для достижения максимальной производительности.

...