166 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			166 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
---
 | 
						||
title: Hash Tables and Hashing Functions
 | 
						||
localeTitle: Хэш-таблицы и функции хеширования
 | 
						||
---
 | 
						||
### Введение в хеширование
 | 
						||
 | 
						||
Хеширование предназначено для решения проблемы необходимости эффективного поиска или хранения элемента в коллекции.  
 | 
						||
Например, если у нас есть список из 10 000 слов английского языка, и мы хотим проверить, указано ли данное слово в списке, было бы неэффективно последовательно сравнивать слово со всеми 10 000 элементами, пока мы не найдем совпадение. Даже если список слов лексикографически отсортирован, как в словаре, вам все равно потребуется некоторое время, чтобы найти искомое слово.  
 | 
						||
Хеширование - это метод, позволяющий сделать вещи более эффективными, эффективно сужая поиск с самого начала.
 | 
						||
 | 
						||
## Что такое хеширование?
 | 
						||
 | 
						||
Хеширование означает использование некоторой функции или алгоритма для сопоставления данных объекта с некоторым репрезентативным целым значением.  
 | 
						||
Этот так называемый хеш-код (или просто хеш) можно затем использовать как способ сузить наш поиск при поиске элемента на карте.  
 | 
						||
Как правило, эти хеш-коды используются для создания индекса, в котором значение сохраняется.
 | 
						||
 | 
						||
## Как работает хэш
 | 
						||
 | 
						||
В хэш-таблицах вы храните данные в виде пар ключей и значений. Ключ, который используется для идентификации данных, задается как вход для функции хэширования. Хэш-код, который является целым числом, затем отображается на фиксированный размер, который у нас есть.
 | 
						||
 | 
						||
Хэш-таблицы должны поддерживать 3 функции.
 | 
						||
 | 
						||
*   insert (ключ, значение)
 | 
						||
*   get (ключ)
 | 
						||
*   удалить (ключ)
 | 
						||
 | 
						||
В качестве примера, чтобы помочь нам понять концепцию, предположим, что мы хотим сопоставить список строковых ключей со строковыми значениями (например, сопоставить список стран со своими столичными городами).  
 | 
						||
Итак, скажем, мы хотим сохранить данные в таблице на карте.
 | 
						||
 | 
						||
Ключ | Стоимость  
 | 
						||
\---------------- | -------------  
 | 
						||
Куба | Гавана  
 | 
						||
Англия | Лондон  
 | 
						||
Франция | Париж  
 | 
						||
Испания | Мадрид  
 | 
						||
Швейцария | Берн
 | 
						||
 | 
						||
Предположим, что наша хеш-функция состоит в том, чтобы просто взять длину строки.
 | 
						||
 | 
						||
Для простоты мы будем иметь два массива: один для наших ключей и один для значений.  
 | 
						||
Поэтому, чтобы поместить элемент в хэш-таблицу, мы вычисляем его хеш-код (в этом случае просто подсчитываем количество символов), затем кладем ключ и значение в массивы по соответствующему индексу.  
 | 
						||
Например, у Кубы есть хеш-код (длина) 4.  
 | 
						||
Таким образом, мы сохраняем Кубу в 4-й позиции в массиве ключей, а Гавана - в 4-м индексе массива значений и т. Д. И мы получаем следующее:
 | 
						||
 | 
						||
Должность | Ключ-массив | Массив значений  
 | 
						||
\--------------------- | ------------------ | --------- ------  
 | 
						||
1 | |  
 | 
						||
2 | |  
 | 
						||
3 | |  
 | 
						||
4 | Куба | Гавана  
 | 
						||
5 | Испания | Мадрид  
 | 
						||
6 | Франция | Париж  
 | 
						||
7 | Англия | Лондон  
 | 
						||
8 | |  
 | 
						||
9 | |  
 | 
						||
10 | |  
 | 
						||
11 | Швейцария | Берн
 | 
						||
 | 
						||
Теперь в этом конкретном примере все работает очень хорошо.  
 | 
						||
Наш массив должен быть достаточно большим для размещения самой длинной строки, но в этом случае это всего лишь 11 слотов.  
 | 
						||
Мы немного теряем пространство, потому что, например, в наших данных нет 1-буквенных ключей, а также ключей от 8 до 10 букв. Но в этом случае потерянное пространство тоже не так плохо. Взятие длины строки является приятным и быстрым, а также процесс нахождения значения, связанного с заданным ключом (конечно, быстрее, чем до пяти сопоставлений строк).
 | 
						||
 | 
						||
Но что нам делать, если наш набор данных имеет строку, которая имеет более 11 символов?  
 | 
						||
Что, если у нас есть еще одно слово с 5 символами «Индия» и попробуйте присвоить его индексу, используя нашу хэш-функцию. Поскольку индекс 5 уже занят, нам нужно сделать вызов, что с ним делать. Это называется столкновением.
 | 
						||
 | 
						||
Если в нашем наборе данных была строка с тысячами символов, и вы создадите массив тысяч индексов для хранения данных, это приведет к потерям пространства. Если бы наши ключи были случайными словами с английского языка, где столько слов с одинаковой длиной, использование длины как функции хэширования было бы бесполезным.
 | 
						||
 | 
						||
## Обработка столкновений
 | 
						||
 | 
						||
Для обработки столкновений используются два основных метода.
 | 
						||
 | 
						||
1.  Раздельная цепочка
 | 
						||
2.  Открытая адресация
 | 
						||
 | 
						||
#### Раздельная цепочка
 | 
						||
 | 
						||
Обработка столкновений хэшей путем отдельной цепочки использует дополнительную структуру данных, предпочтительно связанный список для динамического распределения, в ведра. В нашем примере, когда мы добавляем Индию в набор данных, она добавляется к связанному списку, хранящемуся в индексе 5, тогда наша таблица будет выглядеть так.
 | 
						||
 | 
						||
Должность | Связанные списки глав |  
 | 
						||
\--------------------- | ---------------------------- -------- |  
 | 
						||
1 | |  
 | 
						||
2 | |  
 | 
						||
3 | |  
 | 
						||
4 | [Куба-Гавана\] |  
 | 
						||
5 | \[Испания-Мадрид\] -> \[Индия-Дели\] |  
 | 
						||
6 | \[Франция-Париж\] |  
 | 
						||
7 | \[Англия-Лондон\] |  
 | 
						||
8 | |  
 | 
						||
9 | |  
 | 
						||
10 | |  
 | 
						||
11 | \[Швейцария-Берн\] |](https://en.wikipedia.org/wiki/Linear_probing)
 | 
						||
 | 
						||
Чтобы найти предмет, сначала переходим к ведру, а затем сравниваем ключи. Это популярный метод, и если используется список ссылок, хэш никогда не заполняется. Стоимость `get(k)` в среднем равна `O(n)` где n - количество ключей в ковше, общее количество ключей - N.  
 | 
						||
Проблема с отдельной цепочкой заключается в том, что структура данных может расти без ограничений.
 | 
						||
 | 
						||
#### Открытая адресация
 | 
						||
 | 
						||
Открытая адресация не вводит никакой новой структуры данных. Если происходит столкновение, мы ищем доступность в следующем месте, генерируемом алгоритмом. Open Addressing обычно используется, когда пространство для хранения является ограниченным, то есть встроенным процессором. Открытая адресация не обязательно быстрее, чем отдельная цепочка.
 | 
						||
 | 
						||
Методы открытой адресации
 | 
						||
 | 
						||
*   \[Линейное зондирование
 | 
						||
*   [Квадратичное зондирование](https://en.wikipedia.org/wiki/Quadratic_probing)
 | 
						||
*   [Двойной хеши](https://en.wikipedia.org/wiki/Double_hashing)
 | 
						||
 | 
						||
## Как использовать хэширование в вашем коде.
 | 
						||
 | 
						||
#### питон
 | 
						||
```
 | 
						||
   # Few languages like Python, Ruby come with an in-built hashing support. 
 | 
						||
   # Declaration 
 | 
						||
    my_hash_table = {} 
 | 
						||
    my_hash_table = dict() 
 | 
						||
 
 | 
						||
   # Insertion 
 | 
						||
    my_hash_table[key] = value 
 | 
						||
 
 | 
						||
   # Look up 
 | 
						||
    value = my_hash_table.get(key) # returns None if the key is not present || Deferred in python 3, available in python 2 
 | 
						||
    value = my_hash_table[key] # throws a ValueError exception if the key is not present 
 | 
						||
 
 | 
						||
    # Deletion 
 | 
						||
    del my_hash_table[key] # throws a ValueError exception if the key is not present 
 | 
						||
 
 | 
						||
    # Getting all keys and values stored in the dictionary 
 | 
						||
    keys = my_hash_table.keys() 
 | 
						||
    values = my_hash_table.values() 
 | 
						||
```
 | 
						||
 | 
						||
 [Код запуска](https://repl.it/CVtK)
 | 
						||
 | 
						||
#### Джава
 | 
						||
```
 | 
						||
    // Java doesn't include hashing by default, you have to import it from java.util library 
 | 
						||
    // Importing hashmaps 
 | 
						||
    import java.util.HashMap; 
 | 
						||
 
 | 
						||
   // Declaration 
 | 
						||
    HashMap<Integer, Integer> myHashTable = new HashMap<Integer, Integer>(); // declares an empty map. 
 | 
						||
 
 | 
						||
   // Insertion 
 | 
						||
    myHashTable.put(key, value); 
 | 
						||
 
 | 
						||
   // Deletion 
 | 
						||
    myHashtable.remove(key); 
 | 
						||
 
 | 
						||
    // Look up 
 | 
						||
    myHashTable.get(key); // returns null if the key K is not present 
 | 
						||
    myHashTable.containsKey(key); // returns a boolean value, indicating the presence of a key 
 | 
						||
 
 | 
						||
    // Number of key, value pairs in the hash table 
 | 
						||
    myHashTable.size(); 
 | 
						||
```
 | 
						||
 | 
						||
 [Код запуска](https://repl.it/CVt1)
 | 
						||
 | 
						||
## Ресурсы
 | 
						||
 | 
						||
*   Для дальнейшего чтения вы хотите попробовать эту [ссылку](http://geeksquiz.com/hashing-set-1-introduction/) , которая объясняет хеширование с использованием другого примера.
 | 
						||
*   [Хеширование через 60 секунд](https://www.youtube.com/watch?v=x05KubVlh_M) .
 | 
						||
*   [Хвост кукушки](https://www.youtube.com/watch?v=HRzg0SzFLQQ)
 | 
						||
*   [Consisten Hashing](https://www.youtube.com/watch?v=jznJKL0CrxM)
 | 
						||
*   [Цветные фильтры](https://www.youtube.com/watch?v=-SuTGoFYjZs)
 | 
						||
*   [Стратегии хеширования](https://www.youtube.com/watch?v=D65JQ0qQwZk)
 | 
						||
*   [Хеширование паролей](https://crackstation.net/hashing-security.htm)
 | 
						||
*   [Разница между Хешированием и шифрованием](http://stackoverflow.com/questions/326699/difference-between-hashing-a-password-and-encrypting-it) |