Хэш: Как это работает внутри страны?
Это может звучать как очень неопределенный вопрос, но это не так. Я просмотрел описание Hash Function на wiki, но это не очень полезно понять.
Я ищу простые ответы на довольно сложные темы, такие как Hashing. Вот мои вопросы:
- Что мы понимаем под хешированием? Как это работает внутри страны?
- Какой алгоритм он выполняет?
- В чем разница между
HashMap
, HashTable
и HashList
?
- Что мы подразумеваем под "Constant Time Complexity" и почему различная реализация хэша дает постоянную работу времени?
- И наконец, почему в большинстве интервью задаются вопросы
Hash
и LinkedList
, есть ли какая-то конкретная логика для него от тестирования знаний собеседника?
Я знаю, что мой список вопросов большой, но я был бы очень признателен, если бы смог получить четкие ответы на эти вопросы, поскольку я действительно хочу понять эту тему.
Ответы
Ответ 1
-
Здесь - хорошее объяснение хэширования. Например, вы хотите сохранить строку "Rachel" , вы применяете хеш-функцию к этой строке, чтобы получить ячейку памяти. myHashFunction(key: "Rachel" value: "Rachel") --> 10
. Функция может возвращать 10 для ввода "Rachel" , поэтому, если у вас есть массив размером 100, вы храните "Rachel" в индексе 10. Если вы хотите получить этот элемент, вы просто вызываете GetmyHashFunction("Rachel")
, и он вернется 10. Обратите внимание, что для этого примера ключ - "Rachel" , а значение "Rachel" , но вы можете использовать другое значение для этого ключа, например, дату рождения или объект. Ваша хэш-функция может возвращать одну и ту же ячейку памяти для двух разных входов, в этом случае у вас будет столкновение с вами, если вы реализуете свою собственную хеш-таблицу, о которой вы должны позаботиться, возможно, используя связанный список или другие методы.
-
Здесь используются некоторые общие хеш-функции. Хорошая хэш-функция удовлетворяет тому, что: каждый ключ одинаково вероятен для хэша в любом из n слотов памяти независимо от того, где хэширует любой другой ключ. Один из методов называется методом деления. Наведем ключ k в один из n слотов, взяв остаток k, деленный на n. h(k) = k mod n
. Например, если ваш размер массива n = 100
, а ваш ключ - целое число k = 15
, то h(k) = 10
.
-
Hashtable синхронизируется, а Hashmap - нет.
Hashmap позволяет использовать нулевые значения в качестве ключа, но Hashtable этого не делает.
-
Цель хэш-таблицы - иметь постоянную временную сложность O (c) при добавлении и получении элементов. В связанном списке размера N, если вы хотите получить последний элемент, вам нужно пройти весь список до тех пор, пока вы его не получите, так что сложность O (N). С хэш-таблицей, если вы хотите получить элемент, вы просто передаете ключ, и хеш-функция вернет вам нужный элемент. Если хеш-функция хорошо реализована, она будет находиться в постоянном времени. O (c) Это означает, что вам не нужно перемещать все элементы, хранящиеся в хеш-таблице. Вы получите элемент "мгновенно".
-
Из-за того, что ученый-программист/разработчик должен знать о структурах и сложности данных =)
Ответ 2
- Хеширование означает создание уникального числа, которое представляет собой значение (надеюсь).
- Различные типы значений (
Integer
, String
и т.д.) используют разные алгоритмы для вычисления хэш-кода.
- HashMap и HashTable - карты; они представляют собой набор ключей unqiue, каждый из которых связан со значением.
Java не имеет класса HashList. A Hash Set представляет собой набор уникальных значений.
- Получение элемента из хеш-таблицы является постоянным временем в отношении размера таблицы.
Вычисление хэша не обязательно постоянное время в отношении хэширования значения.
Например, вычисление хеша строки включает итерацию строки и не является постоянным временем относительно размера строки.
- Это вещи, которые люди должны знать.
Ответ 3
-
Хеширование преобразует данный объект (в java terms - объект) к некоторому числу (или последовательности). Хеш-функция не обратима - т.е. Вы не можете получить исходный объект из хэша. Внутренне он реализован (для java.lang.Object
путем получения некоторого адреса памяти с помощью JVM.
-
Объект адреса JVM не имеет значения. Каждый класс может переопределить метод hashCode()
своим собственным алгоритмом. Модренные Java IDE позволяют генерировать хорошие методы hashCode.
-
Hashtable и hashmap - это одно и то же. Они представляют собой пары ключей, где ключи хэшируются. Списки хэшей и хешеты не сохраняют значения - только ключи.
-
Постоянное время означает, что независимо от количества записей в хэш-таблице (или любой другой коллекции) количество операций, необходимых для поиска данного объекта по его ключу, является постоянным. То есть - 1 или близко к 1
-
Это основной компьютерно-научный материал, и предполагается, что все знакомы с ним. Я думаю, Google указал, что хэш-таблица является самой важной структурой данных в информатике.
Ответ 4
Я попытаюсь дать простые объяснения хэширования и его цели.
Сначала рассмотрим простой список. Каждая операция (вставить, найти, удалить) в таком списке будет иметь сложность O (n), что означает, что вам необходимо проанализировать весь список (или половину его в среднем) для выполнения такой операции.
Хешинг - очень простой и эффективный способ ускорить его: подумайте, что мы разделили весь список в наборе небольших списков. Элементы в одном таком небольшом списке будут иметь что-то общее, и это может быть выведено из ключа. Например, имея список имен, мы могли бы использовать первую букву как качество, которое будет выбирать, в каком маленьком списке искать. Таким образом, разбив данные на первую букву ключа, мы получили простой хеш, который сможет разбить весь список в ~ 30 меньших списков, так что каждая операция будет принимать O (n)/30 раз,
Однако мы могли заметить, что результаты не настолько совершенны. Во-первых, их всего 30, и мы не можем их изменить. Во-вторых, некоторые буквы используются чаще, чем другие, так что набор с Y
или Z
будет намного меньше, чем набор с A
. Для достижения лучших результатов лучше найти способ разделения элементов в наборах примерно такого же размера. Как мы можем это решить? Здесь вы используете хэш-функции. Это такая функция, которая способна создавать произвольное количество разделов с примерно одинаковым количеством элементов в каждом. В нашем примере с именами мы могли бы использовать что-то вроде
int hash(const char* str){
int rez = 0;
for (int i = 0; i < strlen(str); i++)
rez = rez * 37 + str[i];
return rez % NUMBER_OF_PARTITIONS;
};
Это обеспечило бы довольно равномерное распределение и настраиваемое количество наборов (также называемых ковши).
Ответ 5
Рассмотрим задачу поиска массива для заданного значения. Если массив не отсортирован, поиск может потребовать проверки всех элементов массива. Если массив отсортирован, мы можем использовать двоичный поиск и, следовательно, уменьшить сложность выполнения в худшем случае до O (log n). Мы могли бы искать еще быстрее, если мы заранее знаем индекс, в котором это значение находится в массиве. Предположим, что у нас есть эта магическая функция, которая сообщит нам индекс для данного значения. С помощью этой магической функции наш поиск сводится только к одному зонду, что дает нам постоянное время выполнения O (1). Такая функция называется хэш-функцией. Хеш-функция - это функция, которая при задании ключа генерирует адрес в таблице.
Ответ 6
Что мы имеем в виду под Hashing, как он работает внутри?
Хеширование - это преобразование строкового более короткого значения фиксированной длины или ключа, представляющего исходную строку. Это не индексирование. Сердцем хэширования является хэш-таблица. Он содержит массив элементов. Таблицы хэшей содержат индекс из ключа элемента данных и используют этот индекс для размещения данных в массиве.
Какой алгоритм он выполняет?
В простых словах большинство алгоритмов Hash работают над логикой "index = f (key, arrayLength)"
Наконец, почему в большинстве интервью вопросы Хеш и LinkedList спросил, есть ли какая-то конкретная логика для это от тестирования знания?
О том, насколько вы хороши в логических рассуждениях. Это самая важная структура данных, которую знают все программисты.