Расширяемое хеширование — различия между версиями

Материал из Викиконспекты
Перейти к: навигация, поиск
Строка 1: Строка 1:
 
При частом добавлении новых значений в хеш-таблицу может возникнуть ситуация, когда хеш-таблица становится полностью заполненной и требуется перехешировать ее. Но при больших размерах хеш-таблицы это требует большого количества времени. Чтобы решить эту проблему, а также чтобы не выделять много дополнительной памяти можно использовать расширяемое хеширование.
 
При частом добавлении новых значений в хеш-таблицу может возникнуть ситуация, когда хеш-таблица становится полностью заполненной и требуется перехешировать ее. Но при больших размерах хеш-таблицы это требует большого количества времени. Чтобы решить эту проблему, а также чтобы не выделять много дополнительной памяти можно использовать расширяемое хеширование.
 +
== Структура и алгоритм ==
 +
'''Метод расширяемого хеширования''' (англ. ''extendible hashing'') заключается в том, что хеш-таблица представлена как каталог (англ. ''directory''), а каждая ячейка будет указывать на емкость (англ. ''bucket'') которая имеет определенную вместимость (англ. capacity). Сама хеш-таблица будет иметь глобальную глубину (англ. ''global depth''), а каждая из емкостей имеет локальную глубину (англ. ''local depth''). Значения будут заноситься в емкости в зависимости от своих последних битов. Если емкость куда следует положить значение переполнена, то смотрим на локальную глубину емкости. Если она меньше чем глобальная глубина то значит на емкость есть несколько указателей и нам достаточно перехешировать ее, разделив при этом на две и занести значения в новые две емкости увеличив у этих емкостей локальную глубину на 1. Если же локальная глубина была равна глобальной то мы увеличиваем глобальную глубину на 1, удваивая при этом количество ячеек, количество указателей на емкости, а также увеличиваем количество последних бит по которым мы распределяем значения. Далее локальная глубина переполненной емкости становится меньше и мы знаем что дальше делать.
 +
==Пример==
 +
<div class="tright" style="clear:none">[[Файл:SecondStep.png|мини|250px|рис2]]</div>
 +
<div class="tright" style="clear:none">[[Файл:FirstStep.png|мини|250px|рис1]]</div>
  
'''Метод расширяемого хеширования''' (англ. ''extendible hashing'') заключается в том, что мы представляем хеш-таблицу в качестве нескольких групп, которые имеют определенное количество ячеек. При переполнении группы нам не требуется перехешировать всю таблицу, а лишь перехешировать заполненную группу, разделив ее при этом на две группы. Таким образом вся хеш-таблица никогда не будет полностью заполнена. К тому же при использовании данного метода использование памяти будет наиболее экономичным.
+
Рассмотрим алгоритм на примере.
== Алгоритм ==
 
В начале у нас есть хеш-таблица с первоначальным количеством ячеек. Все эти ячейки будут являться первой группой. Каждая группа будет содержать некоторый набор значений и номер записи каждого значения, чтобы ее можно было извлечь.
 
 
 
Когда группа заполнится разобьем ее на две группы одинаковых размеров и повторим вставку всех элементов исходной группы в две новые группы. Причем все элементы, которые завершаются нулевым разрядом, поместим в одну группу, а завершающиеся единичным разрядом — в другую. Эти две группы имеют так называемую '''разрядную глубину''' (англ. ''bit—depth''), равную одному разряду. Теперь при каждой вставке пары значение/номер записи она будет помещаться в первую или во вторую группу, в зависимости от последнего разряда значения. При заполнении группы с глубиной <tex>1</tex> будет использоваться предпоследний разряд, при заполнении группы с глубиной <tex>2</tex> пред-предпоследний разряд и так далее.
 
 
 
Для поддержания отображения того, какие значения помещаются в те или иные группы, используется структура, называемая каталогом. По существу каталог содержит список всех возможных окончаний групп и связных с ними номеров групп. Вместо того чтобы поддерживать какой—либо причудливый набор значений разрядной глубины и номеров групп, выбранный методом проб и ошибок, каталог поддерживает собственное значение разрядной глубины, равное максимальной разрядной глубине группы, и имеет ячейку для каждого значения этой разрядной глубины.
 
 
 
[[Файл:7_1.png|400px|мини|Вставка в расширяемую хеш-таблицу]]
 
 
 
При разбиении группы дополняющие друг друга группы не будут размещаться в каталоге по соседству. Для дальнейших рассуждений было бы проще предположить, что записи каталога, соответствующие одной группе, располагаются по соседству, чтобы при разбиении группы дополняющая первую группа помещалась непосредственно за ней.
 
 
 
Для достижения этого следует инвертировать последние разряды значения при вычислении индексной записи каталога. Так, например, если значение завершается разрядами <tex>001</tex>, при поиске мы обратимся не к записи <tex>001</tex> каталога, а к записи <tex>100</tex> (<tex>4</tex>, которая соответствует инвертированному значению <tex>001</tex>). В результате использование каталога значительно упрощается.
 
 
 
==Пример==
 
  
Рассмотрим выполнение алгоритма на примере, выполняемые при этом действия показаны на рис. Мы начинаем с каталога только с одной записью с индексом <tex>0</tex> (a). Принято считать, что в подобной ситуации разрядная глубина равна <tex>0</tex>. Мы заполняем единственную группу (назовем ее  <tex> A </tex> ) и теперь ее нужно разбить. Вначале мы увеличиваем разрядную глубину каталога до <tex>1</tex>. Иначе говоря, теперь он будет содержать две записи (b). В результате будут созданы две группы, на первую из которых указывает запись <tex>0</tex> (исходная запись  <tex> A </tex> ), а на вторую запись <tex>1</tex>,  <tex> B </tex>  (c). Все элементы, значения которых завершаются разрядом <tex>0</tex>, помещаются в группу  <tex> A </tex> , а остальные — в группу  <tex> B </tex> . Снова заполним группу  <tex> A </tex> . Теперь разрядную глубину каталога необходимо увеличить с <tex>1</tex> до <tex>2</tex>, чтобы получить четыре группы, доступных для вставки. Перед разделением заполненной группы записи каталога <tex>00</tex> и <tex>01</tex> будут указывать на исходную группу  <tex> A </tex> , а записи <tex>10</tex> и <tex>11</tex> — на группу  <tex> B </tex>  (d). Группа  <tex> A </tex>  разбивается на группу, которая принимает значения с окончанием <tex>00</tex> (снова  <tex> A </tex> ), и группу, которая принимает значения с окончанием <tex>10</tex>,  <tex> C </tex> . На группу  <tex> A </tex>  будет указывать запись <tex>00</tex> каталога, а на группу  <tex> C </tex>  — запись <tex>01</tex> (e). И, наконец, группа  <tex> C </tex>  (на которую указывает запись 01 каталога) заполняется. Нужно снова увеличить разрядную глубину каталога, на этот раз до трех разрядов.
+
Пусть у нас есть некий каталог со своими указателями и мы хотим добавить значения 9, 20, 26 (см. рис1) где <tex>G</tex> — глобальная глубина,  <tex>l1, l2, l3, l4</tex> — локальные глубины емкостей, а вместимость емкостей равна <tex>3</tex>. Рассмотрим число 9. В двоичном коде оно равно 1001. Окончание 01 соответствует второй ячейке значит смотрим на вторую емкость. В ней есть свободное место и мы просто помещаем 9 в нее (см. рис2). Далее идет значение 20. В двоичном виде оно представляется как 10100. Это значение оканчивается на 00 и должно пойти в первую емкость, но первая емкость полностью заполнена. Следовательно мы смотрим на l1. l1 = G а значит мы должны удвоить количество ячеек каталога, увеличить глобальную глубину, затем увеличить количество последних бит по которым мы раскидываем значения на 1 и перехешировать первую емкость, разделив ее на две, увеличив локальную глубину и разместив значения по новым емкостям (см. рис3). Теперь рассмотрим последнее число 26. Его двоичное представление — 11010. Последние 3 бита соответствуют третьей емкости, но она также полностью заполнена как и во втором случае, но ее локальная глубина меньше чем глобальная а следовательно нам надо только перехешировать емкость и т.д. (см. рис4).
 
== Использование ==
 
== Использование ==
 
Чаще всего расширяемое хеширование используется в базах данных т.к. БД могут быть крайне большими и перехеширование всей БД займет продолжительное время при этом лишая пользователей доступа к БД. А при использовании расширяемого хеширования перехешировать придется только малые группы, что не сильно замедлит работу БД.
 
Чаще всего расширяемое хеширование используется в базах данных т.к. БД могут быть крайне большими и перехеширование всей БД займет продолжительное время при этом лишая пользователей доступа к БД. А при использовании расширяемого хеширования перехешировать придется только малые группы, что не сильно замедлит работу БД.

Версия 21:57, 6 июня 2015

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

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

Метод расширяемого хеширования (англ. extendible hashing) заключается в том, что хеш-таблица представлена как каталог (англ. directory), а каждая ячейка будет указывать на емкость (англ. bucket) которая имеет определенную вместимость (англ. capacity). Сама хеш-таблица будет иметь глобальную глубину (англ. global depth), а каждая из емкостей имеет локальную глубину (англ. local depth). Значения будут заноситься в емкости в зависимости от своих последних битов. Если емкость куда следует положить значение переполнена, то смотрим на локальную глубину емкости. Если она меньше чем глобальная глубина то значит на емкость есть несколько указателей и нам достаточно перехешировать ее, разделив при этом на две и занести значения в новые две емкости увеличив у этих емкостей локальную глубину на 1. Если же локальная глубина была равна глобальной то мы увеличиваем глобальную глубину на 1, удваивая при этом количество ячеек, количество указателей на емкости, а также увеличиваем количество последних бит по которым мы распределяем значения. Далее локальная глубина переполненной емкости становится меньше и мы знаем что дальше делать.

Пример

рис2
рис1

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

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

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

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

См. также

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

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