A. Значение int меньше размера хеш-таблицы. Следовательно, значение является его собственным хешем, поэтому хеш-таблицы нет. Но если бы оно было, оно было бы O (1) и все равно было бы неэффективным.
Это тот случай, когда вы можете тривиально сопоставить ключи с различными сегментами, поэтому массив кажется лучшим выбором структуры данных, чем хеш-таблица. Тем не менее, неэффективность не растет с размером таблицы.
(Вы все еще можете использовать хеш-таблицу, потому что вы не доверяете тому, чтобы целые числа оставались меньше размера таблицы по мере развития программы, вы хотите сделать код потенциально многократно используемым, когда эти отношения не сохраняются, или вы просто не хочу, чтобы люди, читающие / поддерживающие код, теряли умственные усилия на понимание и поддержание отношений).
B. Вы должны вычислить хеш значения. В этой ситуации порядок O (n) для размера ищущихся данных. Поиск может быть O (1) после того, как вы выполняете O (n) работу, но это все равно выходит на O (n) в моих глазах.
Нам необходимо различать размер ключа (например, в байтах) и размер количества ключей, хранящихся в хеш-таблице. Утверждения, что хеш-таблицы предоставляют операции O (1), означают, что операции (вставка / стирание / поиск) не имеют тенденцию к дальнейшему замедлению, так как количество ключей увеличивается с сотен до тысяч от миллионов до миллиардов (по крайней мере, если все данные доступны или обновляются в одинаково быстром хранилище, будь то ОЗУ или дисковые эффекты кэша могут вступить в игру, но даже стоимость пропуска кэша в худшем случае имеет тенденцию быть некоторой постоянной кратной в лучшем случае).
Рассмотрим телефонную книгу: у вас могут быть довольно длинные имена, но независимо от того, содержит ли книга 100 имен или 10 миллионов, средняя длина имени будет довольно последовательной, и это худший случай в истории. .
Мировой рекорд Гиннеса по самому длинному имени, которое когда-либо использовалось кем-либо, был установлен Адольфом Блейном Чарльзом Дэвидом Эрлом Фредериком Джеральдом Хьюбертом Ирвином Джоном Кеннетом Ллойдом Мартином Неро Оливером Полом Куинси Рэндольфом Шерманом Томасом Ункасом Виктором Уильямом Ксерксом Янси Вольфешлегельштайнхаузенбергердорф, старший
... wc
говорит мне, что это 215 символов - это не жесткий верхний предел длины ключа, но нам не нужно беспокоиться о том, что массово больше.
Это верно для большинства реальных хеш-таблиц: средняя длина ключа не имеет тенденцию к увеличению с количеством используемых ключей. Существуют исключения, например, подпрограмма создания ключа может возвращать строки с встраиваемыми целыми числами, но даже в этом случае каждый раз, когда вы увеличиваете количество ключей на порядок, вы увеличиваете длину ключа только на 1 символ: это несущественно.
Также возможно создать хэш из объема ключевых данных фиксированного размера. Например, Microsoft Visual C ++ поставляется с реализацией стандартной библиотеки std::hash<std::string>
, которая создает хэш, включающий всего десять байтов, равномерно распределенных по строке, поэтому, если строки изменяются только при других индексах, вы получаете коллизии (и, следовательно, на практике не O ( 1) поведения на стороне поиска после столкновения), но время создания хэша имеет жесткую верхнюю границу.
И если у вас нет идеального хеша или большой хеш-таблицы, вероятно, в каждом ведре несколько предметов. Так или иначе, в какой-то момент он превращается в небольшой линейный поиск.
В целом верно, но удивительная вещь в хеш-таблицах состоит в том, что количество ключей, посещенных во время этих "небольших линейных поисков", - для отдельного сцепления подход к коллизиям - функция хеш-таблицы коэффициент загрузки (соотношение ключей и ведер).
Например, при коэффициенте загрузки 1,0 средняя длина этих линейных поисков в среднем составляет ~ 1,58 независимо от количества ключей (см. мой ответ здесь ). Для закрытого хеширования это немного сложнее, но не намного хуже, когда коэффициент загрузки не слишком высок.
Это технически верно, потому что хеш-функция не обязана использовать всю информацию в ключе и поэтому может иметь постоянное время, а также потому, что достаточно большая таблица может привести к коллизиям почти до постоянного времени.
Этот вид упускает суть. Любой тип ассоциативной структуры данных в конечном итоге должен иногда выполнять операции с каждой частью ключа (неравенство может иногда определяться только из части ключа, но равенство обычно требует рассмотрения каждого бита). Как минимум, он может хешировать ключ один раз и сохранять хеш-значение, и если он использует достаточно сильную хеш-функцию - например, 64-битный MD5 - он может практически игнорировать даже возможность хеширования двух ключей к одному и тому же значению (компания, в которой я работал, сделала именно это для распределенной базы данных: время генерации хеша было все же незначительным по сравнению с сетевыми передачами в глобальной сети). Таким образом, нет смысла беспокоиться о затратах на обработку ключа: это присуще хранению ключей независимо от структуры данных, и, как сказано выше, в среднем не ухудшается при наличии большего количества ключей.
Что касается достаточно больших хеш-таблиц, приводящих к коллизиям, то здесь тоже не хватает смысла. Для отдельной цепочки у вас все равно будет постоянная средняя длина цепи столкновений при любом данном коэффициенте нагрузки - она выше, когда коэффициент нагрузки выше, и эта зависимость нелинейная. Пользователь SO Ганс комментирует мой ответ, также связанный выше , что:
средняя длина ковша, обусловленная непустыми ковшами, является лучшим показателем эффективности. Это / (1-e ^ {- a}) [где a - коэффициент загрузки, e = 2,71828 ...]
Таким образом, коэффициент загрузки в одиночку определяет среднее количество сталкивающихся ключей, которые вы должны искать во время операций вставки / удаления / поиска. Для раздельной цепочки он не просто становится постоянным при низком коэффициенте нагрузки - он всегда постоянный. Однако для открытой адресации ваше утверждение имеет некоторую обоснованность: некоторые сталкивающиеся элементы перенаправляются в альтернативные сегменты и могут затем мешать операциям с другими ключами, поэтому при более высоких коэффициентах нагрузки (особенно> 0,8 или 0,9) длина цепочки столкновений становится значительно хуже.
Это верно на практике, потому что со временем это работает, пока хеш-функция и размер таблицы выбираются так, чтобы минимизировать коллизии, даже если это часто означает, что хеш-функция с постоянным временем не используется.
Что ж, размер таблицы должен приводить к нормальному коэффициенту загрузки, учитывая выбор хеширования или отдельного сцепления, но также если хеш-функция немного слабая и ключи не очень случайные, с простым числом сегментов часто помогает уменьшить коллизии (hash-value % table-size
затем оборачивается так, что изменения только одного или двух старших разрядов в хеш-значении по-прежнему разрешаются, чтобы сегменты распределялись псевдослучайно по различным частям хеш-таблицы).