Ремонт принтеров, сканнеров, факсов и остальной офисной техники


назад Оглавление вперед




[76]

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

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

В отличие от хеширования с цепочками, при открытой адресации (open addressing) никаких списков нет, а все записи хранятся в самой хеш-таблице: каждая ячейка таблицы содержит либо элемент динамического множества, либо nil. Поиск заключается в том, что мы определённым образом просматриваем элементы таблицы, пока не найдём то, что ищем, или не удостоверимся, что элемента с таким ключом в таблице нет. Тем самым число хранимых элементов не может быть больше размера таблицы: коэффициент заполнения не больше 1.

Конечно, и при хешировании с цепочками можно использовать свободные места в хеш-таблице для хранения списков (упражнение 12.2-5), но при открытой адресации указатели вообще не используются: последовательность просматриваемых ячеек вычисляется. За счет экономии памяти на указателях можно увеличить количество позиций в таблице, что уменьшает число коллизий и сокращает поиск.

Чтобы добавить новый элемент в таблицу с открытой адресацией, ячейки которой занумерованы целыми числами от 0 до га - 1, мы просматриваем её, пока не найдем свободное место. Если всякий раз просматривать ячейки подряд (0,1,..., га- 1), потребуется время О(га), но суть в том, что порядок просмотра таблицы зависит от ключа! Иными словами, мы добавляем к хеш-функции второй аргумент - номер попытки (нумерацию начинаем с нуля), так что хеш-функция имеет вид

h: U x {0,1,..., га - 1} -> {0,1,..., га - 1}

(U - множество ключей). Последовательность испробованных мест (probe sequence), или (короче) последовательность проб для

данного ключа к имеет вид

(h(k,0),h(k,l),...,h(k,m- 1));

функция h должна быть такой, чтобы каждое из чисел от 0 до га- 1 встретилось в этой последовательности ровно один раз (для каждого ключа все позиции таблицы должны быть доступны). Ниже приводится текст процедуры добавления в таблицу Г с открытой адресацией; в нем подразумевается, что записи не содержат дополнительной информации, кроме ключа. Если ячейка таблицы пуста, в ней записан nil (фиксированное значение, отличное от всех ключей).


Hash-Insert(T, к) 1 г <- О

2repeat j <- h(k,i)

3if T[j] = nil

4then T[j] <- A;

5return j

6else i <- г + 1

7until i = m

8error «переполнение хеш-таблицы»

При поиске элемента с ключом к в таблице с открытой адресацией ячейки таблицы просматриваются в том же порядке, что и при добавлении в нее элемента с ключом к. Если при этом мы натыкаемся на ячейку, в которой записан nil, то можно быть уверенным, что искомого элемента в таблице нет (иначе он был бы занесён в эту ячейку). (Внимание: мы предполагаем, что никакие элементы из таблицы не удаляются!)

Вот текст процедуры поиска Hash-Search (если элемент с ключом к содержится в таблице Г в позиции j, процедура возвращает j, в противном случае она возвращает nil).

Hash-Search(T, к)

1г <- О

2repeat j <- h(k,i)

6until T[j] = nil или i = m

7return nil

Удалить элемент из таблицы с открытой адресацией не так просто. Если просто записать на его место nil, то в дальнейшем мы не сможем найти те элементы, в момент добавления которых в таблицу это место было занято (и из-за этого был выбран более далёкий элемент в последовательности испробованных мест). Возможное решение - записывать на место удалённого элемента не nil, а специальное значение deleted («удалён»), и при добавлении рассматривать ячейку с записью deleted как свободную, а при поиске - как занятую (и продолжать поиск). Недостаток этого подхода в том, что время поиска может оказаться большим даже при низком коэффициенте заполнения. Поэтому, если требуется удалять записи из хеш-таблицы, предпочтение обычно отдают хешированию с цепочками.

В нашем анализе открытой адресации мы будем исходить из предположения, что хеширование равномерно (uniform) в том смысле, что все то! перестановок множества {0,1,..., то - 1} равнове-

3

4 5


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

Обычно применяют такие три способа вычисления последовательности испробованных мест: линейный, квадратичный и двойное хеширование. В каждом из этих способов последовательность (h(k, 0), h(k, 1),..., h(k, то - 1)) будет перестановкой множества {0,1,..., то - 1} при любом значении ключа к, но ни один из этих способов не является равномерным по той причине, что они дают не более то2 перестановок из то! возможных. Больше всего разных перестановок получается при двойном хешировании; не удивительно, что и на практике этот способ дает лучшие результаты.

Линейная последовательность проб

Пусть Ы: U -т- {0,1,..., то - 1} - «обычная» хеш-функция. Функция, определяющая линейную последовательность проб (linear probing), задаётся формулой

h(k, г) = (h(k) + г) mod то.

Иными словами, при работе с ключом к начинают с ячейки T[h(k)], а затем перебирают ячейки таблицы подряд: T[h(k) + 1], T[h(k) + 2],... (после Т[т - 1] переходят к Г[0]). Поскольку последовательность проб полностью определяется первой ячейкой, реально используется всего лишь то различных последовательностей.

Открытую адресацию с линейной последовательностью проб легко реализовать, но у этого метода есть один недостаток: он может привести к образованию кластеров, то есть длинных последовательностей занятых ячеек, идущих подряд (по-английски это явление называется primary clustering). Это удлиняет поиск; в самом деле, если в таблице из то ячеек все ячейки с чётными номерами заняты, а ячейки с нечётными номерами свободны, то среднее число проб при поиске элемента, отсутствующего в таблице, есть 1,5; Если, однако, те же то/2 занятых ячеек идут подряд, то среднее число проб примерно равно то/8 = га/4 (га - число занятых мест в таблице). Тенденция к образованию кластеров объясняется просто: если г заполненных ячеек идут подряд, вероятность того, что при очередной вставке в таблицу будет использована ячейка, следующая непосредственно за ними, есть (г + 1)/то, в то время как для свободной ячейки, предшественница которой также свободна, вероятность быть использованной равна всего лишь 1/то. Всё вышеизложенное показывает, что линейная последовательность проб довольно далека от равномерного хеширования.



[стр.Начало] [стр.1] [стр.2] [стр.3] [стр.4] [стр.5] [стр.6] [стр.7] [стр.8] [стр.9] [стр.10] [стр.11] [стр.12] [стр.13] [стр.14] [стр.15] [стр.16] [стр.17] [стр.18] [стр.19] [стр.20] [стр.21] [стр.22] [стр.23] [стр.24] [стр.25] [стр.26] [стр.27] [стр.28] [стр.29] [стр.30] [стр.31] [стр.32] [стр.33] [стр.34] [стр.35] [стр.36] [стр.37] [стр.38] [стр.39] [стр.40] [стр.41] [стр.42] [стр.43] [стр.44] [стр.45] [стр.46] [стр.47] [стр.48] [стр.49] [стр.50] [стр.51] [стр.52] [стр.53] [стр.54] [стр.55] [стр.56] [стр.57] [стр.58] [стр.59] [стр.60] [стр.61] [стр.62] [стр.63] [стр.64] [стр.65] [стр.66] [стр.67] [стр.68] [стр.69] [стр.70] [стр.71] [стр.72] [стр.73] [стр.74] [стр.75] [стр.76] [стр.77] [стр.78] [стр.79] [стр.80] [стр.81] [стр.82] [стр.83] [стр.84] [стр.85] [стр.86] [стр.87] [стр.88] [стр.89] [стр.90] [стр.91] [стр.92] [стр.93] [стр.94] [стр.95] [стр.96] [стр.97] [стр.98] [стр.99] [стр.100] [стр.101] [стр.102] [стр.103] [стр.104] [стр.105] [стр.106] [стр.107] [стр.108] [стр.109] [стр.110] [стр.111] [стр.112] [стр.113] [стр.114] [стр.115] [стр.116] [стр.117] [стр.118] [стр.119] [стр.120] [стр.121] [стр.122] [стр.123] [стр.124] [стр.125] [стр.126] [стр.127] [стр.128] [стр.129] [стр.130] [стр.131] [стр.132] [стр.133] [стр.134] [стр.135] [стр.136] [стр.137] [стр.138] [стр.139] [стр.140] [стр.141] [стр.142] [стр.143] [стр.144] [стр.145] [стр.146] [стр.147] [стр.148] [стр.149] [стр.150] [стр.151] [стр.152] [стр.153] [стр.154] [стр.155] [стр.156] [стр.157] [стр.158] [стр.159] [стр.160] [стр.161] [стр.162] [стр.163] [стр.164] [стр.165] [стр.166] [стр.167] [стр.168] [стр.169] [стр.170] [стр.171] [стр.172] [стр.173] [стр.174] [стр.175] [стр.176] [стр.177] [стр.178] [стр.179] [стр.180] [стр.181] [стр.182] [стр.183] [стр.184] [стр.185] [стр.186] [стр.187] [стр.188] [стр.189] [стр.190] [стр.191] [стр.192] [стр.193] [стр.194] [стр.195] [стр.196] [стр.197] [стр.198] [стр.199] [стр.200] [стр.201] [стр.202] [стр.203] [стр.204] [стр.205] [стр.206] [стр.207] [стр.208] [стр.209] [стр.210] [стр.211] [стр.212] [стр.213] [стр.214] [стр.215] [стр.216] [стр.217] [стр.218] [стр.219] [стр.220] [стр.221] [стр.222] [стр.223] [стр.224] [стр.225] [стр.226] [стр.227] [стр.228] [стр.229] [стр.230] [стр.231] [стр.232] [стр.233] [стр.234] [стр.235] [стр.236] [стр.237] [стр.238] [стр.239] [стр.240] [стр.241] [стр.242] [стр.243] [стр.244] [стр.245] [стр.246] [стр.247] [стр.248] [стр.249] [стр.250] [стр.251] [стр.252] [стр.253] [стр.254] [стр.255] [стр.256] [стр.257] [стр.258] [стр.259] [стр.260] [стр.261] [стр.262] [стр.263] [стр.264] [стр.265] [стр.266] [стр.267] [стр.268] [стр.269] [стр.270] [стр.271] [стр.272] [стр.273] [стр.274] [стр.275] [стр.276] [стр.277] [стр.278] [стр.279] [стр.280] [стр.281] [стр.282] [стр.283] [стр.284] [стр.285] [стр.286] [стр.287] [стр.288] [стр.289] [стр.290] [стр.291] [стр.292] [стр.293] [стр.294]