Действительно ли неупорядоченный_мап неупорядочен?

Я очень смущен именем "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 < k2, ни k2 < k1. Вам нужно будет использовать multimap и перезаписать проверку с равными значениями.)

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

Ответ 1

В ответ на ваш отредактированный вопрос эти два фрагмента вообще не эквивалентны. 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 для операций, которая подразумевает эти внутренние реализации

Ответ 2

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

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

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

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

Ответ 3

Как следует из названия unordered_map, никакой порядок не задается стандартом С++ 0x. Явное упорядочение неупорядоченного_мапа будет зависеть от того, что удобно для реальной реализации.

Ответ 4

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

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

Ответ 5

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

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

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