HTML Diff
1 added 1 removed
Original 2026-01-01
Modified 2026-02-26
1 <p>Ассоциативный массив - абстрактный тип данных, с помощью которого хранятся пары "ключ-значение". В разных языках ему соответствуют разные типы данных. В Python - это Dictionary, в других языках:</p>
1 <p>Ассоциативный массив - абстрактный тип данных, с помощью которого хранятся пары "ключ-значение". В разных языках ему соответствуют разные типы данных. В Python - это Dictionary, в других языках:</p>
2 <ul><li>Ruby - Hash</li>
2 <ul><li>Ruby - Hash</li>
3 <li>Lua - Table</li>
3 <li>Lua - Table</li>
4 <li>JavaScript - Object</li>
4 <li>JavaScript - Object</li>
5 <li>Elixir/Java - Map</li>
5 <li>Elixir/Java - Map</li>
6 </ul><p>Ассоциативные массивы популярны в прикладном программировании. С их помощью удобно представлять составные данные, содержащие множество различных параметров.</p>
6 </ul><p>Ассоциативные массивы популярны в прикладном программировании. С их помощью удобно представлять составные данные, содержащие множество различных параметров.</p>
7 <p>В обычном индексированном массиве значения расположены по индексам, а значит его можно положить в память "как есть". С ассоциативными массивами все работает по-другому. У них нет индексов, которые бы могли определить порядок - значит, и нет простого способа добраться до значений.</p>
7 <p>В обычном индексированном массиве значения расположены по индексам, а значит его можно положить в память "как есть". С ассоциативными массивами все работает по-другому. У них нет индексов, которые бы могли определить порядок - значит, и нет простого способа добраться до значений.</p>
8 <p>Для реализации ассоциативных массивов часто используют специальную структуру данных -<strong>хеш-таблицу</strong>.</p>
8 <p>Для реализации ассоциативных массивов часто используют специальную структуру данных -<strong>хеш-таблицу</strong>.</p>
9 <p>Хеш-таблица позволяет организовать данные ассоциативного массива удобным для хранения способом. Для этого хеш-таблица использует индексированный массив и функцию для хеширования ключей. При этом хеш-таблица - это не просто способ размещать данные в памяти, она включает в себя логику.</p>
9 <p>Хеш-таблица позволяет организовать данные ассоциативного массива удобным для хранения способом. Для этого хеш-таблица использует индексированный массив и функцию для хеширования ключей. При этом хеш-таблица - это не просто способ размещать данные в памяти, она включает в себя логику.</p>
10 <p>В этом уроке мы подробнее поговорим о хеш-таблицах и узнаем, как ассоциативные массивы устроены внутри. Вы поймете, сколько разных процессов происходит в программе, когда мы выполняем подобный простой код:</p>
10 <p>В этом уроке мы подробнее поговорим о хеш-таблицах и узнаем, как ассоциативные массивы устроены внутри. Вы поймете, сколько разных процессов происходит в программе, когда мы выполняем подобный простой код:</p>
11 <h2>Что такое хеширование</h2>
11 <h2>Что такое хеширование</h2>
12 <p>Любая операция внутри хеш-таблицы начинается с того, что ключ каким-то образом преобразуется в индекс обычного массива. Для получения индекса из ключа нужно выполнить два действия:</p>
12 <p>Любая операция внутри хеш-таблицы начинается с того, что ключ каким-то образом преобразуется в индекс обычного массива. Для получения индекса из ключа нужно выполнить два действия:</p>
13 <ul><li>Найти хеш, то есть хешировать ключ</li>
13 <ul><li>Найти хеш, то есть хешировать ключ</li>
14 <li>Привести ключ к индексу - например, через остаток от деления</li>
14 <li>Привести ключ к индексу - например, через остаток от деления</li>
15 </ul><p><strong>Хеширование</strong>- операция, которая преобразует любые входные данные в строку или число фиксированной длины. Функция, реализующая алгоритм преобразования, называется<strong>"хеш-функцией"</strong>. При этом результат хеширования называют<strong>"хешем"</strong>или<strong>"хеш-суммой"</strong>.</p>
15 </ul><p><strong>Хеширование</strong>- операция, которая преобразует любые входные данные в строку или число фиксированной длины. Функция, реализующая алгоритм преобразования, называется<strong>"хеш-функцией"</strong>. При этом результат хеширования называют<strong>"хешем"</strong>или<strong>"хеш-суммой"</strong>.</p>
16 <p>Наиболее известны CRC32, MD5, SHA и много других типов хеширования:</p>
16 <p>Наиболее известны CRC32, MD5, SHA и много других типов хеширования:</p>
17 <p>С хешированием мы встречаемся в разработке часто. Например, идентификатор коммита в git 0481e0692e2501192d67d7da506c6e70ba41e913 - это хеш, полученный в результате хеширования данных коммита.</p>
17 <p>С хешированием мы встречаемся в разработке часто. Например, идентификатор коммита в git 0481e0692e2501192d67d7da506c6e70ba41e913 - это хеш, полученный в результате хеширования данных коммита.</p>
18 <p>При записи в хеш-таблицу сначала нужно получить хеш. Затем его можно преобразовать в индекс массива - например, вычислить остаток от деления:</p>
18 <p>При записи в хеш-таблицу сначала нужно получить хеш. Затем его можно преобразовать в индекс массива - например, вычислить остаток от деления:</p>
19 <h3>Как хеширование работает изнутри</h3>
19 <h3>Как хеширование работает изнутри</h3>
20 <p>Рассмотрим, как работает добавление нового значения в ассоциативный массив. Напомним, в Python он представлен типом данных Dictionary. Напишем такой код:</p>
20 <p>Рассмотрим, как работает добавление нового значения в ассоциативный массив. Напомним, в Python он представлен типом данных Dictionary. Напишем такой код:</p>
21 <p>Такой простой код запускает целый сложный процесс. Для простоты рассмотрим его на Python, хотя в реальности все это происходит на более низком уровне. Опишем процесс хеширования без деталей и с упрощениями.</p>
21 <p>Такой простой код запускает целый сложный процесс. Для простоты рассмотрим его на Python, хотя в реальности все это происходит на более низком уровне. Опишем процесс хеширования без деталей и с упрощениями.</p>
22 <ol><li><p>Мы создаем ассоциативный массив. Внутри интерпретатора происходит инициализация индексированного массива:</p>
22 <ol><li><p>Мы создаем ассоциативный массив. Внутри интерпретатора происходит инициализация индексированного массива:</p>
23 </li>
23 </li>
24 <li><p>Далее мы присваиваем значение:</p>
24 <li><p>Далее мы присваиваем значение:</p>
25 </li>
25 </li>
26 <li><p>Затем интерпретатор хеширует ключ. Результатом хеширования становится число:</p>
26 <li><p>Затем интерпретатор хеширует ключ. Результатом хеширования становится число:</p>
27 </li>
27 </li>
28 <li><p>Далее интерпретатор берет число из предыдущего шага и преобразует его в индекс массива:</p>
28 <li><p>Далее интерпретатор берет число из предыдущего шага и преобразует его в индекс массива:</p>
29 </li>
29 </li>
30 <li><p>В конце интерпретатор ищет по индексу значение внутреннего индексированного массива и записывает его в еще один массив. Первым элементом нового массива становится ключ 'key', а вторым - значение 'value':</p>
30 <li><p>В конце интерпретатор ищет по индексу значение внутреннего индексированного массива и записывает его в еще один массив. Первым элементом нового массива становится ключ 'key', а вторым - значение 'value':</p>
31 </li>
31 </li>
32 </ol><p>Теперь посмотрим, как работает чтение данных:</p>
32 </ol><p>Теперь посмотрим, как работает чтение данных:</p>
33 <p>Разберем, как этот код работает изнутри.</p>
33 <p>Разберем, как этот код работает изнутри.</p>
34 <ol><li><p>Интерпретатор хеширует ключ. Результатом хеширования становится число:</p>
34 <ol><li><p>Интерпретатор хеширует ключ. Результатом хеширования становится число:</p>
35 </li>
35 </li>
36 <li><p>Число, полученное на предыдущем шаге, преобразуется в индекс массива:</p>
36 <li><p>Число, полученное на предыдущем шаге, преобразуется в индекс массива:</p>
37 </li>
37 </li>
38 <li><p>Если индекс существует, то интерпретатор извлекает массив и возвращает его наружу:</p>
38 <li><p>Если индекс существует, то интерпретатор извлекает массив и возвращает его наружу:</p>
39 </li>
39 </li>
40 </ol><h2>Коллизии</h2>
40 </ol><h2>Коллизии</h2>
41 <p>Ключом в ассоциативном массиве может быть абсолютно любая строка, любой длины и содержания. Но здесь есть одно противоречие:</p>
41 <p>Ключом в ассоциативном массиве может быть абсолютно любая строка, любой длины и содержания. Но здесь есть одно противоречие:</p>
42 <ul><li>Все возможные ключи - это бесконечное множество</li>
42 <ul><li>Все возможные ключи - это бесконечное множество</li>
43 <li>В качестве результата хеш-функция выдает строку фиксированной длины, то есть все выходные значения - это конечное множество</li>
43 <li>В качестве результата хеш-функция выдает строку фиксированной длины, то есть все выходные значения - это конечное множество</li>
44 - </ul><p>Из этого факта следует, что не для всех входных данных найдется уникальный хеш. На каком-то этапе могу появиться дубли: под одним хешем будут лежать несколько разных значений.</p>
44 + </ul><p>Из этого факта следует, что не для всех входных данных найдется уникальный хеш. На каком-то этапе могут появиться дубли: под одним хешем будут лежать несколько разных значений.</p>
45 <p>Такую ситуацию принято называть<strong>коллизией</strong>. Есть несколько<a>способов разрешения коллизий</a>. Каждому способу соответствует свой тип хеш-таблицы:</p>
45 <p>Такую ситуацию принято называть<strong>коллизией</strong>. Есть несколько<a>способов разрешения коллизий</a>. Каждому способу соответствует свой тип хеш-таблицы:</p>
46 <p>Простейший способ разрешения коллизий - это<strong>открытая адресация</strong>. Она предполагает последовательное перемещение по слотам хеш-таблицы в поисках первого свободного слота, куда значение будет записано.</p>
46 <p>Простейший способ разрешения коллизий - это<strong>открытая адресация</strong>. Она предполагает последовательное перемещение по слотам хеш-таблицы в поисках первого свободного слота, куда значение будет записано.</p>
47 <p>В примере выше открытая адресация сработает так: интерпретатор возьмет второе значение и проверит для него хеш 1938556050. Если хеш занят, то интерпретатор попробует проверить хеш 1938556051. Так он будет продвигаться до первого незанятого хеша.</p>
47 <p>В примере выше открытая адресация сработает так: интерпретатор возьмет второе значение и проверит для него хеш 1938556050. Если хеш занят, то интерпретатор попробует проверить хеш 1938556051. Так он будет продвигаться до первого незанятого хеша.</p>
48 <p>Коллизии не так редки, как может показаться. Вы можете убедиться в этом сами, если изучите<a>парадокс дней рождений</a>.</p>
48 <p>Коллизии не так редки, как может показаться. Вы можете убедиться в этом сами, если изучите<a>парадокс дней рождений</a>.</p>