Ответы:
Реализованы они очень по-разному.
hash_map
( unordered_map
в TR1 и Boost; используйте их вместо) используйте хеш-таблицу, в которой ключ хешируется в слот в таблице, а значение сохраняется в списке, привязанном к этому ключу.
map
реализован как сбалансированное двоичное дерево поиска (обычно красное / черное дерево).
unordered_map
Должны дать немного более высокую производительность для доступа к известным элементам коллекции, но map
будет иметь дополнительные полезные свойства (например , они хранятся в отсортированном порядке, что позволяет обход от начала до конца). unordered_map
будет быстрее вставлять и удалять, чем map
.
hash_map
было распространенным расширением, предоставляемым многими реализациями библиотек. Именно поэтому его переименовали в, unordered_map
когда он был добавлен в стандарт C ++ как часть TR1. map обычно реализуется с помощью сбалансированного двоичного дерева, такого как красно-черное дерево (реализации, конечно, различаются). hash_map
и unordered_map
обычно реализуются с помощью хеш-таблиц. Таким образом, порядок не поддерживается. unordered_map
insert / delete / query будет O (1) (постоянное время), где map будет O (log n), где n - количество элементов в структуре данных. Так unordered_map
работает быстрее, и если вам не важен порядок элементов, то предпочтение следует отдавать map
. Иногда вы хотите поддерживать порядок (упорядоченный по ключу), и это map
будет выбор.
Некоторые из ключевых отличий заключаются в требованиях к сложности.
A map
требует O(log(N))
времени для операций вставки и поиска, поскольку он реализован в виде структуры данных Red-Black Tree .
Для вставки и поиска unordered_map
требуется «среднее» время O(1)
, но разрешено иметь наихудшее время O(N)
. Это потому, что он реализован с использованием структуры данных Hash Table .
Обычно unordered_map
это будет быстрее, но в зависимости от ключей и хэш-функции, которые вы храните, может стать намного хуже.
Спецификация C ++ не говорит точно, какой алгоритм вы должны использовать для контейнеров STL. Однако это накладывает определенные ограничения на их производительность, что исключает использование хеш-таблиц дляmap
и других ассоциативных контейнеров. (Чаще всего они реализуются с помощью красно-черных деревьев.) Эти ограничения требуют для этих контейнеров более высокой производительности в худшем случае, чем могут обеспечить хэш-таблицы.
Однако многим людям действительно нужны хеш-таблицы, поэтому ассоциативные контейнеры STL на основе хешей уже много лет являются обычным расширением. Следовательно, они добавили unordered_map
и тому подобное в более поздние версии стандарта C ++.
map
том, что обычно сбалансированное btree было связано с использованием operator<()
в качестве средства определения местоположения.
map
реализуется из balanced binary search tree
(обычно a rb_tree
), поскольку все члены balanced binary search tree
сортируются так, как map;
hash_map
реализуется из hashtable
.S Поскольку все hashtable
члены в hash_map(unordered_map)
не отсортированы, поэтому члены в не сортируются.
hash_map
не является стандартной библиотекой С ++, но теперь она переименована в unordered_map
(вы можете подумать о ее переименовании) и становится стандартной библиотекой С ++, так как С ++ 11 см. этот вопрос Разница между hash_map и unordered_map?для более подробной информации.
Ниже я приведу базовый интерфейс из исходного кода, показывающий, как реализована карта двух типов.
Приведенный ниже код просто показывает, что map - это просто оболочка balanced binary search tree
, почти вся ее функция - это просто вызвать balanced binary search tree
функцию.
template <typename Key, typename Value, class Compare = std::less<Key>>
class map{
// used for rb_tree to sort
typedef Key key_type;
// rb_tree node value
typedef std::pair<key_type, value_type> value_type;
typedef Compare key_compare;
// as to map, Key is used for sort, Value used for store value
typedef rb_tree<key_type, value_type, key_compare> rep_type;
// the only member value of map (it's rb_tree)
rep_type t;
};
// one construct function
template<typename InputIterator>
map(InputIterator first, InputIterator last):t(Compare()){
// use rb_tree to insert value(just insert unique value)
t.insert_unique(first, last);
}
// insert function, just use tb_tree insert_unique function
//and only insert unique value
//rb_tree insertion time is : log(n)+rebalance
// so map's insertion time is also : log(n)+rebalance
typedef typename rep_type::const_iterator iterator;
std::pair<iterator, bool> insert(const value_type& v){
return t.insert_unique(v);
};
hash_map
:hash_map
реализован hashtable
, структура которого выглядит примерно так:
В приведенном ниже коде я приведу основную часть hashtable
, а затем дам hash_map
.
// used for node list
template<typename T>
struct __hashtable_node{
T val;
__hashtable_node* next;
};
template<typename Key, typename Value, typename HashFun>
class hashtable{
public:
typedef size_t size_type;
typedef HashFun hasher;
typedef Value value_type;
typedef Key key_type;
public:
typedef __hashtable_node<value_type> node;
// member data is buckets array(node* array)
std::vector<node*> buckets;
size_type num_elements;
public:
// insert only unique value
std::pair<iterator, bool> insert_unique(const value_type& obj);
};
Как map's
только член rb_tree
, hash_map's
единственный член hashtable
. Это основной код, как показано ниже:
template<typename Key, typename Value, class HashFun = std::hash<Key>>
class hash_map{
private:
typedef hashtable<Key, Value, HashFun> ht;
// member data is hash_table
ht rep;
public:
// 100 buckets by default
// it may not be 100(in this just for simplify)
hash_map():rep(100){};
// like the above map's insert function just invoke rb_tree unique function
// hash_map, insert function just invoke hashtable's unique insert function
std::pair<iterator, bool> insert(const Value& v){
return t.insert_unique(v);
};
};
На изображении ниже показано, когда hash_map имеет 53 сегмента и вставляет некоторые значения, это внутренняя структура.
На изображении ниже показана некоторая разница между картой и hash_map (unordered_map), изображение взято из Как выбрать между картой и unordered_map? :
Я не знаю, что дает, но hash_map требуется более 20 секунд для clear () 150K целочисленных ключей без знака и значений с плавающей запятой. Я просто бегаю и читаю чужой код.
Вот как он включает hash_map.
#include "StdAfx.h"
#include <hash_map>
Я прочитал это здесь https://bytes.com/topic/c/answers/570079-perfomance-clear-vs-swap
говоря, что clear () является порядком O (N). Для меня это очень странно, но так оно и есть.