Хеш-таблицы

Автор работы: Пользователь скрыл имя, 16 Января 2012 в 22:16, лабораторная работа

Описание

Необходимо вычислить среднюю трудоемкость поиска при различной заполненности таблицы (например, 25, 50, 75, 90 и 99%). Для этого нужно сначала разместить в таблице нужное число строк, а потом для каждой строки подсчитать число шагов, выполняемых при ее поиске. Все вычисления провести для трех вариантов: линейные пробы, квадратичные пробы и двойное хеширование.

Работа состоит из  1 файл

Лаба 3.docx

— 38.64 Кб (Скачать документ)

3. Хеш-таблицы

     Требуется построить хеш-таблицу, для поиска в которой используется метод  открытой адресации (размещение и поиск  элементов – обязательно, удаление – желательно). Длина таблицы  q – простое число в диапазоне 10-20 тысяч. Таблица строится для набора случайных символьных строк длиной 1-20 символов и хранит номера или адреса этих строк. Хеш-функция для строки S длины L:

     f(S) = ((…(S[1] * 31 + S[2]) * 31 + …+S[L-1]) * 31 +S[L]) mod q.

     Необходимо  вычислить среднюю трудоемкость поиска при различной заполненности таблицы (например, 25, 50, 75, 90 и 99%). Для этого нужно сначала разместить в таблице нужное число строк, а потом для каждой строки подсчитать число шагов, выполняемых при ее поиске. Все вычисления провести для трех вариантов: линейные пробы, квадратичные пробы и двойное хеширование. 
 

Теоретические сведения 

     Хеш-табли́ца — это структура данных, реализующая интерфейс ассоциативного массива, а именно, она позволяет хранить пары (ключ, значение) и выполнять три операции: операцию добавления новой пары, операцию поиска и операцию удаления пары по ключу.

     Существует  два основных варианта хеш-таблиц: с  цепочками и открытой адресацией. Хеш-таблица содержит некоторый  массив H, элементы которого есть пары (хеш-таблица с открытой адресацией) или списки пар (хеш-таблица с цепочками).

     Выполнение  операции в хеш-таблице начинается с вычисления хеш-функции от ключа. Получающееся хеш-значение i = hash(key) играет роль индекса в массиве H. Затем выполняемая операция (добавление, удаление или поиск) перенаправляется объекту, который хранится в соответствующей ячейке массива H[i].

     Ситуация, когда для различных ключей получается одно и то же хеш-значение, называется коллизией. Такие события не так уж и редки — например, при вставке в хеш-таблицу размером 365 ячеек всего лишь 23-х элементов вероятность коллизии уже превысит 50 % (если каждый элемент может равновероятно попасть в любую ячейку) — см. парадокс дней рождения. Поэтому механизм разрешения коллизий — важная составляющая любой хеш-таблицы.

     В некоторых специальных случаях  удаётся избежать коллизий вообще. Например, если все ключи элементов  известны заранее (или очень редко  меняются), то для них можно найти  некоторую совершенную хеш-функцию, которая распределит их по ячейкам хеш-таблицы без коллизий. Хеш-таблицы, использующие подобные хеш-функции, не нуждаются в механизме разрешения коллизий, и называются хеш-таблицами с прямой адресацией.

     Число хранимых элементов, делённое на размер массива H (число возможных значений хеш-функции), называется коэффициентом заполнения хеш-таблицы (load factor) и является важным параметром, от которого зависит среднее время выполнения операций.

     Важное  свойство хеш-таблиц состоит в том, что, при некоторых разумных допущениях, все три операции (поиск, вставка, удаление элементов) в среднем выполняются  за время O(1). Но при этом не гарантируется, что время выполнения отдельной операции мало́. Это связано с тем, что при достижении некоторого значения коэффициента заполнения необходимо осуществлять перестройку индекса хеш-таблицы: увеличить значение размера массива H и заново добавить в пустую хеш-таблицу все пары.

     Открытая  адресация

     В массиве H хранятся сами пары ключ-значение. Алгоритм вставки элемента проверяет ячейки массива H в некотором порядке до тех пор, пока не будет найдена первая свободная ячейка, в которую и будет записан новый элемент. Этот порядок вычисляется на лету, что позволяет сэкономить на памяти для указателей, требующихся в хеш-таблицах с цепочками.

     Последовательность, в которой просматриваются ячейки хеш-таблицы, называется последовательностью проб. В общем случае, она зависит только от ключа элемента, то есть это последовательность h0(x), h1(x), …, h— 1(x), где — ключ элемента, а hi(x) — произвольные функции, сопоставляющие каждому ключу ячейку в хеш-таблице. Первый элемент в последовательности, как правило, равен значению некоторой хеш-функции от ключа, а остальные считаются от него одним из приведённых ниже способов. Для успешной работы алгоритмов поиска последовательность проб должна быть такой, чтобы все ячейки хеш-таблицы оказались просмотренными ровно по одному разу.

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

     

     Рис.1. Пример хеш-таблицы с открытой адресацией и линейным пробированием, получающейся при вставке элементов в левой  колонке сверху вниз. 

     Удаление  элементов в такой схеме несколько  затруднено. Обычно поступают так: заводят  булевый флаг для каждой ячейки, помечающий, удален ли элемент в ней или нет. Тогда удаление элемента состоит в установке этого флага для соответствующей ячейки хеш-таблицы, но при этом необходимо модифицировать процедуру поиска существующего элемента так, чтобы она считала удалённые ячейки занятыми, а процедуру добавления — чтобы она их считала свободными и сбрасывала значение флага при добавлении.

     Последовательности  проб

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

  • Линейное пробирование: ячейки хеш-таблицы последовательно просматриваются с некоторым фиксированным интервалом k между ячейками (обычно, k = 1), то есть i-й элемент последовательности проб — это ячейка с номером (hash(x) + ik) mod N. Для того, чтобы все ячейки оказались просмотренными по одному разу, необходимо, чтобы k было взаимно-простым с размером хеш-таблицы.
  • Квадратичное пробирование: интервал между ячейками с каждым шагом увеличивается на константу. Если размер хеш-таблицы равен степени двойки (N = 2p), то одним из примеров последовательности, при которой каждый элемент будет просмотрен по одному разу, является:

     hash(x) mod N, (hash(x) + 1) mod N, (hash(x) + 3) mod N, (hash(x) + 6) mod N, …

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

Информация о работе Хеш-таблицы