0 / 0 / 0
Регистрация: 05.11.2015
Сообщений: 33
|
|
1 | |
Математическая сложность работы с unordered_map (unordered_set)13.04.2019, 18:08. Просмотров 2586. Ответов 16
Здравствуйте.
Сравниваю сложность вставки/поиска элемента в упорядоченных map/set и неупорядоченных unoredered_map/unordered_set. Везде пишется, что при работе с неупорядоченным массивом операции поиска и вставки O(1) в общем случае, а в упорядоченном - O(log n). И преимущество неупорядоченных массивов сводится к использованию таблицы хешей. Но мне не понятно, почему, например, при поиске, сравнение в контейнере map<string, string> строчек ключа будет происходить НЕ так же, как сравнение хешей контейнера unordered_map<stringm string>. Ведь сами значения хешей - это тоже текстовая строка, пусть и определенного типа. Я понимаю, когда мы в массиве или векторе обращаемся по индексу - там идет прямое обращение к памяти по смещению от начала. Но если, например, есть контейнер unordered_map<string, string>, то почему в нем поиск элемента будет за время O(1), ведь все равно, если нам нужно извлечь пару по ключу, например, "qwe", то мы должны посмотреть все хеши этого контейнера, пока не найдем тот, который будет равен хешу строки "qwe"?
0
|
|
13.04.2019, 18:08 | |
Сложность операции в unordered_map Контейнер unordered_map<string, unordered_map<string,int>> Как вычислять сложность алгоритма, или найти асимптотическую сложность любой программки? |
|
13881 / 7417 / 1759
Регистрация: 30.01.2014
Сообщений: 12,409
|
|
13.04.2019, 18:36 | 2 |
Это нужно будет делать только при возникновении коллизий, которые хорошая хеш-таблица старается минимизировать.
Сами значения хешей - это таки обычно целые числа. Тут так и есть, в среднем случае. По хешу вычисляется индекс и дальше как с обычным массивом. Почитайте где-нибудь про устройство хеш-таблиц, чтобы ваши вопросы были более предметными.
2
|
Комп_Оратор)
![]() |
|
13.04.2019, 18:58 | 3 |
В общем случае нет никакого сравнения. Вычисляется индекс. Другой вопрос, что для вычисления хеш-ключа минимально конфликтующего (минимизирующего вероятность коллизий как указал уважаемый DrOffset, ) нужно задействовать более сложную и медленную хеш-функцию. Хеширование строк, - тема интересная само по себе.
1
|
0 / 0 / 0
Регистрация: 05.11.2015
Сообщений: 33
|
||||||
13.04.2019, 20:23 [ТС] | 4 | |||||
А как по хешу вычисляется индекс? Разве нам не надо пройтись по всем хешам, чтобы найти нужный?
Добавлено через 5 минут Например, есть 5 пар в unordered_map:
Случай с коллизиями я не беру в рассчет - там в целом ясно, что происходит.
0
|
Комп_Оратор)
![]() |
|
13.04.2019, 20:30 | 5 |
Не надо.
Добавлено через 2 минуты Хэш - в простейшем случае это индекс. Или в простой реализации делается целочисленное деление на размер массива (там под капотом массив списков (корзинок/цепочек)). То есть, доступ прямой. В этом и скорость. Проблемы возникают с коллизиями и скоростью хеширования и перехеширования.
0
|
0 / 0 / 0
Регистрация: 05.11.2015
Сообщений: 33
|
|
13.04.2019, 20:35 [ТС] | 6 |
Т.е. я правильно понимаю, что хеш для пары {"e", 3}, а именно для ключа "e" будет 3 (или 03, 003 - как-то так)? Или все же хеш - это результат криптографической функции, который возвращает случайное n-битное значение, зависящее целиком от входного значения?
0
|
Комп_Оратор)
![]() |
|
13.04.2019, 20:44 | 7 |
Вроде того. Если бы использовался тип char то можно было бы код символа использовать как индекс в массиве из 127. Тогда и вычислять ничего не нужно. И если ключи размажутся (хешинг - размазывание) равномерно то ок. А если нужны только строчные английские то размер массива - 26 а пересчёт кода в индекс и будет в данном разе хешфункцией. Очень простой. То есть, ни чего случайного тут нет и быть не может. Ведь "где-то там" положить, это "где-то там" и искать.
0
|
0 / 0 / 0
Регистрация: 05.11.2015
Сообщений: 33
|
|
13.04.2019, 20:50 [ТС] | 8 |
Хорошо, внутри контейнера для пары {"e", 3} хеш-значение будет соответствовать порядковому номеру и составлять, например, 03 - ок. А когда я пытаюсь обратиться к контейнеру с целью поиска значений по ключу строки "e". Как программа поймет, что входную строку "e" надо преобразовать в хеш-значение число 03?
0
|
Комп_Оратор)
![]() |
|
13.04.2019, 20:52 | 9 |
Не ок. Оно соответствует значению строки "e". И когда хеш-мапа пишет и когда читает она находит индекс по значению. Не попадёт в 2 разных места. Перечитайте предыдущий пост. В моём примере, целочисленное значение ключа используется как перечислитель индексов и да, тут всё подряд. Но это простой и частный случай.
под топиком - внизу экрана есть ссылки - пройдите и почитайте.
0
|
0 / 0 / 0
Регистрация: 05.11.2015
Сообщений: 33
|
|
13.04.2019, 21:00 [ТС] | 10 |
Теперь я совсем запутался, что же является результатом работы хеш-функции для ключа контейнера? Как выглядит хеш для строки? Или где можно посмотреть пример реализации хеш-функции?
0
|
13881 / 7417 / 1759
Регистрация: 30.01.2014
Сообщений: 12,409
|
||||||
13.04.2019, 21:04 | 11 | |||||
Нет.
Нет. 3 - это, очевидно, значение. А хеш для "e", это hash("e"), где hash - это некая функция хеширования. Например, она может быть такой:
Дальше значение, полученное после хеширования, трансформируется в индекс для одной из корзин (bucket) контейнера, которая по сути массив и есть. Непосредственное сравнение ключей производится только если одному хешу соответствует несколько элементов, в этом случае сложность превращается в O(n), где n количество коллизий. Добавлено через 2 минуты Как число. Вопроса этого не видел, когда отвечал, но пример есть выше.
2
|
0 / 0 / 0
Регистрация: 05.11.2015
Сообщений: 33
|
|
13.04.2019, 21:11 [ТС] | 12 |
Про коллизии понятно, там сложность О(n).
Не понятно вот это Вот есть у нас значение после хеширования (видимо, 4-х байтное?), которое мы трансформируем в индекс, по которому находится искомая пара. Но как происходит преобразование результата хеширования в индекс?
0
|
13881 / 7417 / 1759
Регистрация: 30.01.2014
Сообщений: 12,409
|
|
13.04.2019, 21:34 | 13 |
В каноническом случае - хеш - это и есть индекс. Но конкретно в unordered_map - это не так. Значение хеша (продукт функции, наподобие представленной выше) используется как ключ, к которому уже применяется один из методов:
* Метод остатка от деления. * Метод умножения * Метод исключающего ИЛИ И др. Какой конкретно применяется - зависит от реализации, нужно смотреть исходники. Подробнее об этих методах я вам советую прочитать, например у Кнута или Кормена.
1
|
0 / 0 / 0
Регистрация: 05.11.2015
Сообщений: 33
|
|
13.04.2019, 21:49 [ТС] | 14 |
Тогда, возвращаясь к сложности, если нам надо найти в контейнере unordered_map пару {"qwe", 123} по ключу "qwe". Тогда мы вычисляем хеш от строки "qwe", а дальше нам надо обратиться точно по индексу, где в контейнере лежит эта пара.
Но ведь это не значение int от 0 до 4, когда можно точечно обратиться как в массиве, это список из хеш-значений, как нам найти нужное хеш-значение за O(1)? Мы ведь не знаем, где именно оно располагается в списке хеш-значений среди остальных. Добавлено через 5 минут В википедии https://ru.wikipedia.org/wiki/... 1%86%D0%B0:
0
|
13881 / 7417 / 1759
Регистрация: 30.01.2014
Сообщений: 12,409
|
||||||
13.04.2019, 21:57 | 15 | |||||
![]() Решение
dexterov,
Очень приблизительно и крайне упрощенно:
Количество Buckets в unordered_map - динамическое. Заканчивается место в существующих - выделяется еще один.
2
|
0 / 0 / 0
Регистрация: 05.11.2015
Сообщений: 33
|
|
13.04.2019, 22:14 [ТС] | 16 |
Да, теперь понятно, получается n-байтный хеш преобразуется в пару маленьких чисел для индексации, что, по идее, сильно увеличивает вероятность возникновения коллизий. При превышении размера таблицы в процессе добавления новых элементов, видимо, все индексы каждый раз перенастраиваются?
0
|
13881 / 7417 / 1759
Регистрация: 30.01.2014
Сообщений: 12,409
|
|
13.04.2019, 22:32 | 17 |
dexterov, в unordered_map все несколько сложнее устроено - там другой метод используется. Предлагаю, если интересно, посмотреть самостоятельно. Я лишь передал общий принцип.
1
|
13.04.2019, 22:32 | |
Заказываю контрольные, курсовые, дипломные и любые другие студенческие работы здесь.
Переделать код для unordered_set Работа с unordered_map Hash_map unordered_map
Доступ к элементам unordered_map Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |