Дональд Кнут. Искусство программирования. т.3 / knuth3
.pdf
252 Original pages: 457-482 |
|
|
|
||||
|
|
|
STA |
KEY + N +1 |
1 |
KN+1 K. |
|
|
|
|
ENT1 |
-1-N |
1 |
i |
−1. |
3H |
INC1 |
2 |
b(C − S + 2)=2c |
Q3. |
Продвижение. (Двойное.) |
||
|
|
|
СМРА |
KEY+N, 1 |
b(C − S + 2)=2c |
Q2. |
Сравнение. |
|
|
|
JE |
4F |
b(C − S + 2)=2c |
На Q4, если K = Ki. |
|
|
|
|
СМРА |
KEY+N+1,1 |
b(C − S + 1)=2c |
Q2. |
Сравнение. (Следующее.) |
|
|
|
JNE |
3B |
b(C − S + 1)=2c |
На Q3, если K 6= Ki+1. |
|
|
|
|
INC1 |
1 |
(C − 5) mod 2 |
Продвинуть i. |
|
4H |
J1NP |
SUCCESS |
1 |
Q4. |
Конец файла? |
||
FAILURE |
EQU |
* |
1 − S |
Выход, если нет в таблице. |
|||
|
|
|
|
|
|
|
|
Инструкции внутреннего цикла выписаны дважды; это исключает примерно половину операторов ”i i + 1”. Таким образом, время выполнения программы уменьшилось до
3:5C − 3:5S + 10(C − S) mod 2 2
единиц. При поиске по большим таблицам программа Q’ на 30% быстрее программы S; подобным образом могут быть улучшены многие существующие программы. Если известно, что ключи расположены в возрастающем порядке, полезно несколько изменить алгоритм.
Алгоритм Т. (Последовательный поиск в упорядоченной таблице.) Имеется таблица записей R1,
R2, : : : , RN, причем ключи удовлетворяют неравенствам K1 < K2 < : : : < KN. Алгоритм предназначается для поиска данного ключа K. В целях удобства и увеличения скорости работы предполагается, что в конце таблицы расположена фиктивная запись RN+1, ключ которой KN+1 = 1 > K.
Т1 [Начальная установка.] Установить i 1. Т2 [Сравнение.] Если K Ki, то перейти на Т4.
Т3 [Продвижение.] Увеличить i на 1 и вернуться к шагу Т2.
Т4 [Равенство?] Если K = Ki, то алгоритм оканчивается удачно. В противном случае—неудачно, нужной записи в таблице нет. 
Если величина K с равной вероятностью принимает все возможные значения, то в случае удачного поиска алгоритм T, по существу, не лучше алгоритма Q. Однако отсутствие нужной записи алгоритм Т дозволяет обнаружить примерно в два раза быстрее.
Приведенные выше алгоритмы в целях удобства использовали индексные обозначения для элементов таблицы; аналогичные процедуры применимы и к таблицам в связанном представлении, так как в них данные тоже расположены последовательно. (См. упр. 2, 3 и 4.)
Частота обращений. До сих пор предполагалось, что с равной вероятностью может потребоваться поиск любого аргумента, однако часто такое предположение не правомерно; вообще говоря, ключ Kj будет разыскиваться с вероятностью pi, где p1 +p2 + +pN = 1. Время удачного поиска при больших N пропорционально числу сравнений C, среднее .значение которого равно
|
|
|
CN = p1 + 2p2 + + NpN: |
(3) |
|
Пусть есть возможность помещать записи в таблицу в любом порядке; тогда величинаCN минимальна при
p1 p2 : : : pN; |
(4) |
т. е. когда наиболее часто используемые записи расположены в начале таблицы.
Посмотрим, что дает нам такое ”оптимальное” расположение при различных распределениях вероятностей. Если p1 = p2 = : : : = pN = 1=N, то формула (3) сводится к CN = (N + 1)=2, что уже было получено нами в (2). Предположим теперь, что
p1 = |
1 |
; p2 |
= |
1 |
; : : :; pN−1 |
= |
1 |
; pN = |
1 |
(5) |
|
|
|
|
|||||||
2 |
4 |
2N−1 |
2N−1 |
Согласно упр. 7, CN = 2 − 21−N; среднее число сравнений меньше двух, если записи расположены в надлежащем порядке. Другим напрашивающимся распределением является
p1 = Nc; p2 = (N − 1)c; : : :; pN = c;
|
|
|
|
|
|
Original pages: 457-482 253 |
где |
|
|
|
|
||
|
|
|
c = 2=N(N + 1): |
|
|
(6) |
Это ”клиновидное” распределение дает более привычный результат |
|
|
||||
|
|
|
X |
N + 2 |
|
|
|
|
|
k (N + 1 − k) = |
; |
(7) |
|
|
CN = c |
2 |
||||
1 |
k N |
|
|
|
||
оптимальное расположение экономит около трети поискового времени, требующегося для записей в случайном порядке.
Разумеется, распределения (5) и (6) довольно искусственны, и их нельзя считать хорошим приближением к действительности. Более типичную картину дает ”закон Зипфа”:
p1 = c=1; p2 = c=2; : : :; pN = c=N; где c = 1=HN: |
(8) |
Это распределение получило известность благодаря Дж. К Зипфу, который заметил, что n-е наиболее употребительное в тексте на естественном языке слово встречается с частотой, приблизительно обратно пропорциональной n. [The Psicho-Biology of Language (Boston, Mass.: Houghton Miffling, 1935); Human Behavior and the Principle of Least Effort (Reading, Mass.: Addison-Wesley, 1949).] Аналогичное явление обнаружено им в таблицах переписи; там столичные районы расположены в порядке убывания населения. В случае, если частота ключей в таблице подчиняется закону Зипфа, имеем
CN = N=HN; |
(9) |
поиск по такому файлу примерно в 12 lnN раз быстрее, чем по неупорядоченному. [Ср. с A. D. Booth et al. Mechanical Resolution of Linguistic Problems (New York: Academic Press, 1958), 79.)
Другое распределение, близкое к реальному, дает правило ”80–20”, которое часто встречается в коммерческих приложениях [ср. с W. P. Heising, IBM Systems J., 2 (1963), 114–115]. Это правило гласит, что 80% работы ведется над наиболее активной частью файла величиной 20%; оно применимо и к этим 20%, так что 64% работы ведется с наиболее активными 4% файла, и т. д. Иными словами,
p1 + p2 + + p:20n |
|
0:80 для всех n: |
(10) |
p1 + p2 + p3 + + pn |
|
|
Вот одно из распределений, точно удовлетворяющих приведенному правилу при n, кратных 5:
p1 = c; p2 = (2 − 1)c; p3 = (3 − 2 )c; : : : ; pN = (N − (N − 1) )c; |
(11) |
|||
где |
log 0:80 |
|
|
|
c = 1=N ; = |
= 0:1386: |
(12) |
||
log 0:20 |
||||
|
|
|
||
Действительно, p1+p2+ +pn = cn при любом n. С вероятностями (11) не так просто работать; имеем, однако, n −(n−1) ) = n −1(1+O(1=n)), т.е. существует более простое распределение, приближенно удовлетворяющее правилу ”80–20”:
p1 = c=11− ; p2 = c=21− ; : : : ; pN = c=N1− ; где c = 1=HN1− : (13)
Здесь, как и раньше, = log 0:80= log0:20, a HN(s) есть N-e гармоническое число порядка s, т. е. 1−s + 2−s + + N−s. Заметим, что это распределение очень напоминает распределение Зипфа (8); когда изменяется от 1 до 0, вероятности меняются от равномерно распределенных к зипфовским. (В самом деле, Зипф нашел, что 12 в распределении личных доходов.) Применяя (3) к (13), получаем для правила ”80–20” среднее число сравнений
CN = HN(− )=HN(1− ) = |
N |
+ O(N(1− )) 0:122N |
(14) |
+ 1 |
(см. упр. 8).
Ю. С. Шварц, изучавший частоты появления слов [см. интересный график на стр. 422 в JACM,
10 (1963)], предложил более подходящее выражение для закона Зипфа: |
|
|
p1 = c=11+ ; p2 = c=21+ ; : : : ; pN = c=N1+ ; |
где c = 1=H1+ ; |
(15) |
|
N |
|
254Original pages: 457-482
при малых положительных Q. [По сравнению с (13) здесь изменен знак .] В этом случае
|
N = HN=HN(1+ ) = N1− =(1 − ) (1 + ) + O(N1−2 ); |
|
C |
(16) |
что значительно меньше, чем (9) при N ! 1.
”Самоорганизующийся” файл. Предыдущие вычисления хороши, но в большинстве случаев распределение вероятностей нам не известно. Мы могли бы в каждой записи завести счетчик числа обращений, чтобы на основании показаний счетчиков переупорядочить записи. Выведенные формулы показывают, что такая процедура может привести к заметной экономии. Но не всегда желательно отводить много памяти под счетчики, так как ее можно использовать более рационально (например, применяя другие методы поиска, излагаемые ниже в данной главе).
Простая схема, происхождение которой не известно, используется уже многие годы. Она позволяет довольно хорошо упорядочить записи без вспомогательных полей для счетчиков: когда мы находим нужную запись, мы помещаем ее в начало таблицы. Подобный метод легко реализовать, когда таблица представлена в виде связанного линейного списка: ведь часто нам бывает нужно значительно изменить найденную запись.
Идея ”самоорганизующегося” метода состоит в том, что часто используемые элементы будут расположены довольно близко к началу таблицы. Пусть N ключей разыскиваются с вероятностями fp1; p2; : : :; pNg соответственно, причем каждый поиск совершается абсолютно независимо от предыдущих. Можно показать, что среднее число сравнений при нахождении записи в таком самооргани-
зующемся файле стремится к предельному значению |
|
|
|
|
|
|
|
||||
|
|
|
|
pipj |
|
1 |
+ |
|
pipj |
|
|
|
CN = 1 + 2 |
= |
|
: |
(17) |
||||||
|
|
pi + pj |
2 |
|
|
||||||
|
|
i<j |
|
|
|
i;j |
pi + pj |
|
|||
|
|
N |
|
|
|
|
|
|
|||
|
|
1 X |
|
|
|
|
|
X |
|
|
|
(См. упр. 11.) Например, если pi = 1=N при 1 i N, самоорганизующаяся таблица всегда находится в случайном порядке, а (17) сводится к знакомому выражению (N + 1)=2, полученному ранее.
Посмотрим, как самоорганизующаяся процедура работает при распределении вероятностей по
закону Зипфа (8). Имеем |
|
|
X |
|
|
|
|
|
|
|
|
X |
|
|
|
|||
|
|
|
1 |
|
(c=i)(c=j) |
1 |
|
|
|
1 |
|
|
||||||
|
CN = |
|
|
+ |
|
|
|
= |
|
|
+ c |
|
|
= |
|
|||
|
2 |
|
c=i + c=j |
2 |
i;j N |
i + j |
|
|||||||||||
|
|
|
|
|
1 i;j N |
|
|
|
|
|
|
1 |
|
X |
|
|||
|
|
|
1 |
X |
|
|
|
|
|
|
1 |
|
X |
|
|
|||
= |
|
2 |
+ c |
(HN+i − Hi) = |
|
2 |
+ c |
|
Hi |
− 2c |
Hi = |
|||||||
|
|
|
1 |
1 i N |
|
|
|
|
|
|
|
|
|
1 i 2N |
1 i N |
|
||
= |
+ c((2N + 1)H2N − 2N − 2(N + 1)HN + 2N) = |
|
||||||||||||||||
|
|
|
||||||||||||||||
2 |
|
|||||||||||||||||
= |
1 |
+ c(N ln4 − lnN + O(1)) |
|
|
|
|
||||||||||||
|
|
|
|
|
|
|||||||||||||
2 |
|
|
|
|
||||||||||||||
2N=log2N:
(см. формулы (1.2.7–8,3)). Это гораздо лучше, чем у N при достаточно больших N, и лишь в ln4 1:386 раз хуже, чем число сравнений при оптимальном расположении записей (ср. с (9)).
Эксперименты, приводившиеся с таблицами символов в компиляторах, показали, что самоорганизующийся метод работает даже лучше, чем предсказывает (18), так как удачные поиски не независимы (небольшие группы ключей часто появляются вместе).
Схему, подобную самоорганизующейся, изучили Г. Шай и Ф. В. Дауэр [SIAM J. Appl. Math., 15 (1967), 874–888.]
Поиск на ленте среди записей различной длины. Рассмотрим теперь нашу задачу в ином ракурсе. Пусть таблица, по которой производится поиск, хранится на ленте и записи имеют различные длины. Лента с системной библиотекой в старых операционных системах служит примером такого файла. Стандартные программы системы, такие, как компиляторы, компоновщики, загрузчики, генераторы отчетов и т. п., являлись ”записями” на ленте, а большинство пользовательских работ должно было начинаться с поиска нужной программы. Такая постановка задачи делает неприменимым предыдущий анализ алгоритма S: теперь шаг S3 выполняется за различные промежутки времени. Значит, нас будет интересовать не только число сравнений.
Обозначим через Li длину записи Ri, а через pi, вероятность того, что эта запись будет отыски-
ваться. Время поиска теперь примерно пропорционально величине |
|
p1L1 + p2(L1 + L2) + + pN(L1 + L2 + + LN): |
(19) |
Original pages: 457-482 255
При L1 = L2 = : : : = LN = 1 это, очевидно, сводится к изученному случаю (3).
Кажется логичным поместить наиболее нужные записи в начало ленты, но здесь здравый смысл подводит нас. Действительно, пусть на ленте записаны ровно две программы—A и B. Программа A требуется в два раза чаще B, но длиннее B в четыре раза, т. е. N = 2, pA = 23, LA = 4, pB = 13, LB = 1. Если мы, следуя ”логике”, поставим A на первое место, то среднее время поиска составит 23 4+ 13 5 = 133 ; но если поступить ”нелогично”, расположив в начале B, то получится 13 1+ 23 5 = 113 . Следующая теорема позволяет определить оптимальное расположение библиотечных программ на ленте.
Теорема S. Пусть Li и pi, определены, как и раньше. Порядок записей на ленте оптимален тогда и только тогда, когда
p1=L1 p2=L2 : : : pN=LN: |
(20) |
Иными словами, минимум выражения
pa1 La1 + pa2 (La1 + La2) + + paN (La1 + + LaN )
по всем перестановкам a1 a − 2 : : : aN чисел f1; 2; : : :; Ng равен (19) тогда и только тогда, когда выполняется (20).
Доказательство. Предположим, что Ri и Ri+1 поменялись местами; величина (19), ранее равная
+ pi(L1 + + Li−1 + Li) + pi+1(L1 + + Li+1) + ;
теперь заменится на
+ pi+1(L1 + + Li−1 + Li+1) + pi(L1 + + Li+1) + :
Изменение равно piLi+1 − pi+1Li. Так как расположение (19) оптимально, то piLi+1 − pi+1Li 0. Значит, pi=Li pi+1=Li+1, т. е. (20) выполняется.
Докажем теперь достаточность условия (20). Разумеется, ”локальная” оптимальность расположения (19) видна сразу: если мы поменяем местами две записи, время поиска изменится на piLi+1 − pi+1Li 0. Однако ”глобальная” оптимальность требует обоснования. Мы рассмотрим два доказательства: одно из них использует дискретную математику, а другое предполагает некоторую математическую изворотливость.
Доказательство. 1. Пусть (20) выполняется. Мы знаем, что любую перестановку записей можно ”отсортировать”, т. е. привести к расположению R1, R2, : : : , RN, последовательно меняя местами лишь соседние элементы. Каждое такое изменение переводит : : : Rj Ri: : : в : : : Ri Rj: : : для некоторых i < j, т. е. уменьшает время поиска на неотрицательную величину piLj −pjLi. Значит, порядок R1 R2
: : : RN оптимален.
Доказательство. 2. Заменим вероятности pi на
pi(") = pi + "i − ("1 + "2 + + "N)=N;
где "—малая положительная величина. Равенство x1p1(") + + xN pN(") = y1p1(") + + yNpN(") выполняется для достаточно малых " лишь при x1 = y1, : : : , xN = yN; в частности, в (20) станут
невозможными равенства pi = pj Рассмотрим N! перестановок записей. Среди них есть по крайней
Li Lj
мере одна оптимальная; в силу первой части теоремы она удовлетворяет (20), но в силу отсутствия равенств условию (20) удовлетворяет лишь одна перестановка. Таким образом, (20) однозначно определяет оптимальное расположение записей в таблице для вероятностей pi(") при достаточно малых ". По непрерывности этот же порядок оптимален и при ". (Такой метод доказательств часто используется в комбинаторной оптимизации.) 
Теорема S принадлежит У. Э. Смиту [Naval Research Logistics Quarterly, 3 (1956), 59–66]. Упражнения содержат дополнительные результаты по оптимальной организации таблиц.
Уплотнение файлов. Последовательный поиск на ленте и других внешних запоминающих устройствах протекает быстрее; если данные занимают меньше места, поэтому полезно рассмотреть несколько различных способов представления данных в таблице. Не всегда нужно запоминать ключи в явном виде.
Пусть, например, требуется таблица простых чисел до миллиона для разложения на множители 12-значных чисел. (Ср. с п. 4.5.4.) Таких чисел имеется 78498; используя 20 битов для каждого из них,
256Original pages: 457-482
мы получим файл длины 1 569 960 битов. Это явное расточительство, так как можно иметь миллионбитовую таблицу, в которой разряды, соответствующие простым числам, равны 1. Поскольку все простые числа (кроме двойки) нечетны, достаточно иметь таблицу в 500000 битов.
Другим способом уменьшения длины файла является хранение не самих простых чисел, а интервалов между ними. В соответствии с табл. 1 величина (pk+1 − pk)=2 меньше 64 для всех простых чисел в пределах 1 357 201, т. е. нам достаточно запомнить 78 496 шестиразрядных чисел (размер интервала)/2. Такая таблица имеет длину примерно 471 000 битов. Дальнейшего уплотнения можно добиться, используя для представления интервалов двоичные коды переменной длины (ср. с п 6.2.2).
Таблица 1 Таблица интервалов между последовательными простыми числами
Интервал (pk+1 − pk) |
pk |
Интервал (pk+1 − pk) |
pk |
1 |
2 |
52 |
19609 |
2 |
3 |
72 |
31397 |
4 |
7 |
86 |
155921 |
6 |
23 |
96 |
360653 |
8 |
89 |
112 |
370261 |
14 |
113 |
114 |
492113 |
18 |
523 |
118 |
1349533 |
20 |
887 |
132 |
1357201 |
23 |
1129 |
148 |
2010733 |
34 |
1327 |
154 |
4652353 |
36 |
9551 |
180 |
17051707 |
44 |
15683 |
310 |
20831323 |
|
|
|
|
Втаблице помещены интервалы pk+1 −pk, превышающие pj+1 −pj для всех j < k. Более подробно см. F. Gruenberger, G. Armerding, ”Statistics on the first six million prime numbers”, RAND Corp. report P-2460 (October, 1961).
Упражнения
1.[М20] Пусть все ключи, по которым проводится поиск, равновероятны. Определите среднеквадратичное отклонение числа сравнений при удачном поиске в таблице из N записей.
2.[16] Измените алгоритм S, приспособив его для работы с таблицами в связанном представлении. (Если P указывает на запись в таблице, то предполагается, что KEY(P) есть ключ, INFO(P)— ассоциированная информация и LINK(P)—указатель на следующую запись. Кроме того, предполагается, что FIRST указывает на первую запись, а последняя запись указывает на .)
3.[16] Напишите MIX-программу для алгоритма упр. 2. Выразите время работы вашей программы через величины C и S, определенные в (1).
>3. [17] Применима ли идея алгоритма Q к таблицам в связанном представлении? (Ср. с упр. 2.)
5.[20] Программа Q0, разумеется, заметно быстрее программы Q при больших C. Существуют ли малые величины C и S, при которых программа Q0 требует больше времени, чем Q?
>6. [20] Увеличив программу Q0 на три команды, сведите время ее работы к (3:33C + const)u.
7.[М20] Определите среднее число сравнений (3), используя ”бинарное” распределение (5).
8.[ВМ22] Найдите асимптотический ряд для Hn(x) при n ! 1; x 6= 1.
>9. [М23] В тексте замечено, что распределения вероятностей (11) и (13) приблизительно эквивалентны и что среднее число сравнений в (13) равно N=( +1)+O(N1− ). Равно ли этому же числу среднее число сравнений при использовании распределения (11)?
10.[М20] Наилучшее расположение записей в таблице определяется формулой (4); каковонаихудшее расположение? Покажите, что средние числа сравнений при наихудшем и наилучшем расположениях связывает простое соотношение.
11.[М30] Целью этого упражнения является анализ поведения самоорганизующегося файла. Сна-
чала необходимо ввести довольно сложные обозначения. Положим fm(x1; x2; : : : ; xm) равным
бесконечной сумме всех различных упорядоченных произведении xi1 xi2 : : : xik , где 1 i1, : : : , ik m и каждое xi, 1 i m, входит во все произведения. Например,
f2 |
X |
|
x y |
|
1 |
1 x + |
1 |
1 y : |
|||
(x; y) = j;k 0(x1+jy(x + y)k + y1+jx(x + y)k) = 1 |
|
||||||||||
|
|
|
xy |
|
|
|
|
|
|
|
|
|
|
− |
− |
|
|
− |
|
− |
|||
|
|
|
|
|
|
|
|
|
|
||
258 Original pages: 483-535
времени, где через d(i; j) обозначен промежуток времени, требующийся на поиск от i-й до j-й позиции. Эта модель применима, например, к поиску на диске [d(i; j)—время перемещения между i-м и j-м цилиндрами].
Результаты данного упражнения позволяют охарактеризовать оптимальное расположение записей при сцепленном поиске. Рассмотрим случай, когда d(i; j) есть возрастающая функция от ji − jj, т. е. d(i; j) = dji−jj; d1 < d2 < : : : < dN−1. (Значение d0 безразлично.) Докажите, что в данном случае расположение записей R1 : : : RN будет наилучшим среди всех N! перестановок тогда и только тогда, когда или p1 pN p2 pN−1 : : : pbN=2c+1,
Picture: Рис. 2.Расположение в виде органных труб минимизирует среднее время сцепленного поиска.
или pN p1 pN−1 p2 : : : pdN=2e. (Значит, показанное на рис. 2 расположение в виде ”органных труб” оптимально.) [Указание. Рассмотрите произвольное расположение, которому соответствуют вероятности q1 q2 : : :qk s rk : : : r2 r1 t1 : : : tm, m 0, k > 0; N = 2k + m + 1. Покажите, что другое
расположение q10 q20 : : : qk0 s rk0 : : : r20 r10 t1 : : : tm лучше, если qi0 = min(qi; ri) и ri0 = max(qi; ri) (исключая случай qi0 = qi и ri0 = ri для всех i и случай qi0 = ri, ri0 = qi, tj = 0 для всех i и j). Утверждение верно и при отсутствии s, когда N = 2k + m.]
19.[М20] (Продолжение упр. 18.) Пусть функция d(i; j)обладает свойством d(i; j)+d(j; i) = cдля всех i и j. Найдите оптимальное расположение для сцепленных поисков. [Такая ситуация встречается при поиске на лентах, когда не предусмотрена возможность читать в обратном направлении
и мы не знаем нужного направления поиска; при i < j имеем d(i; j) = a + b(Li+1 + + Lj)
и d(j; i) = a + b(Lj+1 + + LN) + r + b(L1 + + Li), где r—время перемотки ленты. ]
20.[М28] (Продолжение упр. 18.) Найдите оптимальный порядок записей для сцепленных поисков,
если d(i; j) = min(dji−jj; dn−ji−jj) и d1 < d2 < : : :. [Такая модель применима для исследования поиска в циклическом списке с двумя связями или запоминающем устройстве с возможностью сдвига в обе стороны.]
21.[М28] Рассмотрим n-мерный куб, вершины которого имеют координаты (dn; : : :; d1), di = 0 или 1. Две вершины называются соседними, если у них различаются точно по одной координате. Пред-
положим, что 2n чиселP x0 x1 : : : x2n−1 должны быть поставлены в соответствие 2n вершинам так, чтобы сумма jxi − xjj была минимальна; сумма берется по всем i и j, таким, что xi и xj поставлены в соответствие соседним вершинам. Докажите, что минимум достигается, когда при всех i значение xi присвоено вершине, координаты которой являются двоичным представлением i.
>22. [20] Предположим, что в большом файле нужно найти 1000 ближайших к данному ключу записей, т. е. 1000 записей, придающих наименьшие значения некоторой функции расстояния d(Ki; K). Какая структура данных лучше всего подходит для последовательного поиска в этом случае?
6.2.ПОИСК ПОСРЕДСТВОМ СРАВНЕНИЯ КЛЮЧЕЙ
Вэтом параграфе мы рассмотрим методы поиска, основанные на линейном упорядочении ключей (например, порядок может быть числовым или алфавитным). После сравнения данного аргумента K
сключом Ki из таблицы поиск продолжается одним из трех способов в зависимости от того, какое из соотношений верно: K < Ki, K = Ki, K > Ki. При последовательном поиске мы, в сущности, должны выбирать одно из двух продолжений (K = Ki или K 6= Ki), но если мы освободимся от ограничения иметь лишь последовательный доступ к таблице, то получим возможность эффективно использовать отношение порядка.
6.2.1. Поиск в упорядоченной таблице
Что вы станете делать, если вам вручат большую телефонную книгу и попросят найти имя человека, номер телефона которого 795-68-41? За неимением лучшего придется воспользоваться методами последовательного поиска, изложенными в x 6.1. (Правда, ловкий частный детектив мог бы попытаться набрать номер и спросить, кто говорит; не исключено также, что у него есть друзья на телефонной станции, имеющие доступ к справочникам, где телефоны расположены в порядке возрастания номеров.) Дело в том, что гораздо легче найти запись по фамилии абонента, а не по номеру, хотя телефонная книга содержит всю информацию, нужную в обоих случаях. Если необходимо найти запись в большом файле, о последовательном поиске почти не может быть речи, но использование отношения порядка в огромной степени облегчает работу.
В нашем распоряжении есть много методов сортировки (гл. 5), поэтому для нас не составит труда упорядочить файл, чтобы затем быстрее произвести поиск. Разумеется, если нужен лишь однократный просмотр, то быстрее произвести его последовательно, без предварительной сортировки. Но если
Original pages: 483-535 259
в одной и той же таблице приходится часто производить поиск, то эффективнее упорядочить ее. В этом пункте мы изучим методы поиска в таблицах со случайным доступом и упорядоченными ключами
|
K1 < K2 < : : : < KN: |
После сравнения K и Ki мы имеем или |
|
K < Ki |
[Ri, Ri+1, : : : , RN исключаются из рассмотрения], |
или K = Ki |
[поиск закончен], |
или K > Ki |
[R1, R2, : : : , Ri исключаются из рассмотрения]. |
Умело действуя в каждом из этих случаев, мы сэкономим много времени по сравнению с последовательным поиском, если только i не слишком близко к концам таблицы. Таким образом, упорядочение ведет к эффективным алгоритмам.
Бинарный поиск. Пожалуй, первым приходит в голову следующий очевидный метод: сначала сравнить K со средним ключом в таблице. Результат сравнения позволит определить, в какой половине файла продолжить поиск, применяя к ней ту же процедуру, и т. д. После не более чем примерно log2 N сравнений либо ключ будет найден, либо будет установлено его отсутствие. Такая процедура иногда называется ”логарифмическим поиском” или ”методом деления пополам”, но наиболее употребительный термин—бинарный поиск.
Основная идея бинарного поиска довольно проста, детали же нетривиальны, и для многих хороших программистов не одна попытка написать правильную программу закончилась неудачей. Одна из наиболее популярных реализации метода использует два указателя—l и u, соответствующие верхней и нижней границам поиска, и состоит в следующем.
Алгоритм В. (Бинарный поиск.) С помощью данного алгоритма разыскивается аргумент K в таблице записей R1, R2, : : : , RN, ключи которых расположены в возрастающем порядке: K1 < K2 <
: : : < KN.
В1 [Начальная установка.] Установить l 1, u N.
В2 [Нахождение середины.] (В этот момент мы знаем, что если K есть в таблице, то выполняются неравенства Kl K Ku. Более точное описание ситуации приводится ниже, в упр. 1.) Если u < l, то алгоритм заканчивается неудачно; в противном случае установить i b(l + u)=2c: теперь i указывает примерно в середину рассматриваемой части таблицы.
В3 [Сравнение.] Если K < Ki, то перейти на В4; если K > Ki, то перейти на В5; если K = Ki,
алгоритм заканчивается удачно. |
i − 1 и вернуться к шагу В2. |
|
В4 [Корректировка u]. Установить u |
||
В5 [Корректировка l.] Установить l |
i + 1 и вернуться к шагу В2. |
|
Picture: Рис. 3. Бинарный поиск.
Рисунок 4 иллюстрирует поведение алгоритма В в двух случаях: когда разыскивается аргумент, равный имеющемуся в таблице числу 653, и когда разыскивается отсутствующий аргумент 400. Скобки соответствуют указателям l и u, подчеркнутый ключ представляет Ki. В обоих случаях поиск кончается после четырех сравнений.
Программа B. (Бинарный поиск.) Как и в программах x 6.1, предполагается, что Ki занимает полное слово по адресу KEY + i. Приводимая ниже программа использует rI1 l, rI2 u, rI3 i.
a) Поиск числа 653: |
|
|
[061 087 154 170 275 426 503 509 512 612 653 677 703 |
765 897 |
908] |
061 087 154 170 275 426 503 509 [512 612 653 677 703 |
765 897 |
908] |
061 087 154 170 275 426 503 509 [512 612 653] 677 703 |
765 897 |
908 |
061 087 154 170 275 426 503 509 512 612 [653] 677 703 765 897 |
908 |
|
b) Поиск числа 400: |
|
|
[061 087 154 170 275 426 503 509 512 612 653 677 703 |
765 897 |
908] |
[061 087 154 170 275 426 503] 509 512 612 653 677 703 |
765 897 |
908 |
061 087 154 170 [275 426 503] 509 512 612 653 677 703 |
765 897 |
908 |
061 087 154 170 [275] 426 503 509 512 612 653 677 703 765 897 |
908 |
|
061 087 154 170 275][426 503 509 512 612 658 677 703 |
765 897 |
908 |
Рис. 4. Примеры бинарного поиска.
260 Original pages: 483-535
START |
ENT1 |
1 |
1 |
|
Bl. Начальная установка. l 1. |
||
|
|
ENT2 |
N |
1 |
|
u |
N. |
|
|
JMP |
2F |
1 |
|
На B2. |
|
5H |
JE |
SUCCESS |
C1 |
Переход, если K = Ki. |
|||
|
|
ENT1 |
1,3 |
C1 − S |
B5. |
Корректировка l. l l + 1. |
|
2H |
ENTA |
0,1 |
C + 1 |
− S B2. |
Нахождение середины. |
||
|
|
INCA |
0,2 |
C + 1 |
− S rA |
l + u. |
|
|
|
SRB |
1 |
C + 1 |
− S rA |
brA=2c. (Меняется и rX.) |
|
|
|
STA |
TEMP |
C + 1 |
− S |
|
|
|
|
CMP1 |
TEMP |
C + 1 |
− S |
|
|
|
|
JG |
FAILURE |
C + 1 |
− S Переход, если u < l. |
||
|
|
LD3 |
TEMP |
C |
|
i |
середина. |
3H |
LDA |
K |
C |
|
B3. |
Сравнение. |
|
|
|
СМРА |
KEY,3 |
C |
|
Переход, если K Ki. |
|
|
|
JGE |
5B |
C |
|
||
|
|
ENT2 |
-1,3 |
C2 |
B4. |
Корректировка u. |
|
|
|
JMP |
2B |
C2 |
На B2. |
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Данная процедура ”реализуется” на машине MIX менее удачно, чем предыдущие, так как регистровая арифметика в MIX небогата. Время, работы программы равно (18C − 10S + 12)u, где
Picture: |
Рис. 5. Бинарное дерево, соответствующее бинарному поиску (N = 16). |
C = C1 + C2—количество произведенных сравнений (сколько раз выполняется шаг B3), S = 1 или 0 в зависимости от удачного или неудачного исхода. Заметим, что строка 08 программы расшифровывается как ”сдвиг вправо на 1” (shift right binary 1), что допустимо лишь в двоичных версиях MIX; в общем случае ее следует заменить на ”MUL =1//24+1=”, тогда время работы программы увеличится до (26C − 18S + 20)u.
Представление в виде дерева. Чтобы досконально разобраться в алгоритме B, лучше всего представить его в виде бинарного дерева решений. (На рис. 5 показано такое дерево для случая N = 16.)
При N = 16 первым производится сравнение K : K8, что представлено на рисунке корневым узлом (8). Далее, если K < K8, алгоритм обрабатывает левое поддерево, сравнивая K и K4, аналогично, если K > K8, используется правое поддерево. Неудачный поиск ведет в один из ”внешних”
квадратных узлов, занумерованных от 0 до N ; например, мы достигнем узла 6 тогда и только тогда, когда K6 < K < K7.
Бинарное дерево, соответствующее бинарному поиску среди N записей, можно построить следу-
ющим образом: при N = 0 дерево сводится к узлу 0 . В противном случае корневым узлом является
Picture: Рис. стр. 487
левое поддерево соответствует бинарному дереву с dN=2e−1 узлами, а правое—дереву с bN=2c узлами и числами в узлах, увеличенными на dN=2e.
Аналогичным образом любой алгоритм поиска в упорядоченной таблице длины N, производимого путем сравнений, можно представить бинарным деревом с узлами, помеченными числами от 1 до N (предполагается, что алгоритм не содержит лишних сравнений). Обратно, любое бинарное дерево соответствует некоторому методу поиска в упорядоченной таблице; мы просто помечаем узлы
Picture: |
Рис. стр. 487 |
в симметричном порядке слева направо.
Если аргумент поиска в алгоритме B есть K10, то производятся сравнения K > K8, K < K12, K = K10. На рис. 5 это соответствует пути от корня к узлу (10). Аналогично поведение алгоритма B при других K соответствует иным путям, ведущим из корня дерева. С помощью метода построения бинарных деревьев, соответствующих алгоритму B, и индукции по N легко доказывается

