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>