Отказ от ответственности: я знаю, что есть похожие вопросы уже здесь и на Stackoverflow. Но они все о столкновениях, о которых я не прошу.
Мой вопрос: почему столкновительный меньше LookUp O(1)
в первую очередь?
Давайте предположим, что у меня есть эта хеш-таблица:
Hash Content
-------------
ghdjg Data1
hgdzs Data2
eruit Data3
xcnvb Data4
mkwer Data5
rtzww Data6
Теперь я ищу ключ, k
который h(k)
дает хэш-функция h(k) = mkwer
. Но как поиск "узнает", что хеш mkwer
находится в позиции 5? Почему не нужно пролистывать все клавиши, O(n)
чтобы найти его? Хеши не могут быть какими-то реальными аппаратными адресами, потому что я потерял бы способность перемещать данные. И, насколько я знаю, хеш-таблица не сортируется по хешам (даже если бы это было, поиск также занял бы O(log n)
)?
Как знание хеша помогает найти правильное место в таблице?
Хеш-функция вычисляет позицию массива по заданной строке . Если это идеальный хеш, это означает, что коллизий точно не будет, наиболее вероятный массив, по крайней мере, в два раза больше, чем количество элементов.
Например, я дам очень плохой хэш для букв, просто чтобы проиллюстрировать механизм:х = 0 ;
х = х м о д52
0) 1) для каждого символа в строке принять значение ascii, вычесть 'a', если это строчные буквы, вычесть 'A', если прописные, добавить значение к x. 2) результирующее число, например 15 - индекс массива. х = х м о д 52
Этот очень простой хеш (ограниченный и склонный к коллизиям) отличается от других хешей механизмом хеширования, не учитывает данный ввод. В более продвинутой схеме хэш - это большее число, настроенное на количество элементов. Идеальный хеш генерируется для всех входных данных, чтобы гарантировать отсутствие коллизий.
Это потому что вычисление хеша из строки зависит от того, насколько сложна вычисляемая функция, но не зависит от количества элементов.O ( 1 )
В случае идеального хэша, когда добавляются элементы, пересчитывается, более простой случай с коллизиями, когда нагрузка на массив велика, размер массива увеличивается, функция принимает больший модуль вывода, а элементы перемещаются на новые места.ч ( к )
Массив - это непрерывный фрагмент памяти, чтобы получить элемент, вы берете адрес первого элемента (начало массива), а затем добавляете к этому адресу чтобы у вас была явная ячейка памяти.н * ( сек я г е о е е л е м е н т )н - т ч n ∗ ( s i zе о ее л е м е н т )
источник
Чтобы расширить ответ Дэвида Ричерби, термин « хэш-функция » немного перегружен. Часто, когда мы говорим о хэш-функции, мы думаем о MD5, SHA-1 или о чем-то вроде
.hashCode()
метода Java , который превращает некоторый ввод в одно число. Однако домен этого числа (т. Е. Является максимальным значением) вряд ли будет иметь тот же размер, что и хеш-таблица, в которой вы пытаетесь сохранить данные. (MD5 составляет 16 байт, SHA-1 составляет 20 байт и.hashCode()
представляет собойint
- 4 байт).Итак, ваш вопрос касается следующего шага - когда у нас есть хеш-функция, которая может отображать произвольные входные данные в числа, как мы можем поместить их в структуру данных определенного размера? С другой функцией, также называемой «хэш-функцией»!
Тривиальный пример такой функции - по модулю ; Вы можете легко сопоставить число произвольного размера с определенным индексом в массиве по модулю. Это вводится в CLRS как «метод деления»:
Таким образом, модуль не является отличной хеш-функцией, поскольку ограничивает размеры, которые мы можем безопасно использовать для нашей базовой структуры данных. В следующем разделе представлен чуть более сложный «метод умножения», который также использует модуль по модулю, но имеет преимущество, поскольку «значение не является критическим». Однако он лучше всего работает с некоторыми предварительными знаниями о «характеристиках хешируемых данных» - то, чего мы часто не знаем.m
Java
HashMap
использует модифицированную версию метода деления, которая выполняет этап предварительной обработки для учета слабых.hashCode()
реализаций, чтобы он мог использовать массивы степени двойки. Вы можете точно увидеть, что происходит в.getEntry()
методе (мои комментарии):Java 8 принесла переписывание,
HashMap
которое еще быстрее, но немного сложнее для чтения. Однако он использует тот же общий принцип для поиска по индексу.источник