Анимация
JavaScript


Главная  Библионтека 

0 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

19 JE SUCCESS C-l 24 DECX 1 1-5

20 LDX TABLE, 1 С -1 - 52 25 STX VACANCIES 1-5

21 JXNZ 3B С -1 - 52 25 LDA К 1-5

22 4H LDX VACANCIES 1-5 27 STA TABLE, 1 1-5

23 JXZ OVERFLOW 1-5

Счетчики частот A, С, 51, 52 здесь имеют тот же смысл, что и в программе С, приведенной выше. Еще одна переменная. В, в среднем примерно равна {С - 1)12 (если ограничить диапазон значений h2{K) до, скажем, 1 < hiiK) < М/2, В уменьшится до (С - 1)/4; такое увеличение скорости, вероятно, не компенсируется заметным увеличением числа проб). Если в таблице N = аМ ключей, среднее значение А, конечно, равно а при неудачном поиске и Л = Г - в случае поиска успешного. Как и в алгоритме С, среднее значение 51 при успешном поиске составляет 1 - {{N - 1)/М) SS 1 - а. Среднее число проб трудно установить точно, однако эмпирические тесты показывают хорошую согласованность с формулами, выведенными ниже для "равномерного исследования" при независимых hi{K) и hiK):

M+1-N (неудачный поиск), (26)

Сдг = (Hm+i-Hm+i-n) ~ -а~ In(l-a) (успешный поиск). (27)

Если h2{K) зависит от hi{K) согласно (25), вторичная кластеризация увеличивает (26) и (27) до

W (1-а)"-а-1п(1-а); (28)

Слг - 1 + Ям-ц-Ям+1-лг- ~{Hm+i-Hm+i-n)/N+0{N~)

W 1-1п(1-а)-а (29)

(см. упр. 44). Заметим, что при заполнении таблицы данные значения Cn стремятся к Нм+1 - 1 и Нм+1 - I соответственно; это существенно лучше, чем при использовании алгоритма L, но не так хорошо, как в методе цепочек.

Поскольку каждая проба в алгоритме L отнимает немного меньше времени, двойное хеширование дает вьшгрыш только при заполненной таблице. На рис. 42 сравниваются средние значения времени работы программ L, D и модифицированной программы D (эта модификация влечет за собой вторичное скучивание; сама модификация сводится к замещению медленного вычисления h2{K) в строках 10-13 следующими командами.

ENN2 1-м, 1 с<- М -г.

J1NZ *+2 (30)

ENT2 О Если г = О, с <- 1.

Программа D требует в целом 8C-f 19Л+ B-f 26 - 135- 1751 единиц времени; модификация (30) позволяет сохранить около 15(Л - 51) w 7.5q времени при успешном завершении поиска. В данном случае вторичная кластеризация предпочтительнее независимого двойного хеширования.




Модифицированная программа D (30)

0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 Коэффициент заполненности, a = N/M

0.9 1.0

Рис. 42. Время успешного поиска трех схем открытой адресации.

На двоичном компьютере можно было бы увеличить скорость вычисления /12 (К) другим путем - заменив (если М - простое число, большее, чем, скажем, 512) строки 10-13 строками

AND =511= rA<-rAmod512.

STA *+1(0:2) (31)

ENT2 * с<-тА + 1.

Эта идея (предложенная Беллом (Bell) и Каманом (Кашап), САСМ 13 (1970), 675-677, которые независимо открыли алгоритм D) позволяет избежать вторичной кластеризации без затрат на повторное деление.

Для улучшения алгоритма L было предложено много других последовательностей проб, но ни одна из них не превосходит алгоритм D (за исключением, возможно, метода, описанного в упр. 20),

Используя относительный порядок ключей, можно уменьшить среднее время работы при неудачном поиске согласно алгоритму L или D до среднего времени работы при успешном поиске (см. упр. 66). Эта технология может с успехом применяться для решения задач, в которых неудачный поиск - обычное явление, более частое, чем поиск успешный; например, использует такой алгоритм при поиске исключений из своих правил переноса.

Изменение Брента. Ричард П. Брент (Richard Р. Brent) открыл такой способ модификации алгоритма D, при котором среднее время успешного поиска остается ограниченным при заполнении таблицы. Его метод [САСМ 16 (1973), 105-109] основан на том факте, что обычно успешный поиск встречается гораздо чаще вставок, а потому его предложение сводится к переносу основной работы на вставку элемента путем такого перемещения записей, чтобы уменьшилось ожидаемое время выборки.

Например, на рис. 43 показано, сколько раз каждый идентификатор встречался в типичной процедуре PL/I. Эти данные указывают на то, что компилятор PL/I, который использует хеш-таблицу для хранения имен переменных, будет обращаться к ней за многими именами пять и более раз, вставляя их всего однажды. В подобном исследовании Белл и Каман обнаружили, что компилятор COBOL использовал свой




в S Й g "S * " 5 3 5""

Рис. 43. Количество поисков имен переменных компилятором в типичном случае. Имена перечислены слева направо в порядке их первого появления в программе.

табличный алгоритм при компиляции 10988 раз, в то время как было сделано только 735 вставок в таблицу; следовательно, на одну вставку приходилось около 14 успешных поисков. Иногда таблица создается только один раз (например, таблица символов кодов операций в ассемблере) и используется исключительно для получения из нее данных.

Идея Брента заключается в изменении процесса вставки в алгоритме D, как показано ниже. Предположим, что при неудачном поиске были проверены ячейки Ро, Рь • • •, Pf-b Pt, где Pj = {hi{K) - jhiiK)) mod M и TABLE[pt] пуст Если t < 1, вставляем К в позицию pt, как обычно; однако, если t > 2, вычисляем cq = Н2{Ко), где Ко = KEY[po]i и смотрим, свободен ли узел TABLE [(ро - Со) mod М]. Если это так, помещаем в него TABLE[ро]) а затем вставляем К в позицию ро- Это приводит к увеличению времени выборки Ко на один шаг, но время выборки К уменьшается на i > 2 шагов, что приводит к общему выигрышу во времени выборки. Аналогично, если узел TABLE [(ро - со) mod М] занят и i > 3, проверяем узел TABLE С(ро - 2со) mod М]; если он также занят, вычисляем Ci = /i2(KEY[pi]), проверяем TABLEС(ро - Cl) mod М] и т. д. Вообще, пусть Cj = /i2(KEY[pj]) и pjk = {Pj -kcj) mod M; если для всех j и к, таких, что j + k < г, узлы TABLE [pj,fc] заняты и если i > г -f 1, просматриваем узлы TABLE[ро,г], TABLE[pi,r-i], ..., TABLE[р-ы] • Если первое пустое место оказывается в позиции Pj,r-j, устанавливаем TABLE [pj>-j] <-TABLE Cpj] и вставляем К в позицию pj.

Анализ Брента показывает, что среднее количество проб на один успешный поиск уменьшается до уровней, показанных на рис. 44 на с. 583, с максимальным значением, равным приблизительно 2.49.

Количество проб t+l при неудачном поиске в результате внесенных в алгоритм изменений осталось прежним; оно осталось на уровне, который определен формулой (26) и достигает (М-f 1) при заполпенности таблицы. Среднее количество



0 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