Как работает unordered map
Перейти к содержимому

Как работает unordered map

  • автор:

std:: unordered_map::find

Searches the container for an element with k as key and returns an iterator to it if found, otherwise it returns an iterator to unordered_map::end (the element past the end of the container).

Another member function, unordered_map::count, can be used to just check whether a particular key exists.

The mapped value can also be accessed directly by using member functions at or operator[].

Parameters

k Key to be searched for.
Member type key_type is the type of the keys for the elements in the container, defined in unordered_map as an alias of its first template parameter (Key).

Return value

An iterator to the element, if the specified key value is found, or unordered_map::end if the specified key is not found in the container.

Member types iterator and const_iterator are forward iterator types.

Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// unordered_map::find int main () < std::unordered_mapdouble> mymap = < "mom",5.4>, "dad",6.1>, "bro",5.9> >; std::string input; std::cout "who? "; getline (std::cin,input); std::unordered_mapdouble>::const_iterator got = mymap.find (input); if ( got == mymap.end() ) std::cout "not found"; else std::cout first " is " second; std::cout return 0; >

Possible output:

who? dad dad is 6.1 

Complexity

Average case: constant.
Worst case: linear in container size.

Iterator validity

No changes.

See also

unordered_map::count Count elements with a specific key (public member function) unordered_map::operator[] Access element (public member function) unordered_map::at Access element (public member function)

Когда map быстрее чем unordered (3 стр)

И да, сравнение алгоритмов вы делаете неправильно. Мы говорим что некий хэш будет быстрее R-B дерева при поиске ключа при увеличении N. Никто не говорит, что на малых N R-B дерево не может быть быстрее хэша.

#31
11:21, 25 мар 2015

neumond
Оптимизацию было бы неплохо включить.

#32
11:34, 25 мар 2015

g++ -std=c++11 -O2 test.cpp; A=0; for I in ; do A="$(( A + `./a.out` ))" ; done ; echo $A

2949339 — unordered
1769809 — map

g++ -std=c++11 -O2 -march=athlon64-sse3 -O2 -mmmx -msse -msse2 -m3dnow -msse3 -mcx16 test.cpp; A=0; for I in ; do A="$(( A + `./a.out` ))" ; done ; echo $A

2939051 — unordered
1745114 — map

clang++ -std=c++11 -O2 test.cpp; A=0; for I in ; do A="$(( A + `./a.out` ))" ; done ; echo $A

112 — unordered
107 — map

clang похоже вообще срезал все циклы.

#33
12:39, 25 мар 2015

Что ж, действительно, если увеличить количество данных, unordered_map начинает выигрывать. Причём неслабо так увеличить надо, до 2500. И даже тогда перевес не такой уж большой: 24433267 (map) против 17060605 (unordered). Сильный выигрыш даёт замена хэша на x.first + x.second: 12062029, тогда оно в 2 раза быстрее map на наборе в 2500.

#34
13:21, 25 мар 2015

f1ufx_
> Я привёл тебе пример в котором map быстрее чем unordered_map. Но твоё сознание
> считает написанное за опечатку и отрицает действительность, пытаясь убереч
> сознание.
Ды что ты такое несёшь? Я помимо этого сказал ещё что тестить на 50 элементах производительность не имеет смысла, уже бы сделал несколько тысяч.

#35
15:08, 25 мар 2015

Smouking
У тебя есть инвентарь персонажа, в который заведомо влезает не так уж много предметов.
Игрок кастует заклинание «ржавый кинжал», чтобы у всех персонажей в зоне заклинания все кинжалы поржавели (в том числе и те, которые в рюкзаке).
Т.е. поиск кинжала будет выглядеть так:

foreach( Entity ent : AffectCollector.getEntity() ) < tuple(Kinzhal) tk = ent->getInventory->find(Kinzhal); foreach( kinzhal k : tk ) k->doRust(); >

Как будешь хранить инвентарь персонажа? unordered_map-ой?

#36
15:23, 25 мар 2015

f1ufx_
> Как будешь хранить инвентарь персонажа?

vector items

#37
15:41, 25 мар 2015

-Eugene-
Верно. Об этом и топик.

#38
3:33, 28 мар 2015

На VS.
map обычно быстрее unordered.
Я всегда думал, нафига нужен в таком случае unordered? Не вижу смысла его использовать.

#39
4:29, 28 мар 2015

Чтобы лучше сравнивалось приведу ключевые отличия map от unordered_map:

1.
map — это сортированный массив по ключу, в котором содержится pair
unordered_map — это набор сортированных массивов, в котором содержится pair.
Замечание: Сортировка массивов в unordered_map может и не выполняться, а честно проходит по элементам и искать нужный ключ.
Но здесь сказано, что массивы сортированы. Короче зависит от реализации.

2.
map — Операции поиска, удаления и вставки имеют логарифмическую сложность. Реализуется как массив с бинарным поиском или как красно-черное дерево (в STL RBTree).
unordered_map (С++11) — Поиск, вставка и удаление имеют средний постоянной временной сложности (условно).

Выводы:
map — удобно применять при небольшом количестве элементов. Надо учитывать, что пробегая по map от начала и до конца вы пробегаете уже по сортированному набору.
Хотя я не сравнивал, работу vector> + qsort c map.

у unordered_map важно помнить, что любая операция имеет сложность O(1). Данный контейнер работает очень эффективно при большом наборе элементов и особенно если массивы сбалансированы.

#40
8:12, 28 мар 2015

asvp
Ты не сказал важную штуку в конце. map значительно быстрее работает с группами элементов.

Каким образом unordered_map выдает правильное значение для ключа, если его хеш функция допускает коллизии?

Неупорядоченные контейнеры обычно реализуются в виде хеш-таблицы(рис. 6.3). Таким образом, по существу, контейнер — это массив связанных списков. Позиция элемента в массиве вычисляется с помощью хеш-функции. Цель заключается в том, что бы каждый
элемент имел свою позицию, обеспечивающую к нему быстрый доступ, при условии быстрого вычисления хеш-функции. Однако, поскольку быстрые идеальныехеш-функциине не всегда возможны или могут потребовать огромный объем памяти для массива, разрешается хранить в одной и той же позиции несколько элементов. По этой причине элементами массива являются связанные списки, позволяющие хранить в одной позиции массива несколько элементов контейнера.

Раз уж каждый элемент массива внутри unordered_map является связанным списком и допускаются коллизии, то правильно ли я понимаю как это работает(добавление элемента в unordered_map, приблизительная реализация):
1. По хеш функции вычисляется индекс
2. В связанный список индекса сохраняется значение
3. В случае коллизии в next уже существующего значения для этого ключа добавляется новый элемент
4. В списке дополнительно хранится ключ-оригинал для каждого элемента (что бы при поиске с ним можно было сравнить тот ключ который попросил программист)

Т.е хочу узнать, в случае коллизий происходит ли итерация по списку в поисках соответствующего значения для ключа который попросил программист? А если элемент один — сразу он и возвращается. Я правильно понимаю?

Добавлено через 4 минуты
И ещё вот что интересно:
Зачем может понадобится повторное хеширование всей таблицы? Какой в этом смысл?
В книге сказано что если после удаления элемента происходит добавление — это может привести к повторному хешированию всей таблицы — это может произойти даже если занять через reserve много места? Или только если в таблице осталось всего 1 свободное место для вставляемого элемента после удаления?

C++ Unordered Map

In C++, the STL unordered_map is an unordered associative container that provides the functionality of an unordered map or dictionary data structure.

In contrast to a regular map, the order of keys in an unordered map is undefined.

Also, the unordered map is implemented as a hash table data structure whereas the regular map is a binary search tree data structure.

Create C++ STL unordered_map

In order to create an unordered map in C++, we first need to include the unordered_map header file.

#include

Once we import this file, we can create an unordered map using the following syntax:

unordered_map ump;
  • key_type indicates the data type for the key
  • value_type indicates the data type for the value
// create an unordered_map with integer key and value unordered_map ump_integer; // create an unordered_map with string key and int value unordered_map ump_string;

Initialize an Unordered Map

We can initialize a C++ unordered map in the following ways:

// Initializer List unordered_map unordered_map1 = < , , >; // Uniform Initialization unordered_map unordered_map2 < , , >;

Here, we have initialized the unordered map by providing values directly to them.

Now, both unordered_map1 and unordered_map2 are initialized with , , > .

Example: C++ unordered_map

#include #include using namespace std; int main() < 
// uniform initialization unordered_map unordered_map1 < , , >;
cout return 0; >

Output

Key - Value Three - 3 Two - 2 One - 1

In the above example, we have declared and initialized an unordered map named unordered_map1 using uniform initialization.

unordered_map unordered_map1 < , , >;

Then, we have displayed the unordered map content using a ranged for loop.

for(const auto& key_value: unordered_map1)

In the above code, each element (key-value pair) of the unordered map is stored in variable key_value .

Then, we get the key and value using:

  • key_value.first — gives the key
  • key_value.second — gives the value

Notice that we have created the unordered map in order of the keys: «One» , «Two» , «Three» . However, the output is in undefined order.

This is because the elements are not stored in any particular order based on key, or the values.

Note: Starting from C++17, you can use structure bindings to simplify this code further:

for(const auto& [key, value]: unordered_map1)

Other Ways to Initialize a C++ Unordered Map

Copy one unordered map to another.

We can copy one unordered map to another using range method initialization.

unordered_map unordered_map_1 < , , >; unordered_map unordered_map_2(unordered_map_1.begin(), unordered_map_1.end());

Here, we have first created an unordered map named unordered_map_1 . Then, we created another unordered map called unordered_map_2 by copying all the elements of unordered_map_1 .

C++ Unordered Map Methods

In C++, the unordered_map class provides various methods to perform different operations on an unordered map.

Methods Description
insert() insert one or more key-value pairs
count() returns 1 if key exists and 0 if not
find() returns the iterator to the element with the specified key
at() returns the element at the specified key
size() returns the number of elements
empty() returns true if the unordered map is empty
erase() removes elements with specified key
clear() removes all elements

Insert Key-Value Pairs to an Unordered Map

We can insert a key-value pair in an unordered map using :

  • insert() — insert key-value pairs
  • [] — insert a key and value
#include #include using namespace std; int main() < unordered_mapunordered_map1; 
// insert key-value pair unordered_map1["One"] = 1; // insert a pair unordered_map1.insert(); // insert two pairs , unordered_map1.insert(<, >);
cout return 0; >

Output

Key - Value Four - 4 Two - 2 Three - 3 One - 1

In the above example, we have initialized an empty unordered map to store the key-value pairs of a string and an integer.

Then, we have inserted the pair using [] .

unordered_map1["One"] = 1;

We have then inserted another pair using the insert() method.

unordered_map1.insert();

Finally, we inserted two pairs using insert() .

unordered_map1.insert(, >);

Access Values of Unordered Maps

We can use the following methods to access the values of the specified key of an unordered map:

  • at() — returns value for the specified key
  • [] — returns value for the specified key
#include #include using namespace std; int main() < unordered_mapcapital_city < , , >; 
cout return 0; >

Output

Capital of Nepal is Kathmandu Capital of Australia is Canberra

In the above example,

  • capital_city[«Nepal»] — returns the element with key «Nepal»
  • capital_city.at(«Australia») — returns the element with key «Australia»

Note: While we can use the [] operator to access the elements, it is preferable to use the at() method.

This is because at() throws an exception whenever the specified key doesn’t exist, while [] pairs the key with a garbage value.

// key "Japan" doesn't exist // so the key "Japan" is paired with a garbage value cout 

Change Values of an Unordered Map

We can use the at() method or the [] operator to change the value of the unordered map. For example,

#include #include using namespace std; int main() < unordered_mapcapital_city < , , >; cout // change value for "India" using [] capital_city["India"] = "New Delhi"; // change value for "Pakistan" using at() capital_city.at("Pakistan") = "Islamabad";
cout

Output

Old Capitals: India : Calcutta Pakistan : Karachi New Capitals: India : New Delhi Pakistan : Islamabad

In the above example, the initial key-value pairs for capital_city are and .

Then, we have used the [] operator to change the value for key "India" using:

capital_city["India"] = "New Delhi";

Similarly, we have used the at() method to change the value for the key "Pakistan" using:

capital_city.at("Pakistan") = "Islamabad";

Remove Elements From an Unordered Map

We can remove the element with the specified key of an unordered map using the erase() method. For example,

#include #include using namespace std; // function prototype for display_unordered_map() void display_unordered_map(const unordered_map &); int main() < unordered_mapstudent < , , >; cout // remove element with key: 143 student.erase(143);
cout // utility function to print unordered_map elements void display_unordered_map(const unordered_map &umap) < for(const auto& key_value: umap) < int key = key_value.first; string value = key_value.second; cout >

Output

Initial Unordered Map: 143 - Chris 132 - Mark 111 - John Final Unordered Map: 132 - Mark 111 - John

In the above example, we have used the erase() method to remove an element from the unordered map.

Initially, the content of unordered map named student is , , > .

Then we have used the erase() method to remove the element with key 143.

// removes element with the key 143 student.erase(143);

Note: We can use the clear() method to remove all the elements of the unordered map.

Check if a Key Exists in the Unordered Map

We can use the following methods to check if the specified key exists in the unordered map.

  • find() - returns the iterator to the element if the key is found, else returns the end() iterator
  • count() - returns 1 if the key exists and 0 if not
#include #include using namespace std; int main() < unordered_mapstudent< , , >; cout // find() returns student.end() if the key is not found if (student.find(143) != student.end()) cout else < cout cout // count() returns 0 if the key doesn't exist if (student.count(1433)) cout else < cout return 0; >

Output

Using find(): Does id 143 exist? Yes Using count(): Does id 1433 exist? No

In the above example, we have used find() and count() to check if a given key exists in the unordered map.

Initially, we have used the find() method to check if the key 143 exists.

// checks if key 143 exists if (student.find(143) != student.end()) < cout else

The find() method returns an iterator pointing to the element if it exists. If the key doesn't exist, it points to the end() iterator.

Then, we have used the count() method to check if the key 1433 exists.

// checks if key 1433 exists if (student.count(1433)) < cout else

Table of Contents

  • Introduction
  • Initialize an Unordered Map
  • C++ Unordered Map Methods
  • Insert Key-Value Pairs to an Unordered Map
  • Access Values of Unordered Maps
  • Change Values of an Unordered Map
  • Remove Elements From an Unordered Map
  • Check if a Key Exists in the Unordered Map

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *