Расширяемое хеширование

Материал из Викиконспекты
Перейти к: навигация, поиск

При частом добавлении новых значений в хеш-таблицу может возникнуть ситуация, когда хеш-таблица становится полностью заполненной и требуется перехешировать ее. При малых размерах хеш-таблицы полное перехеширование не вызовет трудностей. При больших размерах хеш-таблицы это требует большого количества времени, также если значения поступают очень часто, то требуется часто перехешировать таблицу либо выделять огромные объемы памяти, которые могут и не понадобиться. Чтобы решить эту проблему, а также чтобы не выделять много дополнительной памяти можно использовать расширяемое хеширование.

Структура и алгоритм

Метод расширяемого хеширования (англ. extendible hashing) заключается в том, что хеш-таблица представлена как каталог (англ. directory), а каждая ячейка будет указывать на емкость (англ. bucket) которая имеет определенную вместимость (англ. capacity). Сама хеш-таблица будет иметь глобальную глубину (англ. global depth), а каждая из емкостей имеет локальную глубину (англ. local depth). Глобальная глубина показывает сколько последних бит будут использоваться для того чтобы определить в какую емкость следует заносить значения. А из разницы локальной глубины и глобальной глубины можно понять сколько ячеек каталога ссылаются на емкость. Это можно показать формулой [math]K = 2 [/math][math]G-L[/math] где [math]G[/math] — глобальная глубина, [math]L[/math] — локальная глубина, а [math]K[/math] количество ссылающихся ячеек. Если емкость имеет свободное место, то помещаем туда значение без всяких хлопот, если же емкость куда следует положить значение переполнена, то смотрим на локальную глубину емкости. Если она меньше чем глобальная глубина то значит на емкость есть несколько указателей и нам достаточно перехешировать ее, разделив при этом на две и занести значения в новые две емкости увеличив у этих емкостей локальную глубину на [math]1[/math]. Если же локальная глубина была равна глобальной то мы увеличиваем глобальную глубину на [math]1[/math], удваивая при этом количество ячеек, количество указателей на емкости, а также увеличиваем количество последних бит по которым мы распределяем значения. Далее локальная глубина переполненной емкости становится меньше и мы повторяем предыдущий алгоритм то есть перехешируем емкость, разделим ее на две емкости и так далее. Для поиска емкости используется цифровое дерево.

Определение:
Цифровое дерево поиска — упорядоченная структура данных, которая используется для хранения динамического множества или ассоциативного массива где ключами обычно являются строки. В отличие от двоичного дерева поиска, ни один узел в дереве не хранит ключ, связанный с этим узлом; Вместо этого, его положение в дереве определяет ключ, с которым он связан. Все потомки узла имеют общий префикс строки, связанной с этим узлом, и корень связан с пустой строкой. Значения, как правило, не связаны с каждым узлом, только с листьями и некоторыми внутренними узлами.

Пример

Рассмотрим алгоритм на примере.

Пусть у нас есть некий каталог со своими указателями и мы хотим добавить значения [math]9, 20, 26[/math] (см. рис1) где [math]G[/math] — глобальная глубина, [math]l1, l2, l3, l4[/math] — локальные глубины емкостей, а вместимость емкостей равна [math]3[/math]. Рассмотрим значение [math]9[/math]. В двоичном коде оно равно [math]1001[/math]. Окончание [math]01[/math] соответствует второй ячейке значит смотрим на вторую емкость. В ней есть свободное место и мы просто помещаем [math]9[/math] в нее (см. рис2). На этом работа с [math]9[/math] закончена. Далее идет значение [math]20[/math]. В двоичном виде оно представляется как [math]10100[/math]. Это значение оканчивается на [math]00[/math] и должно пойти в первую емкость, но первая емкость полностью заполнена. Следовательно мы смотрим на [math]l1[/math]. [math]l1 = G[/math] а значит мы должны удвоить количество ячеек каталога, увеличить глобальную глубину, затем увеличить количество последних бит по которым мы раскидываем значения на [math]1[/math] и перехешировать первую емкость, разделив ее на две, увеличив локальную глубину и разместив значения по новым емкостям (см. рис3). На этом работа с [math]20[/math] закончена. Теперь рассмотрим последнее число [math]26[/math]. Его двоичное представление — [math]11010[/math]. Последние [math]3[/math] бита ([math]010[/math]) соответствуют третьей емкости, но она также полностью заполнена как и во втором случае, но ее локальная глубина меньше чем глобальная а следовательно нам надо только перехешировать емкость, разделив ее на две, увеличив локальную глубину и разместив значения по новым емкостям (см. рис4). На этом работа с [math]26[/math] закончена.

Рис. 1
Рис. 2
Рис. 3
Рис. 4

Использование

Чаще всего расширяемое хеширование используется в базах данных т.к. БД могут быть крайне большими и перехеширование всей БД займет продолжительное время при этом лишая пользователей доступа к БД. А при использовании расширяемого хеширования перехешировать придется только малые группы, что не сильно замедлит работу БД.

См. также

Источники информации

  • Бакнелл Джулиан — Фундаментальные алгоритмы и структуры данных в Delphi — стр. 50.
  • Дейт К. Дж. — Введение в системы баз данных, 8-е издание.: Пер. с англ. — М.: Издательский дом «Вильямс», 2005. — стр. 1236.
  • Wikipedia — Extendible hashing