Алла: А что будет, если для разных объектов хеш-функция выдаст одно и то же значение? Они будут храниться в одной ячейке хеш-таблицы?
Тимофей: Ситуация, когда хеш-функция выдаёт для разных входных данных одно и то же значение, называется коллизией.
В реализации хеш-таблицы должна быть заложена логика разрешения коллизий. Есть несколько вариантов, как с коллизиями бороться. О них я расскажу чуть позже.
Ключи в хеш-таблице в общем случае не упорядочены. Например, сосиска лексикографически больше колбасы, но в хеш-таблице может быть расположена в ячейке с меньшим индексом.
Значениями в хеш-таблице могут быть данные разных типов: массивы, строки, числа, кортежи, и другие структуры данных. Значением может быть даже другая хеш-таблица.
Представьте, что у вас три сайта, и вы хотите собирать статистику по посещениям всех страниц на каждом из них.
В этом случае удобно использовать такую хеш-таблицу:
Скопировать кодPYTHON
pages_visit_stats = {
'site1':{
'page1': 12,
'page2': 22
},
'site2': {
'page1': 2,
'page2': 0
},
'site3': {
'page1': 2,
'page2': 0,
'page3': 10,
}
}
Алла: Я что-то не понимаю. В прошлых примерах на вход подавался объект, от него вычислялся хеш. После этого мы знали номер ячейки массива, в которой должен лежать этот объект. Теперь в ячейках массива лежат другие таблицы?
Тимофей: Да. Мы вычисляем значение хеш-функции от ключа. Например, от 'site1'. Допустим, получили 2. Идём в ячейку с номером 2. Эта ячейка соответствует другой хеш-таблице. Мы спрашиваем: где можно найти значение для 'page1'? Хеш-функция нам говорит, что в ячейке с номером 12. Этот номер относится уже к другому массиву. Таким образом мы узнаем, что элемент pages_visit_stats['site1']['page1'] имеет значение 12.
Это не самый сложный пример того, какой структурой данных могут быть значения в хеш-таблице.
А вот с ключами всё не так просто.
Любой неизменяемый объект может использоваться в качестве ключа, а изменяемые объекты, такие как множество, массив, или другая хеш-таблица, не могут.
Скопировать кодPYTHON
unexisting_dict = {
[1, 2, 3]: 'key_list',
{'a', 'b'}: 'key_set',
{'1': 'one'}: 'key_dict'
}
Кстати, изменяемые объекты также не могут быть элементами множества.
Скопировать кодPYTHON
unexisting_set = set([1, 2, 3])
А любые неизменяемые — могут.
Алла: А почему так?
Тимофей: Представь, что у тебя хеш-таблица, ключ в которой — массив чисел. Ты записала
пару: [1, 2]: value в свою структуру данных. Для этого от ключа был вычислен хеш и данные помещены в соответствующую ячейку.
Потом ты изменила массив. После этого потребовалось найти значение по ключу. Для этого снова было вычислено значение хеш-функции. Но ключ изменился, поэтому функция в общем случае выдаст другое значение. Осуществить поиск не получится. С удалением возникнет такая же проблема.
Алла: А почему функция выдаст другое значение в общем случае, а не в любом?
Гоша: Ну Тимофей же сказал, что иногда разным данным присваивается один и тот же хеш.
Алла: Ах, ну да, коллизии. Тимофей, расскажешь про это подробнее?
Тимофей: Да, конечно. Но сначала я приведу примеры хеш-функций и расскажу, какими свойствами должна обладать хорошая хеш-функция.