Скачиваний:
83
Добавлен:
01.05.2014
Размер:
3.82 Mб
Скачать

Original pages: 378-399 211

требуется начальный отрезок; это дает S = 100. Вот некоторые ключевые шаги процесса:

A1

A1

A1

A1

A1

A1A4

: : : : : : : : :: : : : : : : : :: : : : : : : : : :: : : : : : : : : :: : : : : : : :

A1 A1 A1 A1

A1A4

A1A4

A1A4

A1A4

A1A4

: : : : : : : : :: : : : : : : : :: : : : : : : : : :: : : : : : : : : :: : : : : : : :

A1

A1A4

A1A4

A1A4

A1A4

A1A4

A1A4

A1A4

A1A4

A1A4

A1A4A16

: : : : : : : : :: : : : : : : : :: : : : : : : : : :: : : : : : : : : :: : : : : : : :

— A1A4

A1A4 A1A4 A1A4A16A64

A4

A1A4

A1A4 A1A4 A1A4A16A64

A4A16

— —

A1A4A16A64

A4A16

A4

A1A4A16A64

— — A36 A1A4A16A64

A100 — — — —

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

Оценка времени выполнения. Посмотрим теперь, как вычислить приблизительное время выполнения метода сортировки, использующего ленты MIXT. Можно ли предсказать результаты, изображенные на схеме A, не выполняя детального моделирования?

Один способ, который традиционно использовался для сравнения различных схем слияния, состоит в том, чтобы наложить друг на друга графики, подобные представленным на рис. 70, 74 и 78. Эти графики изображают эффективное число проходов по данным как функцию от числа начальных отрезков в предположении, что все начальные отрезки имеют примерно равную длину (рис. 85). Но это не дает очень реалистичного сравнения, потому что, как мы видели, разные методы приводят к различному числу начальных отрезков; кроме того, имеются различные ”накладные расходы”, зависящие от относительной частоты межблочных промежутков; значительное воздействие оказывает также время перемотки. Все эти зависящие от машины особенности делают невозможным подготовить на машинно-независимой основе схемы, осуществляющие истинное сравнение методов. С другой стороны, из рис. 85 все же явствует, что, за исключением сбалансированного слияния, эффективное число проходов может быть достаточно хорошо аппроксимировано плавными кривыми вида lnS+ . Следовательно, мы можем неплохо сравнивать методы в любой практической ситуации, изучив формулы, аппроксимирующие время выполнения. Конечно, наша цель—найти формулы простые, но достаточно реалистичные.

Picture:

Рис. 85. Несколько обманчивый способ сравнения схем слияния.

Попытаемся теперь вывести такие формулы в терминах следующих параметров:

N = число сортируемых записей; C = число литер в записи;

M = число доступных литерных позиций внутренней памяти (предполагаемое кратным C);= время в секундах, нужное для того, чтобы прочитать или записать одну литеру;

= время в секундах для перемотки одной литеры;

= время в секундах стартстопной задержки;

γ= число литер в межблочном промежутке;

= время в секундах, нужное оператору для снятия и замены вводной ленты; Bi = число литер в блоке неотсортированного ввода;

Bo = число литер в блоке отсортированного вывода.

Для MIXT имеем = 1=60 000, = 2=5, = 300, γ = 480. В примере, рассмотренном выше, N = 100 000, C = 100, M = 100 000, Bi = Bo = 5000, = 30. Обычно именно эти характеристики машины и данных решающим образом влияют на время сортировки (хотя время перемотки часто задается более сложным выражением, чем просто коэффициентом ). Имея указанные параметры и схему слияния,

212Original pages: 378-399

вычислим еще некоторые величины:

P = максимальный порядок слияния в схеме;

P0 = число записей в дереве выбора с замещением;

S= число начальных отрезков;

= lnS + = приблизительное среднее число чтений и записей каждой литеры, не считая на-

чального распределения и окончательного слияния;

0 = 0 lnS + 0 = приблизительное среднее число перемоток каждой литеры во время промежуточных фаз слияния;

B = число литер в блоке в промежуточных фазах слияния;

!i; !; !o = ”коэффициенты накладных расходов”—эффективные времена, требуемые для чтения или записи одной литеры (с учетом промежутков и стартстопного времени), деленные на время .

Впримерах схемы A размеры блоков и буферов выбраны в соответствии с формулой

B =

M

C;

(1)

C(2P + 2)

так чтобы блоки могли быть самыми большими, какие возможны при условии совместимости со схемой буферизации алгоритма F. (Чтобы избежать забот во время последнего прохода, величина P должна быть достаточно малой, чтобы (1) обеспечило B Bo.) Размер дерева во время выбора с замещением будет, следовательно,

P0 = (M − 2Bi − 2B)=C:

(2)

Для случайных данных число начальных отрезков можно оценить, используя результаты п. 5.4.1,

формулой

 

 

 

 

 

S

N

+

7

:

(3)

 

 

2P0

6

Предполагая, что Bi < B и что вводная лента во время распределения может работать с полной скоростью (см. ниже), распределение начальных отрезков займет примерно NC!i с, где

!i = (Bi + γ)=Bi:

(4)

Во время слияния схема буферизации допускает совмещение чтения, записи и вычислений, но частое переключение вводных лент означает, что мы должны учесть стартстопное время; поэтому положим

! = (B + γ + )=B

(5)

и время слияния оценим формулой

 

( + 0)NC! :

(6)

Эта формула слегка преувеличивает время перемотки, так как ! включает стартстопное время, но другие соображения (такие, как взаимная блокировка перемоток и потери на чтение с точки загрузки) обычно компенсирует это. Окончательный проход слияния в предположении Bo B ограничивается коэффициентом накладных расходов

!o = (Bo + γ)=Bo:

(7)

Мы можем оценить время выполнения последнего слияния и перемотки как

NC(1 + )!o ;

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

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

a) Может ли выбор с замещением успеть за вводной лентой? В примере на схеме A, вероятно, может, так как для выбора новой записи требуется около десяти итераций внутреннего цикла алгоритма 5.4.1R, и мы имеем время C!i > 1667 мкс, за которое

Original pages: 378-399 213

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

b) Должны, ли мы на самом деле выбирать в качестве B максимально возможный размер буфера, как в (1)? Большой размер буфера сокращает отношение издержек ! в (5), но он также увеличивает число начальных отрезков S, так как P0 уменьшается. Непосредственно не ясно, какой фактор более важен. Рассматривая время слияния как функцию

от x = CP0, можно выразить его в виде

 

 

 

 

 

 

 

 

 

1 ln

N

 

7

 

 

 

3

x

 

 

 

 

+

 

+ 2

4

x

(8)

x

6

 

 

 

 

 

 

 

 

 

 

 

для некоторых подходящих констант 1, 2, 3, 4, причем 3 > 4. Дифференцирование по x показывает, что есть некоторое N0, такое, что для всех N N0 невыгодно увеличивать x за счет размера буфера. В примерах, приведенных на схеме A, N0 оказалось, грубо говоря, равным 10 000; при сортировке более 10 000 записей большой размер буфера предпочтительнее.

Заметим, однако, что при сбалансированном слиянии число проходов резко изменяется, когда S проходит через степень P. Если заранее известно приближенное значение N, то размер буфера следует выбрать так, чтобы S с большой вероятностью оказалось немного меньше степени P. Например, размер буфера для первой строки схемы A был равен 12 500, так как S = 78. Это было вполне удовлетворительно, но если бы S оказалось равным 82, то было бы значительно лучше немного уменьшить размер буфера.

Формулы для десяти примеров. Возвращаясь к схеме A, попытаемся дать формулы, аппроксимирующие время работы для каждого из десяти методов. В большинстве случаев основная формула

NC!i + ( + 0)NC! + (1 + )NC!o

(9)

будет достаточно хорошим приближением к суммарному времени сортировки, если мы определим число промежуточных проходов слияния = lnS + и число промежуточных проходов перемотки 0 = 0 lnS + . Иногда необходимо внести в (9) некоторую поправку; специфика каждого метода учитывается следующим образом:

Пример 1. Сбалансированное слияние с прямым чтением. Формулы

= dlnS= lnPe − 1; 0 = dlnS= lnPe=P

могут быть использованы для P-путевого слияния с 2P лентами.

Пример 2. Многофазное слияние с прямым чтением. Можно положить 0 , так как за каждой фазой обычно следует перемотка приблизительно такой же длины, как предшествующее слияние. Из табл. 5.4.2-1 получаем в случае шести лент значения = 0:795, = 0:846 − 2. (Величина ”−2” возникает из-за того, что элементы таблицы включают наряду с промежуточными проходами также начальный и конечный.) К (9) нужно добавить время перемотки вводной ленты после начального распределения, а именно NC!i + .

Пример 3. Каскадное слияние с прямым чтением. Таблица 5.4.3-1 приводит к значениям = 0:773, = 0:808−2. Время перемотки сравнительно трудно оценить; возможно, предположение 0 = достаточно точно. Как и в примере 2, мы должны добавить к (9) время начальной перемотки.

Пример 4. Многофазное слияние с расщеплением лент. Из табл. 5.4.2-5 получаем = 0:752,

= 1:024 − 2. Время перемотки почти все совмещается, за исключением перемотки после начальной установки ( NC!i + ) и двух фаз вблизи конца (36% от 2 NC! ). Мы можем также вычесть 0:18 из , так как первая половина фазы совмещается с начальной перемоткой.

Пример 5. Каскадное слияние с совмещением перемотки. Здесь, используя табл. 5.4.3-1 для T = 5, получаем = 0:897, = 0:800−2. Почти вся несовмещенная перемотка встречается непосредственно после начального распределения и после каждого двухпутевого слияния. После точного начального распределения самая длинная лента содержит примерно 1=g всех данных, где g есть ”отношение роста”. После каждого двухпутевого слияния объем перемотки в случае шести лент равен dkdn−k (см. упр. 5.4.3-5), и можно показать, что в случае T лент объем перемотки после двухпутевых слияний приблизительно равен

(2=(2T − 1))(1 − cos(4 =(2T − 1)))

214Original pages: 400-414

от всего файла. В нашем случае (T = 5) это составляет 29(1 − cos80 ) 0:183 файла, и это происходит в

0:946 lnS + 0:796 − 2 случаях.

Пример 6. Сбалансированное слияние с обратным чтением. Оно напоминает пример 1, за исключением того, что значительная часть перемотки устраняется. Изменение направления от прямого к

обратному вызывает некоторые задержки, но они не существенны. С вероятностью 1=2 перед последним проходом нужна будет перемотка, поэтому можно взять 0 = 1=(2P).

Пример 7. Многофазное слияние с обратным чтением. Так как в этом случае выбор с замещением

порождает отрезки, меняющие направление примерно каждые P раз, то следует заменить (3) другой формулой для S. Достаточно хорошим приближением (см. упр. 5.4.1-24) будет S = dN(3 + 1=P)6P0e+ 1. Все время перемотки устраняется, и табл. 5.4.2-1 дает = 0:863, = 0:921 − 2.

Пример 8. Каскадное слияние с обратным чтением. Из табл. 5.4.3-1 имеем = 0:897, = 0:800−2. Время перемотки по этой таблице можно оценить как удвоенную разность [”проходы с копированием” минус ”проходы без копирования”] плюс 1=(2P) в том случае, если перед окончательным слиянием необходима перемотка для получения возрастающего порядка.

Пример 9. Осциллирующая сортировка с обратным чтением. В этом случае выбор с замещением должен много раз начинаться и останавливаться; за один раз распределяется серия от P − 1 до 2P − 1

отрезков (в среднем P); средняя длина отрезков, следовательно, оказывается приблизительно равной P0(2P − 4=3)=P, и можно оценить S = dN=((2 − 4=(3P))P0)e + 1. Некоторое время расходуется на

переключение от слияния к распределению и обратно; это приблизительно время, требуемое, чтобы прочитать с вводной ленты P0 записей, а именно P0C!i , и это происходит примерно S=P раз. Время перемотки и время слияния можно оценить, как в примере 6.

Пример 10. Осциллирующая сортировка с прямым чтением. Этот метод нелегко проанализировать, поскольку окончательная фаза ”чистки”, выполняемая после исчерпания ввода, не так эффек-

тивна, как предыдущие. Пренебрегая этим трудным аспектом и просто считая, что есть один дополнительный проход, можно оценить время слияния, полагая = 1= lnP, = 0 и 0 = =P. Распределение

отрезков в этом случае несколько иное, так как не используется выбор с замещением; мы устанавливаем P0 = M=C и S = dN=P0e. Приложив усилия, можно совместить вычисление, чтение и запись во время распределения, вводя дополнительный коэффициент накладных расходов около (M + 2B)=M. Время переключении режимов, упомянутое в примере 9, в настоящем случае не нужно, так как оно совмещается с перемоткой. Итак, оценкой времени сортировки будет (9) плюс 2BNC!i =M.

 

 

 

 

 

 

 

 

 

 

 

 

 

Таблица 1

 

 

 

 

 

 

Сводная таблица оценок времени сортировки

 

 

Пример P

B

P0

S

!

 

 

0

0

(9)

Добавка к (9) Оценка итога Реальный итог

1

3

12500 650

79 1:062 0:910 −1:000 0:303

0:000 1064

 

1064

1076

2

5

8300 734

70 1:094 0:795 −1:136 0:795

−1:136 1010

NC!i +

1113

1103

3

5

8300 734

70 1:094 0:773 −1:192 0:773

−1:192 972

NC!i +

1075

1127

4

4

10000 700

73 1:078 0:752 −0:994 0:000

0:720

844

NC!i +

947

966

5

4

10000 700

73 1:078 0:897 −1:200 0:173

0:129

972

 

972

992

6

3

12500 650

79 1:062 0:910 −1:000 0:000

0:167

981

 

981

980

7

4

10000 700

79 1:078 0:863 −1:079 0:000

0:000

922

 

922

907

8

4

10000 700

73 1:078 0:897

−1:200 0:098

0:117

952

P0SC!i =P

952

949

9

4

10000 700

87 1:078 0:721

−1:000 0:000

0:125

846

874

928

10

4

10000

100 1:078 0:721

0:000 0:180

0:000 1095

2BNC!i =M

1131

1158

Табл. 1 показывает, что оценки в этих примерах не слишком плохи, хотя в нескольких случаях расхождение составляет порядка 50 с. Формулы в примерах 2 и 3 показывают, что каскадное слияние должно быть предпочтительней многофазного на шести лентах, тем не менее на практике многофазное слияние лучше! Причина этого кроется в том, что графики, подобные изображенным на рис. 85 (где показан случай пяти лент), ближе к прямым линиям для многофазного алгоритма; каскадный метод превосходит многофазный на шести лентах для 14 S 15 и 43 S 55 вблизи ”точных” каскадных чисел 15 и 55, но многофазное распределение по алгоритму 5.4.2D лучше или эквивалентно для всех остальных S 100. Каскадный метод предпочтительнее многофазного при S ! 1, но фактически S не приближается к 1. Заниженная оценка в примере 9 обусловлена аналогичными обстоятельствами; многофазная сортировка лучше осциллирующей, несмотря на то что асимптотическая теория говорит нам, что для больших S осциллирующая сортировка будет наилучшей.

Несколько дополнительных замечаний. Сейчас самое время сделать несколько более или менее случайных наблюдений относительно ленточного слияния:

Original pages: 400-414 215

1) Приведенные формулы показывают, что сортировка является, в сущности, функцией от произведения N и C, а не от N и C порознь. За исключением нескольких относительно незначительных соображений (например, что B выбирается кратным C), из наших формул следует, что сортировка одного миллиона записей по 10 литер каждая займет примерно столько же времени, что и сортировка 100000 записей по 100 литер каждая. На самом деле здесь может появиться различие, не обнаружимое в наших формулах, так как во время выбора с замещением некоторое пространство используется для полей связи. В любом случае размер ключа едва ли окажет какое-либо влияние, если только ключи не будут столь длинными и сложными, что внутренние вычисления не смогут угнаться за лентами.

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

2)Мы видели, что требуется от 15 до 19 мин, чтобы отсортировать 100000 записей по 100 литер при соблюдении наших предположений. Сколько времени заняла бы их сортировка на карточном сортировщике? Этот вопрос имеет практический интерес потому, что карточные сортировщики дешевле

ЭВМ. Допуская, что каждая запись может быть втиснута в 80-колонную карту и что алфавитный ключ

занимает шесть колонок, причем для сортировки по каждой колонке требуется в среднем 123 прохода, получаем, что мы должны пропустить каждую карту через машину примерно 10 раз. При скорости 1000 карт в минуту это заняло бы 1000 мин, т. е. почти 17 ч. (Имеется весьма большая вероятность, что за это время некоторые карты окажутся нечаянно ”перепутанными” или будут ”замяты” в машине.)

3)При написании программы сортировки, которая должна использоваться многократно, разумно очень тщательно оценить время работы и сравнить теорию с действительными наблюдаемыми характеристиками выполнения. Так как теория сортировки развита довольно хорошо, то эта процедура, как известно, способна внезапно выявить дефекты в оборудовании или программном обеспечении ввода/вывода в существующих системах. Оказывается обслуживание работало медленнее, чем следовало, и никто этого не замечал, пока это не проявилось на программе сортировки!

4)Некоторые вычислительные системы имеют два ”банка” лентопротяжных устройств, присоединенных к отдельным ”каналам” таким способом, что одновременное чтение и запись допускается только для лент из разных банков. Для такой конфигурации больше всего подходит сбалансированное слияние. Рассмотрим, например, случай шести лент по три в каждом банке и предположим, что мы хотим выполнить многофазное слияние с T = 6. Во время пятипутевого слияния две из вводных лент будут не в том банке, так что, грубо говоря, две пятых времени ввода не будут совмещены с выводом. Это добавляет ко времени сортировки приблизительно 40%, так что сбалансированное слияние окажется лучше многофазного даже в случае обратного чтения.

5)Наш анализ выбора с замещением был выполнен для ”случайных” файлов, но файлы, встречающиеся на практике, очень часто уже упорядочены в той или иной степени. (Фактически иногда люди будут сортировать файлы, уже упорядоченные, только чтобы убедиться в этом.) Таким образом, опыт даже в большей мере, чем указывают наши формулы, показал, что выбор с замещением предпочтительнее других видов внутренней сортировки. Это преимущество несколько ослабляется в случае многофазной сортировки с обратным чтением, так как должен быть порожден ряд убывающих отрезков; на самом деле Р. Л. Гилстэд (он первый опубликовал многофазное слияние) первоначально по этой причине отверг метод обратного чтения. Но позднее он заметил, что чередование направлений будет все же давать длинные возрастающие отрезки. Кроме того, многофазный метод с обратным чтением—это единственный стандартный метод, который благосклонен к убывающим входным файлам, равно как и к возрастающим.

6)Другое преимущество выбора с замещением состоит в том, что этот метод допускает совмещение процессов чтения, записи и вычислений. Если бы мы просто выполняли внутреннюю сортировку очевидным способом—заполняя память, сортируя ее и затем записывая ее по мере того, как она заполняется новым содержимым,—то проход распределения занял бы примерно вдвое больше времени!

Из рассмотренных нами методов внутренней сортировки еще только один можно приспособить к одновременному чтению, записи и вычислениям—пирамидальную сортировку. (Эта идея была использована при подготовке примера 10 схемы А.) Предположим для удобства, что внутренняя память содержит 1000 записей, а каждый блок на ленте—по 100. Действовать можно следующим образом (через B1, B2, : : : , B10 обозначено содержимое памяти, разделенной на 10 блоков по 100 записей).

Шаг 0. Заполнить память и сделать так, чтобы элементы B2: : : B10 удовлетворяли неравенствам пирамиды (с наименьшим элементом в вершине).

Шаг 1. Свести B1: : : B10 в пирамиду, затем выбрать наименьшие 100 записей и переписать их в

B10.

216 Original pages: 400-414

Шаг 2. Записать из B10; в то же время выбрать наименьшие 100 записей из B1: : : B9 и поместить их в B9.

Шаг 3. Прочитать в B10 и записать из B9; в то же время выбрать наименьшие 100 записей из B1: : :B8 и поместить их в B8.

: : :

Шаг 9. Прочитать в B4 и записать из B3; в то же время выбрать наименьшие 100 записей из B1 B2, поместить их в B2 и сделать так, чтобы неравенства пирамиды были справедливы для B5: : :B10.

Шаг 10. Прочитать в B3 и записать из B2, сортируя B1, в то же время сделать так, чтобы неравенства пирамиды были справедливы для B4: : :B10.

Шаг 11. Прочитать в B2 и записать из B1; в то же время сделать так, чтобы B3: : :B10 удовлетворяли неравенствам пирамиды.

Шаг 12. Прочитать в B1, делая так, чтобы B2: : :B10 удовлетворяли неравенствам пирамиды. Вернуться к шагу 1.

7) Мы предполагаем, что число сортируемых записей N не известно заранее. На самом же деле в большинстве вычислительных машин есть возможность все время следить за числом записей во всех файлах, и мы могли бы считать, что наша вычислительная система способна сообщить значение N. Насколько бы нам это помогло? К сожалению, не очень! Мы видели, что выбор с замещением весьма выгоден, но он ведет к непредсказуемому числу начальных отрезков. В сбалансированном слиянии мы могли бы использовать информацию об N для установления такого размера буфера B, чтобы S оказалось, скорее всего, чуть меньше степени P; в многофазном распределении с оптимальным размещением фиктивных отрезков мы могли бы использовать информацию об N, чтобы решить, какой уровень выбрать (см. табл. 5.4.2-2).

Идя по другому пути и не используя выбора с замещением, мы могли бы применить слияние в прямом порядке, описанное в конце п. 5.4.4, встроив его в осциллирующую сортировку, распределяющую начальные отрезки соответствующего направления в соответствующий момент (вместо того чтобы брать их с ”ленты A”, как описано). Этот метод, в сущности, оптимален среди всех методов, выполняющих внутреннюю сортировку без выбора с замещением, так как он сливает в соответствии с наилучшим возможным P-арным деревом, но он все же работает медленней методов, основанных на выборе с замещением.

8)Лентопротяжные устройства часто оказываются наименее надежными частями ЭВМ. Обслуживающий персонал обычно получает вызовы для исправления лентопротяжных устройств чаще, чем для любого другого компонента машины, и операторы вычислительной машины должны уметь возобновлять работу после сбоя ленты. Автор никогда даже не видел установок с 10 или более лентопротяжными устройствами, которые бы все одновременно находились в хорошем рабочем состоянии. Следовательно, можно принять за аксиому, что исходная вводная лента ни в коем случае не должна изменяться, пока не станет известно, что вся сортировка удовлетворительно завершена. В некоторых примерах схемы A существует досадное ”время, пока оператор не сменит ленту”, но было бы слишком рискованно затирать исходные данные ввиду возможности какой-либо неисправности во время длинной сортировки.

9)При переходе от прямой записи к обратному чтению мы можем сэкономить некоторое время, вовсе не записывая последний буфер на ленту; он в любом случае будет вновь прочитан! Схема A показывает, что этот прием в действительности экономит сравнительно немного времени, за исключением случая осциллирующей сортировки, когда направления меняются часто.

10)Если в нашем распоряжении много ленточных устройств, то не всегда стоит использовать их все в целях получения ”высокого порядка слияния”. Так, например, более высокий порядок слия-

ния обычно означает меньший размер блока, а процентная разность между logP S и logP+1 S не очень велика при больших P. Подумайте также о бедном операторе ЭВМ, который должен установить все эти рабочие ленты. С другой стороны, в упр. 12 описан интересный способ использования дополнительных лентопротяжных устройств, группируемых так. чтобы совместить время ввода и вывода без увеличения порядка слияния.

11)На машинах, подобных MIX, которые имеют фиксированный и довольно маленький размер блоков, для слияния едва ли требуется много внутренней памяти. Здесь осциллирующая сортировка более предпочтительна, потому что становится возможным сохранять дерево выбора с замещением в памяти во время слияния. На самом деле в этом случае можно усовершенствовать осциллирующую сортировку (как предложил К. Дж. Белл в 1962 г.), сливая новый начальный отрезок в вывод каждый раз, когда мы сливаем с рабочих лент!

12)Мы видели, что файлы на нескольких бобинах должны сортироваться последовательно бобина за бобиной, чтобы избежать чрезмерной работы по перестановке лент. Фактически сбалансированное

Original pages: 400-414 217

слияние с шестью лентами, если оно тщательно запрограммировано, может сортировать три бобины до момента окончательного слияния.

Для слияния относительно большого числа отдельно отсортированных бобин быстрейшим будет дерево слияния с минимальной длиной пути (ср. с п. 5.4.4). Это построение было впервые осуществлено Э. X. Фрэндом [JACM, 3(1956), 166–167] и затем У. X. Буржем [Information and Control, 1 (1958), 181–197], которые отметили, что оптимальный способ слияния отрезков данных (возможно, неравных) длин получается с помощью построения дерева с минимальной взвешенной длиной пути, используя длины отрезков в качестве весов (см. п. 2.3.4.5 и 5.4.9), если пренебречь временем установки лент. Но файлы, занимающие несколько бобин, вероятно, следует хранить на дисках или другом запоминающем устройстве большой емкости, а не на лентах.

13)В нашем обсуждении мы, не задумываясь, предполагали, что имеется возможность использовать непосредственно инструкции ввода/вывода и что никакой сложный системный интерфейс не мешает нам использовать ленты с такой эффективностью, на какую рассчитывали конструкторы аппаратуры. Эти идеальные предположения позволили нам проникнуть в суть проблем слияния, и они могут дать некоторый подход к конструированию соответствующих операционных систем. Однако следует понимать, что мультипрограммирование и мультипроцессирование могут значительно усложнить ситуацию.

14)Обсуждаемые нами вопросы были впервые рассмотрены в печати Э. X. Фрэндом [JACM, 3 (1956), 134–165],У. Зобербьером [Electron. Datenverarb., 5 (1960), 28–44] и М. А. Готцем [Digital Computer User’s Handbook (New York, McGraw-Hill, 1967) 1.292–1.320].

Резюме. Мы можем следующим образом вкратце выразить все, что узнали о сравнении различных схем слияния:

Теорема А. Трудно решить, какая схема слияния является наилучшей в конкретной ситуации.

Примеры, которые мы видели на схеме А, показывают, как 100000 записей по 100 литер (или 1 миллион записей по 10 литер), расположенных в случайном порядке, могли бы быть отсортированы с использованием шести лент при достаточно реалистических предположениях. Эти данные занимают около половины ленты и могут быть отсортированы приблизительно за 15–19 мин; однако существующее ленточное оборудование сильно различается по возможностям, и время выполнения такой работы на разных машинах изменяется в диапазоне приблизительно от четырех минут до двух часов. В наших примерах около 3 мин расходуется на начальное распределение отрезков и внутреннюю сортировку, около 4.5 мин—на окончательное слияние и перемотку выводной ленты и около 7.5–11.5 мин—на промежуточные стадии слияния.

Если имеется шесть лент, которые нельзя читать в обратном направлении, то наилучшим методом сортировки при наших предположениях было ”многофазное слияние с расщеплением лент” (пример 4), а для лент, допускающих обратное чтение, наилучшим методов оказался многофазный метод с обратным чтением со сложным размещением фиктивных отрезков (пример 7). Осциллирующая сортировка (пример 9) занимает второе место. В обоих случаях каскадное слияние более просто и лишь незначительно медленнее (примеры 5 и 8). В случае прямого чтения обычное сбалансированное слияние (пример 1) оказалось удивительно эффективным, частично из-за удачи в этом конкретном примере, а частично из-за того, что оно тратит сравнительно мало времени на перемотку.

Положение несколько изменилось бы, если бы в нашем распоряжении было другое число лент.

Генераторы сортировки. В условиях большого разнообразия характеристик данных и оборудования почти невозможно написать единственную программу внешней сортировки, которая была бы удовлетворительной в подавляющем большинстве случаев. Также весьма трудно создать программу, которая в реальных условиях эффективно работает с лентами. Следовательно, изготовление программного обеспечения сортировки—самостоятельная задача, требующая большой работы. Генератор сортировки—это программа, которая, основываясь на параметрах, описывающих формат данных и конфигурацию оборудования, порождает машинную программу, специально приспособленную к конкретному применению сортировки. Подобная программа часто связана с языками высокого уровня, такими, как Кобол или PL/1, или она может быть написана как набор макроопределений для использования совместно с макроассемблером.

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

JUL04 OCT311517 NOV051605 JUL141789NOV201917

(Q) n

218Original pages: 400-414

Трехбуквенные коды месяцев можно найти в таблице и заменить числами, причем наиболее значащие поля могут быть помещены слева:

17760704 15171031 16051105 17890714 19171120

Это уменьшает длину записей и делает более простым последующее сравнение. (Код ключей мог бы быть сделан даже более компактным.) Собственные команды последнего прохода могут использоваться для восстановления исходного формата и/или для внесения других желательных изменений в файл и/или для вычисления какой-либо функции от выводных записей. Алгоритмы слияния, которые мы изучили, организованы таким образом, что последний проход легко отличить от остальных фаз слияния. Заметим, что если имеются собственные команды, то должно быть по крайней мере два прохода по файлу, даже если он первоначально находился в порядке. Собственные команды, изменяющие размер записей, могут затруднить совмещение некоторых операций ввода/вывода в

осциллирующей сортировке.

Генераторы сортировки также заботятся о системных деталях, таких, как соглашения о метках лент; они также часто обеспечивают подсчет контрольной суммы или иные проверки того, что никакая часть файла не пропала и не изменилась. Иногда имеются средства для остановки сортировки в удобных местах и возобновления ее позднее. Самые высококачественные генераторы позволяют записям иметь динамически меняющиеся длины [см. D. J. Waks, CACM, 6 (1963), 267–272].

*Слияние с меньшим числом буферов. Мы видели, что 2P + 2 буферов достаточно для поддержания быстрого движения лент в течение P-путевого слияния. В завершение этого пункта проведем математический анализ времени слияния в том случае, когда имеется меньше 2P + 2 буферов.

Очевидно, что желательны два буфера вывода, так как мы сможем записывать из одного буфера, образуя в это же время следующий блок вывода в другом. Поэтому мы можем вообще не рассматривать вопрос вывода и заняться только вводом.

Допустим, имеется P + Q буферов ввода, где 1 Q P. Воспользуемся для описания нашей ситуации моделью, предложенной Л. Дж. Вудрамом [IBM Systems J., 9 (1970), 118–144]. Чтение одного блока ленты занимает одну единицу времени. Имеется вероятность p0 того, что в течение этого времени ни один из буферов ввода не станет пустым, p1—что один буфер станет пустым, p 2—что два или больше буферов станут пустыми и т. д. По завершении чтения ленты мы оказываемся в одном из Q + 1 состояний:

Состояние 0: Q буферов пусты. Мы начинаем читать блок подходящего файла в один из них, используя метод прогнозирования, описанный ранее в этом пункте. Через одну единицу времени мы переходим в состояние 1 с вероятностью p0, в противном случае мы остаемся в состоянии 0.

Состояние 1: Q−1 буферов пусты. Мы начинаем читать в один из них, предсказывая подходящий файл. Через одну единицу времени мы переходим в состояние 2 с вероятностью p0, в состояние 1 с вероятностью p1 и в состояние 0 с вероятностью p 2.

.

.

.

Состояние Q − 1: один буфер пуст. Мы начинаем читать в него, предсказывая подходящий файл. Через одну единицу времени мы переходим в состояние Q с вероятностью p0, в состояние Q − 1 с вероятностью p1, : : :, в состояние 1 с вероятностью PQ−1, и в состояние 0 с вероятностью p Q.

Состояние Q: все буферы заполнены. Чтение лент останавливается в среднем на единиц времени, и затем мы переходим в состояние 1.

Мы начинаем с состояния 0. Эта модель ситуации соответствует марковскому процессу (см. упр. 2.3.4.2-26), который можно проанализировать с помощью производящих функций следующим интересным способом. Пусть z—произвольный параметр, и предположим, что каждый раз, когда мы решили читать с ленты, делаем это с вероятностью z, а с вероятностью 1 − z завершаем алгоритм. Пусть gQ(z) = Pn 0 a(nQ)zn(1−z) будет средним числом появлений в этом процессе состояния Q; отсю-

да следует, что a —это среднее число появлений состояния Q, если было прочитано ровно n блоков. Тогда n+an —среднее суммарное время, затраченное на ввод и вычисления. Если бы имелось полное совмещение, как в алгоритме с (2P +2) буферами, то суммарное время включало бы только n единиц, так что an представляет время задержки чтения.

Пусть Aij—вероятность того, что мы переходим из состояния i в состояние j в этом процессе при 0 i, j Q + 1, где Q + 1—новое состояние ”остановки”. Например, для Q = 1, 2, 3 матрицы A

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Original pages: 400-414 219

будут следующими:

 

0

 

 

 

 

 

 

 

1 − z

1;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

p 1z

p0z

 

 

 

 

 

 

 

 

 

 

 

 

 

Q = 1 :

 

1

 

0

 

 

0

 

 

 

 

 

 

 

 

 

 

 

 

 

 

@

 

0

 

0

 

 

0

A

 

1;

 

 

 

 

 

 

 

 

 

 

 

 

p 1z p0z

 

 

0 1 − z

 

 

 

 

 

 

 

 

Q = 2 : 0p 2z p1z p0z 1 − z

 

 

 

 

 

 

 

 

 

 

B

 

0

 

1

 

 

0

 

 

0

 

C

 

 

 

 

 

 

 

 

 

 

 

0

 

0

 

 

0

 

 

0

 

 

 

 

 

 

 

 

 

 

 

@

 

 

 

 

 

 

 

 

 

 

 

 

 

 

A

 

1

 

 

 

 

 

 

 

 

 

 

p 1z p0z

 

 

0

 

 

0 1 − z

 

 

 

 

 

 

 

 

0p 2z p1z p0z

 

0 1 − z

 

 

 

 

 

 

Q = 3 :

B

p 3z p2z p1z p0z 1 − z

C

:

 

 

 

 

 

 

 

 

0

 

0

 

 

1

 

 

0

 

 

 

 

0

 

 

 

 

 

 

 

 

 

B

 

0

 

0

 

 

0

 

 

0

 

 

 

 

0

 

C

 

 

 

 

 

 

 

 

B

 

 

 

 

 

 

 

 

 

 

 

C

 

 

 

 

 

 

 

 

@

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

A

 

 

 

 

 

Из упр. 2.3.4.2-26b имеем, что gQ(z) = алгебраическое дополнение Q0(I −A)= det(I −A). Так, напри-

мер, если Q = 1, имеем

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

0

p0z z − 1

 

 

1

 

 

p 1z −p0z z − 1

1 =

g1(z) = det01

0

 

 

 

0

1= det0

1

 

 

 

 

 

1

 

0

 

@p00z

0

 

 

 

 

p10z A

 

 

@

 

n0

 

 

 

 

 

0

 

1

A

=

 

=

 

 

 

= n

 

0 np0z

(1 − z);

 

 

 

 

 

 

1 − p1z − p0z

1 − z

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

X

 

 

 

 

 

 

 

 

 

 

 

 

 

 

так что an(1) = np0. Это, конечно, очевидно заранее, так как при Q = 1задача очень проста. Аналогичное

вычисление для Q = 2 (см. упр. 14) дает менее очевидную формулу:

 

 

 

 

 

 

 

a(2)

=

 

p02n

p02(1 − p1n)

:

 

 

 

 

 

 

(10)

 

 

 

− p1

 

 

 

 

 

 

 

 

 

n

 

1

(1 − p1)2

 

 

 

 

 

 

 

 

 

 

В общем случае можно показать, что a(Q) имеет вид (Q)n + O(1) при n

! 1

, где константу (Q) не

 

 

 

 

n

 

 

 

 

 

 

 

 

 

 

 

 

 

 

(3)

 

 

3

 

2

слишком трудно вычислить. (См. упр. 15.) Как оказывается,

 

 

= p0=((1 − p1)

− p0p2).

Исходя из природы слияния, довольно разумно предположить, что = 1=P и что вероятности pk

соответствуют биномиальному распределению

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

P

1

 

k

 

P −

1

 

P−k

 

 

 

 

 

 

 

 

 

pk

=

 

 

 

 

 

.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

k P P

 

 

 

 

 

 

 

 

 

 

 

 

 

Например, если P = 5, то p0 = :32768, p1 = :4096, p2 = :2048, p3 = :0512, p4 = :0064 и p5 = :00032; следовательно, (1) = 0:328, (2) = 0:182 и (3) = 0:127. Другими словами, если мы используем 5 + 3 вводных буферов вместо 5 + 5, то можно ожидать дополнительного времени задержки чтения порядка 0:127=5 2:5%.

Конечно, эта модель—только очень грубое приближение. Мы знаем, что при Q = P вообще нет времени задержки, но если судить по модели, то есть. Дополнительное время задержки чтения для меньших Q почти точно уравновешивает выигрыш в накладных расходах, получаемый от использования более крупных блоков, так что простая схема с Q = P кажется оправданной.

Упражнения

1.[13] Выведите формулу для точного числа литер на ленте, если каждый блок содержит n литер. Считайте, что лента могла бы вместить ровно 23000000 литер, если бы не было межблочных промежутков.

2.[15] Объясните, почему первый буфер файла 2 в строке 6 рис. 84 совсем пуст.

3.[20] Будет ли алгоритм F работать должным образом, если вместо 2P буферов ввода имеется только 2P − 1? Если да, докажите это, если нет— приведите пример, когда алгоритм терпит неудачу.

4.[20] Как изменить алгоритм F, чтобы он работал также и при P = 1?

>5. [21] Если в различных файлах имеются равные ключи, необходимо в процессе прогнозирования действовать очень аккуратно. Объясните, почему, и покажите, как избежать трудностей, если более строго определить операции слияния и прогнозирования в алгоритме F.

220 Original pages: 400-414

6. [22] Какие изменения следует сделать в алгоритме 5.4.3С, чтобы преобразовать его в алгоритм каскадного слияния с совмещением перемотки на T + 1 лентах?

>7. [26] Начальное распределение в примере 7 схемы А порождает

(A1D1)11 D1(A1D1)10 D1(A1D1)9 D1(A1D1)7

на лентах 1–4, где (A1D1)7 означает A1D1A1D1A1D1A1D1A1D1A1D1A1D1. Покажите, как вставить дополнительные отрезки A0 и D0 наилучшим из возможных способов (в том смысле, что общее число обрабатываемых во время слияния начальных отрезков будет минимальным), чтобы привести распределение к

A(DA)14 (DA)28 (DA)26 (DA)22:

[Указание. Чтобы сохранить четность, необходимо вставлять A0 и D0 в виде соседних пар. Числа слияния для каждого начального отрезка могут быть подсчитаны, как в упр 5.4.4-5; здесь появляется некоторое упрощение, так как соседние отрезки всегда имеют соседние числа слияния.]

8.[20] Из схемы А видно, что большинство схем начального распределения отрезков (за исключением начального распределения для каскадного слияния) имеет тенденцию помещать последовательные отрезки на различные ленты. Если бы последовательные отрезки попали на одну ленту, то мы могли бы сэкономить стартстопное время; можно ли поэтому считать хорошей мысль изменить алгоритмы распределения так, чтобы они реже переключали ленты?

>9. [22] Оцените, сколько времени занял бы многофазный алгоритм с обратным чтением из схемы А, если бы мы использовали для сортировки все T = 6 лент, а не T = 5, как в примере 7. Было ли разумно избегать использования вводной ленты?

10.[М23] Используя анализ, проведенный в п. 5.4.2 и 5.4.3, покажите, что длина каждой перемотки во время стандартного многофазного слияния с шестью лентами или каскадного слияния редко превышает 54% файла (исключая начальную и конечную перемотки, которые охватывают весь файл).

11.[23] Изменив подходящие элементы табл. 1, оцените, сколько времени заняли бы первые девять примеров схемы А, если бы мы имели двухскоростную перемотку (быструю и медленную). Считайте, что p = 1, если лента заполнена меньше чем на одну четверть, а для более заполненной ленты время перемотки равно приблизительно пяти секундам плюс то время, которое получилось бы при = 1=5. Измените пример 8 так, чтобы он использовал каскадное слияние с копированием, поскольку перемотка и прямое чтение в этом случае медленнее копирования [Указание: используйте результат упр. 10].

12.[40] Рассмотрим разбиение шести лент на три пары лент, где каждая пара играет роль одной ленты в многофазном слиянии с T = 3. Одна лента каждой пары будет содержать блоки 1, 3, 5, : : : , а другая—блоки 2, 4, 6, : : : , таким способом мы, по существу, добиваемся того, чтобы во все время слияния две вводные и две выводные ленты оставались активными, причем эффективная скорость слияния удваивается.

(a)Найдите подходящий способ распространить алгоритм F на этот случай.

(b)Оцените общее время выполнения, которое получилось бы, если бы этот метод был использован для сортировки 100000 записей по 100 литер, рассмотрев случай как прямого, так и обратного чтения.

13.[20] Может ли осциллирующая сортировка с пятью лентами, в том виде как она определена в алгоритме 5.4.5В, использоваться для сортировки четырех полных бобин исходных данных до момента окончательного слияния?

14.[М19] Выведите (10).

15.[ВМ29] Докажите, что gQ(z) = hQ(z)=(1 − z), где hQ(z) является рациональной функцией z, не имеющей особенностей внутри единичного круга; следовательно, a(nQ) = hQ(1)n+O(1) при n ! 1. В частности, покажите, что

 

B

0

−p0

0

 

1

0

C B

1

−p0

0

0

C

 

h3(1) = det

1

0 2

0

 

0 0

0

0 2

1 1

1 0

:

0

0

1 − p1

−p0

 

0

1

= det

0

1

1 − p1

−p0

0

1

 

@

0

p

1

p

 

p

A

 

@

1

p

p

A

 

 

 

 

 

 

 

1 p

 

 

15.[M46] Проанализируйте слияние с P + Q буферами более тщательно, чем это было сделано в тексте, используя более точную модель.

17.[41] Проведите детальное изучение задачи сортировки 100000 записей по 100 литер, нарисуйте схемы, подобные схеме А, в предположении, что имеется 3, 4 или 5 лент.

Соседние файлы в папке Дональд Кнут. Искусство программирования. т.3