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)
							 |