Python

Устройство хэш-функций (...)

Ознакомился с чисто теоретической частью предмета. Насколько понял суть там такова...
Для того чтобы организовать быстрый доступ к значению массива по ключу за время O(1) нужно ключ побайтово преобразовать в индекс массива и чтобы он не выходил за пределы массива.
Хэширование ведь именно в этом заключается?
Если да, то с этим легко справился:
 mass = [None] * 15 

def to_hash(x):
res = [bin(ord(i)) for i in x]
res = ''.join([i[2:] for i in res])
x = int(res, 2) % len(mass)
return x


print(to_hash('Василий')) # 1
print(to_hash('Прокопий')) # 13
print(to_hash('Виниамин')) # 14
print(to_hash('Евстигней')) # 11
Но дальнейшая задача сложнее... Нужно избегать возникновения "коллизий", то есть повторяющихся индексов. Например George и Joe дадут одинаковый хэш 1.
Для этого существует с десяток математических формул.
Но вообще есть вот такая функция. Он бегает по массиву по кругу и выводит элементы, соответственно будет показывать какой индекс занят, какой свободен (содержит None).
Её тут можно привинтить к решению этого нелегкого дела? Или там всё только строго по давно придуманным для этого формулам?
Насколько помню там и есть подобный алгоритм. Индекс занят - увеличиваем хэш на 1 и двигаемся дальше пока не найдем None
 mass = [None] * 15 
head = 0

def get_head():
global head
head = (head + 1) % len(mass)
return mass[head - 1]

for i in range(len(mass)):
print(get_head())
Прочитай про парадокс близнецов. Коллизии будут всегда - и они практически гарантировано начнутся, когда объём данных дойдёт до квадратного корня из размера массива.

Да, описанная тобой схема - один из вариантов решения. Сначала хэш-функцией вычисляем место в массиве, а потом от этого места ищем нужный элемент / пустое место. Но не обязательно с постоянным шагом: например, есть вариант, когда каждый следующий шаг больше предыдущего.

Другая популярная схема - делаем массив списков. И элемент с хэшем q просто добавляем в список q.

Ты немного переборщил с хэш-функцией:
 def to_hash(x):
return sum(ord(i) for i in x) % len(mass)
Достаточно просто просуммировать коды символов и взять остаток.
И коллизий будет меньше, если размер массива - простое число.
Bahadir Karayev
Bahadir Karayev
68 378
Лучший ответ
А никак не избегать. Чисто статистическая вещь. Если у тебя есть массив на 1000 элементов, вот и делай так, чтобы хеши давали примерно 1000 разных значений, можно больше. Фокус в том, что проверить найденное значение на совпадение - все равно гораздо быстрее, чем заниматься его поиском перебором.
Серик Ибраев
Серик Ибраев
82 097
 mass = [None] * 15 

def to_hash(x):
res = [bin(ord(i)) for i in x]
res = ''.join([i[2:] for i in res])
x = int(res, 2) % len(mass)
return x

def insert(key, value):
index = to_hash(key)
while mass[index] is not None:
index = (index + 1) % len(mass)
mass[index] = value

insert('Василий', 'value1')
insert('Прокопий', 'value2')
insert('Виниамин', 'value3')
insert('Евстигней', 'value4')
print(mass)
Пашка Попков
Пашка Попков
25 860