Текст
                    Г, ЛОЕЙН
еортировк.
и сиетЕмы


г. ЛОРИН СОРТИРОВКА И СИСТЕМЫ СОРТИРОВКИ Перевод с английского Р. Л. смелянского щ щ МОСКВА «НАУКАх ГЛАВНАЯ РЕДАКЦИЯ ФИЗИКО-МАТЕМАТИЧЕСКОЙ ЛИТЕРАТУРЫ 19 8 3
22.18 J178 УДК 519.6 SORTING AND SORT SYSTEMS HAROLD LORIN ADDISON-WESLEY PUBLISHING COMPANY Г. Лорин СОРТИРОВКА И СИСТЕМЫ сортировки Редакторы: Я. Я. Васина. В. Ю. Королев Технич. редактор: С. Я. Шкляр Корректоры JI. И. Назарова, Я. Д. Дорохова ИБ № 11809 Сдано в набор 05.10.82. Подписано к печати 23.06.83. Формат 60X90Vie- Бумага тип. № 1. Литературная гарнитура. Высокая печать. Условн. печ. л. 24. Уч.-изд. л. 28,66. Тираж 13 000 экз. Заказ № 359. Цена 2 р. 30 к. Издательство «Наука» Главная редакция физико-математической литературы 117071, Москва, В-71, Ленинский проспект, 15 Ленинградская типография Яг 2 головное предприятие ордена Трудового Красного Знамени Ленинградского объединения «Техническая книга» им. Евгении Соколовой Союзполиграф- прома при Государственном комитете СССР по делам издательств, полиграфии и книжной торговли. 198052, г. Ленинград, Л-52, Измайловский проспект, 29. 1702070000-110 053(02)-83 ) 1975, by Addlson-Wesley Publishing Company, Inc. Phillippines copyright 1975 by Addison-Wesley Publishing Company ) Перевод на русский язык. Издательство «Наука». Главная редакция физико-математической литературы, 1983
ОТ РЕДАКЦИОННОГО БЮРО IBM*) Область системного программирования возникла как результат усилий многих программистов и менеджеров, чья творческая энергия воплотилась в практически полезных системных программах, которые требовались в бы¬ стро развивающейся вычислительной индустрии. Программирование было искусством, каждый программист решал стоящие перед ним задачи по- своему, при незначительном влиянии со стороны других специалистов, с ко¬ торыми он был непосредственно связан. В 1968 г. покойный Эшер Оплер, работавший тогда в IBM, осознал, что знания, накопленные в программи¬ ровании, необходимо объединить в форме, доступной для всех системных программистов. Изучив состояние дел в этой области, он решил, что име¬ ется достаточное количество полезного материала, оправдывающего значи¬ тельные усилия по публикации. По его рекомендации фирма IBM приняла решение финансировать издание «Серии системного программирования». Цель этого долгосрочного проекта — собрать, систематизировать и опубли¬ ковать те принципы и методы, которые надолго сохранят свою актуальность в вычислительной технике. Серия состоит из книг учебно-справочного характера и открыта для расширения. Содержание каждой книги должно отражать точку зрения ин¬ дивидуального автора, которая не обязательно совпадает с точкой зрения корпорации IBM. Каждая книга организуется как учебный курс, однако материал описывается достаточно подробно, чтобы ей можно было пользо¬ ваться как справочником. Серия имеет три уровня: нижний составляют тома, содержащие вводный материал, средний— тома, посвященные мате¬ матическому обеспечению и содержащие материал более узкого профиля и, наконец, верхний уровень — специальные теоретические работы. Организо¬ ванная таким образом Серия будет полезна и новичкам, и опытным програм¬ мистам, и теоретикам. Серия включает следующие книги: Уровень 1: The Program Development Process Part I — The Individual Programmer Joel D. Aron The Program Development Process *) Состав редакционного бюро IBM: Joel D. Aron, Chairman; Edgar F. odd, Robert H. Claser; Charles L. Gold; James Griesmer; Paul S. Herwitz; ames P. Morrissey; Ascher Opler; George Radin; David Sayre; Norman A. anton (Addison-Wesley); Heinz Zemanek.
ОТ РЕДАКЦИОННОГО БЮРО Уровень 2: Уровень 3: Part II — The Programming Team The Design and Structure of Programming Languages Mathematical Background of Prog¬ ramming Structured Programming An Introduction to Database Systems Compiler Engineering Interactive Computer Graphics Sorting and Sort Systems Compiler Design Theory*) Recursive Programming Techniques Compilers and Programming Lan¬ guages Joel D. Aron John E. Nicholls Frank Beckman Harland D. Mills Richard C. Linger C. J. Date Particia Goldberg Andries Van Dam Harold Lorin Philip M. Lewis Daniel J. Rosenkrantz Richard E. Stearns William Burge J, T. Schwartz John Cocke *) Русский перевод: Льюис Ф., Розенкранц Д., Стирнз Р. Теоретические основы проектирования компиляторов: Пер. с англ. — М.: Мир, 1979. (Прим. перев.)
Институту системных исследований, моим коллегам и студентам. ПРЕДИСЛОВИЕ Эта книга написана для программистов. Ее стиль и содержание рассчи¬ таны на специалиста, которому нужны полные, но практические знания о сортировке и системах сортировки при условии, однако, что специалист не хочет изучать для этого ни специфический язык программирования, ни статистику, ни какую-либо гипотетическую машину. Цель книги — подгото¬ вить программиста к созданию программ сортировки. Для тех же, кому нужна более тщательная или формальная характеристика конкретных мето¬ дов, эта книга послужит основой для чтения более специальной литературы. В любом случае, для того чтобы его знания не устарели, программист дол¬ жен постоянно внимательно читать эту литературу. Ануй *) во введении к своей пьесе «Беккет» сказал, что он не форма¬ лист и не историк, он — драматург. И доказал это, написав прекрасную пьесу на основе исторической нелепицы, согласно которой Плантагенет, граф Анжуйский (Генрих II, король Англии), один из наиболее образованных людей в Европе в XII столетии, считался варваром по сравнению с его саксонским другом Томасом Беккетом. Профессиональные историки крити¬ куют пьесу за то же, за что специалисты по вычислительной технике могут критиковать эту книгу. Однако пьеса раскрывает прежде всего сущность поступков людей, а не историю этого периода, и я надеюсь, что эта книга аналогично даст возможность понять сущность процесса сортировки. Из-за конкретных особенностей текста я бы хотел обсудить вначале, как эту книгу, по-моему, следует использовать и почему в некоторых слу¬ чаях я поступил так, а не иначе. Я грубо упрощал формулы и избегал искус¬ ственной краткости везде, где это возможно, полагая, что лучше быстро прочесть несколько страниц текста, чем медленно разбирать десяток слов. Я считаю, что книгу следует прочесть от корки до корки и, таким об¬ разом, основательно изучить область сортировки. Читатель, я думаю, найдет изложение естественным и динамичным. Описание каждого метода сопро¬ вождается примерами, после чего неформально обсуждаются свойства ме¬ тода и его варианты. Между изложением внутренних методов (часть I) и внешних (часть II) есть качественная разница. В первой части приведено очень много подробностей, так как с большой долей вероятности читатель будет программировать внутреннюю сортировку. С другой стороны, опти¬ мальные слияния, как правило, создаются в «лабораторных» условиях уз¬ кими специалистами. Часть II позволит читателю общаться с этими специа¬ листами и, если «жизнь заставит», создать сносное слияние для лент или дисков. Причина такого подхода в том, что тонкости создания оптималь¬ ного слияния существенно зависят от машины, ее конфигурации и опера¬ ционной системы. Читатель со срочной задачей— необходимо запрограммировать эффек¬ тивную сортировку — может использовать эту книгу иначе. Если ему нужно отсортировать порядка 100 элементов во внутреннем списке, он может про¬ честь первые две главы и выбрать сортировку. Он может использовать «просеивание» в точности так, как оно описано. Если нужны более мощные сортировки, можно пропустить первые главы и читать о быстрой сортировке, *) Ж. Ануй (Anouilh) — французский драматург, р. 1910. (Прим. перев.)
6 ПРЕДИСЛОВИЕ слиянии и турнирной сортировке, выбрав одну из этих хороших сортировок для пробы и приспособить к своему случаю. В книгу включено много описаний простых сортировок. С одной сто¬ роны, они образуют основу более сложных методов, с другой стороны, по¬ лезны и сами по себе для малых списков и как внутренние алгоритмы для внешних сортировок. По ряду причин обсуждение факторов, влияющих на производительность сортировки, дано в конце гл. 1. Во-первых, я полагаю, что по смыслу лучше описать некоторые простые сортировки до обсужде¬ ния их производительности. Во-вторых, я считаю, что о неалгоритмическом влиянии на производительность следует сказать как можно быстрее. В силу этого, окончание гл. 1 — самое подходящее место для этого обсуждения. После ознакомления с тремя методами читатель спросит: «Как же мне вы¬ брать подходящую сортировку»? Рассуждения, приведенные в конце гл. 1, помогут ему лучше разобраться в последующих методах. Важным является вопрос о формулах. Я не хочу создавать иллюзию точности и требовать от читателя знания теории вероятностей и статистики. Такая формула, как C = 2(N+ l)log(-^py). N>M, теоретически может быть правильным выражением числа сравнений в бы¬ строй сортировке для файлов со случайным упорядочением. Однако легче пользоваться ее приближением 2/V log N. Более того, так как немногие файлы действительно случайны, точный результат может на самом деле вводить в заблуждение. Другая общая формула имеет вид ^ N(N- 1) 2 • Она может быть аппроксимирована формулой N2/2 с ошибкой 1 % при Д/ = 100 и ошибкой 0,1% при N = 1000. Так как основное назначение этих формул — позволить оценить эффективность различных методов сортировки на основе требуемых параметров, то достаточно, чтобы формулы устанав¬ ливали соответствующие различия между конкурирующими методами. По этой причине везде, где это возможно, я выбрал для простых сортировок аппроксимацию, легкую для использования, учитывая прежде всего практи¬ ческие свойства сортировки. Для более эффективных сортировок я привел формулы, используемые в современной литературе. Многочисленные ссылки помогут заинтересованному читателю подробнее изучить источники. Полез¬ ной универсальной ссылкой для студентов, специализирующихся в области вычислительной техники, является The Art of Computer Programming, v. 3: Sorting and Searching. Prof. D. E. Khuth, изданное Addison-Wesley Publ. Comp, 1973 [21] *). Когда читатель полностью прочтет эту книгу, он будет готов, если за¬ хочет, стать ассистентом системного программиста в Лаборатории Сорти¬ ровки и/или разрабатывать собственные методы сортировки для своих задач. Нью-Йорк Февраль, 1975 Г. Л. *) Русский перевод: Кнут Д. Искусство программирования для ЭВМ. Сортировка и поиск.— М.: Мир, 1978, т. 3. (Прим. перев.)
ЧАСТЬ I. ВНУТРЕННЯЯ СОРТИРОВКА Глава 1. ОСНОВНЫЕ ПОНЯТИЯ И МЕТОДЫ СОРТИРОВКИ 1.1. Введение Сортировка — это процесс расстановки элементов «в некотором поряд¬ ке». Элементы размещаются так, чтобы, во-первых, вычисления, требующие определенного порядка расположения данных, могли выполняться эффек¬ тивно, во-вторых, результаты имели осмысленный вид, и в-третьих, после¬ дующие процессы имели бы пригодные исходные данные. Для человека, как правило, порядок данных весьма важен, так как позволяет подметить свой¬ ства, имеющие решающее значение. Кроме того, современная аппаратура работает наиболее эффективно при упорядоченных данных. Понятие упо¬ рядоченности в меру интуитивно. Есть много «естественных» упорядочений таких, например, как упорядочение имен в списке по алфавиту или упоря¬ дочение ряда чисел по возрастанию. Когда мы осмысливаем понятие упорядоченности, то в основном пред¬ ставляем себе, конечно же, физическое упорядочение такое, как расположе¬ ние пакета перфокарт или записей на магнитной ленте. Однако сортировка не обязательно предполагает фактическую перестановку. Упорядочение в файле может быть описано по-разному, например при помощи индексов. Представим себе набор учебников, каждый из которых имеет определен¬ ный номер. Можно составить картотеку этого набора и на каждой индекс¬ ной карточке указать название учебника, его место на полках, дату опуб¬ ликования и тематический классификатор. Изредка нам, возможно, при¬ дется просматривать наш набор, например, если мы захотим сравнить но¬ мера наших учебников с номерами в полном списке изданных учебников, расположенном в порядке числового ряда. Картотека, естественно, может быть упорядочена по тематическому классификатору или дате опубликова¬ ния. Чтобы сравнить картотеку со списком, мы переставляем индексные карточки, но не сами книги. Не всегда очевидно, что лучше сортировать — индексы или записи. На самом деле не всегда очевидно, стоит ли сортировать вообще. Пусть у нас есть вычислительная машина, оснащенная магнитными лентами и запоми¬ нающим устройством очень малого объема. Предположим, что мы хотим составить итоговый отчет о работе филиала некоторой торговой фирмы. нас есть лента с отчетами каждого филиала о каждой продаже. По-ви-
8 ГЛ. 1. ОСНОВНЫЕ ПОНЯТИЯ И МЕТОДЫ СОРТИРОВКИ димому, записи о продажах будут сгруппированы по филиалам, а для кон¬ кретного филиала все они могут быть собраны вместе и даже в некоторой последовательности. Если мы знаем, что это так, то программа сортировки не нужна. Убедиться, что каждая запись обработана так, как надо, можно простой последовательной проверкой. Элементы, не вошедшие в последова¬ тельность, могут быть собраны в небольшие группы или просто отложены для последующей обработки. Если же данные упорядочены случайным об¬ разом или их порядок нам неизвестен, то сортировка — самый быстрый и дешевый способ, гарантирующий их определенную последовательность. Возможности вычислительной машины также влияют на принятие ре¬ шения о сортировке. Предположим, что записи о продажах упорядочены на ленте случайным образом. Если мы решили не сортировать, и памяти нашей машины хватает только для итоговой суммы по одному продукту в одном филиале, то мы будем вынуждены просматривать всю ленту в по¬ исках нужных нам записей. Если было продано 100 различных продуктов в 50 торговых филиалах, то потребуется 5000 полных просмотров ленты. Конечно же, сортировка до составления итогового отчета более эффективна. Если объема памяти достаточно для 100 итоговых сумм, то за каждый про¬ смотр ленты будет составлен полный отчет по одному филиалу, и потре¬ буется только 50 просмотров. Но это все же менее эффективно, чем обра¬ ботка упорядоченной ленты. Однако если объем памяти достаточен для 5000 итоговых сумм, то сор¬ тировка не нужна. Каждая запись по мере поступления может добавляться К соответствующей итоговой сумме в памяти, а сортировка ленты не даст никаких преимуществ. Отказ от сортировки если и увеличит время состав¬ ления отчета, то очень незначительно. Ответ на вопрос, сортировать или не сортировать, хотя часто и очевид¬ ный, как в данном примере с лентой, иногда бывает достаточно тонким. В особенности это касается случаев с использованием дисков, когда осуще¬ ствляется прямой доступ к данным. Ценой отказа от сортировки данных может быть чрезмерное движение головки диска между обращениями к записям при обработке, дополнительные задержки вследствие вращения диска, и, как результат, увеличение времени' обработки данных. Когда оче¬ видно, что сортировка сократит общее время, все еще непонятно, что лучше сортировать — записи или индексы. Для ответа на этот вопрос необходим анализ, детальное изучение устройства и используемого формата данных. Соображения, которые следует принимать во внимание для того, чтобы решиться на сортировку или отказаться от нее, включают анализ различных необходимых результирующих сообщений, возможностей устройств и рас¬ положения их каналов, объема оперативной памяти, частоты обращений и т. д. Решение о применении сортировки в информационной системе явля¬ ется настолько важным, что его следует принимать только тогда, когда тщательное изучение аппаратуры и параметров данных оправдывает сорти¬ ровку, непродуктивную в основе своей. По существу, правило таково: сор¬ тируйте только тогда, когда нет другого выхода. 1.1.1. Записи, поля и ключи. Единица данных, типично обрабатываемая информационными системами, называется записью. Запись — это совокуп¬
1.2. ПРОЦЕДУРЫ СОРТИРОВКИ 9 ность элементов информации о каком-то событии или структуре. Каждый ялемент информации в записи, такой как номер служащего, цена единицы товара или валовой объем, называется полем записи. Совокупность полей идентифицирует и описывает то, что представлено в записи. Из записей составляются файлы или наборы данных. Сортировка является процессом пе¬ рестановки записей или их индексов, при котором их взаимное расположе¬ ние в файле приводится в порядок, определяемый некоторым известным ключом *). В предположении, что результатом сортировки является физическое упорядочение, сортировка двух записей в своей простейшей форме состоит из сравнения их ключевых полей и определении, которое из них «меньше». После этого записи переставляются так, что запись с «меньшим» ключом ставится перед записью с «большим» ключом. Определить, какой ключ «меньше», можно, используя любое правило. Очевидными правилами являются: алфавитное упорядочение, числовое и бук¬ венно-цифровое. (В последнем правиле ключи могут содержать смесь букв и цифр; соглашения, принятые в системе, определяют упорядочение букв и цифр.) Ключом записи может быть одно поле или комбинация полей, распре¬ деленных по записи. Если ключ состоит из нескольких несоприкасающихся полей, то он называется составным ключом. Иногда желательно упорядочение внутри упорядочения. Например, файл может быть упорядочен по номеру места работы, а внутри этого упорядо¬ чения — по номеру служащего. Поле, содержащее номер места работы, на¬ зывается старшим ключом, а поле, содержащее номер служащего, — млад¬ шим ключом. Так можно определить несколько уровней ключей, и все уров¬ ни, отличные от первого, называются младшими ключами. Старший и млад¬ ший ключи можно рассматривать как один составной ключ в записи. В информационной системе иногда удрбно, чтобы файлы упорядочива¬ лись не единственным способом. Различные сортировки в качестве ключа могут использовать различные поля. Запись может состоять только из поля ключа. В обработке научных приложений это не является чем-то исключительным. В этой книге при ил¬ люстрациях методов сортировки будет предполагаться, что записи состоят из одного поля. Это сделано для того, чтобы упростить первоначальное пред¬ ставление о методах сортировки за счет устранения побочных проблем, воз¬ никающих при перемещении данных. Поскольку эти методы одинаково хо¬ рошо применимы к записям, содержащим как ключевые, так и неключевые поля, то это предположение не ограничивает общности. 1.2. Процедуры сортировки Есть много различных алгоритмов сортировки и много подходов к их программированию. Установление различия между двумя процедурами ) Ключом называется поле, содержащее величину, используемую в правилах упорядочения файла.
10 ГЛ. 1. ОСНОВНЫЕ ПОНЯТИЯ и МЕТОДЫ СОРТИРОВКИ сортировки — суть один из вариантов проблемы установления эквивалентно¬ сти двух программ. Процедуры сортировки, которые ранее рассматривались как разные [3, И, 25], рассматриваются как таковые и в этой книге. В конечном счете любая сортировка есть программа, и процедура сор¬ тировки будет зависеть от различия способов кодировки. Различие в произ¬ водительности двух разных алгоритмов сортировки может быть в несколько раз меньше, чем между «хорошо» и «плохо» запрограммированным одним и тем же алгоритмом. Это также относится к различию в производительности версий одного и того же алгоритма на языке высокого уровня и языке ма¬ шины. Процедуры, описанные в этой книге, являются только иллюстрациями. Их следует рассматривать как начальный, но не заключительный этап со¬ здания сортировки. Помимо необходимой адаптации к особенностям уст¬ ройств и данных, сами эти методы следует рассматривать как объект для уточнения, комбинирования и расширения. Традиционно методы сортировки делят на внутренние и внешние [23]. Внутренние методы — это такие методы, которые могут применяться с при¬ емлемой производительностью только к тем спискам данных, которые цели¬ ком помещаются в основной (оперативной) памяти процессора. Внешние методы — это такие методы, которые приемлемы для файлов данных, кото¬ рые слишком велики, чтобы поместиться в основной памяти, и поэтому должны в течение процесса сортировки располагаться на устройствах внеш¬ ней памяти (лентах, дисках, барабанах). Слово список часто обозначает набор записей, расположенных в основной памяти. В процессе внешней сортировки часть файла считывается в основную память, там упорядочивается, а затем переписывается на внешние устрой¬ ства. Этот процесс повторяется несколько раз. Внутренние методы исполь¬ зуются для перестановки данных, обрабатываемых между их пересылками. Поэтому, когда говорят о сортировке на лентах, то подразумевают не толь¬ ко процесс считывания и записи на эти ленты, но также и внутреннюю сортировку, которая упорядочивает и комбинирует элементы с этих лент по мере их считывания. 1.3. Характеристики внутренних методов сортировки, Сортировки могут быть охарактеризованы сложностью метода опреде¬ ления последовательности сравнений, комбинацией используемых методов, основным способом упорядочения и объемом необходимой памяти. 1.3.1. Линейные или нелинейные. Сложность метода, определяющего по¬ следовательность сравнений, зависит от того, как много информации о струк¬ туре используется в организации записей. Линейный алгоритм предполагает отсутствие структуры в списке, который он упорядочивает. Список рассмат¬ ривается как линейная последовательность элементов, и последовательность их сравнений и пересылок отражает этот факт. Сравниваемые элементы вы¬ бираются последовательно сверху или снизу списка один за другим. Нели¬ нейные методы, наоборот, предполагают наличие структуры у списков, ко¬ торые они сортируют. Они наиболее эффективны, когда списки рассматри¬
1.4. ОСНОВНЫЕ АЛГОРИТМЫ И ваются как двоичные деревья или структурированные иным способом, и вы¬ бирают последовательности сравнений более сложным способом, чем ли¬ нейные сортировки. Все «эффективные» сортировки, т. е. сортировки, в ко¬ торых достигается теоретически минимальное число сравнений, являются нелинейными. 1.3.2. Простые или комбинированные. Простая сортировка использует один и тот же метод в течение всего процесса сортировки, При этом сам метод не зависит ни от состояния данных, ни от какой-либо точки в про¬ цедуре. Алгоритм, напротив, может быть комбинированным. Разработчик сортировки может определить, что наилучшим методом для его данных яв¬ ляется комбинация методов, переключающаяся с одного метода на другой в зависимости, например, от числа элементов в подсписке. Простые алго¬ ритмы не обязательно являются несложными; многие методы, ориентирован¬ ные на обработку древовидных структур, являются «простыми» только в том смысле, в каком это слово используется здесь. 1.3.3. Сравнительные или распределительные. В сравнительном методе данные упорядочиваются по относительной величине ключей в списке. Боль¬ шинство методов сортировки, которые мы будем рассматривать, являются сравнительными. Распределительный метод, наоборот, обследует каждый ключ либо целиком, либо символ за символом. Промежуточное размещение ключа зависит не от относительной величины ключа, а от характеристики, получаемой при сравнении этого ключа с некоторым стандартом. Распреде¬ лительные сортировки полезны в тех случаях, когда о сортируемых данных известно многое, например, распределение ключей по некоторым интервалам, длина ключей и число записей. Когда предварительной информации меньше, предпочтительнее сравнительные сортировки, так как они менее чувстви¬ тельны к распределению конкретного множества сортируемых величин. Они чувствительны к упорядоченности величин, обрабатываемых ими. 1.3.4. Минимальные или не минимальные по памяти. В минимальном по памяти методе память требуется только для программы и упорядочиваемого списка. (Некоторые алгоритмы, которым нужно некоторое количество простой дополнительной памяти, также считаются минимальными по памяти.) Не минимальный по памяти метод, помимо этого, требует память и для копии исходного списка. Преимущество минимальной по памяти сортировки в том, что она позволяет сортировать большие списки в основной памяти, хотя и ценой продолжительности сортировки. Некоторые алгоритмы — это по су¬ ществу минимальные и не минимальные по памяти версии одного и того же процесса. 1.4. Основные алгоритмы Начнем с обсуждения семи фундаментальных алгоритмов внутренней сортировки. Первые три представлены в этой главе как основа для введения в сравнительные сортировки. Остальные четыре представлены в главе 2. от эти семь алгоритмов: линейный выбор, линейный выбор с обменом, ли¬ нейный выбор с подсчетом, стандартный обмен, основной обмен, просеива¬ ние, линейная вставка.
12 ГЛ. 1. ОСНОВНЫЕ ПОНЯТИЯ и МЕТОДЫ СОРТИРОВКИ Это очень простые алгоритмы, использование которых ограничено слу¬ чаями, когда по тем или иным причинам скорость сортировки или объем требуемой памяти не важны или когда количество хранимых записей очень невелико*). Это линейные простые сравнительные сортировки. Они нас ин¬ тересуют частично в учебных целях, частично в прагматических, так как могут служить в качестве простых полезных инструментов. 1.5. Линейный выбор Прямой линейный выбор является не минимальным по памяти методом. 1.5.1. Линейный выбор. Один просмотр **) в линейном выборе включает выбор из сортируемого списка элемента с наименьшим ключом и размещение его в формируемом списке вывода. Просмотры выполняются до тех пор, пока список вывода не будет сформирован полностью. В готовом виде список вывода представляет собой упорядоченный исходный список. В начале каж¬ дого просмотра первый элемент списка считается элементом с наименьшим ключом. Ключ и адрес этого элемента передаются в рабочую память, где ключ сравнивается с ключом второго элемента. Если первый ключ меньше, то он сравнивается с ключом третьего элемента и т. д. Он сравнивается со всеми линейными преемниками до тех пор, пока в списке не найдется мень¬ ший элемент. Затем ключ найденного наименьшего элемента вместе с его адресом заменяет в рабочей памяти находившиеся там ключ и адрес и уча¬ ствует в последующих проверках. Ключ наименьшего на данный момент времени элемента всегда распо¬ ложен в рабочей памяти и используется при сравнениях с оставшимися в списке ключами. По достижении конца списка наименьший элемент изве¬ стен, так как это именно тот элемент, чей ключ и адрес находятся в рабо¬ чей памяти. Затем этот элемент передается из исходного списка в текущую позицию области вывода. В исходном списке ключ каждого перемещенного элемента заменяется фиктивной величиной (например, полем из одних де¬ вяток), превосходящей любой ключ в списке, для того чтобы предотвратить повторный выбор этого элемента. То, что адрес выбранного элемента . находится в рабочей памяти, позво¬ ляет определять не только его место при пересылке, но и место, куда сле¬ дует поместить фиктивный ключ. Если поле ключа является одновременно и полем элемента, то пересылка в список вывода может выполняться непо¬ средственно из рабочей памяти, так как в ней находится вся запись. При каждом просмотре в список вывода добавляется текущий наименьший член сортируемого списка. Первый просмотр добавляет наименьший элемент, второй просмотр — следующий наименьший и т. д. Таким образом, в обла¬ сти вывода формируется упорядоченный список. Сортировка заканчивается, когда все члены исходного списка окажутся в списке вывода. *) Эти методы предпочтительны для малых списков. **) В отечественной литературе также используется термин «проход». |Прим. перев.)
1.5. ЛИНЕЙНЫЙ ВЫБОР 13 1 5.2. Пример. Рассмотрим список элементов (представленных их клю¬ чами), изображенный на рис. 1.1. В начале первого просмотра ключ первого Исходный список Рабочая память 1, 3 LOW = 3 2. 11 SOUR СЕ = 1 3, б Последовательность сравнений 4, 4 Ключ 3 : ключ 11 5. 9 Ключ 3 : ключ б 6. 5 Ключ 3 : ключ 4 7, 7 Ключ 3 : ключ 9 8. 8 9. 10 10. 2* Ключ 3 : ключ 10 11. 1 Ключ 3: ключ 2* (найдено меньшее значение) Рис. 1.1. Линейный выбор, первый просмотр. члена списка помещается в ячейку LOW, а его адрес — в ячейку SOURCE рабочей памяти. Первым в этом просмотре сравнивается ключ 3 из рабочей памяти с ключом 11 из позиции 2. При сравнении выясняется, что ключ 3 меньше, и он продолжается считаться наименьшим ключом. Простой линей¬ ный указатель списка (первоначально установленный на позицию 2) про¬ двигается для подготовки следующего сравнения. При втором сравнении ключ 3 сравнивается с ключом 6 из позиции 3. При этом выясняется, что ключ 3 опять меньше, поэтому затем с ключом 3 сравнивается ключ 4. Последовательность сравнений с ключом 3 оканчива¬ ется по достижении позиции 10, содержащей ключ 2 — первое значение Исходный список Рабочая память 3 И LOW=2 6 SOURCE = 10 4 9 Последовательность сравнений 5 Ключ 2 : ключ 1* (найдено меньшее 7 значение) 8 10 2 1* Рис. 1.2. Линейный выбор, конец первого просмотра. в этом списке, меньше 3. Ключ (2) и адрес (10) нового меньшего эле¬ мента (см. рис. 1.2) становятся содержимым ячеек LOW и SOURCE. Теперь сравнения выполняются между ключом 2 и его линейными пре¬ емниками. При первом таком сравнении обнаруживается величина, меньшая ключа . Новая величина и адрес помещаются в ячейки LOW и SOURCE. ^ этот ^момент просмотр заканчивается, так как список исчерпан. Ключ списЯЧеИКИ пересылается в область вывода. Если бы записи в этом иске имели не только ключевые поля, то пересылка в область вывода
14 ГЛ. 1. ОСНОВНЫЕ ПОНЯТИЯ И МЕТОДЫ СОРТИРОВКИ выполнялась бы из списка по адресу из SOURCE. По окончании пересылки в список помешается фиктивная величина (z), и начинается новый просмотр. На рис. 1.3 показаны состояние исходного списка и области вывода после пяти просмотров. 1.5.3. Обсуждение. Так как каждый просмотр добавляет по одному эле¬ менту в список вывода, то просмотров должно быть столько, сколько эле¬ ментов в списке. Если их число равно N, то будет N просмотров. Поскольку каждый просмотр начинается с первого элемента списка, то каждый просмотр потребует N—1 сравнений, независимо от начального Просмотр Список 1 2 3 4 5 3 3 г Z Z 11 11 11 11 11 6 6 6 6 6 4 4 4 Z Z 9 9 9 9 9 5 5 5 5 Z 7 7 7 7 7 8 8 8 8 8 10 10 10 10 10 2 Z Z Z Z Z Z Z Z Z 1 1 1 1 1 2 2 2 2 3 3 3 4 4 5 Вывод Рис. 1.3. Состояние списка после каждого из пяти просмотров (z — фиктивная величина). упорядочения списка. Число сравнений никак не зависит от упорядочения начальных данных. Таким образом, для этого метода наилучшее, наихудшее и ожидаемое (среднее) число сравнений одно и то же. Общее число сравне¬ ний всегда равно N(N—1). Практической оценкой может служить N2. Число пересылок из исходного списка в список вывода равно N. Од¬ нако эта величина не характеризует данный метод, так как не учитывает пересылки ключей и адресов в ячейки LOW и SOURCE. Если размер записи мал, то время, необходимое для такой пересылки, будет относительно ве¬ лико, так как время, необходимое для пересылки адреса и ключа, будет близко к времени, необходимому для пересылки записи. Число пересылок ключей и адресов зависит от начального упорядочения списка. В полностью упорядоченном списке содержимое LOW в течение одного просмотра не из¬ менялось бы. В списке с обратным упорядочением потребовалась бы N — 1 пересылка. При линейном выборе для данных обычно выделяется в два раза боль¬ ше памяти, чем для исходного списка, и упорядоченный список увеличива¬ ется от просмотра к просмотру. Если нет необходимости хранить в памяти весь упорядоченный список, то можно сократить используемую память, вы¬ водя результат по ходу формирования списка.
1.6. ЛИНЕЙНЫЙ ВЫБОР С ОБМЕНОМ 15 1.6 Линейный выбор с обменом: использование обменов В качестве первого примера обмена в процессе сортировки рассмотрим здесь минимальную по памяти версию линейного выбора. Обменом называ¬ ется перестановка позиций двух записей в списке в зависимости от резуль¬ тата проверки их относительной величины. Если в списке встречается запись с ключом, меньшим, чем у предыдущей, то эти записи меняются местами. Производительность методов обмена зависит от сложности определения по¬ следовательности сравнений и обменов. Часто число обменов сокращают, откладывая обмен до конца каждого просмотра. Этот прием,, в частности, используется в методе, который сейчас будет описан. 1.6.1. Линейный выбор с обменом. В начале первого просмотра предпо¬ лагается, что первый элемент списка имеет наименьший ключ. Этот ключ вместе с адресом пересылается в рабочую память, где сравнивается со все¬ ми линейными преемниками до тех пор, пока не встретится меньший ключ. Меньший ключ и его адрес становятся содержимым рабочей области памяти. Сравнения продолжаются при новом содержимом рабочей памяти. Пе¬ ресылка выполняется всегда, когда в списке встречается ключ, который меньше ключа в рабочей памяти. Таким образом, в рабочей памяти всегда расположен наименьший из уже просмотренных ключей. Просмотр закан¬ чивается по достижении конца списка. До этого момента процесс идентичен простому линейному выбору. Сортировка обменом отличается следующим шагом. По окончании первого просмотра запись, ключ которой расположен в рабочей памяти, переставляется с записью из вершины списка. Теперь наи¬ меньшая величина в списке занимает первую позицию. Второй просмотр идентичен первому с той лишь разницей, что вторым по величине считается второй ключ, так как первым стоит наименьший элемент. Первая позиция исключается из процесса. По окончании второго просмотра вторая запись с наименьшим ключом помещается во вторую позицию списка. Третий про¬ смотр начинается сравнением ключа из третьей позиции и т. д. Эта про¬ цедура заканчивается, когда свое место занимает (N—1)-я запись. 1.6.2. Пример. На рис. 1.4 показан исходный список. При первом про¬ смотре содержимое первой позиции (ключ 3) последовательно сравнивается со всеми своими линейными преемниками до обнаружения меньшего ключа, после чего содержимое LOW и SOURCE изменяется. Никаких физических изменений в списке не происходит; изменяется только содержимое LOW и SOURCE, как показано на рис. 1.5. Ключ 2, находящийся в LOW, сравни¬ вается со своим линейным преемником из позиции И. Результатом этого сравнения является обмен, так как ключ 1 меньше (к тому же он последний в списке). Преобразованный список показан на рис. 1.6. Читатель наверное заметил идентичность рисунков 1.1 и 1.4, что подчеркивает аналогичность версий линейного выбора с обменом и без него. Следующие просмотры идентичны, за исключением того, что исходные значения для каждого просмотра, помещаемые в рабочую память, выбира¬ ются из различных позиций: из позиции 2 для второго просмотра, из пози¬ ции 3 для третьего и т. д. На рис. 1.7 показаны преобразования, выполянемые
16 ГЛ. 1. ОСНОВНЫЕ ПОНЯТИЯ и МЕТОДЫ СОРТИРОВКИ при втором просмотре. Так же выполняются и последующие просмотры, причем список, в котором происходят сравнения, с каждым просмотром со¬ кращается до тех пор, пока не будут расставлены (N—1) позиций. При Рабочая память Исходный список 1. 3 2. 11 3. 6 4- 4 5. 9 6. 5 7. 7 8. 8 9. 10 10. 2* 11. 1 Рис. 1.4. LOW = 3 SOURCE = 1 Последовательность сравнений Ключ 3 : ключ 11 Ключ 3 : ключ б Ключ 3 : ключ 10 Ключ 3 : ключ 2* (найдено меньшее значение) Рис. 1.4. Линейный выбор с обменом, первый просмотр. Исходный список 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. И. 3 11 6 4 9 5 7 8 10 2 1* Рабочая память LOW = 2 SOURCE = 10 Ключ 2 : ключ 1* (найдено меньшее значение) Исходный список 1. 1 2. 11 3. 6 4. 4 5. 9 6. 5 7. 7 8. 8 9. 10 10. 2 11. 3 Рабочая память LOW = 1 SOURCE = ll Рис. 1.5. Линейный выбор с обменом в течение первого просмотра. Рис. 1.6. Линейный выбор с обменом, Первый просмотр: обмен ключей 1 и 3. Исходный список 1 11 6 4 9 5 7 8 10 2 3 LOW=ll SOURCE » Ключа 11 с ключом 6 После сравнения: Ключа 6 с ключом 4 1 11 6 4 9 5 7 8 10 2 3 LOW = 6 SOURCE=3 1 11 6 4 9 5 7 8 10 j 2 3 LOW = 4 SOURCE= Ключа 4 с ключом 2 1 11 6 4 9 5 7 8 10 2 3 LOW = 2 SOURCE= 10 Окончатель- ный список 1 2 6 4 9 5 7 8 10 11 3 Рис. 1.7, Линейный выбор с обменом, второй просмотр: обмен ключей 2 и И. этом в последней позиции будет находиться наибольший ключ. Таким об¬ разом, процедура заканчивается. 1.6.3. Обсуждение. Замечательное свойство этого метода заключается в сокращении списка от просмотра к просмотру. На каждом последующем просмотре выполняется на одно сравнение меньше, так что последовательно
1.7. ЛИНЕЙНЫЙ ВЫБОР С ПОДСЧЕТОМ 17 выполняется (Д^ — 1), (N — 2), (N — 3), ...,2, 1 сравнений. Общее число сравнений равно произведению среднего числа сравнений за один просмотр на число просмотров, т. е. (N — 1) (N)/2 (оценивается величиной /V2/2) и совершенно не зависит от состояния данных. Количество обменов равно количеству просмотров. Но опять-таки, не учитывается число пересылок в LOW и SOURCE. Интересная модификация этого метода состоит в отказе от ячеек LOW и SOURCE. Каждый раз, когда находится меньший ключ, происходит об¬ мен с содержимым верхней позиции текущей неотсортированной части списка. Теперь при просмотре обмен выполняется не один раз, а при каждом появлении меньшего ключа. Для списков, размеры записей которых больше размеров ключей, затраты на дополнительные обмены были бы тяжелым бременем. В методе, описанном ранее, все сокращенно до (N—1) обменов и пересылок ключа и адреса. Для списков, у которых ключи являются за¬ писями, эти две версии примерно равноценны. При выполнении обменов непосредственно в списке возникает побочный эффект, который заключается в том, что сам список подвергается промежу¬ точным переупорядочиваниям. Этот эффект может привести к увеличению количества обменов, так как небольшие числа, расположенные в верхних позициях списка, будут «погружаться» на дно. Возможны перестановки дан¬ ных, при которых это погружение даст некоторое преимущество, но если у программиста нет исчерпывающих сведений о данных, то предпочтение следует отдать методу с сокращенным числом обменов. 1.7. Линейный выбор с подсчетом Метод сортировки с подсчетом описывается в литературе как процедура упорядочения внутреннего списка чисел. Фактически, это не метод сорти¬ ровки, а технический прием, который можно использовать в различных ме¬ тодах для сокращения количества обменов или полного их устранения. Он является формой индексирования, в которой счетчик относительной позиции каждого элемента корректируется в течение процесса сравнения. В следу¬ ющем разделе этот технический прием описан применительно к линейному выбору. 1.7.1. Подсчет как технический прием. Память, используемая линейным выбором с подсчетом, будет включать область вывода (так же как и при линейном выборе) для хранения окончательно упорядоченного списка. Раз¬ мер области вывода отвечает тем же соображениям, что и при линейном выборе. Дополнительно должна быть обеспечена память под счетчик для каждого элемента списка. В результате действий над значениями этих счет¬ чиков образуется множество индексов позиций для элементов в упорядо¬ ченном списке. При каждом просмотре ключ сравнивается со своими линей¬ ными преемниками. Каждый раз, когда находится больший ключ, его счет- увеличивается на единицу. Если найденный ключ меньше или равен, то чейЛИЧИВаеТСЯ счетчик’ соответствующий большему из сравниваемых клю- е • Следовательно, в любой момент времени счетчик элемента указывает
18 ГЛ. 1. ОСНОВНЫЕ ПОНЯТИЯ И МЕТОДЫ СОРТИРОВКИ количество ключей, о которых известно, что они меньше ключа рассматри¬ ваемого элемента. При первом просмотре первый ключ в списке сравнивается со всеми остальными ключами. В его счетчике подсчитывается количество меньших ключей. В счетчиках больших ключей будут 1. При втором просмотре пер¬ вый ключ не рассматривается. Второй ключ сравнивается с ключами всех 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. Ключ 3 11 6 4 9 5 7 8 10 2 1 Счетчик Рис. 1.8. Линейный выбор с под¬ счетом, конец первого просмотра. Ключ 1. 3 2. 11 3. 6 4. 4 5. 9 6. 5 7. 7 8. 8 9. 10 10. 2 11. 1 Счетчик 2 10 О о Рис. 1.9. Линейный выбор с под¬ счетом, конец второго просмотра. преемников. Подсчеты фиксируются. Этот процесс продолжается N—1 раз. На этом этапе известна относительная позиция каждого элемента. Помещая ключи в выходной список в соответствии со значениями их счетчиков, по¬ лучаем упорядоченный список. 1.7.2. Пример. Рассмотрим список на рис. 1.8. В течение первого про¬ смотра ключ 3 сравнивается с ключами всех линейных преемников. Все Ключ Счетчик Ключ Счетчик 1. 3 2 1. 3 2 2. 11 10 2. 11 10 3. 6 5 3. 6 5 4. 4 1 4. 4 3 5. 9 2 5. 9 8 6. 5 1 6. 5 4 7. 7 2 7. 7 6 8. 8 2 8. 8 7 9. 10 2 9. 10 9 10. 2 0 10. 2 1 11. 1 0 11. 1 0 Рис. 1.10. Линейный выбор с под¬ Рис. 1.11. Линейный выбор с под¬ счетом; , конец третьего просмотра. счетом, последний просмотр. ключи, кроме 1 и 2, больше ключа 3 и, следовательно, в их счетчиках бу¬ дут 1. В счетчике ключа 3 будет 2, так как этот ключ больше двух ключей из списка. При втором просмотре сравнивается ключ 11 (позиция 2) и вы¬ ясняется, что он больше девяти оставшихся в списке ключей. К единице, оставшейся в его счетчике после первого просмотра, в течение второго про¬ смотра прибавляются одна за другой еще девять. В итоге значение счет¬ чика, соответствующего ключу 11, равно 10 (см. рис. 1.9). При третьем просмотре (рис. 1.10) сравнения выполняются с ключом 6. Так как он боль-
1.8. ФАКТОРЫ, УЧИТЫВАЕМЫЕ ПРИ СОРТИРОВКЕ 19 е четырех из оставшихся в списке элементов, то значение его счетчика Ш<еличивается до 5. Значение счетчиков, соответствующих ключам 7, 8, 9 и 10, Увеличивается так, чтобы показать, что эти ключи больше ключа 6. По окончании последнего просмотра установлены все счетчики, и могут выпол¬ няться пересылки в список вывода. Окончательное значение счетчиков пока¬ зано на рис. 1.11. Список вывода имеет точно такой же размер, как у исходного списка, следовательно, может быть вычислен адрес позиции любого элемента в списке вывода. При размещении в списке вывода адрес ключа получается сложением значения счетчика этого ключа и начального адреса -области вы¬ вода. Этот процесс занимает один просмотр сверху вниз списка значений счетчиков. 1.7.3. Обсуждение. Число сравнений равно (N) (N—1)/2 (приблизительно ДГ2/2). Выполняется (N — 1) просмотров с N/2 сравнениями в среднем на каждом просмотре. Значения счетчиков изменяются столько раз, сколько раз выполняется сравнение, поскольку каждое сравнение — это изменение зна¬ чения счетчика. Число пересылок равно N. Метод подсчета можно модифицировать. Например, если за исходное значение каждого счетчика взять адрес начала списка вывода и при каж¬ дом последующем изменении увеличивать его на длину записи, то значение счетчика будет представлять собой итоговый адрес соответствующей записи. 1.8. Факторы, учитываемые при сортировке Цель данного раздела — познакомить с теми факторами, которые сле¬ дует учитывать при выборе метода сортировки. Сделаем это сейчас, чтобы читатель мог приступить к обсуждению последующих методов, имея общее представление о параметрах, влияющих на производительность. Три метода сортировки (все варианты линейного выбора) уже были описаны. Какие же факторы надо учитывать, если должен быть выбран только один метод? Какие факторы, помимо алгоритма сортировки, влияют на производительность сортировки данных? Надо учесть, насколько важна производительность сортировки. Случа¬ ется, что программист не получает реальной компенсации за те усилия, ко¬ торые были вложены в создание превосходной сортировки. Вполне доста¬ точно будет наиболее примитивных методов сортировки, так как сортировка может совпадать по времени с другой операцией или быть слишком корот¬ кой, чтобы иметь сколь-нибудь важное значение. Бывает, что программист не рассматривает производительность сорти¬ ровки как решающий фактор, хотя она и интересует его. Он заинтересован лишь в том, чтобы производительность предлагаемого им метода сортировки находилась бы в определенных пределах. Если задаться целью разработать действительно очень хороший метод сортировки, то к его созданию следует подходить как к сложному процессу, состоящему из множества этапов. Первое необходимое условие выбора под¬ ходящей сортировки состоит в глубоком понимании природы сортируемых Данных. Когда такое понимание есть, то у нас достаточно информации,
20 ГЛ. 1. ОСНОВНЫЕ ПОНЯТИЯ И МЕТОДЫ СОРТИРОВКИ чтобы определить, какой метод использовать — сравнительный или распреде¬ лительный, сколько может потребоваться памяти и много ли мы выиграем, если будем сортировать только ключи. Следующий шаг — это поиск общего метода, который кажется эффек¬ тивным с точки зрения ожидаемого числа сравнений и перемещений данных. Этот метод следует промоделировать на языке высокого уровня. Если все же не ясно, какой метод лучше, то следует промоделировать несколько ме¬ тодов и испытать их на тестовых данных, влияние которых на сортировку еще не известно. Можно попытаться комбинировать методы. Хотя об алго¬ ритмах сортировки известно многое, многое все же не известно, и возможно, что какое-нибудь коварное сочетание характеристик данных окажется «кам¬ нем преткновения» для обычно хорошего метода. Когда метод выбран, для достижения наилучшей производительности он должен быть закодирован на языке машины*). Следует учесть такие по¬ дробности, как использование регистров машины, сопоставление пересылки в оперативной памяти с пересылкой через регистры, относительная скорость пересылок элементов различной длины, относительная скорость различных типов сравнений разных видов данных, отображение данных на адресную структуру машины и доступный объем оперативной памяти. В следующих разделах рассматриваются факторы, не относящиеся к основным свойствам методов сортировки. 1.8.1. Характеристики данных. Характеристики данных, влияющие на вы¬ бор сортировки, таковы: 1. Размер списка, который надо отсортировать; 2. Длина ключей и наличие составных ключей; 3. Вид ключей (двоичный, десятичный, с плавающей запятой и т. д.); 4. Распределение ключей списка: а) диапазон значений; б) сгруппированность значений; в) дублирование; г) перестановки ключей; 5. Размер записей и изменчивость длины записи; 6. Последующее использование данных. 1.8.1.1. Размер списка. Количество элементов определяет: 1. Нужна ли внешняя сортировка; 2. Должно ли использоваться минимальное количество памяти; 3. Могут ли быть оправданы накладные расходы, связанные с усовер¬ шенствованными методами. Некоторые методы сортировки зависят от конкретного значения N (яв¬ ляется ли оно точной степенью какого-нибудь числа и т. п.). Объем работы, необходимый для сортировки, когда N не является степенью, часто непро- *) Если по каким-либо причинам программирование на уровне языка машины нежелательно, то должен быть найден компромисс между произво¬ дительностью сортировки и стоимостью ее создания в свете указанных факторов.
1.8. ФАКТОРЫ, УЧИТЫВАЕМЫЕ ПРИ СОРТИРОВКЕ 21 ионально близок к объему работы, необходимому при сортировке с N, равным следующей большей степени. 18.1.2. Длина ключа и наличие составных ключей. Длина и место расположения поля ключа будут определять время, необходимое для выполнения сравнений. Влияние размеров ключей и их размещения в записи на продолжительность сравнений существенно зависит от харак¬ теристик конкретного центрального процессора. Важны следующие вопросы: 1. Соответствует ли ключ структуре, непосредственно обрабатываемой машиной? 2. Является ли он полем слова или должен извлекаться из. слова и сравниваться по «маске»? Не слишком ли много времени займет извлечение или маскирование? 3. Размещается ли ключ в нескольких словах? Включает ли доступ к нему работу с несколькими словами, определением поля, сдвигом и т. д.? Не слишком ли много времени займет преобразование ключа в удобную форму? 4. Является ли время сравнения непосредственной функцией размера ключа? Зависит ли на данной машине время сравнения от числа символов в ключе? Можно ли ключ разбить на части так, чтобы сравнения этих час¬ тей было бы достаточно для упорядочения большинства ключей? Если необходима предварительная обработка ключа, то можно выпол¬ нить все манипуляции с ключами, добавив сначала в запись специально построенный управляющий ключ. Ключ в удобной форме можно строить динамически при каждом сравнении. Выбор других технических приемов зависит от доступного объема памяти и временных характеристик централь¬ ного процессора. 1.8.1.3. Вид ключей. Время сравнения зависит от способа кодировки ключей и от доступности и временных характеристик команд сравнения для различных видов данных. Если нет команд «десятичного сравнения», то может потребоваться преобразование в чисто двоичный вид. Время, необ¬ ходимое для преобразования ключей, добавляется к времени сортировки. 1.8.1.4. Распределение и расстановка*). В большинстве слу¬ чаев при обсуждении производительности сортировки предполагается, что данные «случайны». Это означает, что задан диапазон возможных значений ключей, и что все значения из этого диапазона равновероятны. Расстанов¬ ка— конкретным образом упорядоченное множество чисел — случайна, если все исходные варианты упорядочения чисел равновероятны. Существует N\ возможных расстановок списка из N различных чисел. Разработчику сортирующей программы часто полезно проверить пред¬ положение о случайности его данных. Он может обнаружить, что заданная процедура сбора данных привносит устойчивое смещение или частичное упо¬ рядочение. Он может усовершенствовать метод, чтобы использовать это ') В оригинале «permutation», т. е. «перестановка». Однако далее ис¬ пользуется термин «расстановка» для обозначения «перестановки» как опре¬ деленной последовательности чисел, чтобы не путать с «перестановкой» как изменением расположения объектов. (Прим. перев.)
22 ГЛ. 1. ОСНОВНЫЕ ПОНЯТИЯ И МЕТОДЫ СОРТИРОВКИ смещение или, наоборот, чтобы защитить метод от нежелательного смеще¬ ния в данных. Важной характеристикой распределения является дублирование. Когда необходимо распознать повторяющиеся ключи, как это бывает в некоторых приложениях, в процедуру сравнения должна быть включена проверка на равенство. При каждом сравнении необходимо определять, является ли один ключ больше, меньше или равен другому. Когда мы говорим об N «сравне¬ ниях», то имеем в виду N комбинированных сравнений. На некоторых ма¬ шинах проверка на равенство требует дополнительной команды, что фак¬ тически удваивает время сравнения; на других же машинах операнды для сравнения берутся из регистров, и поэтому увеличения времени почти не происходит. В некоторых архитектурах используется логика «кода условия», требующая незначительного увеличения времени на выполнения сравнения болыпе-меньше-равно по сравнению со временем простого сравнения боль¬ ше-меньше. Когда повторения распознавать не надо, важно предотвратить обмены при равенствах. 1.8.1.5. Длина и изменчивость записей. Длина записей (вме¬ сте с их количеством) определяет, поместится ли список целиком в опера¬ тивной памяти и, следовательно, потребуются ли для сортировки списка ми¬ нимальные по памяти методы. Длина записей также определяет, следует ли использовать сортировку с обособленными или необособленными ключами. Сортировка с обособленными ключами упорядочивает отдельный список уп¬ равляющих признаков. Каждый признак содержит ключ и его адрес в ис¬ ходном списке. Сортировка с необособленными ключами формирует список адресов, который используется для ссылок на ключи в исходном списке. Оба способа не перемещают исходные записи при сортировке. Если метод сортировки влечет большое количество обменов или пересылок и если длина записи больше длины ключа, то время на построение вспомогательных списков может превзойти время, сэкономленное за счет перемещения за¬ писей. Для методов, требующих дополнительных рабочих областей, память можно экономить, размещая в этих областях не записи, а только признаки или адреса. Если над ключами необходимо выполнять действия (см. раз¬ дел 1.8.1.2), то они будут частью процесса формирования обособленных ключей. В некоторых случаях можно вовсе избежать перемещения запи¬ сей. При последующей после сортировки обработке исходный список может быть индексирован посредством упорядоченной таблицы признаков или ад¬ ресов. При непосредственных действиях над записями переменной длины воз¬ никают свои проблемы. 1. Очень неэффективны обращения к записям, которые не являются со¬ седними. Это ограничение весьма существенно для нелинейных методов. 2. Обмен не может выполняться с записями разной длины. Сортировки с обособленными или необособленными ключами могут эф¬ фективно применяться к различным данным. Изменение длины записей иг¬ рает роль только на последнем просмотре, когда записи упорядочиваются окончательно.
1.8. ФАКТОРЫ, УЧИТЫВАЕМЫЕ ПРИ СОРТИРОВКЕ 23 Если ключи широко разнесены по записи и велики относительно сред¬ ней длины записи, если значительно изменение длины записей как следствие разнообразия длины полей (а не числа полей), то полезно рассмотреть перестроение записей в сжатую форму фиксированной длины с соответствую¬ щим обратным преобразованием [1]. 1.8.1.6. П о с л е д у ю щ е е использование записей. Отсортиро¬ ванный список может быть использован в памяти другой программой. Он мо¬ жет выводиться на некоторое устройство как для последующей обработки ка¬ кой-то программой, так и для последующего использования человеком. Ха¬ рактер процесса, использующего результат сортировки, определяет, нужно ли физически упорядочить список или просто расставить индексы. Последующее использование влияет на количество памяти, необходимое для некоторых методов, и ограничивает объем переупорядочения записей, выполняемого сортировкой для собственного удобства. 1.8.2. Программные связи. Процесс сортировки окружен другими про¬ граммными процессами. Иногда эти процессы входят в сортирующую про¬ грамму; иногда они остаются внешними по отношению к ней. Например, продвижение вниз по списку обычно считается функцией сортировки. В сор¬ тировках вставками, однако, функция, доставляющая «следующий» элемент для сортировки, может быть внешней по отношению к собственно сорти¬ рующей подпрограмме. Варианты конструкций сортирующих программ неисчислимы, и надо применять обычные принципы составления хороших программ. Выгодно ли программу обмена и программу движения по данным создавать внешними по отношению к программе сравнений, передать ли предварительную обра¬ ботку записей и ключей в функцию сравнения, сосредоточить ли ее на пред¬ варительном просмотре — все эти факторы влияют на реализацию сорти¬ ровки и ее конечную производительность. Сортировка существует как программа или подпрограмма и, как тако¬ вая, связана с другими программами. Она обитает в специфическом про¬ граммном окружении, которое будет определять «оттенок» сортирующей программы. Программное окружение, определяя источник данных, место на¬ значения данных, объем доступной оперативной памяти, относительную важ¬ ность некоторых функций и т. д., часто будет косвенно указывать, какие методы сортировки могут использоваться, либо ограничивать применение тех или иных методов. 1.8.3. Характеристики машины. Предпочтительность одной сортировки Перед другой и специфика реализации сортировки в основе своей опреде¬ ляются машиной, на которой эта сортировка будет работать. Вот почему, как °тмечалось выше, кодирование на языке машины предпочтительнее, чем кодирование на языке высокого уровня. Почти невозможно перечислить все ХаРактеристики архитектуры машины, которые влияют на производитель¬ ность сортировки и отражаются на реализации. Укажем некоторые из К Количество регистров; ?• Логика сравнений и временные характеристики сравнений;
24 ГЛ. 2. СОРТИРОВКИ ОБМЕНОМ И ЛИНЕЙНАЯ ВСТАВКА 3. Эффективность декрементов *) индексных регистров и проверок огра¬ ничений; 4. Наличие специальных команд поиска; 5. Возможности маскирования и извлечения; 6. Наиболее эффективно перемещаемая длина полей данных; 7. Размеры памяти. Как правило, алгоритм сортировки, хороший на одной машине, будет хорошим и на другой. Когда есть явные различия между сортировками, ка¬ кая-нибудь особенность машины может способствовать выбору между ними. Например, наличие у машин серии UNIVAC 1100 быстрой команды линей¬ ного поиска может привести к тому, что линейные методы будут эффектив¬ нее для этих машин, чем для машин, где такой команды нет. Глава 2. СОРТИРОВКИ ОБМЕНОМ И ЛИНЕЙНАЯ ВСТАВКА 2.1. Сортировка обменом Сортировка обменом — это общий термин, используемый для описания семейства минимальных по памяти методов сортировки, которые меняют ме¬ стами элементы списка, если предшествующий элемент больше последующе¬ го. Просмотр файла может протекать сверху вниз или снизу вверх или из¬ меняться от просмотра к просмотру. Существует ряд определенных вариантов, которые различаются после¬ довательностями сравнений элементов списка. Во всех элементарных мето¬ дах обмена элемент сравнивается со своим ближайшим соседом, а возмож¬ ными перемещениями являются перемещение элемента с большим ключом на одну позицию вниз и перемещение элемента с меньшим ключом на одну позицию вверх. Парный обмен, стандартный обмен и просеивание являются тремя простыми формами сортировки обменом. 2.1.1. Парный обмен: метод. Метод парного обмена (также называемый «нечетно-четная перестановка») состоит из различного числа «нечетных» и «четных» просмотров. При нечетных просмотрах каждый элемент из нечет¬ ной позиции сравнивается со своим соседом из четной позиции и больший из них занимает четную позицию. Нисходящий просмотр списка продолжа¬ ется до тех пор, пока последний нечетный элемент (N—1) в списке не сравнивается с последним четным элементом (N). Если в списке нечетное число элементов, то последний элемент не будет участвовать в сравнении. В течение каждого просмотра ведется подсчет обменов. При четных просмотрах четные позиции сравниваются с соседними нечет¬ ными. Обмены выполняются тогда, когда надо, чтобы больший из пары за- *) Декремент (decrement — англ.) — постоянная величина, используемая для многократного, периодически повторяющегося уменьшения значения пе¬ ременной величины (в данном случае хранящейся на регистре). (Прим, перев.)
2.1. СОРТИРОВКА ОБМЕНОМ 25 п нечетную позицию. Таким образом, ключи с большими значениями пере¬ мешаются на дно списка. При этом должно быть столько просмотров, сколько необходимо для того, чтобы переместить в позицию число, наиболее удален¬ ное от своей конечной позиции. Затем выполняется заключительный про¬ смотр, необходимый для того, чтобы опознать упорядоченность. В течение этого просмотра счетчик обменов равен 0. Данный метод требует по крайней мере двух просмотров — одного нечетного и одного четного. 2.1.1.1. Пример. Будем опять использовать список из главы I (см. рис. 2.1). На первом просмотре последовательность сравнений будет такой, как показано в заголовках столбцов справа от исходного списка. Числа, ис¬ пользуемые при сравнении, помечены звездочками; стрелка указывает обмен, выполняемый в результате сравнения. На рис. 2.2 показан второй просмотр. Сравнения и их результаты ука¬ заны так же, как на рис. 2.1. На втором просмотре начинается перемещение ключа 1 — наиболее смещенного элемента в списке. На рис. 2.3 показаны состояния списка к концу каждого из оставшихся просмотров. Заметим, что от просмотра к просмотру ключ 1 поднимается на одну позицию. Сортировка заканчивается, когда он займет соответствующую позицию. Значимость клю¬ ча 1 в данном примере определяется не тем, что он является наименьшим в списке, а тем, что он изначально расположен дальше всех от своей заклю¬ чительной позиции. Сортировка оканчивается, когда наиболее смещенный ключ займет нужную позицию И обмены прекратятся (EXCOUNT=0). 2.1.1.2. Обсуждение: число сравнений. Число сравнений на каждом просмотре приблизительно равно N/2. Число сравнений в этом методе зависит от числа просмотров, которое в свою очередь зависит от перемеще* ния ключа, наиболее удаленного от своей конечной позиции. Обычно число просмотров на единицу больше абсолютного значения раз- ности между номером позиции наиболее смещенного элемента и номером его конечной позиции. Теоретически максимальное значение этого числа равно N + 1, так как наибольшее возможное перемещение ключа равно /V — 1, и возможно, как в данном примере, что на первом просмотре этот ключ не будет перемещаться. Однако максимальное число просмотров обычно пола¬ гается равным М. Минимальное число просмотров, которое достигается, когда список упорядочен, равно двум. Следовательно, аппроксимацией максималь¬ ного числа сравнений будет N2/2, а минимального N. Каково же для этого метода среднее число просмотров, а следовательно, и среднее число сравнений? Так как число просмотров зависит от максималь¬ ного перемещения, необходимо определить, каким может быть это переме¬ щение. Чтобы вычислить величину ожидаемого максимального перемещения, мы Должны рассмотреть все возможные расстановки списка и определить число расстановок с различными значениями перемещения. Но уже при 11 числах сделать практически невозможно. Оценку ожидаемого числа сравнений Можно получить, используя формулу (Л/2/2) _ (ДГ/2) л/гЩ, где W2/2 — ма- ВычгтЛЬН°е ЧИСЛ0 равнений за N просмотров при N/2 сравнениях на каждом, не бПаемое Уменьшает число сравнений: положив, что ^/зл'/2 просмотров ут выполняться и что наиболее смещенное число будет установлено
26 ГЛ. 2. СОРТИРОВКИ ОБМЕНОМ И ЛИНЕЙНАЯ ВСТАВКА Сравнение позиций Исходный список 1 : 2 3 : 4 5 : 6 7 : 8 9 : 10 1. 3 3* 3 3 3 3 2. 11 11* 11 11 11 11 3. 6 6 4* <—г 4 4 4 4. 4 4 6* 6 6 6 5. 9 9 9 5* 5 5 6. 5 5 9 9* «—! 9 9 7. 7 7 7 7 7* 7 8. 8 8 8 8 8* 8 9- 10 10 10 10 10 2* 10. 2 2 2 2 2 10* ! И. 1 1 1 1 1 1 EXCOUNT 0 1 2 2 3 Замечание. EXCOUNT —суммарный счетчик обменов. Звездочками отмечены сравниваемые элементы, стрелками отмечены обмениваемые элементы. Рис. 2.1. Парный обмен, просмотр 1. Сравнение позиций Исходный список 2 : 3 4 : 5 6 : 7 8 : 9 10 : 11 1. 3 3 3 3 3 3 2. 11 4* 4— 4 4 4 4 3. 4 11*4-- 11 11 11 11 4. 6 6 S* 4- 5 5 5 5. 5 5 6* 4—1 6 6 6 6. 9 9 9 7* 4~| 7 7 7. 7 7 7 9* 4—1 9 9 8. 8 8 8 8 2* 4— 2 9. 2 2 2 2 8* 4—! 8 10. 10 10 10 10 10 1*4— И. 1 1 1 1 1 10*4 EXCOUNT 1 2 3 4 5 Замечание. EXCOUNT —суммарный счетчик обменов. Звездочками отмечены сравниваемые элементы, стрелками отмечены обмениваемые элементы. Рис. 2.2. Парный обмен, просмотр 2. Список в конце просмотра 2 £ 4 £ £ 7_ 8 9 10 И 12 1. 3 3 3 3 3 3 3 2 4— 2 1 2. 4 4 4 4 4 4 2 4-г 3 4—1 14— 2 4—1 2 3. 11 5 4— 5 5 5 2 4 Г 4 4—1 1 4 | 3 4—1 3 3 4. 5 114-1 6 4— 6 2ч'-1 5 4—1 1 4— 4 4—1 4 4 4 5. 6 6 11 4—1 6 4—1 1 4—j 5 4-! 5 5 5 5 6. 7 7 2 4— 114-1 14— 6 4—1 6 6 6 6 6 7. 9 2 4-- 7 4—! И 4—1 7 4— 7 7 7 7 7 8. 2 9 4—1 1 4—7 7 4—1 7 11 4—J 8 4 — 8 8 8 8 9. 8 1 1 9 4- 1 8 4— 8 8 11 4- J 9 4— 9 9 9 10. 1 8 4-1 8 9 4—1 9 9 9 1U-1 10 4— 10 10 11. 10 10 10 10 10 10 10 10 U4-J 11 и EXCOUNT 3 3 3 2 3 3 3 2 1 0 Рис. 2.3. Парный обмен, просмотры.
2.1. СОРТИРОВКА ОБМЕНОМ 27 соответствующую позицию за (/V- УзУУ/2) просмотров, получим, ЧТО В /М2 сравнений не будут выполняться. Заметим, что при N = 100 максимальное число сравнений равно 5000, а ожидаемое — 4350. Так как N2/2 астет намного быстрее, чем (N/2) УЗА72 , то ожидаемое число сравнений с ростом N приближается к максимальному, и этот метод не следует приме¬ нять к спискам, имеющим солидные размеры. Для списка из 100 элементов этот метод превышает наихудшее ожидаемое число сравнений «хорошего» метода в отношении 3:1, для списка из 1000 элементов — в отношении 24: 1. Для списка из 25 элементов этот метод примерно равноценен известным «хо¬ рошим» методам. Для списка из 50 элементов число сравнений в этом методе увеличивается примерно вдвое*). 2.1.1.3. О б с у ж д е н и е: число обменов. Число обменов изменяется от нуля (для упорядоченных списков) до числа, чуть меньшего числа сравне¬ ний (для списка, упорядоченного в обратном порядке). Так как при послед¬ нем просмотре обмены не выполняются, то максимальное число обменов равно дг(дг—1)/2; ожидаемое число обменов N(N—1)/4. Приемлемыми оценками являются N2/2 и N2/4. 2.1.1.4. Комментарий. По-видимому, среди сортировок обменом этот метод наименее эффективен. Хотя в этом методе ожидаемое число сравнений не намного меньше, чем в методе стандартного обмена (который обсуждается в следующем разделе), этот метод требует дополнительных затрат на управ¬ ление четными/нечетными просмотрами и, следовательно, предполагает боль¬ ший объем памяти под процедуры и занимает больше времени. Однако в главе 20 он будет фигурировать как эффективный метод сортировки для па¬ раллельных процессоров. 2.1.2. Стандартный обмен: метод. А4етод стандартного обмена (называ¬ емый также «методом пузырька») перемещает один элемент списка в соответ¬ ствующую позицию при каждом просмотре. Таким образом, при первом про¬ смотре запись с наибольшим ключом помещается в последнюю позицию, при втором просмотре запись со следующим по величине ключом перемещается в предпоследнюю позицию и т. д. Метод может быть преобразован так, что будет размещать элементы по убыванию. При первом просмотре первый элемент списка сравнивается со своим непосредственным преемником, и, если этот преемник меньше, они меняются местами. Теперь больший элемент, расположенный во второй позиции, срав¬ нивается с элементом из третьей позиции. Обмен происходит, если необхо¬ димо больший из них разместить в третьей позиции. Затем позиция 3 сравни¬ вается с позицией 4, позиция 4 с позицией 5 и т. д. Когда позиция N — 1 сравнивается с позицией N, просмотр заканчивается. ) Эга оценка ожидаемого числа сравнений является очень упрощенным ариантом выражения, использованного К. Айверсоном в книге «Язык про¬ гревания» (К. Iverson. A Programming Language. N.-Y.: Wiley, 1962). МетодааВЛеИИе ЧИСла сРавнений этого метода с числом сравнений «хорошего» Цавмл ол?С1Н°ВаН0 на том’ что ожиДаемое число сравнений в этих методах г °но 2N • log2 N.
28 ГЛ. 2. СОРТИРОВКИ ОБМЕНОМ И ЛИНЕЙНАЯ ВСТАВКА Если в списке элемент k — 1 расположен раньше ку то при каждом срав¬ нении (k—1) \к больший элемент попадает в позицию к. Элемент, переме¬ щаемый вниз, считается в данный момент наибольшим в списке. Когда при сравнении обнаруживается, что &-й элемент больше, обмена не происходит. Следовательно, каждый раз сравниваются элемент, считающийся наибольшим (к— 1), и его непосредственный преемник к. Второй просмотр идентичен первому с той лишь разницей, что уже уста¬ новленная позиция исключается из последовательности. Каждый последую¬ щий просмотр исключает очередную установленную позицию, укорачивая список. Подсчет обменов ведется для каждого просмотра. Просмотр, в резуль¬ тате которого число обменов не увеличилось, заканчивает сортировку. 2.1.2.1. Пример. Рассмотрим обычный список из чисел (рис. 2.4). Для первого просмотра, показанного подробно, указаны состояния списка после каждого сравнения. Сравниваемые позиции указаны в заголовках столбцов. После сравнения позиции 2 с позицией 3 (т. е. 2:3), происходит обмен клю¬ ча 6 и ключа И. После 3:4 обмениваются ключ 11 и ключ 4. Продвижение наибольшего ключа вниз по списку можно легко проследить на этом примере, так как ключ 11 является наибольшим ключом. В конце этого просмотра (10:11) ключ И попадает в соответствующую позицию. В течение этого просмотра выполнено девять обменов. Как и ранее, счетчик обменов, обеспе¬ чиваемый алгоритмом, обозначен через EXCOUNT. К концу второго просмотра два наибольших элемента занимают соответ¬ ствующие позиции, к концу третьего — три наибольших и т. д. Этот пример требует максимального числа просмотров для завершения сортировки. 2.1.2.2. Обсуждение: число сравнений. Число сравнений для этого метода зависит от числа просмотров, необходимых для упорядочения данных. На каждом просмотре будет К — 1 сравнение, где К есть число не¬ упорядоченных элементов списка к началу каждого просмотра. Для первого просмотра Ку естественно, равно N. Число сравнений задается арифметической прогрессией (N — 1) + (N — 2) + (/V — 3) + .. где сумма зависит от числа слагаемых, а число слагаемых соответствует числу просмотров. Так как в этом методе будет как минимум один просмотр, то минимальное число сравнений равно N — 1 или приблизительно N. В худ¬ шем случае будет N просмотров и соответственно максимальное число сравне¬ ний будет равно (N) (N — 1) /2 (приблизительно N2/2). Ожидаемое число сравнений будет близко к ожидаемому числу сравнений для парного обмена (см. раздел 2.1.2.4). Для читателей, заинтересованных в анализе этого алгоритма, полное обсуждение есть у Кнута в книге «Сорти¬ ровка и поиск» [21]. Оценка ожидаемого числа сравнений — (N2/2) — (3iV/4)— указана на рис. 2.7. 2.1.2.3. Обсуждение: обмены. Число обменов изменяется с изме¬ нением упорядоченности списка. При упорядоченном списке обменов нет. Максимальное число обменов бывает при списке с обратным порядком; в этом случае обмен происходит при каждом сравнении, т. е. всего (N)(N—1)/2
После сравнения 2.1. СОРТИРОВКА ОБМЕНОМ 29 П о I еосо^о>ю^ооо«м — —| I-! I г P}(0^0>mS00O(N - — | 00
30 ГЛ. 2. СОРТИРОВКИ ОБМЕНОМ И ЛИНЕЙНАЯ ВСТАВКА обменов. Ожидаемое число обменов равно (N)(N—1)/4. Оценки — N2/2 и А'2/4 — даны на рис. 2.7. 2.1.2.4. Сравнение парного обмена и стандартного об¬ мена. Обычно считается, что в стандартном обмене по сравнению с парным мало просмотров, но много сравнений, так как число сравнений в стандарт¬ ном обмене зависит от максимального положительного перемещения; в пар¬ ном обмене оно зависит от наибольшего перемещения в любом из двух на¬ правлений. Число перестановок с максимальным положительным перемеще¬ нием, большим некоторого заданного числа, меньше числа перестановок с перемещением в любом из двух направлений, большим этого заданного числа. Среднее число сравнений за просмотр увеличивается, компенсируя сокраще¬ ние числа просмотров. Однако так как вероятность немногочисленности про¬ смотров больше у стандартного обмена, чем у парного, то стандартный об¬ мен, по-видимому, будет более обоснованным. Эта характеристика в сочета¬ нии с простотой его процедуры (читатель может сравнить алгоритмы на PL/1, данные в приложении) делает стандартный обмен, как правило, пред¬ почтительнее парного обмена, хотя максимальное число сравнений одина- наково, а ожидаемое число сравнений при стандартном обмене значительно выше. 2.1.2.5. Сравнение стандартного обмена и линейного выбора с обменом. Метод стандартного обмена похож на метод стан¬ дартного выбора с обменом. Основное различие между ними в том, что при линейном выборе с обменом число просмотров фиксировано, в то время как в стандартном обмене оно меняется и зависит от исходной последователь¬ ности данных. Если при просмотре обменов не было, то ясно, что список упо¬ рядочен и процедура может закончиться. Сравнивая линейный выбор с обменом и стандартный обмен, мы должны определить, может ли экономия за счет отказа от обмена записей при каждой перестановке компенсировать возможное увеличение числа просмотров для сортировки списка. 2.1.3. Просеивание: метод. Метод просеивания (также называемый «линейной вставкой с обменом» или «челночной сортировкой») является са¬ мым лучшим из этих методов. Он отличается от других методов обмена тем, что не сохраняет фиксированной последовательности сравнений. Кроме этого, исчезает разделение на отдельные просмотры как следствие схемы последова¬ тельностей сравнений. Метод просеивания работает точно так же, как стандартный обмен до тех пор, пока не надо выполнять перестановку. Сравниваемая величина с меньшим ключом поднимается насколько это возможно вверх по списку. Она сравнивается «в обратном порядке» со всеми ее линейными предшественни¬ ками по направлению к вершине списка. Если ее ключ меньше, чем у пред¬ шественника, то выполняется обмен и начинается очередное сравнение. Когда элемент, передвигаемый вверх, встречает элемент с меньшим ключом, этот процесс прекращается и нисходящее сравнение возобновляется с той позиции, с которой выполнялся первый обмен. Назовем нисходящее сравнение первичным, а восходящее вторичным. Любое первичное сравнение может увеличить число вторичных сравнений.
2.1. СОРТИРОВКА ОБМЕНОМ 31 Если первичное сравнение охватывает позиции 6 и 7, то цепочка вторичных нений может иметь самое большее пять сравнений. Этот максимум дости¬ гается если исходный ключ из позиции 7 меньше всех ключей в списке, рас¬ положенных выше этой позиции. Фактическая длина последовательности вторичных сравнений зависит от величины двигающегося вверх элемента от¬ носительно величины каждого элемента из предшествующей упорядоченной части списка. Сортировка заканчивается, когда первичное сравнение охватит (УУ+1)-й элемент. 2.1.3.1. Пример. На рис. 2.5 указан обычный список из чисел. Метод будет начинаться с первичного сравнения позиций 1 и 2. Так как обмен не нужен, то следующим шагом будет первичное сравнение позиций 2 и 3, ко¬ торый вызовет обмен ключей б и 11. Теперь последовательность вторичных сравнений начинает продвигать ключ 6 вверх по списку, насколько это воз¬ можно. Поэтому следующими сравниваются позиции 2 и 1. Поскольку ключ 3 меньше ключа 6, то обмен не выполняется, и вторичная последовательность кончается. Она окончилась бы в любом случае, так как при попытке про¬ должить эту последовательность была бы обнаружена вершина списка. Следующий шаг возобновляет первичное сравнение. Так как последним первичным сравнением было 2:3, то следующим будет 3: 4. В позиции 3 находится ключ И, который был помешен туда при последнем первичном обмене. Первичное сравнение 3 : 4 обнаруживает инверсию, выполняется об¬ мен с последующей вторичной последовательностью 2:3, 1:2 для размеще¬ ния ключа 4. Заметим, что выше позиции последнего первичного сравнения список упорядочен. На рис. 2.5 показаны первичные и вторичные сравнения до того момента, как ключ 2 достигнет позиции 6. Эта вторичная цепочка будет содержать более пяти сравнений, оканчиваясь размещением ключа 2 в позиции 1 в ре¬ зультате сравнения 1 : 2. Затем будет выполнено последнее первичное сравне¬ ние 10:11, а вторичная последовательность из девяти сравнений и обменов переместит ключ 1 в позицию 1, упорядочив тем самым список. 2.1.3.2. Обсуждение: число сравнений. Число сравнений ми¬ нимально, N—1, когда исходный список полностью упорядочен. Число срав¬ нений максимально, когда список имеет обратный порядок. В этом случае каждое из N — 1 первичных сравнений порождает вторичную последователь¬ ность, что увеличивает общее расстояние от точки первичного сравнения до вершины списка. Средняя длина вторичной последовательности будет равна (ДГ__1)/2 Следовательно, общее число сравнений равно (N—1)2/2. Прием¬ лемыми оценками минимального и максимального числа сравнений можно считать соответственно N и N2/2. Чтобы определить ожидаемое число сравне- нни, учтем, что средняя длина поиска любой позиции списка равна половине Алины списка. Процесс «просеивания» аналогичен поиску в упорядоченном списке чисел нужной позиции для нового числа. Лучше всего предположить, няя Н°ВЫ** элемент будет располагаться у центра списка. Следовательно, сред- поск ДЛИНа DTOPH4HOl,Jl послеДовательности приблизительно равна (N—1)/4, ной ЛЬК^ каждая последовательность будет равна половине всей максималь- Длины. В случае N — 1 первичного сравнения будет приблизительно
ГЛ. 2. СОРТИРОВКИ ОБМЕНОМ И ЛИНЕЙНАЯ ВСТАВКА (iV—1)2/4 вторичных сравнений. К этому необходимо добавить М—1 первичных сравнений, тогда общее число ожидаемых сравнений будет равно N— 1 + ((/V — 1)2/4); оценка N + N2/4 не приведет к ошибке. Исходный список Р 1 : 2 Р 2 : 3 S 1 : 2 Р 3 : 4 S 2 : 3 S 1 : 2 1. 3 3* 3* 3* 3 3 3* 2. 11 11* 6* <-i 6* 6 4*4-, 4* 3. 6 6 11*4-1 И 4* 4-1 6* 4-1 6 4. 4 4 4 4 И* <-» 11 И 5. 9 9 9 9 9 9 9 6. 5 5 5 5 5 5 5 7. 7 7 7 7 7 7 7 8. 8 8 8 8 8 8 8 9. 10 10 10 10 10 10 10 10. 2 2 2 2 2 2 2 11. 1 1 1 1 1 1 1 Р 4 : 5 S 3 : 4 Р 5 :6 S 4 : 5 S 3 : 4 S 2 : 3 Р 6 : 7 S 5 : j> $4:5 1 3 3 3 3 3 3 3 3 3 2. 4 4 4 4 4 4* 4 4 4 3. 6 6* 6 6 5* 4-, 5* 5 5 5 4. 9* 4-, 9* 9 S* 4-, 6* 4-1 6 6 6 6* 5. 11*4-1 11 5*4-, 9* 4-1 9 9 9 7* 4-, 7* 6. 5 5 11*4-1 И 11 И 7* 9* 4-1 9 7. 7 7 7 7 7 7 11*4-1 И 11 8. 8 8 8 8 8 8 8 8 8 9. 10 10 10 10 10 10 10 10 10 10. 2 2 2 2 2 2 2 2 2 11. 1 1 1 1 1 1 1 1 1 Р 7 : 8 S6 : 7 S 5 : 6 Р 8 : 9 S 7 : 8 Р 9 ; 10 S 8 : 9 S 7 : 8 S 6 : 7 1. 3 3 3 3 3 3 3 3 3 2. 4 4 4 4 4 4 4 4 4 3. 5 5 5 5 5 5 5 5 5 4. 6 6 6 6 6 6 6 6 6 5. 7 7 7“ 7 7 7 7 7 7 6. 9 8*4-, 8* 8 8 8 8 8 2* 7. 8* 4-, 9*4-1 9 9 9* 9 9 2* 4-, 8* 8. 11*4-1 11 11 10*4-, 10* 10 2* 4-, 9* 4-' 9 9. 10 10 10 11*4-1 11 2* 4-, 10* 4-1 10 10 10. 2 2 2 2 2 11*4-1 11 11 11 11. 1 1 1 1 1 1 1 1 1 Замечание. Звездочки приписаны ключам, участвующим в указанном сравнении. Стрелки обозначают обмены, произведенные в результате этих сравнений (Р —первичное сравнение, S — вторичное). Рис. 2.5. Метод просеивания. 2.1.3.3. Ч и с л о обменов. Минимальное число обменов равно нулю, если список упорядочен, максимальное равно числу сравнений, если список имеет обратный порядок. Ожидаемое число обменов очень близко к ожидае* мому числу сравнений. Самое большее, может быть 2N — 2 Сравнений, не со*
2.2. СОРТИРОВКА ВСТАВКАМИ 33 вождаемых обменами. Это — первичные и последние вторичные сравнения. Если каждое первичное сравнение вызывает обмен, то имеем максимальное число обменов. Так как ожидается приблизительно N2/4 вторичных сравне¬ ний, то можно ожидать примерно N2/4 обменов. 2.2. Сортировка вставками Сортировка вставками есть общее название группы методов сортировки, основанных на последовательной вставке «новых» элементов в увеличиваю¬ щийся упорядочиваемый список. Среди них есть три существенно разных ме¬ тода: линейная вставка, центрированная вставка и двоичная вставка. Эти методы сортировки различаются методами поиска подходящего места для вставки элемента. Простейшим методом является линейная вставка. Как сле¬ дует из названия, в этом методе уже существующий список рассматривается как простой линейный список, просматриваемый поэлементно сверху вниз, пока не будет найдена соответствующая позиция для нового элемента. Этот метод обычно используется тогда, когда процесс, внешний к данной сортировке, динамически вносит добавления в список, все элементы которого известны и который должен все время поддерживаться в упорядоченном со¬ стоянии. Сортировка выполняется каждый раз при получении нового элемен¬ та, размещая этот элемент в нужное место списка и облегчая контроль. Не¬ которые характеристики систем реального времени делают вставку полезным техническим приемом. Связь между процессом, порождающим подлежащие сортировке числа, и сортировкой такова, что сортировка привлекается многократно. Такое по¬ вторное привлечение может быть сопряжено с некоторыми издержками, та¬ кими как передача параметров, вход и выход из процедуры. Эти издержки должны быть выявлены и учтены при анализе использования метода вставок таким способом. Сортировку вставками можно организовать как один унифи¬ цированный процесс (см. раздел 2.1.3). 2.2.1. Линейная вставка: метод*).Под сортировку выделяется количество памяти, равное предполагаемой длине окончательного списка из всех элемен¬ тов. Счетчик длины списка в самом начале устанавливается равным нулю. При помощи этого счетчика контролируется длина области поиска нужной позиции для элемента, вставляемого в список. Сортировка привлекается для каждого элемента. Один «вызов» сортирующей подпрограммы размещает один элемент в списке и увеличивает счетчик списка на единицу. Первый элемент помещается в верхнюю позицию области вывода. Сле¬ дующий элемент, присоединяемый к списку, сравнивается с первым. Если ключ нового элемента больше, он помещается в позицию, следующую за по¬ зицией первого элемента. Если ключ нового элемента меньше, то первый эле- Мент ПеРсмещается в позицию 2, а новый элемент помещается в позицию 1. В Дальнейшем все новые элементы последовательно сравниваются с каж- А1е,м элементом списка, ший. *) См. - JUM списка, начг 0льший. Этот больший э, начиная с первого, до тех пор, пока не встретится лемент и все последующие элементы списка также раздел 2.1.3. ^ С Лорин
34 ГЛ. 2. СОРТИРОВКИ ОБМЕНОМ И ЛИНЕЙНАЯ ВСТАВКА передвигаются на одну позицию вниз. Таким образом освобождается место, на которое вставляется новый элемент. Первое обращение Второе обращение Третье обращение Длина=0, новый = 3 Длина = 1. новый = 11 Длина=2, новый=6 TOSORT = 3 <- TOSORT = 3 TOSORT=3 О 11<- 6«- 0 О И* О 0 0 0 0 0 0 0 0 0 0 0 0 0 0 О 0 0 обо Четвертое обращение Пятое обращение Шестое обращение Седьмое обращение Длина = 3, новый=*4 Длина = 4, новый=»9 Длина=»5, новый=»5 Длина=6, новый=>7 = 3 TOSORT=3 TOSORT=3 TOSORT=3 4 4г- 4 4 4 6* 6 5<- 5 11* 9<- 6* G 0 11* 9* 7 <г 0 0 U* 9* 0 0 0 11* 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Одиннадцатое Росьмое обращение Девятое обращение Десятое обращение обращение Длина = 7, новый = 8 Длина = 8. новый = 10 Длина=9, новый = 2 Длина = 10, новый = 1 TOSORT=3 TOSORT = 3 TOSORT = 2 TOSORT = 1 <- 4 4 3* 2* 5 5 4* 3* 6 6 5* 4* 7 7 6* 5* 8 <- 8 7* 6* 9 9 8* 7* 11* 10<- 9* 8* 0 11* 10* 9* 0 0 11* 10* 0 0 0 11* Замечание: Звездочками отмечены перемещаемые элементы, стрелки указывают на размещаемый элемент. Рис. 2.6. Линейная вставка. 2.2.2. Пример. Линейная вставка иллюстрируется на рис. 2.6. При пер¬ вом обращении к сортировке длина списка вывода равна нулю. Первым эле¬ ментом, помещаемым в список вывода, является ключ 3. В столбце, озаглав¬ ленном «Первое обращение», ключ 3 отмечен стрелкой, установленной на на-
2.2. СОРТИРОВКА ВСТАВКАМИ 35 чало области вывода — ячейка TOSORT. Длина списка увеличивается на 1. (Как обычно, все элементы, помещаемые в список, указываются стрелкой, а все перемещаемые — звездочкой.) При втором обращении к сортировке длина = 1. Новый ключ 11 сравни¬ вается с ключом 3, ищется больший и помещается во вторую позицию. Для третьего обращения длина списка устанавливается равной 2. Ключ 6, боль¬ ший ключа 3, сравнивается затем с ключом 11, и выясняется, что ключ б меньше. Поскольку ключ 6 должен быть между ключом 3 и 11, то позиция, ныне занимаемая ключом 11, должна быть освобождена для ключа 6. Ключ 11 опускается на одну позицию, а ключ б вставляется в список на нужное место. Все последующие обращения к сортировке происходят аналогичным об¬ разом. Ключ 4 вызывает перемещение вниз ключей 11 и 6, так что 4 может быть вставлен между ключами 3 и 6; ключ 9 вызывает перемещение ключа 11 н т. д. 2.2.3. Обсуждение: число сравнений. Число сравнений при любом про¬ смотре зависит от количества элементов в списке. Пусть длина области вы¬ вода, вмещающей все ожидаемые элементы, равна N. Так как элементы по¬ ступают по одному, то область вывода не заполнена, пока сортировка не закончена. Как правило, ожидаемое число элементов в списке равно N/2, так как длина списка изменяется от 0 до N. Сравниваться элементы будут при N — 1 обращении к сортировке, поскольку при первом обращении элемент только помещается в список. В худшем случае каждый новый элемент поме¬ щается вниз списка, и число сравнений на каждом просмотре равно N/2 — средней длине списка для всех просмотров. Таким образом, худшим случаем для сравнений является тот, при котором элементы списка упорядочиваются в той же последовательности, в какой они поступают. Здесь мы впервые на¬ блюдаем чувствительность к упорядоченности, когда чем лучше упорядочены данные, тем больше выполняется сравнений. Когда элементы поступают в нужной последовательности, будет N(N— 1)/2 сравнений (~iV2/2). Если элементы поступают в обратном порядке, то потребуется N — 1 сравнений. При появлении каждого нового элемента за одно сравнение будет обнаруживаться, что первый элемент в списке больше. Как правило, в любой момент времени до того, как найти больший ключ, будет обследована половина уже существующего списка. Следовательно, ожи¬ даемое число сравнений равно N(N—1)/4. В качестве оценки можно ис¬ пользовать N2/4. 2.2.4. Обсуждение: число перемещений данных. В отличие от методов обмена, рассмотренных в предыдущих разделах, методы сортировки встав¬ ками предполагают перемещение записей из одной позиции в другую, а не пзаимный обмен позициями. Поэтому каждое перемещение данных составляет примерно половину работы как по вставке, так и по обмену. Точное различие МеждУ Функциями обмена и перемещения определяется, конечно, спецификой ины. На машине с быстрой командой пересылки память-память и перс- 0Чен- Длнной поля перемещение набора записей вниз списка может быть ь эффективным> gce записИ} которые должны быть перемещены, могут 2*
36 ГЛ. 2. СОРТИРОВКИ ОБМЕНОМ И ЛИНЕЙНАЯ ВСТАВКА быть перемещены одной командой, и эффективность освобождения места для вставки по сравнению с выполнением обмена очень высока. Минимальное число перемещений 0 бызает, когда входной список уже упорядочен. Максимальное число перемещений бывает, когда он имеет обрат¬ ный порядок; в этом случае первый элемент перемещается N—I раз, второй N—2 раза, третий N — 3 раза и т. д. Среднее число позиций, на которое перемещается элемент, равно N/2. При N — 1 элементах (последний элемент не перемещается) будет N(N—1)/2 перемещений. Ожидаемое число переме¬ щений равно половине этого или N(N— 1)/4 (примерно /V2/4). 2.3. Краткий обзор основных сравнительных методов Нами уже описаны основные сравнительные методы. На рис. 2.7 перечис¬ лены характеристики их производительности, что дает читателю средство для выбора метода. Сортировка (память) Линейная выборка (от N цо 2N) Линейная выборка с обменом (N) Линейный подсчет (от N до 3N) Парный обмен {N) ■Стандартный обмен для N < 100 (N) Просеивание (N) Вставка (от N до 2N) Сравнения (минимум, ожидаемое, максимум) N2, N\ N2 N2(2, NV2, N*l2 N2/2, N2/2, N2/2 N, Ы212-{М/2)л/Ш/2, N2/ 2 N, N2/2—3/V/4, N'V2 N, N + N'V4, N'V2 N, NV4, NV2 Перемещения даниых (перемещения или обмены) N перемещений N обменов N перемещений 0, N2/4, N'42 обменов 0, N2/4, N212 обменов 0, N2/4, N2/2 обменоп 0, N214, N2/2 переме¬ щений Другие функции N2I\ перемещении кл ючей N2/A перемещений ключей N2I2 подсчетов Рис. 2.7. Итоговые характеристики семи основных методов сортировки. При¬ близительные результаты для сортировки списка из N элементов. Однако цель рис. 2.7 не в том, чтобы дать руководство для точного вы¬ числения числа сравнений и перемещений. Методы сортировки, описанные в главах 1 и 2, не следует использовать, когда надо «на глаз» выбрать сорти¬ ровку с целью минимизации или точного прогнозирования производительности. Поэтому в итоговой таблице использованы не точные числа, а их оценки. Таким образом, рис. 2.7 является лишь приблизительным указанием произво¬ дительности рассмотренных методов. Больше подробностей приведено в рабо¬ тах [3, 7, 12, 17, 21]. Очень приблизительный и предварительный характер рис. 2.7 не следует преувеличивать. Тщательный анализ точности каждой функции на конкретной машине есть только первый шаг к разумной процедуре. Большой разрыв между «ожидаемым», максимумом и минимумом должен заполняться умением программиста хорошо разобраться в своих данных и их исходном порядке или отсутствии такового.
3.3. ПРИМЕР 37 Глава 3. МЕТОД СОРТИРОВКИ ШЕЛЛА 3.1. Введение 28 июля 1959 г. Д. Л. Шелл описал минимальный по памяти метод сор¬ тировки [27], который стал широко известен как сортировка Шелла, хотя ее иногда называют слияние с обменом [18]. В литературе ей было уделено много внимания и активное обсуждение ее свойств еще продолжается.' В этой главе мы опишем сам подход, обсудим влияние вариантов вычисления крити¬ ческого параметра и опишем варианты кодирования. Читателя, нуждающегося в более подробной информации, отсылаем к работам [10, 14, 27]. 3.2. Метод Сортировка Шелла является расширением сортировки просеиванием. По¬ следний просмотр в сортировке Шелла идентичен методу просеивания, опи¬ санному в гл. 2. Предшествующие просмотры используют тот же техниче¬ ский прием, но в них сравниваются и обмениваются не непосредственные соседи, а элементы, отстоящие на заданное расстояние. Например, позиция 1 сравнивается с позицией 5, позиция 5 с 9, 9 с 13 и т. д. Когда обнаружена инверсия, цепочка вторичных сравнений охватывает те элементы, которые входили в последовательность первичных сравнений. Например, если обнару¬ жена инверсия между позициями 9 и 13, то возможная вторичная последова¬ тельность состоит из сравнений 5 : 9 и 1 : 5. На каждом просмотре шаг между сравниваемыми элементами определя¬ ется путем сокращения вычисленного исходного шага. На последнем про¬ смотре он сокращается до 1. Цель метода на ранних просмотрах — сократить число вторичных сравнений и обменов на более поздних просмотрах. В этом методе элементы могут совершать большие скачки к нужным позициям на ранних просмотрах, а не передвигаться на одну позицию за один раз. На последнем просмотре числа будут стремиться располагаться близко к своим позициям и, следовательно, потребуют незначительных перемещений при окон¬ чательном размещении. Модификации метода различаются способами вычисления начального шага между элементами и правилами сокращения этого шага от просмотра к просмотру. 3.3. Пример Здесь будет использован технический прием разбиения на части, впервые уписанный Шеллом. Список длины N умозрительно разбивается на N/2 частей если N нечетно), каждая из которых содержит два элемента. 11 число элементов в списке нечетно, то одна из частей будет содержать ^Ри элемента. Элементы каждой части отстоят друг от друга на N/2 позиций. по*6 И3 0ДИН11аДЦати элементов будет пять частей с расстоянием в пять Ии между элементами одной части. Следовательно, первая часть
38 ГЛ. 3. МЕТОД СОРТИРОВКИ ШЕЛЛА содержит элементы из позиции 1, 6 и 11; вторая часть — элементы из позиций 2 и 7; и последняя часть — элементы из позиций 5 и 10. Первый просмотр в этом методе упорядочивает элементы каждой части. Последовательность сравнений передвигается от одной части к другой по ходу просмотра списка. Например, первичная последовательность сравнений — 1:6, 2:7, 3:8; т. е. первый элемент части 1 сранивается со вторым элемен¬ том этой же части, затем первый элемент части 2 сравнивается со вторым эле¬ ментом части 2 и т. д. На рис. 3.1 показаны последовательность сравнений, Первичные Вторичные 1 2 3 4 5 Исходный После После После После список 2 : 7 5 : 10 6 : 11 1 : 6 1. 3 3 3 3 1 <— 2. 11 7 <— 7 7 7 3. 6 6 6 6 6 4. 4 4 4 4 4 Б. 9 9 2<~ 2 2 6. 5 5 5 1 <— 3 7. 7 11 11 11 11 8. 8 8 8 8 8 9. 10 10 10<— 10 10 10. 2 2 9 9 9 11. 1 1 1 5 Ч— 5 Последовательность сравнений и обменов (по позициям) Сравнения. Обмены 1 : 6 - 1 : 7 2, 7 3 : 8 - 4 : 9 - 5 : 10 5, 10 6 : 11 6, 11 1 : 6 (вторичное) 1. 6 Замечание. Стрелки указывают обмены. Рис. 3.1. Первый просмотр сортировки Шелла с числом частей, равным N/2. обменов и порядок в списке после нескольких сравнений и в конце первого просмотра. До сравнения 6:11 каждое сравнение охватывало новую часть, и при этом каждый элемент сравнивался только один раз. Сравнение 6:11 исполь¬ зует два элемента из первой части, один из которых (6) был использован ранее. Следовательно, известно, что ключ, находящийся в позиции 6, — боль¬ ший из двух предыдущих элементов. Если сравнение 6:11 выявит, что со¬ держимое позиции 11 больше, то часть (1, 6, 11) упорядочена. Однако если ключ из позиции 11 меньше, то необходимо выполнить обмен между пози¬ циями 6 и 11. На рис. 3.1 в столбце 4 показано состояние списка после этого обмена (ключей 1 и 5). Теперь уже нет информации об относительной величине ключа, переме¬ щенного в позицию 6, и ключа первого элемента этой части (из позиции 1). • Для того чтобы определить, полностью ли упорядочена эта часть, необходимо
3.3. ПРИМЕР 39 ,еше раз выполнить сравнение 1 : 6. Сравнения этого типа — вызванные обме¬ ном меньших величин в этой части — называются «вторичными», как и в ме¬ тоде просеивания. Сравнения Обмени Исходный список Первичные Вторичные 1 : 3 2 : 4 2, 4 3 : 5 1 : 3 3, 5 4 : 6 4, 6 2 : 4 2, 4 5.: 7 и : 8 7 : 9 5 : 7 7, 9 8 : 10 9 : 11 7: 9 5: 7 9, 11 3 : 5 7. 9 5. 7 Рис. 3.2. Просмотр Сравнения Обмены Первичные Вторичные .1 : 2 2*: 3 1 : 2 2, 3 3 : 4 4 : 5 5 : 0 0 : 7 5 : 6 6, 7 7 : 8 8 : У 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. И. 1 7 6 4 2 3 И 8 10 9 5 Окончательный список 1 3 2 4 5 7 6 8 10 9 11 Исходный список Окончательно упорядоченный список 1. 1 1 2. 2 2 3. 2 3 4. 4 4 5. 5 5 6. 7 6 7. 6 7 8. 8 8 9. 10 9 10. 9 10 11. 11 11 9 : 10 9, 10 8 : 9 Ю : 11 Рис. 3.3. Последний просмотр сортировки Шелла (шаг=1). Вторичное сравнение между позициями 1 и 6 вызывает обмен между соответствующими элементами, в результате чего часть 1 становится упоря¬ доченной. Все части теперь упорядочены. На рис. 3.1 в столбце 5 показан СПИсок к концу первого просмотра.
40 ГЛ. 3. МЕТОД СОРТИРОВКИ ШЕЛЛА В конце этого просмотра части переопределяются путем изменения шага между элементами одной части. Шелл предложил устанавливать шаг для второго просмотра равным половине начального шага (берется целая часть). В соответствии с этим шаг между элементами одной части при втором про¬ смотре равен 2. Второй просмотр упорядочивает новые части тем же способом, что и первый просмотр. На рис. 3.2 показаны последовательности первичных и вто¬ ричных сравнений, а также состояние списка в конце второго просмотра. Отметим, что этот метод не гарантирует, что при обменах элемент всегда перемещается ближе к нужной позиции. На самом деле ключ 10 прежде, чем он вернется в позицию 9, перемещается вверх в позицию 7. В конце второго просмотра части переопределяются вновь. Шаг опять сокращается до половины предыдущего шага. Для данного примера этот шаг теперь равен 1. Последний просмотр в сортировке Шелла всегда имеет шаг, равный 1, и является простым просеиванием. На рис. 3.3 показаны последова¬ тельности первичных и вторичных сравнений в процессе завершения упоря¬ дочения списка. Три просмотра упорядочивают список. Число просмотров равно числу делений на 2 для сведения IV к 1. Когда N равно степени двойки, алгоритм Шелла требует log2 N просмотров. 3.4. Вычисление шага Распределение объема работы в этом методе — эффективная подготовка, которая выполняется на ранних просмотрах — тесно связано с последователь¬ ностью расстояний между элементами частей от просмотра к просмотру. К настоящему времени предложено несколько взаимоисключающих мето¬ дов вычисления шагов. Хиббард [14] разработал алгоритм, который гаран¬ тирует, что шаг между элементами всегда будет нечетным числом. Функцию Хиббарда можно записать так: 2entier log2 N j Для списка из одиннадцати чисел entier Iog2 /V = 3, и 23 есть наибольшая целая степень двойки, меньшая 11. 23 = 8, и первый шаг по Хиббарду равен 23 — 1 =7. Последующие шаги у Хиббарда вычисляются так же, как и у Шелла, т. е. как целая часть половины предыдущего шага. Сравнение последовательности шагов у Хиббарда и у Шелла на списке из 16 элементов показывает значение выбора шага. Вариант Хиббарда тре¬ бует трех просмотров. Вариант Шелла требует длительного четвертого про¬ смотра. На рис. 3.4 дано сравнение результатов этих двух вариантов*). На¬ чальный шаг, равный 7, при 16 элементах объясняется требованием, чтобы показатель степени давал число, меньшее N. Следовательно, при N = 16, как и при Л'= 11, (entier log2 N) есть 3. Существует коренное различие в рас¬ пределении работы между последним и предшествующими просмотрами. За- *) Заключительный просмотр у Хиббарда (шаг = 1); у Хиббарда шаг = = 7, 3, 1; у Шелла шаг = 8, 4, 2, 1.
3.5. ВАРИАНТ С ОТЛОЖЕННЫМИ ОБМЕНАМИ 41 метим, что у Хиббарда 18 из 37 обменов (около половины) выполняются на последнем просмотре, в то время как у Шелла на последнем просмотре выполняются 29 из 44 (около двух третей) обменов. Число обменов, выпол¬ няемых на последнем просмотре, обратно пропорционально количеству полез¬ ных перестановок, сделанных на предыдущих просмотрах, и, следовательно, эффективности метода. На заключительном просмотре в варианте Шелла есть две части, одна из четных позиций 2, 4, 6, 8, ..., а другая из нечетных 1, 3, 5, 7. ... Каждая Метод Хиббарда Метод Шелла Сравнений Обменов Сравнений Обменов Просмотр 1 11 8 8 5 Просмотр 2 22 11 14 4 Просмотр 3 * 32 18 19 6 Просмотр 4 - 43 29 65 37 84 44 * Последний просмотр в методе Хиббарда (шаг = 1). В методе Хиббарда D = 7, 3, 1; в методе Шелла D = 8, 4, 2, 1. Рис. 3.4. Сравнение выбора шага в методах Хиббарда и Шелла. часть сортируется отдельно, но порядок одной относительно другой не имеет значения. Этот случай возникает всегда, когда N равно степени 2, поскольку в этом случае шаг всегда будет четным. При этом числа из нечетных позиций никогда не сравниваются с числами из четных позиций. Вследствие этого на заключительном просмотре должно выполняться слияние двух независи¬ мых строк. В данном примере, при N = 16, производительность способа Хиббарда превосходит производительность способа Шелла. У Хиббарда на один про¬ смотр, 19 сравнений и 7 обменов меньше. В своем комментарии к методу Шелла, Фрэнк и Лазарус [10] рассмо¬ трели необходимость сохранения шага нечетным. Они предложили уменьшать шаг быстрее, чтобы увеличить число вторичных сравнений и сократить число первичных. Оптимальная последовательность неизвестна. Весь фокус в том, чтобы найти число, которое бы сбалансировало число просмотров, распределение работы на каждом просмотре, предполагаемую длину вторичных сравнений и т. п. Помимо упомянутых здесь последовательностей есть и другие. При изучении этого метода Кнут [21] исследовал различные величины (включая числа Фибоначчи) при условии, что DISTANCE (/) всегда делится на DISTANCE (/ —|— 1). Он пришел к заключению, что в определении наилучшей последовательности есть какое-то «колдовство». Ожидаемое число сравнений До сих пор не определено для общего случая. Минимум, найденный для ожи¬ даемого числа сравнений, равен N log2 N. 3.5. Вариант с отложенными обменами В разделе 3.2 при описании метода предполагалось, что обмен следует За кажДым сравнением, которое выявляет элемент больший, чем предыдущий элемент части. В алгоритме, опубликованном Хиббардом [14], использован Метод> сокращающий число обменов. Этот алгоритм отличается от ранее.
42 ГЛ. 4. СТРУКТУРЫ В СОРТИРОВКЕ описанного тем, что он использует временную память для хранения сравни* ваемых элементов в течение всей последовательности сравнений. Каждое первичное сравнение ключ*: ключ/ + шаг включает пересылку ключ,- + шаг во временную память. Сравнение позиции 1 с позицией 4, напри* мер, на самом деле включает пересылку из позиции 4 во временную память и сравнение ключа из временной памяти с ключом из позиции 1. Если ключ/ больше, он перещается в позицию ключ/ -f- шаг. Если ключ/ + шаг больше,, то перемещение не нужно. Пересылка во временную память позволяет эффек¬ тивно освобождать позицию последующего элемента этой части. Когда ключ/ больше, чем ключ/ + шаг, то ключ/ пересылается из своей позиции в «свободную» позицию, и метод начинает последовательность вто- ричных сравнений. Содержимое временной памяти (ключ/ + шаг) — это за¬ пись, поднимающаяся на верх данной части. Ключ каждой записи сравни¬ вается с временной памятью и, если обнаружено, что он больше, пересылается вниз списка в текущую свободную позицию. Каждая пересылка освобождает позицию перемещаемого элемента. Когда в списке обнаружен элемент с ключом,, меньшим ключа временной памяти, содержимое временной памяти помещается в позицию списка, освобожденную самой последней, т. е. в нужное место. Использование временной памяти эффективно тогда, когда длина после¬ довательности вторичных сравнений не меньше 2. Поскольку скорее всего это верно для списков произвольной конечной длины со случайно упорядо¬ ченными данными, то вариант с отложенными обменами может, вообще го¬ воря, быть лучше других сортировок Шелла. Глава 4. СТРУКТУРЫ В СОРТИРОВКЕ 4.1. Представление о структуре Для того чтобы сократить количество сравнений, любой из эффективных сравнительных внутренних методов сортировки предполагает некоторую не¬ линейную структуру или разбиение сортируемого списка. Конкретной струк¬ турой, которая используется в широком классе методов сортировки, является дерево. В этой главе будут введены основные понятия о деревьях и древо¬ видных структурах, необходимые для обсуждения методов сортировки, кото¬ рые вводятся в последующих главах. Любой алгоритм, оперирующий с нелинейными структурами, зависит от способа образования адресов элементов данных, которые согласно некото¬ рому критерию являются «следующими». Часто используются встроенные- указатели. Иногда для перехода от одного элемента к другому применяются алгоритмы образования адресов, используются деление и умножение адресов. 4.2. Двоичные деревья На рис. 4.1 показана структура, именуемая двоичным деревом. Числа вне кружков — относительные номера позиций элементов, представленных этими кружками. Числа внутри кружков — хранимые значения. Элементы дерева называются узлами. Каждый элемент сортируемого списка чисел является
4.2. ДВОИЧНЫЕ ДЕРЕВЬЯ 43 узлом дерева. Линии между узлами называются дугами. Они обеспечивают средство передвижения от одного узла к другому. Узел, соединенный дугой с другим узлом, может быть предком (предшественником), левым преемником либо правым преемником. На рис. 4.1 узел 1 — предшественник (PRED) для Уровень 2°=1 Zf=2 2=4 23=6 Узлы 1 2,3 Ь,5,6,7 8,9, Ю, 11 (12,13,14,15) Узлы Позиция 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. к_ 3 11 6 4 9 5 7 8 10 2 1 LSUC 2 4 6 8 10 N N N N N N RSUC | PRED | 3 5 7 9 11 N <- N N N N N X <— указатель 1 корня 1 2 2 3 указатель 3 «пусто» 4 4 5 5 Рис. 4.1. Структура и табличное описание двоичного дерева, узлов 2 и 3. Узел 2 — левый преемник (LSUC) узла 1, а узел 3 — правый преемник (RSUC). Узлы 2 и 3 в свою очередь являются предшественниками узлов 4, 5, 6 и 7. У двоичного дерева должен быть один и только один корневой узел, ко¬ торый не имеет предшественников. Любой узел, отличный от корневого, мо¬ жет иметь только одного предшественника. Любой узел может иметь только двух преемников. Последнее требование отличает двоичное дерево от деревьев Других видов [13]. Деревья иногда изображают в форме списка так, что предки и преемни¬ ки показаны явно. Список в верхней части рис. 4.1 представляет дерево. Ниже приведены дополнительные характеристики. 1. Левым преемником любого заданного узла всегда является тот узел, чси номер позиции в два раза больше номера позиции заданного узла. Левый преемник узла 1 есть узел 2. Левый преемник узла 2 — узел 4. Левый преем¬ ник узла 4 — узел 8. 2. Правым преемником любого заданного узла всегда является тот узел, ?еи номер позиции равен удвоенному номеру позиции заданного узла плюс I, Правый правый преемник узла 1 есть узел 3; правый преемник узла 2 — узел 5| преемник узла 3 — узел 7 и т. д.
44 ГЛ. 4. СТРУКТУРЫ В СОРТИРОВКЕ 3. Номер позиции п-то левого преемника любого узла i равен i X 2\ Корневой узел есть узел 1. Номер позиции первого левого преемника корне¬ вого узла равен 21 X 1 = 2. Номер позиции второго левого преемника (ле¬ вого преемника второго уровня) корневого узла равен 22 X 1 = 4. Показа¬ тель степени равен длине пути (количеству дуг) от одного узла до другого, проходящего через левых преемников. Множитель i устанавливает исходную позицию. Каково расстояние от узла 1 до узла 8? Оно равно количеству дуг на пути от узла 1 до узла 8. Есть три таких дуги; 23 дает номер позиции узла 8. Каков номер позиции третьего левого преемника узла 3? 23 X 3 = 24. 4. Показатель п также указывает количество узлов на уровне, у кото¬ рого самый левый узел есть п, если дерево полно на всех уровнях. Положим, что узел 2п существует, тогда на том уровне, где расположен узел 2п, есть 2п узлов, если данное дерево является полным на этом уровне. Если узел 2п существует, то в дереве есть по крайней мере 2п узлов. Всего в дереве на всех уровнях, связанных с корнем, есть п-1 £ 2* = 2"— 1 (=0 узлов; таким образом, если на уровне 2п только один узел, то всего в дереве (2п—1) + 1 = 2п узлов. Если 2n+i узла нет, то максимум в дереве есть (2rt+1— 1) узлов. Наше дерево имеет п — 3 уровня, максимум 15 узлов, фак¬ тически 11 узлов. 5. Номер позиции непосредственного правого преемника равен удвоен¬ ному номеру позиции его предшественника плюс I. Номер крайнего правого узла, отстоящего на п уровней от корня, равен 2'1+1 — 1. Номера узлов уровня п находятся в диапазоне от 2п до 2n+i — 1. Имея эти правила, не надо явно указывать номера позиций узлов в де¬ реве при обращении к ним. Можно переходить от произвольного узла к лю¬ бому другому, используя только что указанные правила вычисления позиций и адресов. Например, если мы хотим, находясь в узле 4, перейти к его крайне правому преемнику (узел 9), то можно вычислить его позицию (номер узла), умножив четыре на два и прибавив единицу. Переход от некоторого узла к его предшественнику включает целочисленное деление на два. Заметим, что любой узел в дереве может быть корнем другого дерева — поддерева. Поддерево именуется номером узла, выбранного в качестве его корня. В нашем примере есть поддеревья 2, 3, 4, 5, 6, 7, 8, 9, 10, 11. В де¬ реве размера п есть п—1 поддеревьев. Для любого узла поддерева либо должен быть путь в корневой узел этого поддерева, либо сам узел должен являться корневым. Таким образом, 4, 8, 9 — узлы поддерева 4, а И—нет. 4.3. Объем двоичного дерева Всякий путь в дереве имеет длину, равную числу дуг в этом пути. В двоичном дереве длина пути, проходящего только через левых преемников от корневого узла до концевого узла на самом нижнем уровне, есть высота дерева, выраженная через количество уровней.
4.4. ПЕРВЫЙ ПРИМЕР ИСПОЛЬЗОВАНИЯ ДЕРЕВА 45 Понятие высоты дерева полезно при определении объема дерева. Объем дерева определяется разными способами. Определение, используемое здесь, взято с незначительными изменениями у Уиндли [29]. Сначала корневому узлу приписывается объем, равный 0. Каждому из оставшихся узлов при¬ сваивается объем, равный номеру того уровня, на котором он расположен. V N (Уровень) (Число у зло 8) У * N 0 1 О 1 2 2 2 4 8 3 4 12 22 Рис. 4.2. Объем дерева. Непосредственный преемник корневого узла имеет объем 1, узлы следующего уровня имеют объем 2 и т. д. Объем дерева равен сумме объемов всех узлов. Эта величина задается как k £ N(L)-V (L), L=0 где k равно количеству уровнен в дереве, N — количество узлов на уровне и V номер уровня. Заметим, что точно так же можно вычислить объем любого поддерева, присвоив нулевое значение корневому узлу поддерева. Объем дерева, изобра¬ женного на рис. 4.2, равен 22. 4.4. Первый пример использования дерева Первый пример использования понятия древовидной структуры для упо¬ рядочивания данных покажет, как построить двоичное дерево, представляю¬ щее список, так, чтобы с ростом дерева увеличивалась упорядоченность (рис. 4.3). Будем использовать явные указатели, а также предполагать, что есть место для описателей предшественника, левого и правого преемников. Сначала выбираем первый элемент из списка (ключ 3) в качестве корня Дерева. Ключ 11 помещаем в дерево так, чтобы удовлетворить условию: чис¬ ло» меньшее значения данного узла, становится его левым преемником, а большее число — правым. Следовательно, ключ 11 становится правым преем¬ ником корневого узла, ключ которого равен 3. Поле правого преемника У Элемента с ключом 3 будет содержать номер позиции ключа 11. 8 9 10 11
46 ГЛ. 4. СТРУКТУРЫ В СОРТИРОВКЕ Чтобы разместить третий элемент списка (ключ равен 6), сравним его с корневым узлом. Поскольку он больше, то должен стать правым преемни¬ ком этого узла. Однако место правого преемника уже занято. Адрес эле¬ мента, занимающего это место, находится в описателе правого преемника узла, соответствующего ключу 3. Ключ 6 сравнивается с ключом II. Выяс¬ няется, что он меньше, и, следовательно, ключ 6 становится левым преемни¬ ком узла, представляющего ключ 11. Чтобы отразить это, поле левого пре¬ емника узла 2 устанавливается на 3, а поле предшественника элемента, соот¬ ветствующего ключу 6, устанавливается на 2. Таблица, формируемая таким способом, содержит явные связи между узлами дерева, содержащими ключи. Лругие узлы не показаны. Как же получить последовательность 3, 6, 11 из только что построенной структуры? Есть много алгоритмов хождения от узла к узлу для получения Левый Правый Предшест- Позиция К преемник преемник венник 1 3 N 2 X 2 11 3 N 1 3 6 U N Z Рис 4.3. Рост дерева. последовательности. Например, начинаем с корневого элемента списка. На рис. 4.3 меньше элемента в списке нет. Это проявляется в отсутствии левого преемника. Таким образом, ключ 3 из корневого узла должен быть пока наименьшим элементом в списке. Теперь рассмотрим правый преемник этого узла, чтобы определить, есть ли число, большее 3. Оно есть, и мы перемещаемся в узел правого преемника позиции 2. Рассмотрим поле, соответствующее левому преемнику этого узла, чтобы выяснить, есть ли в списке число, меньшее этого. У позиции 2 (ключ II) есть левый преемник — позиция 3 (ключ 6). Отсутствие левого преемника у узла, соответствующего ключу 6, пока¬ зывает, что между числами 3 и 6 нет других чисел. Теперь ясно, что после ключа 3 ключ 6 — наименьший в списке. Выясним, есть ли числа между 6 и 11, рассмотрев правый преемник ключа 6. Больших чисел нет. Поскольку у ключа 6 есть только адрес предшественника, то возвра¬ щаемся к ключу 11 (предок ключа 6). Рассмотрим правый преемник ключа 11, чтобы определить, есть ли большее число. Такового нет. Возвращаемся к предшественнику ключа 11, обнаруживаем, что это корневой узел, и завер¬ шаем нашу экскурсию по дереву. При этом, конечно, надо запоминать, какие левые и правые преемники уже были использованы. Примененный здесь ал¬ горитм кратко описан ниже. 1. Рассматриваем поле левого преемника узла. Если оно «пусто» или по¬ мечено «использовано», то данный узел является очередным наименьшим
4.4. ПЕРВЫЙ ПРИМЕР ИСПОЛЬЗОВАНИЯ ДЕРЕВА 47 элементом в списке. В противном случае проверяем узел, на который это поле указывает. Двигаемся по левым преемникам до тех пор, пока либо не встретим «пусто», либо использованный левый преемник. 2. Когда встречаем «пусто» или использованный левый преемник, просма¬ триваем поле правого преемника. Если оно пусто или использовано, то пере- УроВеиь Число N*!/ узлов 0 1 О 3 12 1 5 Всего 29 Узлы Позиция Значение К Левый преемник 1 Правый преемник | Предшестве 1. 3 10 2 N 2. 11 3 N 1 3. 6 4 5 2 4. 4 N 6 3 5. 9 7 9 3 6. 5 N N 4 7. 7 N 8 5 8. 8 N N 7 9. 10 N N S 10. 2 11 N 1 11 1 N N 10 Рис. 4.4. Построенное дерево. водим по полю предшественника к предшествующему узлу. Повторить, начи¬ ная с шага !. 3. Если есть неиспользованный правый преемник, то повторяем этот про¬ вес, начиная с шага 1, для правого преемника данного узла. Просмотр пра- вого преемника выполняется только тогда, когда найден очередной наимень¬ ший элемент. 4. Условие окончания — обнаружение узла, у которого поле правого пре¬ емника пусто, а предшественник — корневой узел. На рис. 4.4 показано построенное дерево для списка из 11 чисел, который Используется по всей книге. Его странная форма объясняется тем, что, для
4.5. ЧИСЛО СРАВНЕНИИ И ФОРМА ДЕРЕВА 49 того чтобы упорядочить всего И элементов, наши правила размещения тре¬ буют дерево из пяти уровней. Построение этого дерева можно выполнить, не используя явные связи. Начинаем с выбора первого элемента списка в качестве корневого узла. По¬ мещаем его в ячейку 1 произвольной пустой области, используемой для пред¬ ставления дерева. Каждый последующий элемент будет отыскивать свой узел, просматривая корневой узел и другие подходящие ячейки. Рассмотрим некоторую ячейку С. Если в С есть элемент, то выполняем сравнение. Если элемент в С больше нового элемента, то следующим должен сравниваться левый преемник С. Левый преемник С по определению есть удвоенное С. Если элемент в С меньше, то следующим сравниваться должен элемент из 2С + 1 — правый преемник С. Следовательно, последовательности сравнений могут порождаться вычислениями 2С или 2С + 1. В данном случае явные указатели не нужны. Ответ на вопрос, что эффективнее: только что описанная процедура или использование явных связей, зазисит от подробностей кодирования таких, как относительная стоимость проверки пригодности ячейки по сравнению с определением состояния полей левого и правого преемников. В общем случае, однако, область, необходимая для представления дерева, непредсказуема и будет, как правило, больше области, необходимой для построения явного де¬ рева. Необходимое количество памяти зависит от формы дерева. Дерево с пятью уровнями (не считая корневого узла) потребует около 25 ячеек. По¬ скольку форма дерева зависит от расстановки и обычно не известна, то не¬ возможно точно предсказать требуемый объем памяти. На рис. 4.5 представ¬ лено дерево из рис. 4.4, отображенное на дерево из пяти уровней. Это дерево построено без езязующих адресов. Каждый номер узла в этом дереве соот¬ ветствует некоторому адресу памяти. По наибольшему занятому адресу рас¬ положен ключ 8, который был присоединен к дереву после первого сравне¬ ния с ключом 3 из ячейки 1. Так как ключ 8 больше, то затем просматрива¬ лась ячейка 3, содержащая ключ 6. После этого проверялась ячейка 13, содержащая ключ 9. Далее, в соответствии с алгоритмом, проверялась ячей¬ ка 26 с ключом 7, и возможным местом для ключа 8 стала ячейка 53. Обна¬ ружив, что в ней нет элемента, ключ 8, наконец, водворился на место. Использование явных связей допускает значительное и предсказуемое сжатие памяти, отводимой под дерево (за счет издержек на связующие поля). Однако при этом предполагается использование методов сортировки по дереву, которые будут обсуждаться в следующих разделах и которые не требуют дополнительной памяти или требуют ее настолько мало, что счи¬ таются минимальными по памяти методами. 4.5. Число сравнений и форма дерева На рис. 4.6 указано число сравнений, необходимых для размещения один¬ надцати элементов, изображенных на рис. 4.4 и 4.5. Там же показан путь Каждого элемента до соответствующей ячейки. Общее число сравнений рав- 110 29. Вычисленный объем этого дерева равен 29 (см. рис. 4.4). Число срав- 110111111 при построении дерева всегда равно объему дерева.
50 ГЛ. 4. СТРУКТУРЫ В СОРТИРОВКЕ Построение дерева зависит от расстановок данных перед сортировкой. Изменение его формы отражает начальный порядок данных; на рис. 4.7 по¬ казано дерево и число сравнений для упорядоченного списка. Дерево вытя¬ нуто в линию, а число сравнений равно 55. Это число, которое является максимальным, соответствует списку с обратным порядком. Максимум числа сравнений достигается при упорядоченном списке и при списке с обратным порядком, потому что в образующемся дереве нет либо правых, либо левых ветвей и, следовательно, каждый новый элемент дерева должен сравниваться со всеми своими предшественниками. Длинная линия элементов дерева указывает на то, что каждый из них есть либо левый, либо правый преемник, а само дерево имеет максимальную Число Сравниваемые Ключ сравнений элементы 3 0 - 11 1 3 6 2 3, 11 4 3 3, 11, 6 9 3 3. 11, 6 5 4 3, 11, 6, 4 7 4 3. 11, 6, 9 8 5 3. 11, 6, 9, 10 4 3, И, 6, 9 2 1 3 1 2 29 3, 2 Рис. 4.6. Построение дерева. высоту. Каждый элемент при поступлении в дерево сравнивается с одним элементом, на каждом из существующих уровней. Обратите на эго внимание на рис. 4.5 и рис. 4.6. Максимальное число сравнений при формировании дерева необходимо тогда, когда формируемое дерево имеет максимальную высоту. Для вывода максимального объема дерева следует заметить, что для первого элемента, следующего за корнем, потребуется N—(N—1) сравне¬ ний, для второго N— (N — 2). Среднее число сравнений (вдоль прямой линии в графе) равно N/2. Эта ситуация повторяется N—1 раз. Такшм образом, максимальное число сравнений равно (N2—N)/2. Минимум числа сравнений достигается при минимальном объеме дерева. У двоичного дерева объем минимален, когда минимальна его высота. Высота у него минимальна при максимальном числе «хороших» вершин, т. е. вершин, имеющих сразу двух преемников. На рис. 4.8 показано полностью построен¬ ное дерево (каждая вершина либо свободна, либо «хорошая»); у него мини¬ мальное количество уровней и минимальный объем. Минимальное число уровней (без корневого) в дереве равно целой части двоичного логарифма N. Таким образом, 10 000 элементов будут занимать 13 уровней. Минимум числа сравнений можно определить, вычислив объем дерева, оптимального для заданного значения N. В качестве приблизительной оценки минимального числа сравнений читатель может использовать формулу A*(log2 N) —N.
4.5. ЧИСЛО СРАВНЕНИЙ И ФОРМА ДЕРЕЗА 51 Ожидаемое число сравнений при построении дерева зависит от формы дерева и вероятности того, что дерево будет иметь именно эту форму. Ожи- Ключ 1 Z 3 it 5 6 7 В 9 10 11 L 0 1 г 3 4 s е 7 в 9 N 1 1 1 1 1 1 1 1 1 1 1 10 55 Объём дерева '55 Число сравнений 55 Рис. 4.7. Дерево для списка с упорядоченными данными. О N_ 1 11) 2 б 12 Всего 22 Рис. 4.8. Дерево минимального объема. Даемое число сравнений равно сумме по всем расстановкам произведении ВеРоятности расстановки на число сравнений, выполняемых при этой расста¬ новке.
62 ГЛ. 4. СТРУКТУРЫ В СОРТИРОВКЕ 7 2 3 4 1 1 / 7 1 1 2 2 2 2 2 2 3 3 3 3 3 3 4 4 4 4 4 2 2 3 3 4 4 1 1 3 3 4 4 1 1 2 2 4 4 1 1 2 2 3 3 4 2 4 2 3 3 4 1 4 1 3 2 4 1 4 1 2 2 3 1 3 1 4 J 4 2 3 2 4 3 4 1 3 1 4 2 4 1 2 1 3 2 3 1 2 © © © <2 © (2 <??% .© © <6 © 0® 4 сравнения в 12 случаях 5 сравнений в 4 случаях 6 сравнений в 8 случаях Рис. 4.9. Форма дерева при разных расстановках данных.
4.7. ДРУГИЕ ДЕРЕВЬЯ 53 На рис. 4.9 показано, как на форму дерева влияет упорядоченность рас¬ становки списка из четырех элементов. Заметим (см. табл. внизу рис. 4.9), что число удачных расстановок относительно велико по сравнению с общим числом расстановок. Для 24 (4!) расстановок, 12 требуют минимального числа сравнений. Возьмем «случайные» данные, где все расстановки равно¬ вероятны. Тогда ожидаемое число сравнений меньше в том методе, у кото¬ рого больше вероятность встретить хороший случай, нежели в том, у кото¬ рого вероятность встретить такой случай меньше. Случайность данных, без¬ условно, будет влиять на поведение метода. Поскольку мы вправе надеяться на хороший случай, то ожидаемое число сравнений будет ближе- к минимуму N\og2N— N, чем к максимуму (N2— N)/2. Выражение N \og2 N широко используется в литературе как оценка ми¬ нимального ожидаемого числа сравнений при сравнительной сортировке. Под этим подразумевается следующее: возьмем произвольный алгоритм сортиров¬ ки и подсчитаем для него ожидаемое число сравнений при каждой расста¬ новке, без учета специальной обработки при дублировании ключей. В этом случае можно ожидать не менее N\og2N сравнений. Эта оценка дает боль¬ шую погрешность. Читатель должен понимать разницу между «минимальным числом сравнений» и «минимальным ожидаемым числом». В хорошем, с точки зрения среднего числа сравнений, методе выполняется порядка N log2 N сравнений. В алгоритме, использующем дерево, ожидаемое число сравнений часто выражается в виде aN\og2N, где значение а зависит от метода или его модификации. Диапазон изменений а — от 1.1 до 2. Умень*. шение значения а часто достигается ценой затрат на подготовительную ра¬ боту. 4.6. Разбиение Поскольку каждое дерево содержит поддеревья, то переупорядочение де¬ рева можно рассматривать как переупорядочение семейства поддеревьев. Следствием этого является то, что операция переупорядочения будет зависеть как от N, так и от /С, где К — величина поддерева. Принцип разбиения не обязательно предполагает использование деревьев. В любом методе сортировки, число сравнений которого зависит от N, раз¬ биение N на подсписки дает преимущества. Рассмотрим произвольный метод линейного выбора или обмена. Разде¬ ление списка из N элементов на К частей по 5 элементов сократило бы об¬ щее число сравнений с N2 до S2 -f S2 + ... -f S2 плюс операции для упорядо¬ чения частей. Возьмем 100 элементов и отсортируем их как 10 подсписков. Общее число сравнений будет порядка 10ХЮ2 = 1000 сравнений против обычных 10 000. Для упорядочения 10 частей в одну необходимы дополни¬ тельные сравнения. (Выбор, использующий большие степени, обсуждается з главе 8.) 4.7. Другие деревья Ф Можно построить дерево, узлы которого имеют более двух преемников. гРаничение, заключающееся в том, что узел может иметь только одного предшественника, по-прежнему должно соблюдаться, но теперь узел может
54 ГЛ. 5. ТУРНИРНЫЕ СОРТИРОВКИ 1 2 J 4 Рис. 4.Ю. Узлы с многочисленными преемниками. иметь произвольное число преемников. На рис. 4.Ю изображено вполне до¬ пустимое дерево. Мы будем рассматривать деревья такого типа в разделе, связанном со слиянием и аналогичными ему методами. Глава 5. ТУРНИРНЫЕ СОРТИРОВКИ 5.1. Общие замечания Сортировки по дереву представляют интерес в тех случаях, когда мы хотим быстро сортировать, используя минимальный объем памяти, или когда нам надо строить очень длинные строки для внешнего слияния. Здесь мы Круг 7 Круг 2 Круг 6 2=5 1=3 1=2 3=4 2 Рис. 5.1. Граф турнира. рассмотрим два алгоритма. Семейство быстрых сортировок рассматривается в главе 7. Все последующие сравнительные алгоритмы в той или иной степени ориентированы на использование древовидных структур. Полезной аналогией для описания сущности метода сортировки по дереву является обычное со¬ ревнование по теннису. Рассмотрим рис. 5.1, где указаны пять игроков — участников первого круга соревнований. Для того чтобы разбить всех игро¬ ков по парам (чтобы каждый игрок имел партнера), необходимо с самого
Б.1. ОБЩИЕ ЗАМЕЧАНИЯ 55 начала иметь четное число участников. При нечетном числе один участник должен пропустить первый круг. Фактически этому игроку «уступается» по¬ беда в игре первого круга. Рис. 5.1 показывает, что первый круг пропускает игрок 1, игрок 3 играет с игроком 4, игрок 2 — с игроком 5. Победители попадают в следующий круг. В общем случае, если есть N участников и N — четное число, то в первом круге будет сыграно N/2 игр. На рис. 5.1 показано, что игроки 2 и 3 выигра¬ ли свои первые матчи. Вместе с игроком 1, который пропустил первый круг, они попадают во второй круг игр. Здесь опять нечетное число участников, и кому-то надо сделать поблажку. Второй круг пропускает игрок 2, а иг¬ рок 1 встречается с игроком 3. В этой встрече побеждает игрок 1, и он попадает в финал, где встречается с игроком 2. Победитель финала — игрок 1—чемпион. В терминах сор¬ тировки — выбран наименьший эле¬ мент. Граф турнира на рис. 5.1 зна¬ ком нам по спортивным разделам газет. Перерисованный, как на рис. 5.2, он превращается в двоичное дерево. Корневой узел соответствует наи¬ меньшему элементу списка — «побе¬ дителю соревнований». Рассмотрим некоторые общие правила турнира. 1. Результат турнира не зависит от метода определения «поблажек». Если мы будем делать поблажку разным элементам, то число 1 все равно победит в турнире (см. рис. 5.1 и 5.2). 2. Число кругов в турнире зависит от числа участников. В общем случае будет flog2AT] кругов. При пяти участниках будет три круга: П°^2 5Т = = 3*). 3. Каждый круг охватывает половину «игр» (сравнений) по сравнению с предыдущим. «Поблажек» можно избежать, только если исходное количество элементов есть точная степень 2. 4. При любом N в турнире будет N—1 игра (сравнение). Если не учи¬ тывать поблажки, то победитель будет участвовать в log? N состязаниях, по одному на каждом уровне или круге. Вспомним линейный выбор, там на каждом просмотре для выбора «побе¬ дителя» выполнялось (N — 1) сравнение. Турнирная сортировка на самом Деле является сортировкой «выбором», в которой на каждом просмотре вы¬ бирается наименьший элемент из оставшихся в списке. При линейном выборе на каждом просмотре выполняется (N—1) сравнение, а в его модификации с обменом (К—1), где К уменьшается на 1 при каждом просмотре от *) Символы Г 1 означают «ограничение сверху», т. е. «взять логарифм и 0кРуглить его с избытком до ближайшего целого». Рис. 5.2. Граф турнира рис. 5.1. в виде двоичного дерева. Узлы со звездочками содержат побе¬ дителей.
66 ГЛ. 5. ТУРНИРНЫЕ СОРТИРОВКИ (N — 1) до 1. Последовательные просмотры турнирной сортировки требуют значительно меньше сравнений для выбора победителя. Каждый просмотр этой сортировки ставит одного участника выше оставшихся так, что в конце всех просмотров мы получаем упорядоченный список. На каждом «утеши¬ тельном» просмотре используется информация об относительном положении элементов, полученная на предыдущем просмотре, поэтому не надо проводить новый турнир за второе, третье и последующие места. 5.2. Турнирная сортировка: использование рабочей памяти Этот метод турнирной сортировки, по существу, есть Алгоритм 143, опу¬ бликованный в Communications of the ACM (САСМ) (дек. 1962). Этот алго¬ ритм написан на основе алгоритма 113 Р. Флойда (САСМ, авг. 1961) *). Он является одним из возможных подходов к турнирной сортировке, которая, Адрес А —длина списка, (А—1) —объем памяти для списка и рабочей области» (ЛГ—1) —объем памяти для адресов. Исходный список 8 Адреса могут быть организованы разными способами. 9 Здесь предполагается, что они встроены в записи. Рис. 5.3. Организация памяти для пяти элементов. как следует из ее названия, аналогична разбиению конкурентов на пары в спортивных состязаниях. Этот метод не является в точности минимальным по памяти вариантом сортировки по дереву, хотя и близок к нему при сортировке длинных записей с короткими ключами. По существу, это сортировка отдельных таблиц. В па¬ мяти необходимо место для представления 2N — 1 ключей и 2N — 1 адресов. Это место должно быть связным и организовано так, чтобы сортируемые элементы (или признаки) занимали последние N логических позиций рабочей области памяти. Первые N — 1 логических позиций должны быть свободны. Схема организации области памяти для пяти элементов показана на рис. 5.3. (Организация памяти также будет рассмотрена в разделе 5.2.2.) На этом рисунке адреса используются для того, чтобы найти победителя, когда его надо переместить из списка. На первом просмотре путем сравнения ключей и выбора «победителя» (наименьшего из сравниваемых) строится древовидная структура. Победитель перемещается в предшествующую позицию, адрес которой равен целой части от половины адреса текущей позиции победителя. Например, меньший из клю¬ чей в позициях 8 и 9 переместится в позицию 4. Наличие пустых позиций в расширенной области памяти гарантирует непосредственный доступ к адре¬ сам, соответствующим предшествующим гнездам. *) См. Приложение А. (Прим. перев.)
5.2. ИСПОЛЬЗОВАНИЕ РАБОЧЕЙ ПАМЯТИ 57 Первый просмотр начинается со сравнения последних позиций списка. Меньший ключ помещается в предшествующую позицию. Первоначальный адрес этого ключа перемещается в соответствующую позицию адресного про¬ странства. Сравнения в списке выполняются снизу вверх (N: N—1, N — 2 : N — 3 и т. д.) до тех пор, пока какой-нибудь элемент не займет пер¬ вую позицию, соответствующую корневому узлу в дереве. Если при сравне¬ нии используется элемент, ранее перемещенный в списке вверх (например, 5:4), то создается новый уровень дерева. На рис. 5.4 числа внутри узлов — это ключи, а рядом с узлами — относительные адреса узлов в списке. При сравнениях образуется первый уровень дерева. «Круг» турнира закончен, так как далее все сравнения будут проводиться на следующем уровне дерева. На рис. 5.4 есть три поддерева, но мы пока еще не знаем их относитель¬ ного места в структуре файла. Новый круг начинается, как только при сравнении используется элемент из предшествующей позиции. Поскольку в узле 4 находится ключ 3, который попал туда в результате сравнения 9:8, сравнение 5:4 на втором круге использует узел, расположенный в дереве выше. В результате сравнения 5 : 4 в позицию 2 попадает ключ. Победитель сравнения 5:4 на самом деле пере¬ ходит в следующий круг, и, таким образом, формируется новый уровень де¬ рева. Сравнение 3:2 является финалом, в котором победитель — наименьший ключ в списке — помещается в корневой узел. На рис. 5.5 показано дерево, полученное в конце просмотра 1. Список на рис. 5.5 соответствует содержи¬ мому рабочей области после первого просмотра. Запись, представляющая корневой узел, помещается в область вывода, а в позицию, которую занимал победитель в начале просмотра, помещается ключ (Z), наибольший среди всех ключей, какие могут встретиться в сортируемых данных. Остальные вершины остаются без изменения, даже несмотря на то, что некоторые ключи встре¬ чаются в разных местах. Второй просмотр начинается со сравнения позиций, первоначально содер¬ жавших предыдущего победителя и его соперника. Предыдущий победитель, Пербый уровень дереба Рабочая область Адреса Последова¬ тельность сравнений (позиций) Перемещения ( меньший перемещ ается в предшеству¬ ющую позицию) 7-6 2 3 6 9 Позиции 5 6 7 8 9 5 1 2 5 4 5 5 6 7 8 9 6 7 8 9 Рис. 5.4. Дерево и память после первого круга.
58 ГЛ. 5. ТУРНИРНЫЕ СОРТИРОВКИ позиция 5, теперь содержит фиктивный ключ, и его соперник, позиция 4, должен быть меньше. Он перемещается в дереве вверх, в предшествующую позицию 2. В этой предшествующей позиции он сравнивается с соперником, узел которого расположен на этом же уровне. Победитель продвигается дальше. На рис. 5.6 показан список в начале и в конце просмотра 2, дерево 5. 6. 7. Область вывода Zeфиктивная величина, * первоначально i Ключ Адреса Последовательность сравнений (позиции) 1. 1 5 Круг 1 9 :8 9-М 2. 1 5 7:6 6-*3 3. 2 6 Круг 2 5: 4 5->2 4. 3 9 Круг 3 3:2 2-> 1 Рис. 5.5. Турнирная сортировка, окончательное дерево, первый просмотр. в конце этого просмотра и последовательность сравнений. В конце просмо¬ тра 2 содержимое корневого узла добавляется к списку вывода. Дополни¬ тельные просмотры достроят список вывода до правильной последовательно¬ сти ключей. Необходимо позаботиться о вычислении адресов для начального сравне¬ ния в просмотрах, отличных от первого. Если известна позиция победителя, то надо определить, находится ли его соперник в позиции на единицу боль¬ шей или меньшей. При четном N, если позиция победителя четна, соперник всегда находится в позиции, на единицу меньшей, если же позиция победи¬ теля нечетна, то в позиции, на единицу большей. Когда N нечетно, все на¬ оборот. Сравнение фиктивной величины с соперником может быть заменено каким-то другим приемом, перемещающим соперника вверх по дереву. 5.2.1. Пример. Принципиальная важность этого метода может служить оправданием более сложному примеру. Рассмотрим рис. 5.7. Там — три столбца с именами TOSORT, WORKITM, WORKADD. TOSORT содержит обычный список. Две области, WORKITM и WORKADD, представлены так, как они выглядят в начале процесса, который получает поле памяти и пере¬
5.2. ИСПОЛЬЗОВАНИЕ РАБОЧЕЙ ПАМЯТИ 59 сылает ключи из TOSORT в WORK1TM, а их адреса в TOSORT —• в WORKADD. (WORKADD может быть полем WORKJTM.) На рис. 5.8 показано состояние рабочей области в конце первого круга первого просмотра и фрагменты формируемого дерева. Элементы списка, расположенные в позициях с 10 по 6, являются победителями первого круга. Следующим сравнением будет 11 : 10. Позиция 10 является предшествую¬ щей для позиций 20 и 21 и содержит ключ 1—содержимое позиции 21. Исходный список просмотра 2 Дерево в конце просмотра Список после просмотра 2 1. 1 5 1. 2 6 2. 1 5 2. 3 9 3. 2 6 3. 2 6 4. 3 9 4. 3 9 5. Z 5 5. Z 5 6. 2 6 6. Z 6 7. 5 7 7. 5 7 8. 4 8 8. 4 8 Ч 3 9 9. 3 9 Область вывода 1 По следовательность сравнений (позиции) Круг 1 5:4, 4-*2 Круг 2 3:2, 3-» 1 Рис. 5.6. Турнирная сортировка, просмотр 2. Сравнение 11: 10, таким образом, — это сравнение, использующее победителя первого круга, и оно является первым из сравнений второго круга. Пози¬ ция 11 практически пропустила первый круг. Это автоматически поднимет пропущенную вершину на следующий уровень дерева, где она используется в первом сравнении следующего круга. Второй круг продолжается до тех пор, пока при некотором сравнении не будет использована позиция 5. В этот момент список будет иметь вид такой, как на рис. 5.9, а дерево будет расти так, как там указано. Номера позиций у узлов указаны на рисунке в обрат¬ ном порядке для того, чтобы было удобнее изобразить сравнение 10: 11. На третьем круге, показанном на рис. 5.10, позиция 3 пропускается. По¬ следний круг показан на рис. 5.11. В списке в исходной позиции победителя, который указан в дереве, находится фиктивная величина. Когда полное де¬ рево построено, победитель готов для перемещения в область вывода. Сфор¬ мированный список соответствует древовидной структуре.
60 ГЛ. 5. ТУРНИРНЫЕ СОРТИРОВКИ TOSORT WORKITM WORKADD 1. 3 1. - - 2. 11 2. - - 3. 6 3. - - 4. 4 4. - - 5. 9 5. - - 6. 5 6. - - 7. 7 7. - - 8. 8 8. - - 9. 10 9. - - 10. 2 10. - - 11. 1 11. 3 11 12. 11 12 13. 6 13 14. 4 14 15. 9 15 16. 5 16 17. 7 17 18. 8 18 19. 10 19 20. 2 20 21. 1 21 Рис. 5.7. Турнирная сортировка, подготовительный этап. WORKITM WORKADD Первый круг 1. - - 2. - - 3. - 4. - - 5. — — 6. 6 131 7. 4 14 1 8. 5 16 > 9. 8 18 10. 1 21 * 11. 3 И ' 12. 11 12 13. 6 13 14. 4 14 15. 9 15 16. 5 16 17. 7 17 18. 8 18 19. 10 19 20. 2 20 21. 1 21 - 7 (7) в(7 Первый уровень Сравнения Пересылки Исходный список 20 : 21 18 : 19 16: 17 14 : 15 12 : 13 21-> 10 18->9 16 —> 8 14—>> 7 13-^6 'ый уровень Элементы исходного списки \^l) (ю) (л 15 14 15 16 17 18 19 20 21 Замечание. Стрелками показаны перемещения элементов. Рис. 5.8. Турнирная сортировка, конец первого просмотра, первый круг.
5.2. ИСПОЛЬЗОВАНИЕ РАБОЧЕЙ ПАМЯТИ б' Хотя в целях наглядности при изложении мы проводили различия между кругами, соответствующий алгоритм этого не делает. Из рис. 5.11 видно, что последовательность сравнений постепенно перемещается вверх по списку до 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. Второй уровень Первый уровень Элементы исходного списка 20 21 18 19 16 17 19 15 12 13 Заменами е. Стрелками показаны перемещения элементов. Рис. 5.9. Турнирная сортировка, второй круг. тех пор, пока позиция I не будет использована в качестве адреса предше¬ ствующей позиции. На этом просмотр заканчивается. Переход от круга к кругу никаких промежуточных действий не требует. К началу второго просмотра известен адрес победителя. В просмотре 2 первыми сравниваются победитель и его соперник. Сравнение позиции 20 и 21 вызовет перемещение содержимого позиции 20 вверх по дереву. Ключ 2 из позиции 20 поднимается в позицию 10. На рис. 5.12 показано это перемеще¬ ние ключа 2 в списке. Соперником позиции 10 является позиция 11. Следую¬ щее сравнение — это сравнение позиций 10 и 11. На рис. 5.13 показан список после этого сравнения. Ключ 2 находится в позиции 5; он следует по марш¬ руту, по которому ключ 1 двигался на первом просмотре. На рис. 5.14 пока¬ зан список к концу просмотра 2. Победитель — ключ 2 — помещается в KITM. WORKADD 3 И 6 4 9 5 7 8 10 2 1 14 ^ m J 21 ) Второй уровень Первый уровень 11 12 13 14 15 16 17 18 19 20 21 Второй круг Просмотр 1 Сравнения 10 : 11 8: 9 6: 7 Пересылки 10-»5 8-М 7-»3 ^ Исходный список
62 ГЛ. 5. ТУРНИРНЫЕ СОРТИРОВКИ область вывода. Устанавливается фиктивный ключ, и можно начинать третий просмотр. Для выбора победителя на втором просмотре понадобилось четыре сравнения. Количество сравнений на всех просмотрах, кроме первого, равно числу уровней в дереве: для нахождения победителя нужно по одной проверке на WORKITM WORKADD 1. - - 2. 1 21 1 1 Третий 3. 4 14 j [ уровень 4. 5 16 1 1 Второй 5. 1 21 j [ уровень 6. 6 13 1 7. 8. 9. 4 5 8 к 18 Первый уровень 10. 1 21 ' Сравнение Пересылка 4 : 5 5->2 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 3 11 6 4 9 5 7 8 10 2 1 11 12 13 14 15 16 17 18 19 20 21 Исходный список 20 21 Замечание. Стрелками показаны перемещения элементов. Рис. 5.10. Турнирная сортировка, третий круг, каждом уровне. Следовательно, при каждом просмотре, кроме первого, про¬ исходит Г lcg2 А^ "1 сравнений. На рис. 5.15, иллюстрирующем просмотр 3, слева направо указаны спи¬ сок, исходный для этого просмотра, преобразованный список после каждого сравнения и пересылки, а также окончательный список после этого просмотра. Сравниваемые позиции указаны в заголовках столбцов. В изображенном дереве фиктивные величины показаны на момент начала просмотра как за¬ крытые поля. Состояние этого дерева соответствует концу просмотра, но
5.2. ИСПОЛЬЗОВАНИЕ РАБОЧЕЙ ПАМЯТИ 63 WORKITM WORKADD TOSORT 1. 1 21 ] ! Четвертый J ’ уровень 2. 1 21 ] 1 Третий уровень 3. 4 14 'J 4. 5 16 ! , Второй 5. 1 21 J уровень 6. 6 13 ч *7. 4 14 1 8. 5 161 > Первый 9. 8 18 уровень 10. 1 21 ' 11. 3 11 12. 11 12 13. 6 13 14. 4 14 15. 9 15 16. 5 16 . Исходный 17. 7 17 список 18. 8 18 19. 10 19 20. 2 20 21. 999 21 Сравнение 3: 2 Пересылка 2*1 Область вывода Четвертый уровень Третий уровень Второй уровень Первый уровень Элементы исходного списка Итог просмотра Итог просмотра Итог просмотра Сравнения Пересылки Сравнения Пересылки Сравнения Пересылки 20 : 21 18 : 19 16 : 17 21-» 10 18-» 9 16-» 8 14 : 15 12 : 13 10: 11 14—» 7 13-»6 10 —» 5 8 : 9 6 : 7 4 : 5 2:3 8-»4 7-»3 5-»2 2-»1 Рис. 6.11. Турнирная сортировка, последний круг.
64 ГЛ. 5. ТУРНИРНЫЕ СОРТИРОВКИ победитель еще ие заменен фиктивной величиной. Заметим, что первое сравне¬ ние 20:21 — это сравнение фиктивных величин. По нашему соглашению ле- WORKITM WORKADD 1. 1 21 2. 1 21 3. 4 14 4. 5 16 5. 1 21 6. 6 13 7. 4 14 8. 5 16 9. 8 18 ->10. 2 20* 11. 3 11 Сравнение Пересылка 12- 11 12 21:20 20-* 10 13. 6 13 14. 4 14 15. 9 15 16. 5 16 17. 7 17 18. 8 18 19. 10 19 Г 20. 2 20 |_21. 999 21 Замечание. На рис. 5.12, 5.13, [5.14 и 5.15 скобкой, стрелкой и звездочкой указы? вшогся сравнение и пересылка. Рис. 5.12. Турнирная сортировка, размещение ключа 2. WORKITM WORKADD 1. 1 21 2. 1 21 3. 4 14 4. 5 16 -> 5. 2 20* 6 13 Сравнения Пересылки 7. 4 14 11:10 10-> 1 8. 5 16 9. 8 18 Г10. 2 20 |_11. 3 И 12. 11 12 13. 6 13 14. 7 14 15. 9 15 16. 5 16 17. 7 17 18. 8 18 19. 10 19 20. 2 20 21. 999 21 Рис. 5.13. Турнирная сортировка, размещение ключа 2. вый преемник в этом сравнении — победитель, и он продвигается вверх. Ре¬ зультатом применения этого правила будет размещение фиктивной величины в позиции 10. Процесс продолжается без всякой путаницы.
Б.2. ИСПОЛЬЗОВАНИЕ РАБОЧЕЙ ПАМЯТИ 65 Сортировка заканчивается, когда все элементы данных окажутся в обла¬ сти вывода. Будет N просмотров: первый просмотр строит дерево, а N—1 последующих просмотров заполняют его фиктивными величинами. 5.2.2. Память. Объем памяти, необходимый для этой версии турнирной сортировки, определяется программным окружением, в котором используется этот метод, и относительной длиной ключа по сравнению с длиной записи. Сортировка, по существу, является сортировкой ключей. Если ключи яв¬ ляются записями, то требуемый объем памяти зависит от способа представле¬ ния адресов. В машине с пословной организацией памяти список из 11 эле¬ ментов занял бы 42 слова: 21 слово под рабочую память для ключей и 21 — под рабочую память для адресов. Можно, конечно, объединить короткие ключи и адреса в одно слово машины. На этапе начальной подготовки сор¬ тировки, до начала первого просмотра, пересылаются ключи и формируются признаки. Таким образом, весь объем необходимой памяти велик по сравне¬ нию с размером списка, если ключи и записи совпадают. В случае длинных записей, состоящих из нескольких полей, относительный объем памяти, необ¬ ходимый для представления 2N—1 признаков (ключ и адреса), становится существенно меньше. Можно работать только со списком адресов. При этом доступ к ключам осуществлялся бы через таблицу адресов. Адреса в таблице перемещались бы от «узла» к «узлу» в зависимости от результата сравнения. Изменения в методе состояли бы только в том, что не надо было бы отдельно представ¬ лять ключи, однако, потребовалась бы косвенная адресация. В этом случае Довольно много внимания пришлось бы уделять представлению списков адре¬ сов и работе с ними. Размер области вывода в случае записей из нескольких полей зависит от того, .каким образом данные будут использоваться впоследствии. Он также WORKITM WORKADD 6. 7. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 8. 10 999 999 2 2 4 5 2 6 4 5 8 2 3 11 6 4 5 7 8 9 20 20 14 16 20* 13 14 16 18 20 11 12 13 14 15 16 17 18 19 20 21 Сравнения sm 3:2 Итог просмотра Сравнения Пересылки 21 : 20 И : 10 5: 4 3: 2 Пересылки 5-»2 2-> 1 20 ->10 10-> 5 5-> 2 2-> 1 Рис. 5.14. Конец второго просмотра, 3 Г. Лорин
65 ГЛ. 5. ТУРНИРНЫЕ СОРТИРОВКИ зависит от системы команд машины (которая может позволять собирать за¬ писи из разных мест памяти одной командой), наличия у машины «собираю¬ щей записи», требованиями буферизации для устройств вывода [5]. Третий просмотр Сравнение (позиции) _ — Окончательный список V 2 а <v а. ч Ч ЪС < * 3 11 3 11 4 14 5 18 3 11 6 13 4 14 5 16 8 18 999 20 3 11 11 12 6 13 4 14 9 15 5 16 7 17 8 18 10 19 999 20 999 21 Вывод 4- Область 1 2 3 20 21 18 19 16 17 Рис. 5,15. Турнирная сортировка, просмотр 3. Другие варианты турнирной сортировки изложены в разделе 5.3 и в главе 11, где к этому методу добавляется принцип «замещения». 5.2.3. Число сравнений и пересылок. Число сравнений в турнирной сор¬ тировке равно (ЛГ — 1) + (N —\) П°&2 ЛП • На первом просмотре требуется
5.3. МИНИМАЛЬНАЯ ПО ПАМЯТИ ТУРНИРНАЯ СОРТИРОВКА 67 N— 1 сравнений, а на каждом последующем — f l°g2 "| . Когда N есть сте¬ пень 2, это — точное число сравнений. В противном случае оно служит хоро¬ шей оценкой и будет меньше числа сравнений для ближайшей сверху степе¬ ни 2 из-за наличия «поблажек». Число пересылок записей и время на пересылки зависят от специфики организации турнирной сортировки. В рассматриваемом методе при каждом сравнении всегда будет пересылаться пара ключ-адрес, а в конце каждого просмотра — либо запись, либо адрес, либо и то, и другое. Таким образом, время на пересылку данных, без учета подготовительного этапа, равно С (где С — число сравнений), умноженному на время пересылки пары ключ- адрес плюс N пересылок в конце просмотров: сравнения X пересылка признаков + (N X пересылка записи) 5.2.4. Комментарий. При подсчете времени в этом методе программист не должен забывать о таких факторах, как время подготовительного этапа для построения таблицы признаков и время на вычисление адресов предше¬ ствующих вершин. Эти вычисления требуют больших затрат. Учтите, что вычисление адресов предшествующих узлов по адресам сравниваемых эле¬ ментов может потребовать log2 N делений (зловещий признак) за просмотр и может загубить метод, заставляя его работать значительно медленнее ме¬ тодов с большим числом сравнений. Есть много способов программирования вычисления адресов. На двоич¬ ных машинах команда сдвига может заменить деление на 2. В алгоритме сортировки по дереву из Приложения А применен способ, в котором предше¬ ствующая позиция используется как указатель и сравнивается ее удвоенная величина с ее удвоенной величиной плюс 1. Программисту также следует обратить внимание на способы адресации, так как вычислять адрес надо при каждом сравнении и пересылке. Для большинства машин для нахождения позиций узлов, несомненно, следует рассматривать способы, не использующие деление или умножение. Один из таких способов состоит во введении разных указателей на предшествующие и сравниваемые позиции с начальными зна¬ чениями 2N — 1 и N — 1 соответственно. Проблема сокращения затрат на вычисление адреса является частью раздела 5.4. 5.3. Минимальная по памяти турнирная сортировка Способ использования древовидных структур, не требующий дополнитель¬ ного пространства памяти, но целиком зависящий от обменов, был предложен Р- Флойдом в алгоритме 245 в С ACM (см. Приложение А). Основной упор на структуру двоичного дерева сохранился, но взаимосвязь между предше¬ ственником и его потомками изменена. Этот метод интересен для тех про¬ граммистов, которые готовы ослабить ограничения на время ради сокращения До минимума требований к памяти. 5.3.1. Метод. При первом просмотре строится дерево, в котором ключ каждого узла (за исключением корня) больше ключа любого из его потомков. Для любой тройки узлов /С, 2 К у 2/С + 1 наибольший ключ расположен в узле /(. Рассмотрим рис. 5.16. Тройки узлов этого дерева перечислены в столбце «Позиции троек». При обработке дерева снизу (от конца списка) 3*
68 ГЛ. 5. ТУРНИРНЫЕ СОРТИРОВКИ сравниваются концевые соперники и их предшественники. Соперники сравни¬ ваются, и больший из них сравнивается с предшественником. Если предше¬ ственник меньше, то позиции меняются местами. В то же время при движении вверх по списку начинают сравниваться соперники, которые сами являются предшественниками. Если предшественник оказался меньше, то, для того чтобы все вершины остались больше своих потомков, его, возможно, придется опустить более чем на один уровень. Рас¬ смотрим последовательность сравнений для тройки (3, 6, 7) на рис. 5.16. Позиции троек 7. 14, 15 6, 12, 13 5, 10. 11 4, 8, 9 3, 6, 7 2, 4, 5 в 9 10 11 12 13 п 15 *• 2- 3 (исключается на первом просмотре) Замечание. Стрелками показаны обмены, упорядочивающие вершины. Рис. 5.16. Тройки дерева. Сначала в узле 3 находится ключ 3. Этот ключ вытесняется ключом 14 а позицию 6. Дополнительные сравнения (13 :12, 12:6) обеспечивают упоря¬ доченность тройки (6, 12, 13). «Тонущий» элемент спускается в дереве на столько уровней, сколько потребуется для нахождения нужной позиции, т. е. позиции, где он больше своих потомков или где он является корневым. Ключ 3 остановится в позиции 13. Содержимым тройки 3, 6, 7 будет 14, 9, 7, а тройки 6, 12, 13 — 9, 8, 3. В конце первого просмотра левое поддерево будет упорядочено так, что у его корня (левого потомка корня всего дерева) наибольший элемент будет слева, а правое поддерево будет упорядочено так, что у его корня (правого потомка корня всего дерева) наибольший элемент будет справа. Больший из элементов в вершинах 2 и 3 должен быть наибольшим в списке до тех пор, пока он не попадет в корневой узел. Второй просмотр начинается с размещения содержимого корневого узла -в рабочей памяти. При этом позиция, соответствующая корневому узлу, осво¬ бождается для победителя в первом сравнении этого просмотра. Первоначаль¬ ные сравнения состоят в следующем: (1) сравниваются левый и правый потомки корневого узла; (2) больший из них сравнивается с исходным содержимым корневого узла уже в рабочей памяти. Победитель является наибольшим в списке и помещается в корневой узел. Если в рабочей памяти находится не наибольший элемент, то позиция для него должна быть выбрана так, чтобы условия упорядоченности троек,
Б.З. МИНИМАЛЬНАЯ ПО ПАМЯТИ ТУРНИРНАЯ СОРТИРОВКА 69 выполненные к началу второго просмотра, соблюдались и к началу третьего. Позиция для содержимого рабочей памяти ищется в поддереве, где распо- Деребо Список 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. U. 3 И 6 4 9 5 7 8 10 2 1 Рис. 5.17. Минимальная по памяти турнирная сортировка, исходное дерево лагался победитель. Поиск начинается с определения наибольшего элемента среди потомков победителя, который затем сравнивается с содержимым рабо- Позиция 1. 2. 3. 4. 5. 9. 10. 11. Начало просмотра 1 3 11 6 4 9 5 7 8 10 2 1 Конец просмотра 1 3 И 7 10 9 5 6 8 4 2 1 Сравнение позиций 11 : 10 10 : 5 9 : 8 9: 7 : 7: 5: 4 : Обмен позиций Нет сравнения с корневым узлом Стрелками показаны обмены. Рис. 5.18. Минимальная по памяти турнирная сортировка, первый просмотр чей памяти. Если содержимое рабочей памяти больше, то оно помещается в позицию, только что освободившуюся при пересылке победителя из поддерева
70 ГЛ. 5. ТУРНИРНЫЕ СОРТИРОВКИ в корневой узел. Если оно меньше, го в освободившуюся позицию пересы¬ лается наибольший потомок, а позицию для рабочей памяти надо искать на другом уровне дерева. Так продолжается до тех пор, пока содержимое ра¬ бочей памяти не окажется больше и не станет вершиной тройки или пока оно не опустится до концевых вершин. Заключительным действием просмотра должен быть обмен содержимого корневого узла и последнего текущего узла. После обмена последний теку¬ щий узел становится последней ячейкой минус 1. От просмотра к просмотру Сравнения Пересылки )ЗИЦИЯ Начало Конец позиций позиций 1. 3 11 2 : 3 2. 11 10 2 : TEMP 2-> 1 3. 7 7 4 : 5 4. 10 8 4 : TEMP 4-*2 5. 9 9 8 : 9 6. 5 5 6 : TEMP 8-* 4 7. 6 6 ТЕМР->8 8. 8 3 9. 4 4 10. 2 2 И. 1 1 Рис. 5.19. Минимальная по памяти турнирная сортировка, второй просмотр. упорядоченный список растет снизу, каждый просмотр добавляет очередной наибольший элемент списка и так до тех пор, пока не будет найден (N — 1)-й наибольший. Если при каждом просмотре содержимое корневого узла с са¬ мого начала больше содержимого его потомков, то обмен между корневым и последним текущим узлами происходит сразу. Основные способы сравнения при втором и последующих просмотрах мо¬ гут быть теми же, что и при первом просмотре. Поиск позиции для опускае¬ мого корневого узла аналогичен упорядочению на первом просмотре. Если при первом просмотре содержимое корневого узла помещать во временную память, то кодирование будет совершенно аналогичным. 5.3.2. Пример. На рис. 5.17 элементами дерева являются обычные чис¬ ла. При первом просмотре список и дерево преобразуются так, как показано
5.3. МИНИМАЛЬНАЯ ПО ПАМЯТИ ТУРНИРНАЯ СОРТИРОВКА 71 на рис. 5.18. В этом дереве вершина каждой тройки содержит наибольший в тройке ключ. На рис. 5.18 показаны сравнения и обмены первого просмотра. Последовательность сравнений обрабатывает список снизу вверх, двигаясь вдоль по дереву от уровня к уровню. К моменту сравнения 5 : 4 в вершине 4 уже находится ключ 10. Второй просмотр показан на рис. 5.19. Содержимое корневого узла (ключ 3) помещается во временную память (TEMP). Сравнения начинаются с определения наибольшего элемента списка путем нахождения максималь¬ ного из TEMP, узла 2 и узла 3. Наибольший — ключ в узле 2 (11). Узел 2 размещенные элементы. Рис. 5.20. Минимальная по памяти турнирная сортировка, начало просмотра 3. теперь свободен. Элемент, который займет этот узел, будет наибольшим среди узлов 4, 5 и TEMP. Наибольший — ключ 4 в узле 4. Перемещение этого элемента из узла 4 в узел 2 освобождает узел 4. Этот узел должен занять наибольший элемент среди узлов 8, 9 и TEMP. Наибольший — ключ 8 в узле 8 — перемещается в узел 4. Теперь в дереве не осталось уровней, под¬ ходящих для поиска, и содержимое TEMP помещается в узел 8. Корневой узел и последняя текущая позиция (в данный момент узел 11) обмениваются содержимым, и просмотр заканчивается. На рис. 5.20 показаны дерево и спи¬ сок к началу третьего просмотра. Пересылка из корневого узла в последний текущий уже сделана. Есть одна деталь, о которой необходимо позаботиться при переходе от просмотра к просмотру, — это правильное определение последнего текущего узла. Изменение значения этой переменной нужно для того, чтобы обеспечить наличие подходящего указателя последней текущей позиции. Но этим не ис¬ черпывается применение данной переменной. По мере того, как список необ¬ работанных элементов укорачивается, а дерево теряет узлы и уровни, необ¬ ходимо скорректировать проверки соперников так, чтобы они не захватывали Узлы, которые содержат уже обработанные элементы. Пример этому мы уви- Дим в конце просмотра 3. Просмотр 3 изображен на рис. 5.21, где показан список в начале и в конце этого просмотра. Дерево соответствует окончанию просмотра в момент
72 ГЛ. 5. ТУРНИРНЫЕ СОРТИРОВКИ обмена между последней текущей позицией (позиция 10 для этого просмот¬ ра) и корневым узлом. После этого обмена в узле 1 находится ключ 10, а в узле 10 — ключ 1. Узел 10 надо исключить из последующих сравнений. При просмотре 3 не происходит сравнение 11:10. Поскольку узел 11 содержит наибольший элемент списка, он должен быть исключен из сравне¬ ний. У узла 5 в это время есть только левый потомок — узел 10. Сравнение 10 : TEMP выполняется непосредственно, и содержимое узла 10 продвигается Просмотр 3 Сравнения Пересылки зиция Начало Конец позиций позиций 1. 2. 1 10 1 9 1->ТЕМР 3. 7 7 2 : 3 4. 8 8 2 : TEMP 2-> 1 б. 9 2 4 : 5 6. 5 5 5 : TEMP 5->2 7. 6 6 10 : TEMP 10 —> 5 8. 3 3 ТЕМР-И0 9. 4 4 10. 2 10* [10->1, 1 -> 10] 11. 11 11* Рис. 5.21. Минимальная по памяти турнирная сортировка, просмотр 3. в узел 5. После этого содержимое TEMP помещается в узел 10, происходит обмен между узлом 1 и узлом 10 (последней текущей позицией), и просмотр заканчивается. На рис. 5.22 показан четвертый просмотр. Дерево соответствует списку в конце этого просмотра после заключительного обмена. Всегда выполняется N просмотров: N—1 для размещения N—1 наибольших элементов и один для построения дерева. 5.3.3. Число сравнений. Число сравнений при первом просмотре зависит от исходного порядка данных. Минимум этого числа достигается, когда все тройки упорядочены должным образом, и равен удвоенному числу узлов в дереве без корневого узла. N — достаточно хорошее приближение минималь¬ ного числа сравнений первого просмотра.
5.3. МИНИМАЛЬНАЯ ПО ПАМЯТИ ТУРНИРНАЯ СОРТИРОВКА 73 Максимум числа сравнений первого просмотра достигается при расста¬ новках, где каждый узел меньше своего потомка и, чтобы разместить вытес¬ ненные узлы, приходится спускаться к концевым узлам. Расстановка, обла¬ дающая таким свойством, — упорядоченный список. Удовлетворительной оценкой для списка, состоящего более чем из 256 элементов, является 21V. Максимум числа проверок для малых списков можно вычислить, непосред¬ ственно используя дерево. Те, кто согласен пренебречь ошибкой, привносимой Просмотр 4 Сравнения Пересылки зиция Начало Конец позиций позиций 1. 1 1 2. 9 8 2 : 3 3. 7 7 2 : TEMP 2-> 1 4. 8 4 4 : 5 5. 2 2 4: TEMP 4->2 6. 5 5 8 : 3 7. 6 6 9 : TEMP 9-> 4 8. 3 3 TEMP-^9 9. 7 9* [9-Я, 1-»9] 10. 10 10* И. 11 11* Рис. 5.22. Минимальная по памяти турнирная сортировка, просмотр 4. предположением о полноте деревьев, могут быстро получить оценку следую¬ щим образом. 1. Подсчитайте количество узлов без корневого и концевых. Составьте таблицу количества узлов на каждом уровне дерева от уровня 1 (2 узла) До уровня flog2Af—2“| . При N = 127 flog2An = 7, а таблица имеет вид Уровень| 1 2 3 4 5 Узел | 2 4 8 16 32 2. Подсчитайте число сравнений на каждом уровне и сложите их. На са- нижнем уровне { flog 2N—21 ) на каждый узел приходится два сравнения.
74 ГЛ. 5. ТУРНИРНЫЕ СОРТИРОВКИ На каждом последующем уровне сравнений будет в два раза больше (см. таблицу) Уровень Узлы Количество сравнений 1 2 па один узел 10 на одном уровне 20 2 4 8 32 3 8 6 48 4 16 4 64 5 32 2 64 Всего 228 Эта процедура работает для любого целого /V. Для N, больших 256, при¬ емлемой оценкой является 2N. При N = 2047 максимальное число сравнений равно 4056; 2N = 4094. Основная часть сравнений приходится на N — 1 просмотров, следующих за первым. Максимальное число равно примерно 4 сравнениям за просмотр или всего 4(А7 — 1). Вывод этой величины основан на следующих рассужде¬ ниях. Известно, что после первого просмотра все концевые узлы меньше своих предшественников, и это условие сохраняется от просмотра к просмотру. В результате заключительных обменов в конце просмотров начальное значе¬ ние корневого узла может быть наибольшей величиной только на втором про¬ смотре. На всех других просмотрах ключ в корневой узел попадает после обмена с концевым узлом; таким образом, он не может быть наибольшим в списке. Следовательно, необходимо выполнить какое-то количество сравне¬ ний, чтобы найти позицию для перемещаемого содержимого корневого узла на каждом просмотре. % Общее минимальное число сравнений для этой сортировки равно N — 2 + 4(W—1) или 5N— 6. Максимальное число сравнений, которое дости¬ гается, когда каждый перемещаемый корневой узел опускается до самого нижнего уровня, было указано Р. Флойдом в опубликованном алгоритме в виде 2yV(log2(M—1)). Ожидаемое число сравнений аналитически выразить трудно. Автору не известно доступное изложение этого вопроса в литературе. 5.3.4. Обмены. Перемещение данных в этом методе лучше всего излагать в терминах обменов. Если во всех тройках предшественники являются наи¬ большими, то обменов не будет. Такой случай возникает, когда число сравне¬ ний минимально. Каждый раз, когда предшественник меньше, происходит обмен. На каждую тройку приходится два сравнения, но обмен может быть только один. Таким образом, максимальное число обменов равно половине числа сравнений. В общем случае два сравнения и один обмен упорядочивают любую тройку, и число обменов приближается к половине числа сравнений, когда число сравнений значительно превосходит минимум. В рассматриваемом алгоритме на всех последовательных просмотрах каж¬ дое сравнение вызывает пересылку. Пересылка происходит как в результате сравнений, перемещающих потомка вверх по дереву, так и в результате сравнений, отыскивающих позицию для содержимого TEMP. Число пересылок
5.4. ОРГАНИЗАЦИЯ ТУРНИРНОЙ СОРТИРОВКИ 75 равно числу сравнений плюс число заключительных обменов на всех просмо¬ трах после первого. Поскольку пересылка составляет примерно половину об¬ мена, то число обменов приблизительно равно половине числа сравнений. 5.4. Подробности организации турнирной сортировки Турнирная сортировка, в той ее форме, которая использует дополнитель¬ ную память и избегает вычисления адресов, в настоящее время является весьма широко используемым алгоритмом сортировки в программах сорти¬ ровка-слияние. Из-за большого интереса к турнирной сортировке и ее ва¬ рианту замещение-выбор, равно как и к ее чисто внутренним версиям, мы здесь продолжим обсуждение организации этой сортировки. В примере, используемом здесь, будут собираться меньшие значения и упорядочиваться по возрастанию, а не по убыванию. 5.4.1. Организация памяти. Этот метод является, по существу, сортиров¬ кой ключей. Пусть дано шестнадцать 100-символьных записей с ключами из пяти символов. На подготовительном этапе метода память может быть орга¬ низована так, как показано на рис. 5.23. Фактически это копия алгоритма ИЗ из С ACM, описанного в разделе 5.2. Свойство обособленных таблиц этой сор¬ тировки наглядно показано на рис. 5.23, где представлено формируемое де¬ рево к концу просмотра 1. Первые N/2 мест (с £ по £ + 7) представляют первый уровень дерева, следующие 7V/4 мест (с L -|- 8 по £+11)—второй уровень дерева, следующие N/S мест (£+12 и £+13)—третий уровень и т. д. до тех пор, пока победитель не будет представлен подсписком длины N/N. Различие между рис. 5.23 и алгоритмом ИЗ состоит в том, что распо¬ ложение вспомогательного поля памяти выбирается произвольно и не обяза¬ тельно вычисляется по адресу основного списка записей. Программе началь¬ ной подготовки передается базовый адрес (£), который она использует при ссылке на вспомогательный список. Первые N/'2 позиций этого списка запол¬ нены признаками меньших из спаренных записей (0,100), (200, 300) и т. д. Каждая обведенная в рамку позиция на рис. 5.23 соответствует месту при¬ знака в списке, начиная с £. Программист может использовать возможность произвольного выбора места в памяти для вспомогательного дерева, заготовив семейство адресов, по одному адресу для начала каждого уровня дерева. Базовых адресов будет столько же, сколько уровней в дереве. Эти адреса разделяют уровни дерева, Облегчая использование разделенного на части пространства памяти. Однако, Что важнее, они сокращают число делений, умножений, сдвигов и других операций при сортировке. Обработав один уровень, сортировка переходит к новому индексу (£«) и так до тех пор, пока индексный список не исчерпается. Один вариант турнирной сортировки размещает исходные признаки в про¬ странстве между записями. Обращение к списку — это обращение к месту, которое определяется адресом записи плюс ее длина плюс 1. Этот прием позволяет, по существу, размещать ключи этих записей отдельно, не разру¬ шая сами записи, причем так, что эти записи можно переписывать из исход¬ ной области. Отдельно стоящие величины размещаются в разбросанных мас¬ сивах ключей, фактически исключая отобранные записи из турнирной
Вспомогательный 76 ГЛ. б. ТУРНИРНЫЕ СОРТИРОВКИ
5.4. ОРГАНИЗАЦИЯ ТУРНИРНОЙ СОРТИРОВКИ 77 сортировки. Другие варианты этой сортировки используют пространство между записями для представления всего дерева, установив правила обращения к первому и последующим уровням. 5.4.2. Поиск пути. После начальной подготовки программа должна опре¬ делить путь в дереве. На рис. 5.23 программа начальной подготовки выбрала в качестве победителя запись, начинающуюся в ячейке 100. Парная ей запись в ячейке ООО должна начать свое выступление в турнире. Возникает ряд про¬ блем. Пока нельзя указать адрес в дереве, куда должен быть перемещен Ячейка Содержимое 0 10 100 9 200 191 300 22 400 3817 500 16 600 91 700 121 800 36 900 18 1000 427 1100 116 1200 41 1300 627 1400 111 1500 1611 1600 2500 1601 2503 1602 2506 1603 2509 1604 2512 I 1605 2515 I 1606 2518 1 1607 2521 ) Рис. 5.24. Список записей с присоединенными указателями. парный признак, нельзя определить адрес операнда сравнения ни на одном уровне, нельзя переслать признак на другой уровень, и кроме того, нельзя определить новый операнд сравнения без вычисления адреса. Решения этих проблем различны и зависят от машины и реализации. Мы рассмотрим один метод организации турнира. Он основан на существенном расширении понятия явного указателя и заставит нас изменить наше пред¬ ставление об использовании древовидной структуры. Список указателей базо¬ вых адресов дополняется указателями каждого узла дерева. Теперь указатели базовых адресов образуют дерево, структура которого становится неизменной и явной. Часть процесса начальной подготовки должна каждой паре записей поставить в соответствие адрес позиции на первом уровне дерева. На рис. 5.24 показан список записей с присоединенными указателями для каждой пары, Добавленными к пространству записей. Для N/2 вершин первого уровня ука¬ зано N/2 присоединенных указателей. На рис. 5.24 для каждого адреса ис¬ пользуется ячейка так, что если указатель 1 находится в ячейке 1600, то Указатель 2 — в ячейке 1601 и т. д. В ячейках 0—1500 находятся записи,
78 ГЛ. 5. ТУРНИРНЫЕ СОРТИРОВКИ подлежащие сортировке (список). Длина каждой записи—100 ячеек с клю¬ чом в первой ячейке. Ячейки «1600» связаны с записями списка. Ячейка 1600 связана с записями в ячейках 0 и 100; 1601 соответствует записям в ячейках 200 и 300 и т. д. Для каждой пары списка в ячейках 1600 находится указа¬ тель на «пакет сравнения», который является узлом первого уровня. Узлы 2600 Г 0 2501 Г 2600 2602 Г 2503 200 2504 2600 2505 2506 400 2507 260Г 2508 2509 700 2510 2603 2511 2512 800 2513 2606 2514 2515 г 1000 2516 2606 2517 2518 1300 2519 2605 2520 2521 1500 2522 2609 2523 | 2600 2607 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 Уровень 1 Уровень 2 Рис. 5.25. Содержимое узлов. первого уровня начинаются с ячейки 2500. Каждый узел — это блок из трех слов, содержащих информацию о турнире. На рис. 5.25 содержимое узлов первого уровня, начинающегося с адре¬ са 2500, показано в обозначениях используемых в примере. Каждый узел первого уровня содержит адрес проигравшего (адрес в исходном списке за¬ писей), NLPA*)—адрес узла следующего уровня (пакетов второго уровня) и набор кодов. Предполагается, что адрес занимает одно слово и заполнен кодами, использование которых здесь не обсуждается. Множество победителей первого уровня неявно определяется пакетами этого уровня, в которых за¬ писаны адреса проигравших. Заметим, что если в исходном списке мы введем указатель на адрес проигравшего, то этот метод превратится в сортировку *) NLPA (Next Level Packet Adress) — адрес пакета следующего уровня. (Прим. перев.)
6.1. ВВЕДЕНИЕ 79* неотделенных ключей. Адреса победителей могут храниться в пакете, если предположить, что они доступны на регистрах машины. NLPA указывает на следующий уровень так же, как указатели «1600» указывают на первый уро¬ вень. Рис. 5.25 есть полный список пакетов, образующих дерево. Таким обра¬ зом, 0: 100 дает проигравший ключ 10 и победителя — ключ 9. Этот результат записывается в узел 2500 в виде (0,2600), где 0 — место проигравшего, а 2600 — пакет следующего уровня. Важно понимать, что связи между узлами одного уровня отсутствуют. То есть структура на рис. 5.25 не описывает турнир, когда на нее смотришь сверху вниз. Нам не надо сравнивать элемент, представляемый узлом в 2500, с элементом, представляемым узлом в 2503. Нам не надо сравнивать ключ 10 с ключом 191. Стоит просмотреть дерево. В конце первого просмотра пакет первого уровня, связанный с победителем, содержит адрес его напарника. Обращение к пакету происходит через указатель в ячейке 1600, связанный с парой (0,100) (рис. 5.25). В ячейке 2500 указан адрес ключа 10, этот ключ и его адрес можно поместить на регистры. Теперь надо найти соответствующий операнд для сравнения. На него указывает NLPA в 2501. Этот операнд есть ключ, который проиграл па пре¬ дыдущем просмотре победителю на втором уровне. Это был ключ 22 из ячейки 300 списка. Выполняется сравнение. Если элемент, определяемый этим пакетом, меньше, чем элемент на регистрах, то адрес в списке заменяется в пакете, и ранее проигравший становится победителем. Если в ячейке 0 списка был ключ 83, то содержимое ячейки 2600 будет изменено на адрес 0. Однако в ячейке 0 находится ключ 10, гак что ключ 22 опять проигрывает. Выбор его NLPA для сравнения с ключом 10 продвигает ключ 10 в следую¬ щий круг. Следующий пакет находится в 2700. Этот пакет указывает на ячейку 500 в списке. Ее содержимое — ключ 16, который проиграл ключу 9 на преды¬ дущем круге. Вновь выполняется сравнение; ключ 10 опять побеждает и продвигается на другой уровень для сравнения, определяемого пакетом в 2500. Сравнение рис. 5.23 и 5.25 подтверждает, что мудреная структура на рис. 5.25 на самом деле представляет простое дерево с рис. 5.23. Общий характер такой организации турнира дает читателю представление о том, как выглядит управление турниром в деталях. Пытливому читателю предоставляется право сделать свою реализацию на своей машине. Глава 6. ДЕРЕВЬЯ ПРИ СОРТИРОВКЕ ВСТАВКОЙ 6.1. Введение Сортировка вставкой была описана в главе 2 как линейный метод, в ко¬ тором новый элемент, пытаясь попасть в упорядоченный список, сравнивается со всеми элементами списка до тех пор, пока не найдется подходящей для него позиции. К этому времени за счет пересылки элементов списка для но- ного элемента освобождается место.
ГЛ. 6. ДЕРЕВЬЯ ПРИ СОРТИРОВКЕ ВСТАВКОЙ Введение «структуры» в этот метод сокращает количество сравнений, выполняемых при поиске позиции для нового элемента. При использовании структуры в сортировке вставкой получаются два широко известных мето¬ да: центрированная вставка, двоичная вставка. Хотя в принципе они просты, в них возникают некоторые проблемы представления расширяющегося списка в памяти. В двоичной вставке, кроме того, возникают проблемы построения последовательностей сравнений и управления ими. Использование этих методов заманчиво, когда списки значительного раз¬ мера собираются динамически, а расширяющийся список должен быть все время упорядоченным. 6.2. Центрированная вставка Предположим, что в некоторый момент процесса сортировки список чисел выглядит так, как показано на рис. 6.1. «Дерево» там не двоичное. Для двух .ветвей предшествующим будет корневой узел, в котором находится медиана (элемент упорядоченного списка, у которого количество элементов, его превосходящих, равно количеству элементов, меньших его). На одной ветви располагаются элементы, чьи ключи больше медианы, на другой — те, чьи ключи меньше ее. Размещение предполагаемой медианы в центральной позиции приводит к методу центрированной вставки. В следующем разделе мы будем предполагать, что медиана всегда находится в центральной позиции. (Ее возможные перемещения рассматриваются в разделе 6.2.2.) Рис. 6.1. Упрощенное дерево 6.2.1. Метод центрированной вставки. В по¬ зицию, расположенную в середине поля, доста¬ точно большого, чтобы вместить все хранимые элементы, помещается первый элемент. Счетчику текущей длины списка присваивается начальное значе¬ ние 1, а на ближайшие к началу и к концу списка занятые позиции уста¬ навливаются указатели. Вначале они указывают на центральную позицию. Каждое последующее обращение к сортировке перемещает один элемент данных в позицию списка. При втором обращении новый элемент сравнивает¬ ся с величиной в центральной позиции. Если новый элемент меньше, то он размещается со стороны начала списка. Соответствующий концевой указа¬ тель продвигается. Счетчик длины списка увеличивается на единицу. При каждом последующем поступлении новый элемент сравнивается с содержимым центральной позиции. Если новый элемент больше, то последова¬ тельно просматриваются элементы, расположенные вслед за центральным, да тех пор, пока не найдется элемент, больший нового. Когда это произойдет, больший элемент и все элементы, расположенные за ним, перемещаются на одну позицию в сторону конца списка. Если новый элемент меньше содержимого центральной позиции, то по¬ следовательно просматриваются все элементы со стороны начала списка до
6.2. ЦЕНТРИРОВАННАЯ ВСТАВКА 81 тех пор, пока не будет найден элемент, меньший нового. Когда это произой¬ дет, этот элемент и все элементы, расположенные выше него (в направлении начала списка), переместятся к началу списка на одну позицию. Если большего или меньшего элемента не нашлось, то новый элемент добавляется к соответствующему краю списка. При каждом размещении но¬ вого элемента изменяется соответствующий указатель. Эти указатели опре¬ деляют длину области поиска в каждом из двух направлений и указывают на концы списка. Интересный вариант этого метода включает использование какой-нибудь известной хорошей оценки медианы списка в качестве значения содержимого центральной позиции. Эта оценка не обязательно должна встречаться в списке. 6.2.2. Центрирование. Нижний и верхний указатели используются для того, чтобы можно было определить, достаточно ли места для нового эле¬ мента с соответствующей стороны медианы. Пространство памяти, выделенное для одной «ветви», может быть уже исчерпанным при одностороннем про¬ смотре, который переместит текущую медиану списка из центральной позиции. Когда поле памяти с одной стороны исчерпано, список должен быть переме¬ щен в противоположном направлении, чтобы освободить место для нового элемента. Альтернативой этому перемещению при исчерпании памяти с нуж¬ ной стороны является оттягивание верхнего и нижнего указателей. Всегда, когда поле памяти становится несбалансированным, список перемещается в сторону большей его половины. При этом все перемещения выполняются в направлении, в котором медиана движется к центральной позиции. Эту про¬ блему можно устранить, отведя под список 2N ячеек. 6.2.3. Пример. На рис. 6.2 показаны просмотры метода центрированной вставки при сортировке обычного списка чисел. Состояния списка показаны в конце каждого просмотра. Начальная засылка 00 в незанятые позиции выше середины и 99 — ниже нее, как показано на рисунке, не обязательна. Для каждого просмотра показано несколько величин: LENGTH — длина списка в конце просмотра; HILIMIT — позиция указа¬ теля на конец правой ветви; LOLIMIT— позиция указателя на конец левой ветки. «Сравнения» и «пересылки» представляют количество сравнений и пере¬ сылок на каждом просмотре. Элемент, выделенный полужирным шрифтом, — это элемент, который включается в список на данном просмотре. Стрелки указывают направление перемещений. Число перемещений в данном примере можно сократить, если перемещение всегда выполнять в направлении, вырав¬ нивающем количества элементов по обе стороны центральной позиции поля памяти. 6.2.4. Число сравнений и пересылок. Минимальное число сравнений 2N — 4 достигается на расстановках, при которых на N — 2 просмотрах (по¬ сле начального вызова) после сравнения с медианой выполняется еще только одно сравнение. Расстановка, для которой это условие выполнено, показана На рис. 6.3. В этой расстановке, расстановке обычных чисел, медиана является Первым элементом, все позиции с четными номерами образуют возрастающую Строку, а все позиции с нечетными номерами (кроме первой) образуют
Список в конце: просмотра 1 просмотра 2 просмотра 3 просмотра 4 просмотра 82 ГЛ. 6. ДЕРЕВЬЯ ПРИ СОРТИРОВКЕ ВСТАВКОЙ «—ч-' s «ДД s I и я а II хс? s <и 55 •—1 J CQ <U SJJ «в о, е? —| О р. <У "(MCO^IOIDSOOOO- - сч’ со Ю* (О t'~.’ об О) О - II S -1| || * s S^gSS SJJ я о. «=; —■ о сх «■> cjXjUE ООО 00«^(С®-0) ^ 05 СЧ* СО Т Ю Ф N 00 05* О* —* OOOOOCOtJ*cO~C505 — 05 05 -н’ СЧ* СО тг* Ю СО 00* 05 05 СО || s , II II « 5 lit- * 3 11 X <1 а> <у X _ —< ш 4> s j J я а •— о & <у 4IJUU ’ 05 О - 00 со || S «ids! II = а si^is S _J i-J со о. on®-05 05 05 г=з — о СХ <1> — 05 05 05 t^x_iUU сч* со’ - о о о о ) 'Т IO О t>-’ 00 05* о 1^сО || S «дд|| «5? 15» О О О О СО — 0505050) л>< х 2 ^ О) 05 05 05 Е •—. I £2 (U KJ J Я о. СЧ СО 'Т со СО* ^ ос 05 о —j О ONrt44O0SOOO)O- —' СЧ* СО '«f* Ю СО* СО* 05* О оосоч*Ю(д Nooa о - — СЧ* СО* ■*•* Ю СО К СО 05 О - OOOn^LOONOOO) —<* СЧ СО 'Т Ю СО 00* 05* о* —- £ II » - S II tt * = 11 X *-< а> <и s s X —.И О EjJ Я сх ъ —■ о о. <и 4IJUC =« II = • I'Ss <55 S3 к s X I—1 •—< и (м 5JJ Я СХ О & «у 4IJUC II я 50 II И g | »~~sl (У О х 2 я <и *=»,-« О Cl<V 4IJUC си н Я t СЧ О. <0 н и о S 2 0« 2 СЧ к СО CD || s II ь £ X ^ 11 Х«- «и <У [50) 05 ге ^ < я S 5 05 05 Е _ —• д <у 5JJ «а ^ннЛ Q.4) —'СЧС0-^ЮС0Г^000)О—. ~ (J [-Н ООООПЧ'ЮЯ^О). —<■ СЧ* СО* 'Т LO со’ 00* 05* о* - 11 я г1нн 5 э *—■ CQ 45 SJ-J я о. О сх v ад joc СО—'СОТОЮС^ОООСЧ- —* СЧ* СО -т Ю* со’ l''-’ СО* 05* о* - и с ОООООПЧЧОС0 05 —’ СЧ* СО -ч* Ю со’00* 05* О ч? II со IIII нн и _ * з £5Н = * *~* 5^*1 И 11 SjJ а сх • • ^ ’—' О СХ 45 Sz: Вдиис: (=с о с
6.3. ДВОИЧНАЯ ВСТАВКА: ДЕРЕВО ВСТАВОК 83 убывающую строку. В результате этого новый элемент всегда расположен между медианой и ее левым либо правым преемником. Максимум числа сравнений достигается, когда каждый элемент должен пройти путь от медианы до концевой позиции. Этот путь удлиняется при каждом последовательном просмотре. При первом просмотре выполняется одно сравнение (с медианой), при втором — два, на последнем — М/2 сравнений. Позиция Значение 1. 6 2. I 3. И 4. 2 5. 10 6. 3 7. 9 1 1 8. 4 1 1 2 2 9. 8 1 1 2 2 3 3 10. 5 1 1 2 2 3 3 4 4 И. 7 1 2 2 3 3 4 4 5 5 в в 6 6 в 6 6 6 6 1Г 11 10 10 9 9 8 8 7 11 И 10 10 9 9 8 11 11 10 10 9 11 11 10 И Рис. 6.3. Оптимальная расстановка. Средняя длина ветви, которая растет от 1 до М/2, равна N/4. Ветвь средней длины Л74 исследуется N — 1 раз. Максимальное число сравнений равно N (N— 1) /4, когда все N — 1 элементов составляют ветвь средней дли¬ ны. Ожидаемое число сравнений, равное N(N—1)/8, основано на предполо¬ жении, что /V — 1 элементов будут проходить половину половины списка. N2/8 — хорошая оценка для ожидаемого числа сравнений. 6.3. Двоичная вставка: дерево вставок Структура центрированного двоичного дерева может быть наложена на список так, как показано на рис. 6.4. Это упорядоченный список чисел ог единицы до тридцати одного. Для этого дерева так же, как для дерева из главы 4, выполнено соглашение о том, что левый преемник узла содержит меньшую величину, а правый преемник — большую. Корневой узел этого де,- рева содержит медиану списка. Поскольку медиана должна располагаться в центре списка, корневой узел должен располагаться в центре поля памяти, отведенного под список. Следовательно, корневой узел упорядоченного списка ключей от 1 до 31, представленных в позициях памяти с 1 до 31, должен располагаться в позиции 16 и содержать ключ 16. Левый и правый преемники корневого узла находятся в позициях, содер¬ жащих ключи, являющиеся соответственно 1/4- и 3/4-квантилями списка*). *) а-квантилыо (0 ^ а ^ 1) списка из N элементов называется элемент, обладающий следующими свойствами: во-первых, число элементов, не превос¬
84 ГЛ. 6. ДЕРЕВЬЯ ПРИ СОРТИРОВКЕ ВСТАВКОЙ Узел левого преемника, на рис. 6.4 узел 8, содержит наибольший из ключей меньших 3/4 элементов списка. Узел правого преемника, на рис. 6.4 узел 24, содержит наименьший из ключей больших 3/4 элементов списка. Левый преем¬ ник узла 8 — узел 4, содержит величину, меньшую 7/8 элементов списка; левый преемник узла 4 — меньшую 15/16 элементов списка и т. д. Естествен¬ но, что медиана находится в середине списка; точка 1/4 находится в середине Позиция памяти (узел) Значение Квартили 16 = ЛГ/2 16 15 меньших, 15 больших —медиана 8 = W4 8 7 меньших, 16 + 7=23 больших — первая квартиль 4 = ЛГ/8 4 3 меньших, 3 + 8+16 = 27 больших 2= N/16 2 1 меньший, 1+4 + 8+16 = 29 больших 24 = ЛГ/4 24 7 больших, 16 + 7=23 меньших — третья квартиль Рис. 6.4. Центрированное двоичное дерево. между начальной и средней точками; точка 1/8 —в середине между началь¬ ной точкой и точкой 1/4. 6.3.1. Двоичная вставка: статическое дерево. Пример. Наиболее непо¬ средственный способ реализации двоичной вставки должен учитывать, что де¬ рево, представляющее окончательный список формируется уже на первом про¬ смотре. Рассмотрим рис. 6.5. Список занимает поле из 27 элементов, из кото¬ рых в наличии 8. Центр поля в ячейке 13, в которой находится предполагае¬ мая медиана (корневой узел). Левая квартиль находится в ячейке 6, правая квартиль — в ячейке 20; октили — в ячейках 2, 10, 16, 24. (Позициями ме¬ дианы и квартилей являются 13, 6, 20, а не 14, 7, 21, так как начальный адрес поля есть 0, а не 1.) Каждый новый элемент при размещении в этом списке будет сравниваться пять раз, по одному на каждом уровне дерева. Поскольку список занимает только часть поля, некоторое число раз могут сравниваться меньшая фиктивная и большая фиктивная величины. На рис. 6.5 ходящих его, не меньше, чем a7V, и во-вторых, число элементов, не меньших его, не меньше, чем (1—a)N. 1/4- и 3/4-квантили называются квартилями; 1/8-, 3/8-, 5/8- и 7/8-квантили называются октилями и т. д. (Прим. перев.)
6.3. ДВОИЧНАЯ ВСТАВКА: ДЕРЕВО ВСТАВОК 85 они представлены как L и Н. Сначала одна половина поля заполнена вели¬ чинами L, а другая половина — величинами Н. Каждый элемент, пытающийся попасть в список, прежде всего будет сравниваться с ячейкой 13, затем, в 0. L 1. L 2. L 3. L Если 4. L следующим Сравнения 5. L поступает (позиции) 6. 1 9 13, 6, 10, 12, 13 7. 2 —5 13, 6, 2, 4, 5 8. 3 25 13, 20, 16, 14, 13 9. 4 14 13, 20, 16, 14, 13 10. 5- 11. 6 12. 8 13. 10 14. 11 15. Н 16. Н 17. Н 18. Н 19. Н 20. Н 21. н 22. н 23. н 24. н 25. н 26. н -Медиана Рис. 6.5. Двоичная сортировка со статическим деревом. зависимости от его величины, с ячейкой 6 или 20 (квартилью), и т. д. На Рис. 6.5 показаны сравнения для некоторого набора ключей. Важными харак¬ теристиками этой реализации являются: 1. Ячейки, используемые для сравнения, остаются одними и теми же 0т просмотра к просмотру. Они могут быть вычислены предварительно, и
86 ГЛ. 6. ДЕРЕВЬЯ ПРИ СОРТИРОВКЕ ВСТАВКОЙ адресных вычислений можно избежать. Структура дерева фиксирована и не зависит от формы списка. 2. Число сравнений зависит не от длины текущего списка, а от ожидае¬ мой длины всего списка. Эти две характеристики показаны на рис. 6.5. Следует отметить, что истинная медиана на этом рисунке расположена в ячейке 10 и что число сравнений с фиктивными величинами может быть очень большим. Особенно это относится к случаю, когда текущий список мал по сравнению с отве¬ денным ему полем памяти. Можно предотвратить сравнения фиктивных величин, используя ограничители, и, возможно, на многих машинах стоит поступать именно так. Заметим, однако, что, как в случае с —5 на рис. 6.5, выполнив сравнение с фиктивной величиной, положить конец сравнениям не удается. На рис. 6.5 список не балансируется. Как и в центральной вставке, ме¬ диана может располагаться близко к центру, а свободное пространство па¬ мяти может быть одинаково распределено по обеим сторонам. За исключе¬ нием сравнения в вершинах дерева, скорее не линейного, после первого срав¬ нения этот метод идентичен центрированной вставке. Начинается метод с раз¬ мещения некоторого элемента в центре поля памяти и т. д. 6.3.2. Двоичная вставка: динамическое дерево. Можно сократить число сравнений, придав структуру дерева фактическому списку, находящемуся в памяти, отведенной под список. Как и в случае статического дерева, список расширяется от центра и захватывает в каждый момент времени порции памяти. На каждом просмотре в сравнениях используется фактическая ме¬ диана и точки «/г-тилей» существующего списка, а не такие же точки во всем пространстве. Посмотрите на рис. 6.6. Список из восьми элементов, точно такой же, как на рис. 6.5, представлен на таком же поле памяти. Рисунок 6.6 отличается от рисунка 6.5 тем, что на нем медиана списка расположена в центральной позиции поля. На рисунке 6.5 этого можно было бы добиться балансировкой поля памяти. Динамическое, дерево, однако, не только балансирует поле па¬ мяти, но и сокращает число сравнений, ограничивая область сравнений фак¬ тическими элементами. Это требует значительной дополнительной работы. Характер этой работы косвенно выражен в адресах ячеек на рис. 6.6. Число, предшествующее наклонной черте, есть относительный адрес элемента в поле памяти, т. е. его фактической ячейки относительно начала рабочего поля. Число за наклонной чертой есть относительный адрес в списке — относитель¬ ная позиция элемента в фактическом текущем списке. Например, элемент с ключом 3 занимает относительную позицию И в поле памяти, относительную позицию 2 в списке. Относительная позиция в списке есть относительная по¬ зиция в поле памяти минус начало списка, в данном примере позиция 9. Каждый элемент, добавляемый к списку, определяет новое дерево. Для по¬ следовательности сравнений просмотра необходимо подготовить соответствую¬ щие относительные позиции в списке, а также относительные позиции в поле памяти для каждого просмотра. Процедура адресации древовидной структуры такова.
6.3. ДВОИЧНАЯ ВСТАВКА: ДЕРЕВО ВСТАВОК 87 1. Вычислить адрес медианы относительно начала списка. Адрес медианы в поле памяти есть сумма относительного адреса списка медианы и адреса начала списка. Относительный адрес медианы в списке равен целой части от половины длины списка. Например, текущий список на рис. 6.6 состоит из восьми элементов — одна вторая от восьми плюс начало списка равно 4 + 9=13. 2. Чтобы перейти от медианы к другому узлу, а впоследствии от одного узла к другому, вводятся две переменные CURRENT и DISTANCE. Началь¬ ное значение CURRENT равно относительному адресу медианы. Начальное Список 0. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 1G. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. L L L L L L L L L 1 - 2 3 4 5 6 8 Ю. Н н н н н н н н н н LOL1MIT 4- Q1 <- Медиана <- Q2 — H1L1MIT /3/4 Если следующим поступает 25 14 Сравнение (позиции) 13/4, 15/6, 16/7 13/4, 11/2, 10/1, 9/0 13/4, 15/6, 16/7 13/4, 15/6, 16/7 Рис. 6.6. Двоичная вставка: динамическое дерево. значение DISTANCE равно целой части от половины относительного адреса медианы плюс единица. Чтобы перейти от медианы к левому преемнику, надо вычесть DISTANCE из CURRENT. Чтобы перейти от медианы к правому преемнику, надо сложить CURRENT и DISTANCE. Затем прибавить адрес начала списка, чтобы сформировать адрес в поле памяти. Для перехода от узла к узлу, каждый раз вычисляют значение DISTANCE как целую часть от половины DISTANCE плюс единица. Расстояние от точки, соответствующей квартили, до точки, соответствующей октили, равно половине расстояния от медианы до квартили. Новое значение DISTANCE складывается или вычи¬ тается из CURRENT, чтобы сформировать относительный адрес в списке. Ис¬ пользуя CURRENT = 4, как на рис. 6.6, получаем начальное значение distance, равное 2. Следовательно, квартилями являются позиции списка 2
88 ГЛ. 7. БЫСТРАЯ СОРТИРОВКА и 6. Фактические ячейки поля памяти образуются добавлением 9 (адрес на¬ чала списка) к полученным 13, 11, 15. По мере роста списка в дереве формируется все больше уровней и тре¬ буется больше сравнений. Полное текущее дерево пройдено, когда вычислен¬ ное значение DISTANCE равно 0 и (или) когда полученный адрес выходит за границы списка. 6.3.3. Фиксированное или статическое. Программист должен учитывать тяжкое бремя вычислений адресов, необходимых для сокращения числа срав¬ нений за счет сравнений с фиктивными величинами. В разделе 6.4 приведены формулы для оценки числа сравнений. По-видимому, весьма желательна какая-нибудь форма управления памятью для того, чтобы минимизировать перемещения данных, занимающие массу времени. От N и машины зависит, является ли вычисление адреса при каждом сравнении приемлемой платой за управление памятью и минимизацию числа сравнений. Здесь возможен ком¬ промисс: использовать динамическое дерево, пока оно не достигнет опреде¬ ленных размеров, а затем использовать статическое дерево. При N = 1023, например, окончательное дерево будет иметь 10 уровней и 512 элементов будут концевыми. В зависимости от архитектуры машины, может быть, вы¬ годно ограничиться сравнениями в фактическом списке до тех пор, пока его длина не превысит 128. В этот момент в дереве списка не более 7 уровней. Когда список превысит 128 и можно будет сэкономить только три сравнения на элемент, можно использовать статическое дерево. Следует также учесть возможность использования в методе величин, не входящих в список. Если известны хорошие оценки медианы и п-тилей, то в сравнениях можно использовать эти оценки. 6.4. Сравнения и пересылки Число сравнений для статического дерева равно W flog* ЛП • Число сравнений при динамическом дереве равно сумме log2 К по всем просмотрам. К есть целая степень 2 такая, что число элементов в списке лежит между 2«:-1 и 2К— 1. В общем случае ожидаемое число сравнений равно AMog2(A7e), где е « 2,72. Число пересылок можно принять равным N(N — 1)/8. Глава 7. БЫСТРАЯ СОРТИРОВКА 7.1. Введение Метод быстрой сортировки впервые был описан Ч. А. Р. Хоаром в 1962 году в работе [16] и в алгоритмах 63, 64, 65 в САСМ (см. приложе¬ ние А). С тех пор уже опубликовано много вариантов этого метода, часть из которых развивают предположения и рекомендации исходной статьи. По¬ добно сортировке Шелла, быстрая сортировка — это общее название ряда ал¬ горитмов, которые отражают различные подходы к получению критичного параметра, влияющего на производительность метода.
7.2. МЕТОД 89 Быстрая сортировка — это метод, ориентированный на исподъзование де¬ рева, хотя связь между двоичным деревом и алгоритмом сортировки в нем не столь явная, как в турнирной или двоичной сортировке. 7.2. Метод Некоторый элемент списка выбирается в качестве «основы». Все элемен¬ ты, меньшие основы, размещаются в позициях с начала списка; все элементы, большие основы, размещаются в позициях с конца списка. Элементы сравни¬ ваются с основой и изменяют свою позицию, когда они больше и располо¬ жены в списке выше нее, или когда меньше и расположены в списке ниже нее. Это упорядочение составляет этап сортировки. В конце этапа для раз¬ мещения основы пригодна некоторая позиция в списке. Эта позиция соответ¬ ствует месту основы в окончательном списке, поскольку ее относительный адрес в списке определяется числом элементов выше и ниже нее. Этап определяет две части. Если значение основы хорошо аппроксимирует медиану списка, то эти две части будут примерно равной длины. Если основа является наихудшей возможной оценкой медианы (наибольшим или наимень¬ шим элементом списка), то эти части будут длиной 0 и К— 1, где К — длина исходного списка. Способ построения частей, по существу, один и тот же во всех версиях алгоритма. Устанавливаются два указателя, один на начало, другой на конец списка. После выбора основы поиск меньшей величины начинается с указа¬ теля конца, перемещающегося вверх к началу списка. Сравнения продол¬ жаются до тех пор, пока не будет найден элемент, меньший основы, или не будет исчерпан список. Когда элемент, меньший основы, найден, его необходимо переместить в позицию, содержащую элемент, больший основы. Эта позиция находится при сравнениях, использующих указатель начала. Сравнения выполняются сверху вниз по списку до тех пор, пока указатель начала не укажет на больший элемент. Таким образом, элементы, больший и меньший основы, идентифици¬ рованы, и теперь выполняется обмен между ними. Модификации возникают только в методе пересылки элементов данных. Один способ состоит в том, что основа пересылается во временную память, а содержимое начала списка перемещается в освободившуюся позицию. При этом освобождается начальная позиция, куда можно переместить элемент. После пересылки свободная позиция сдвигается в ячейку, расположенную близко к концу списка. При нисходящем поиске отыскивается элемент для пересылки в эту свободную позицию. Свободная позиция чередуется с верх¬ ней и нижней позициями до тех пор, пока указатели не совместятся. После обмена или двойной пересылки возобновляется поиск другого эле¬ мента, меньшего основы. Когда он найден, начинается поиск большего эле¬ мента с использованием указателя начала. Этот процесс продолжается до тех пор, пока два указателя не встретятся. Относительная длина частей определяется позицией в списке, в которой совместятся указатели начала и конца. В некоторых версиях этого метода необходимо сравнивать относитель¬ ные позиции указателей после каждого перемещения по списку вверх или
90 ГЛ. 7. БЫСТРАЯ СОРТИРОВКА вниз. Однако этого можно избежать, используя прием ограничения данных, который будет описан в следующем разделе. На первом этапе строятся две части. Одна из них используется в каче¬ стве исходной на втором этапе, вторая помещается в стек LIFO. Общее правило таково: первой обрабатывать меньшую часть, а границы большей запоминать в стеке. Второй этап порождает две части. Меньшая обрабаты¬ вается на третьем этапе, а большая помещается в стек над большей частью, построенной на этапе 1. Процесс порождения частей, запоминания большей из них в стеке и разделения меньшей продолжается до тех пор, пока все части не сократятся до одного элемента. При возникновении одноэлементной части новая часть для стека не строится. Ожидающие части выбираются из стека и обрабатываются. Сортировка выполнена, когда стек пуст. Обработка меньшей из двух частей гарантирует, что ожидающих частей в стеке будет не более log2 N. Последовательность обработки частей совер¬ шенно произвольна и может изменяться по желанию программиста. Быстрая сортировка может использоваться в комбинированном алгоритме, чтобы сократить части до заранее определенного размера, после чего они упорядочиваются другим методом, более эффективным для малых списков. 7.3. Подробности этапа На рис. 7.1 изображена специальная расстановка обычного списка чисел. Некоторый механизм выбора основы (объясняемый в разделе 7.5) выбирает ключ 6 из позиции 3 и помещают его в рабочую память, именуемую PIVOT. Элемент из начала списка пересылается в позицию 3. Первая позиция теперь свободна и получает значение из восходящей последовательности сравнений. Столбец, на рис. 7.1 озаглавленный «Выбор основы», показывает список после удаления основы и пересылки содержимого первой позиции. Указатель BEG изначально устанавливается на первую позицию списка, указатель END — на последнюю. Начальная расстановка этих указателей определяет ту часть списка, ко¬ торая обрабатывается на этапе. Поскольку на первом этапе обрабатывается весь список, то первый раз указатели устанавливаются на начало и конец списка. На последующих этапах указатели предварительно расставляются по границам обрабатываемой части. Эта предварительная установка происходит до выбора основы, так как выбор основы надо ограничить «активной» в на¬ стоящий момент частью. Первыми сравниваются элемент списка (части), на который указывает END, и выбранная основа. Первым элементом списка сравнений и пересылок является POS11: PIVOT. Элемент в позиции 11 (ключ 5) меньше основы и пересылается в свободную позицию в начало списка. Теперь свободна пози¬ ция 11. Чтобы заполнить эту позицию, начинается поиск с начала списка, ис¬ пользующий BEG. Так как значение BEG до начала поиска было увеличено, то первым, сравнением является POS2 : PIVOT. Элемент в позиции 2 больше основы, поэтому он пересылается в свободную позицию, на которую указы¬ вает END. После этой пересылки свободной становится позиция 2, а
7.3. ПОДРОБНОСТИ ЭТАПА 91 Первый Второй Третий Четвертый Список Выбор основы обмен обмен обмен обмен 1. 3 — <- BEG 5 5 5 5 2. 11 11 “ <- BEG 1 1 1 3. 6 3 3 3 3 3 4. 9 9 9 — <- BEG 2 2 5. 7 7 7 7 - «-BEG 4 6. 8 8 8 8 8 Ь 14-BEG. END 7. 4 4 4 4 4*>END 8 8. 2 2 2 2 7 7 9. 10 10 10 10<- END 10 10 10. 1 1 14-END 9 9 9 И. 5 5<- END 11 11 11 11 Замечание. Полужирным шрифтом выделены перемещаемые величины. PIVOT=6 Сравнения и пересылки POS11 : PIVOT POS 2 : PIVOT POSIO : PIVOT POS 3 : PIVOT POS 4: PIVOT POS 9: PIVOT POS 8 : PIVOT POS 5 : PIVOT POS 7: PIVOT POS 6: PIVOT Рис. 7.1. Быстрая сортировка, первый просмотр. POSU-»POS 1 1 POS 2->POSll } POSIO-»POS 2 'I POS 4-»POSIO J первый обмен второй обмен POS 8-» POS 4 POS 5-» POS 8 . POS 7-» POS 5 POS 6-» POS 7 третий обмен четвертый обмен Стек частей Начало 1 7 Конец 6 11 Рис. 7.2. Дерево и стек частей.
92 ГЛ. 7. БЫСТРАЯ СОРТИРОВКА указатели и состояние списка такими, как показано в столбце, озаглавленном «Первый обмен». Теперь возобновляется сравнение снизу вверх. Первое проверенное зна¬ чение (1 в позиции 10)—оно меньше основы — пересылается из позиции 10 в свободную позицию 2. Позиция 10 освобождается, и опять начинаются сравнения сверху вниз. Для поиска величины (ключ 9), большей основы, BEG перемещается в позицию 4. Выполняется пересылка в позицию 10. В столбце, озаглавленном «Второй обмен», показаны список, указатели и сво¬ бодная позиция после этой пересылки и предварительной установки END для новых сравнений снизу вверх. На рис. 7.1 показаны остальные сравнения, пересылки и преобразования списка. Просмотр заканчивается, когда BEG и END сойдутся в одной пози¬ ции. Обнаружить это можно, используя тот факт, что каждый раз при своем изменении END сравнивается с BEG, и BEG при каждом своем перемещении сравнивается с END. По окончании просмотра основа помещается в список в соответствующую ей позицию. Сформированные части являются левой и правой ветвями дерева, корневая вершина которого — 6. Это дерево показано на рис. 7.2. Меньшая часть занимает позиции 1—5, большая — позиции — 7—11. 7.4. Межэтапные действия На следующем этапе будет обрабатываться меньшая из только что полу¬ ченных частей. Длина частей легко определяется разностью значений началь¬ ной и конечной позиций. У выбранной части первая позиция будет помещена Список 1. • 5«- BEG 2. 1 3 3 Стек частей 4. 2 Начало Конец 5. 4 «-END „ ~ ГГ" Вершина стека->7 11 6. о 7. 8 8. 7 9. 10 10. 9 И. И Рис. 7.3. Быстрая сортировка, начало второго этапа. в BEG, а последняя — в END. Вторая часть останется в стеке. Когда части равны, выбор произволен. На рис. 7.3 показан список с новыми значениями BEG и END. Естественно, основа будет выбираться из той части, которая будет обрабатываться на этом этапе. Необходимо обеспечить правильность обрабатываемой части. Правильная часть при использовании быстрой сортировки должна иметь по крайней мере два элемента. Если BEG не меньше END, то в построенной части только один элемент. Другую часть берут из стека частей. Если таковой нет, сортировка закончена. На этапе 2 элементы списка 1—5 разделяются на две части. Если пред¬ положить, что основой на этапе является ключ 3, то эти части занимают
7.5. ОСНОВА 93 позиции 1—2 и позиции 4—5. На рис. 7.4 показан список в конце этапа 2, последовательность сравнений этого этапа, сформированные части и состояние Первоначально 1. 5<-BEG 2. 1 3. 3 4. 2 5. 4 «-END 6. 6 7. 8 8. 7 9. 10 10. 9 И. 11 После выбора основы 1. 2. 1 3. 5 4. 2 5. 4 В конце просмотра 1. 2 2. 1 3. 3<- BEG, 4. 5 5. 4 Рис. 7.4. Быстрая сортировка, этап 2. стека частей. Вид дерева показывает, что в результате этого этапа сформи¬ ровано поддерево левой ветви. На рис. 7.5 показан третий этап. Построение одноэлементной части экви¬ валентно достижению концевого узла дерева. Выбор разных основ приводит к построению деревьев различной формы, с разными объемами и различным числом сравнений. 7.5. Основа Механизм выбора основы еще не был описан. Есть множество приемов, используемых в опубликованных версиях этого метода. Цель этих приемов — выбрать основу ближе к медиане части и избежать неудачных выборов основы. Сравнения и пересылки POS5 : PIVOT POS4 ; PIVOT POS2 : PIVOT POS3 : PIVOT POS4->POSl POS3-»POS4 Стек В начале 1- 5 7-11 В конце 1- 2 4- 5 7-11 Дерево PIVOT = 3 END
94 ГЛ. 7. БЫСТРАЯ СОРТИРОВКА Хороший механизм должен быть защищен от возможных расстановок, в маленький, либо Первоначально очень большой элемент. Сравнения н Очень плохой пересылки 1. 2«- BEG POS2 : PIVOT POS2-» POS1 2. 1 <- END 3. 3 Стек 4. 5 В начале В конце 5. 4 1- 2 1 6. 6 4- 5 4- 5 7. 8 7-11 7-11 8. 7 9. 10 10. 9 11. И Разделение после выбора основы — PIVOT = 2 Разделение в конце просмотра 1 «-BEG, END 2 Дерево Рис. 7.5. Быстрая сортировка, этап 3. сводит метод по производительности к линейному выбору с обменом. Выбор основы определяет размер частей, порождаемых на этапе. Метод оптимален, когда на каждом этапе основа является медианой части этого этапа. Если усложнить выбор основы, то можно сократить ожидаемое число сравнений для этого метода с \AN\og2N более чем до 1.1JV lcg2 А/. Если предположить, что числа случайны, то любая расстановка этих чисел в списке равновероятна, и медиана с равным успехом может встре¬ титься в любой позиции. Метод выбора основы, использованный в алгоритме Хиббарда, в качестве таковой берет элемент из первой позиции части. Опас¬ ность здесь представляет устойчивая тенденция к упорядоченности в списке,
7.6. ЗАКЛЮЧИТЕЛЬНЫЙ ЭТАП 95 которая может приводить к наличию малого элемента в первой позиции; следовательно, создаваемые части не будут сбалансированными. Но если основу доставляет первая позиция, то она автоматически становится свобод¬ ной, и пересылка из первой позиции в позицию основы, упомянутая в приг мере, не нужна. Если возможна устойчивая тенденция к упорядоченности в списке, то разумно выбирать основу из средней позиции. Если список действительно случаен, то выбор из средней позиции не опасен — он не хуже других, а если упорядоченность есть, то такой выбор мог бы быть весьма выгоден. Синглтон (алгоритм 347 в Приложении А), следуя (возможно) замеча¬ нию основной статьи Хоара, пытается определить медиану, выбирая ее из пробной группы элементов (выборки). В своем алгоритме он в начале этапа сравнивает первый, последний и средний элементы списка и использует сред¬ нее значение этой выборки как основу. (Эта процедура имеет полезный по¬ бочный эффект, который мы обсудим в следующем разделе.) Стремление со¬ кратить выполняемую работу приводит к рассмотрению выборки любой желаемой длины. За три проверки и пересылки, беря в качестве медианы части медиану случайной выборки из части, можно сократить коэффициент до 1.188. Используя семь пробных элементов, можно сделать его меньшим 1.1. Сортировка выборкой Фрейзера [9] и сортировка Ван Эмдена [28] суще¬ ственно используют технику выборок при определении основы. Хоар для определения основы использует на каждом этапе генератор слу¬ чайных чисел. Ценность этого приема заключается не столько в определении хорошей аппроксимации позиции медианы, сколько в защите метода от не¬ желательного смещения в данных. Случайный выбор основы для каждой но¬ вой части делает практически невероятной зависимость выбираемых основ ог нежелательной особенности в данных. Если программисту известно многое о его данных, то возможны даль¬ нейшие улучшения. Неявные возможности «дистрибутивной» сортировки мож¬ но применить к сравнительной быстрой сортировке, используя медианы, не принадлежащие списку. Основа необязательно должна быть фактическим значением части. Если программисту известны медиана, точки квартилей и т. д., он может ввести в качестве основы внешние значения. Он может после некоторого просмотра конкретной части определить, где расположена ее медиана, а затем изменить алгоритм выбора медианы для данной части в соответствии с тем, что он узнал. 7.6. Заключительный этап Распознать окончание этапа можно многими способами. Один из них ис¬ пользует сравнение указателей при каждом обмене. На некоторых машинах это сравнение адресов может быть достаточно дорогим и фактически удваи¬ вать время сравнения в методе. На других машинах сравнивать адреса мож¬ но эффективнее, используя технику индексирования. В «ускоренной сортировке» используется модификация приема проверка- обмен. В этой версии поиск происходит в обратном направлении, начиная сверху от второго элемента, следующего за первой свободной позицией. Если
96 ГЛ. 7. БЫСТРАЯ СОРТИРОВКА большего элемента нигде нет, то по исчерпании списка нисходящий поиск прекращается, и этап заканчивается. Если при поиске сверху вниз больший элемент найден, то выполняется поиск снизу вверх. Поиск снизу вверх огра¬ ничен верхним и нижнем указателями. Когда указатели встретятся, в теку¬ щую свободную позицию загружается содержимое позиции, расположенной над той, где встретились указатели, а основа помещается в освободившуюся Первоначально Первый обмен Второй обмен Третий обмен 1. 3 3 3 3 2. 11 —> 1 1 1 3. 6 6<-BEG 6 —> 5 4. 4 4 4 4 5. 9 9 —> 2 2 6. 5 5 5<- BEG -> 6 4-END 7. 7 7 7 7<-BEG 8. 8 8 8 8 9. 10 10 10 10 10. 2 2^-END —> 9-» END 9 11. 1 ->11 11 11 PIVOT “6 Сравнения 1 : PIVOT 3 : PIVOT 6: PIVOT 2 : PIVOT 4 : PIVOT 7 : PIVOT 11 : PIVOT 5 : PIVOT 9 : PIVOT BEG над END 10 : PIVOT 8 : PIVOT 2 -*-> 11 BEG над END 5 <-> 10 7 : PIVOT 6 : PIVOT END над BEG BEG под PIVOT 3 > 6 Замечание. Положение указателей BEG и END показано в конце последова¬ тельности сравнений. Рис. 7.6. Быстрая сортировка, конец этапа. PIVOT представляет временную ячейку, в которой находится 6. при этом позицию. Указатели всегда встречаются у элемента, большего осно¬ вы, а над этим элементом всегда находится меньший элемент. В первой опубликованной на алголе версии Хоара указатель сравни¬ вался с границей списка, обрабатываемого на данном этапе. Для восходящего указателя границей является первая позиция списка, для нисходящего — последняя позиция списка. Каждый раз, когда перемещается указатель, он сравнивается с границей. Это сравнение с границей должно выполняться при каждом сравнении величин в качестве меры предосторожности против выхода за границы списка. Указатели сравниваются только при обмене. Если при сравнении верхний указатель (BEG) оказался не выше нижнего указателя (END), то запускает¬ ся процедура окончания этапа. Первым выполняется поиск сверху вниз. В процедуре окончания этапа, предложенной Хоаром, указатели могут пересекать друг друга в течение поиска (см. рис. 7.6). В столбце «Тре¬ тий обмен» при поиске сверху вниз было обнаружено, что ключ 7 в по¬ зиции 7 больше основы. Поиск снизу вверх начинается с позиции 9 и про¬ должается до позиции 6 с пересечением верхним указателем нижнего и по¬ вторной проверкой позиции, рассмотренной при поиске сверху вниз. Сравнение
7.8. ОБСУЖДЕНИЕ 97 указателей, которое происходит только тогда, когда должен произойти обмен, обнаруживает их пересечение. Если верхний указатель расположен выше основы, то обмен между величинами из позиции основы и позиции, на кото¬ рую указывает верхний указатель, размещает основу должным образом. Если это условие не выполнено, то основа размещается при обмене между пози¬ цией основы и позицией, на которую указывает нижний указатель. Так, на рис. 7.6, когда END обнаруживает, что ключ 5 в позиции 6 меньше основы 6, BEG сравнивается с END, и выявляется пересечение. Затем выясняется, что BEG ниже позиции основы, и PIVOT и END обмениваются (позиции 3 и 6). Изящный подход к окончанию этапа использован в версии Синглтона. Этот подход является побочным эффектом его способа выбора основы. Он помещает наименьший элемент из его трехэлемеитной выборки в первую по¬ зицию части, а наибольший элемент в последнюю позицию. Ему не надо про¬ верять границы или указатели на совпадение за исключением случая обмена. Список представляет собой «ограниченные данные»: маленький ключ нахо¬ дится в верхней позиции, а большой — в конце. Указатель, перемещающийся от конца к началу, будет всегда вызывать обмен, когда он достигнет вер¬ шины списка. Здесь нет опасности выйти за границы списка при поиске. Аналогичный результат можно было бы получить независимо от выбора основы, поместив по краям списка такие значения, о которых известно, что они вне его диапазона. Еще один побочный эффект ограничения данных, предложенного Синглто¬ ном, состоит в ограничении размера части, получаемой в худшем случае, до К — 2, поскольку меньшая часть должна содержать по крайней мере гранич¬ ное число (меньшее из выборки, используемой для выбора основы). 7.7. Быстрая сортировка и комбинации Ценность быстрой сортировки можно увеличить, определив, когда часть становится слишком маленькой для того, чтобы продолжение построения ча¬ стей было выгодным. Эта часть потом упорядочивается другим методом. Со¬ ответствующий размер минимальной записи зависит от конкретной машины. В качестве другого приемлемого способа Синглтон выбрал просеивание. Про¬ цесс, которым упорядочивается данная часть, никак не связан с другими частями, так что никаких изменений в методе не происходит за исключением дополнительной проверки длины части и перехода к другому способу. В лю¬ бом случае надо в некоторой форме проверять длину частей, поскольку не¬ обходимо проверять части на правильность. Все опубликованные алгоритмы кроме алгоритма Синглтона являются быстрой сортировкой в чистом виде, за исключением ускоренной сортировки, которая исключает части, состоящие менее чем из трех элементов. 7.8. Обсуждение В этом методе ожидаемое число сравнений изменяется от 1.1 N f log2 N 1 До IAN flog2^") в зависимости от выбора основы. Минимум числа сравнений Достигается, когда выбранная основа каждый раз является медианой. Этот 4 г. Лории
98 ГЛ. 8. СОРТИРОВКА ВЫБОРОМ минимум меньше N flog2^“| . Максимум числа сравнений достигается, когда на каждом этапе основа выбирается наихудшим образом. В этом случае на каждом этапе строится только одна правильная часть. Эта часть будет иметь на один элемент меньше по сравнению с поступившей на вход данного этапа. Число сравнений будет N — 1 + N — 2 + N — N + 1. Сумма этого ряда равна N(N—1)/2. Выбор основы из первой позиции части при сортировке упорядоченного списка будет представлять наихудший случай. Число обменов трудно подсчитать. Но их не может быть больше, чем сравнений. Разумное представление дает приближенный подсчет половины числа сравнений. Глава 8. СОРТИРОВКА ВЫБОРОМ: МЕТОДЫ БОЛЬШЙХ СТЕПЕНЕЙ 8.1. Введение Разбиение списка на подсписки, по существу, является эффективным под¬ ходом к сортировке, поскольку оно сокращает значение N (например, в таких выражениях как N2 и N(N—1)/2) до величины К, меньшей N. При этом время сортировки по характеру становится скорее аддитивным, чем мульти¬ пликативным. В линейном выборе разбиением списка на части длины К число сравнений можно сократить с N2 до К\-\- К\ + К\ + X. Переменная X соот¬ ветствует действиям, необходимым для упорядочения («слияния») между со¬ бой упорядоченных подсписков. Методы этой главы и следующей отличаются от ранее описанных мето¬ дов с древовидным разбиением по двум направлениям. Во-первых, они не обязательно связаны с двоичным деревом, хотя их можно мысленно пред¬ ставить себе, как сортировку древовидных структур. Во-вторых, функция, обеспечивающая упорядоченность всего списка (между частями), является явной. Выполняются специальные сравнения между частями, чтобы выбрать наименьший элемент среди возможных из каждой части. В литературе традиционно уделялось внимание семейству сортировок, на¬ зываемому «выбор п-й степени», и в особенности квадратичному выбору. На основании порядка глав в этой книге, читателю не следует предполагать, что методы, описанные в этом разделе, являются столь же эффективными, как сортировки, у которых основные характеристики имеют порядок N log2 N. Однако до перехода к внутреннему слиянию полезно познакомиться с кон¬ цепциями и принципами, демонстрируемыми в этой главе. 8.2. Квадратичный выбор Метод квадратичного выбора получил свое название потому, что число частей, на которые разбивается список, равно корню квадратному из числа элементов в списке. Для упорядочения каждой части и сравнений между ча¬ стями используется линейный выбор. В литературе этот метод описывается в двух основных вариантах. В первом части не упорядочиваются, а периоди-
8.2. КВАДРАТИЧНЫЙ ВЫБОР 99 чески .просматривается для выбора текущего наименьшего элемента; в дру¬ гом, называемом квадратичным выбором с предварительной сортировкой, ча¬ сти полностью упорядочиваются до выполнения сравнений между частями. 8.2.1. Квадратичный выбор без предварительной сортировки: метод. Спи¬ сок разделяется на частей. Если N не является точным квадратом, то список разделяется на частей, где N' есть ближайший точный квадрат„ больший N. Каждый подсписок подлежит одному просмотру линейного вы¬ бора, который выбирает из него наименьший элемент. Каждый наименьший Часть 1 Часть 2 Часть 3 Часть 4 1. 16 'у Вспомогательный список Вывод 2. 11 3. 6 4. 4 5. 6. 7. Р. П) 10. 2 11. 12. 13. 14. 12 15. 16. 9 ;) Э П Рис. 8.1. Квадратичный выбор, разбиение на части. Выбранный элемент (или признак, представляющий его) пересылается во вспомогательный список. После того как все наименьшие элементы выбраны (и заменены в их подсписках большими фиктивными величинами), к вспомо¬ гательному списку применяется линейный выбор для выбора «наименьшего из меньших» — наименьшего элемента всего списка, который затем пересы¬ лается в список вывода. Размер списка вывода зависит от сортировки и по¬ следующего процесса так, как об этом говорилось в связи с линейным вы¬ бором. Из части, содержавшей наименьший элемент, выбирается новый наимень¬ ший, который помещается во вспомогательный список. Затем другой просмотр вспомогательного списка выбирает новый наименьший — элемент, который является вторым по величине во всем списке. Он пересылается в список вы¬ вода. Процесс продолжают, попеременно просматривая то вспомогательный список, то часть, до тех пор, пока все части не будут исчерпаны. Такое со¬ стояние наступает, когда все части посылают во вспомогательный список фиктивные величины. 8.2.2. Пример. Рассмотрим список чисел на рис. 8.1. Шестнадцать элемен¬ те образуют четыре подсписка, границами которых являются позиции 1—4, 9—12, 13—16. Вспомогательный список имеет четыре ячейки. В ячейке 1 Размещается элемент из части 1, в ячейке 2 — из части 2 и т. д. Начальный ВЬ1бор наименьших элементов из каждой части показан па рис. 8.2. Когда, пРриесс выбора, примененный к вспомогательному списку, определяет, что^ 4*
100 ГЛ. 8. СОРТИРОВКА ВЫБОРОМ ключ 1 из позиции 3 — наименьший, этот ключ пересылается в список вывода. Поскольку «победивший» элемент поступил из третьей ячейки вспомогатель- Вспомогательный список Вывод Часть I Часть 2 Часть 3 Часть 4 1. 2. 3. 4. 5. 0. 7. 8. У. 10. 11. 12. 16 И 6 Z 15 Z 13 8 10 2 Z 14 13. 14. 15. 16. 7 12 Z 9 1 - 3 Рис. 8.2. Квадратичный выбор, начальный выбор. ного списка, то теперь вновь просматривается часть 3, откуда был взят этот элемент (рис. 8.3). После серии проверок возникает состояние, изображенное на рис. 8.4. Ключ 9 только что был перемещен в список вывода, и вновь будет просма- Вывод 1. 16 Вспомогательный список 2. И 3. 6 1 4 4. Z 2 5 1 5. 15 3 I 2 I - 1 6. Z 1 1 7. 13 4 3 8. 8 9. 10 10. Z 11. Z 12. 14 13. 7 14. 12 15. Z 16. 9 Часть 1 Часть 2 Часть 3 Часть 4 Рис. 8.3. Квадратичный выбор, замещение. триваться часть 4. Этот просмотр исчерпает часть 4. С выбором ключа 10 часть 3 иссякнет, передав ключ 14, после чего с выбором ключа 11 иссякнет часть 1. На рис. 8.5 ключ 12 выбирается в список вывода. Просмотр части 4 для замены ключа 12 приведет к появлению во вспомогательном списке первой фиктивной величины. На рис. 8.6 изображен момент, когда ключ 15 пересы¬ лается во вспомогательный список. Все дальнейшие выборы из вспомогатель¬ ного списка вызовут пополнение его фиктивными величинами. Окончание сор¬
8.2. КВАДРАТИЧНЫЙ ВЫБОР 101 тировки показано на рис. 8.7. Для распознавания окончания сортировки не обязательно использовать фиктивные величины или пустые части. Для того чтобы остановить сортировку после ее окончания, достаточно подсчитать число элементов, пересланных в список вывода. В приведенном примере было бы бесполезно пытаться перестроить вспомогательный список так, чтобы избе¬ жать сравнений с фиктивными величинами. Большие элементы списка равно¬ мерно распределены среди частей, и, следовательно, список не исчерпаете* Вспомогательный список • Вывод Часть 1 Часть 2 Часть 3 Часть 4 2. 3. Z Z 1. 11 1 2 4. Z 2. 13 з ^ 1 1 1 15 3. 10 4 6. Z 4. 9- г 5 9. 10. 11. 12. 13. 14. 15. 16. Z V Z Z Z J2 Z 12 Z Z Рис. 8.4. Квадратичный выбор, исчерпывание чаете и очень быстро. Первый раз фиктивная величина используется в сравнении во вспомогательном списке при выборе ключа 13. При этом выборе выполняется одно сравнение с фиктивной величиной. Одно сравнение с фиктивной величи¬ ной происходит при выборе ключа 14, два — при выборе ключа 15, три — при выборе ключа 16. Только семь сравнений с фиктивными величинами происхо¬ дят во вспомогательном списке. Нет способа, который бы позволил избежать их и занимал меньше времени, чем занимают семь сравнений. 8.2.3. Исчерпанные части. Для распознавания исчерпанных частей можно применять разные стратегии. Одна из них состоит в том, чтобы игнорировать исчерпание. Когда подсписок исчерпан, он будет пополнять вспомогательный список фиктивными величинами. Поскольку фиктивная величина никогда не будет выбрана в качестве наименьшего элемента во вспомогательном списке, то будет выполнен только один «ненужный» просмотр исчерпанной части. Может быть выгодно выявить наличие исчерпанной части и устранить ненужные сравнения с фиктивными величинами во вспомогательном списке. Обычно первая часть посылает свои элементы в первую позицию вспомога¬ тельного списка, вторая часть — во вторую и т. д. Когда некоторая часть послала фиктивную величину, можно сократить вспомогательный список, за¬ претив обращения как к позиции с фиктивной величиной, так и к соответ¬ ствующей ей части. Использование этой процедуры позволит устранить сравнения с фиктивными величинами. Если у программиста есть основания ожидать сильную концентрацию малых элементов, что может привести к
ГЛ. 8. СОРТИРОВКА ВЫБОРОМ тому, что будет быстро исчерпано значительное число частей, ему следует изучить возможность сжатия вспомогательного списка. Часть 1 Часть 2 Часть 3 Часть 4 1. Z Вспомогательный список Вывод 2. Z 3. Z 16 1 4. Z 13 5. 15 . -> 14 6. Z 1 12 - | . 7. Z 1 1 I 8. Z 1 1 1 10 9. Z | 1 1 11 10. Z | --> 12 11. Z | 12. Z 1 13. Z 1 14. Z ] 15. Z 16. Z Рис. 8.5. Квадратичный выбор, завершение просмотров. Вспомогательный список Вывод Часть 1 Часть 2 Часть 3 Часть 4 2. Z 3. Z ! 16 £• £ ->2 15- 5. Z 3 14 1 6. Z 4 Z 1 ■ 7. Z 1 8. Z 9. Z 10. Z 11. Z 12. Z 13. Z 14. Z 15. Z 16. Z 1 11 12 13 Рис. 8.6. Квадратичный выбор, опустошение вспомогательного списка. Вспомогательный список 16 - Z Z Z Вывод 1 14 15 ► 16 Рис. 8.7. Квадратичный выбор, окончание сортировки. Например, предположим, что список из 2500 элементов разделен на 50 подсписков. Есть основания подозревать, что 15 из этих частей будут исчерпаны быстро. Все элементы из этих 15 частей, всего их 750, могут быть,.
8.2. КВАДРАТИЧНЫЙ ВЫБОР 103 скажем, среди наименьших 1200 элементов. Следовательно, после того как первые 1200 элементов будут выбраны и пересланы в список вывода, эти части будут пусты. Каждый раз при поиске во вспомогательном списке после того, как эти части исчерпаются будут тратиться 15 бесполезных сравнений. Так как этот поиск будет происходить 1300 раз, то всего будут выполне¬ ны .19 500 ненужных сравнений. Следующая процедура позволит их избе¬ жать. 1. Сравнивать с фиктивной величиной каждый раз при пересылке во вспомогательный список. Этот шаг будет выключать до 2500 дополнительных сравнений. 2. Вести подсчет исчерпанных частей. Этот шаг включает до 50 под¬ счетов. 3. Сравнить счетчик исчерпанных частей с предельным числом исчерпан¬ ных частей. Этот шаг включает до 50 проверок. 4. Перестроить вспомогательный список, чтобы изменить адреса для пере¬ сылок из части и обеспечить сплошную последовательность значений факти¬ ческих ключей. Если эта процедура требует меньше времени, чем 19 500 сравнений, то она полезна. Если нет конкретных оснований ожидать несбалансированного пополнения, то лучше не касаться всех этих тонкостей. Вместо незначитель¬ ного улучшения квадратичной сортировки, следует обратить внимание на другие методы. 8.2.4. Разделение на части. Число частей, на которое разбивается список, приблизительно равно дДу! Каждая часть и вспомогательный список будут содержать одинаковое число элементов. Это условие сводит число сравнений к минимуму. Попытка минимизировать число сравнений во вспомогательном списке, уменьшив число частей, потребовала бы дополнительных сравнений в соот¬ ветственно увеличенных частях. С другой стороны, большее количество ча¬ стей привело бы к большему числу сравнений во вспомогательном списке. Задача определения частей решается только раз, но она не проста. Про¬ цесс разделения на части досконально в литературе не обсуждался. Здесь мы объясним одну процедуру и в глубине души надеемся возбудить интерес к другим. • Процедура расчленения должна определить, является ли число элементов в списке квадратом. Если это так, то число элементов в списке и размер вспо¬ могательного списка равны числу частей. Процедура расчленения может за¬ фиксировать начальный адрес каждой части в виде указателя части, начав с начального адреса и прибавив корень квадратный из N для второй части, еШс раз прибавив ту же самую величину для третьей части и т. д. Если число элементов в списке не является квадратом, то число частей будет равно целой части квадратного корня из фактического числа элементов списка. Чтобы подсчитать число элементов в каждой части, умножим число частей на корень квадратный из следующего квадрата N'. Если это произве¬ дение | д/дл J х удр- равно N, то число элементов в каждой части равно корню квадратному из N', и все части — одинаковой длины. На рис. 8.8(a) Доказаны четыре значения N, для которых это условие выполняется.
104 ГЛ. 8. СОРТИРОВКА ВЫБОРОМ Если произведение ([ J X ) больше N, то число элементов в обычной части будет равно N' , а в последней части их будет меньше. На рис. 8.8(b) показаны четыре примера этого условия. Последняя часть, мень¬ шая остальных, не будет мешать сортировке, так как она исчерпается обыч¬ ным путем. Если она очень маленькая, то может быть поглощена предпо¬ следней частью, или можно установить границы так, чтобы перераспределить ее немногие элементы. Число элементов (АО Ближайший квадрат (ЛГ) Число частей (VF) Число элементов в части (VaT) 12 16 3 4 20 25 4 5 56 64 7 8 2450 2500 49 50 a) L VWJxVn' =N Число элементов Ближайший квадрат Число частей Число элементов в части (АО (ЛГ) (VaT) в обычной в последней 11 16 3 4 3 18 25 4 5 3 50 64 7 8 2 2402 2500 49 50 2 ь> LVwJx Va/'>w Число элементов Ближайший квадрат Число частей Число элементов в части (АО (ЛГ) (VaT) в обычной в последней 15 16 4 4 3 23 25 5 5 3 60 64 8 8 4 2470 2500 50 50 20 с) iVnix VaF<AT Рис. 8.8. Разделение на части для различных N. Аналогичная ситуация наблюдается, когда L УлГ J X меньше N. В этом случае число элементов в каждой части также равно aJ N', и остаток помещается в маленькую часть. Число частей также возрастает до VN'. На рис. 8.8 этот случай иллюстрируется на четырех примерах. 8.2.5. Число сравнений и пересылок данных. Выбор первого элемента списка вывода включает просмотр всех частей и вспомогательного списка. Если есть К частей по К' элементов в каждой, то выбор первого элемента займет — 1) + (/(— 1) сравнений. Это выражение сокращается до N— I, когда N есть точный квадрат. Для выбора каждого из остающихся N—1 элементов будет просматриваться одна часть и вспомогательный список. Про¬ смотр этой пары включает (Kf—1) + (/С—1) сравнений. Если N — точный квадрат, это равно 2д/N — 2. Парный просмотр выполняется N—1 раз, что
8.2. КВАДРАТИЧНЫЙ ВЫБОР 105 в и«гоге составляет (N — 1)(2 УЖ" — 2). Общее число сравнений для случая точного квадрата, таким образом, равно TV — 1 + (А^ — 1) (2 л/W — 2). Прак¬ тической оценкой, конечно, является 2 <yjN X N, что при N от 100 до 1000 приводит к ошибке менее чем 10%. Если N — не точный квадрат, то К и К' не равны, и последняя (непол¬ ная) часть дополняется фиктивными величинами и считается полной. Число сравнений, тем не менее, можно аппроксимировать числом N — 1 + (N — 1)Х Х(2л/Л^ “2) или, приблизительно, 2 л/N' X N. Перемещение данных в этом методе состоит из пересылки записи из списка во вспомогательный список, пересылки записи из вспомогательного списка в список вывода и перемещения ключей в процессе линейного выбора. Из-за того что запись перемещается из исходного списка в список вывода через вспомогательный, в основном будет 2N пересылок записей. Кроме того, каждая часть при каждом исчерпывании, кроме последнего, вносит во вспо¬ могательный список фиктивную запись. Следовательно, есть еще — 1 дополнительных пересылок. Всего пересылок записей будет примерно 2N + a/jV — 1 . Помимо этого, есть N заполнений фиктивными величинами н по крайней мере одна пересылка ключа в каждом процессе линейного выбора. В качестве оценки числа пересылок используйте 2N + N . 8.2.6. Вариант с признаками. Перемещение записей во вспомогательный список может быть заменено перемещением ключей. Обычно это выгодно. Ли¬ нейный выбор включает вычисление адреса при размещении фиктивной вели¬ чины в ячейку победителя. Этот адрес доступен при пересылке во вспомога¬ тельный список, который в этом случае становится обособленным каталогом текущих наименьших величин из каждой части. Примерно половина пересы¬ лок может быть сведена к перемещениям ключа и адреса или адреса. При выборе наименьшего из вспомогательного списка адрес в этом списке исполь¬ зуется для пересылки записи из исходного списка в список вывода. Если физическое упорядочение исходного списка не обязательно, то подход, ис¬ пользующий признаки, можно, конечно, обобщить так, что пересылаться в об¬ ласть вывода будут только признаки. 8.2.7. Предварительная сортировка. Подсписки квадратичного выбора мож¬ но предварительно отсортировать — упорядочить полностью до формирования вспомогательного списка или просмотра. При этом число сравнений можно сократить, применив к частям метод, более эффективный, чем линейный выбор. Из-за использования более эффективного алгоритма для частей число сравнений может уменьшиться. Число перемещений может увеличиваться из-за перемещений при упорядочении частей. При тщательном анализе сле¬ дует учитывать, что предварительная сортировка устраняет заполнение фик¬ тивными величинами, что определенное число пересылок можно свести к перемещениям признаков и т. д. В комбинированной сортировке такого типа можно использовать любое сочетание алгоритмов. Идея предварительной сортировки подсписков и выбо- Ра малых элементов из вершины является основным принципом слияния1 ко¬ торое описано в следующей главе.
106 ГЛ. 9. ВНУТРЕННЕЕ СЛИЯНИЕ 8.3. Выбор больших степеней Можно организовать список в структуры более высокого порядка, чтобы использовать кубический выбор или выбор п-й степени с предварительной сортировкой или без нее. Используемые при этом принципы те же, но меха¬ низмы становятся намного сложнее. На рис. 8.9(a) показана сортировка вто¬ рой, третьей, четвертой, пятой и шестой степени для разных N. На рис. 8,9 (Ь) показано, как для файлов одинаковой длины различные сортировки влияют- Степень iP) N 2 16 3 27 4 16 5 1024 6 4096 a) Сортировка списков различной длины степени не выше 6. 2 65536 256 256 1 1 X X X X 4 65536 16 4096 3 256 16 1 X X b) Сортировка списка из 65 536 элементов двух разных степеней. Рис. 8.9. Организация сортировок различных высоких степеней. на процесс упорядочения. Если эти сортировки представить в виде деревьев,, то корневым узлом каждого дерева является ячейка области вывода, конце¬ выми узлами — исходный список, а промежуточными уровнями узлов — вспо¬ могательные списки. Глава 9. ВНУТРЕННЕЕ СЛИЯНИЕ 9.1. Введение: основной процесс слияния Основой процесса слияния является фундаментальная идея упорядочения данных путем чередобания элементов из двух или более упорядоченных спи¬ сков. На рис. 9.1 показаны две упорядоченные части списка из десяти эле¬ ментов. Упорядоченное объединение этих частей представляет собой оконча¬ тельный упорядоченный список из десяти элементов. Процесс достижения этого упорядочения называется двухпоточным *) слиянием — «двухпоточным», потому что есть два входных списка. Последовательность сравнений показана на рис. 9.1, упорядоченный список дан в виде исходных позиций элементов. Поле памяти, необходимое для данных, включает, помимо поля для S1 и S2, поле для списка вывода. Последовательность сравнений на рис. 9.1 показывает, что сравниваются наименьшие элементы каждой части и меньший из них продвигается в список *) В отечественной литературе также используется термин «двухпутевое слияние». (Прим. перев.) Число Число уровней элемен- Число (вспомога- тов частей тельных в части в списке списков) 4 4 1 3 9 2 2 8 3 4 256 4 4 1024 5 Число вспомогательных епископ на каждом уровне _____ Уро- Уро- Уро- Уро- Уро¬ вень I вень 2 вень 3 вень 4 веиь 5 1 X X X ..X 3 1 X X X 4 2 1 X X 64 16 4 1 X 256 64 16 4 1
9.2. МНОГОПРОСМОТРОВОЕ ДВУХПОТОЧНОЕ СЛИЯНИЕ 107 вывода. Процесс сравнения элементов, продвижения меньшего в список вы¬ вода и выбор преемника в «победившей» части продолжается до тех пор, пока не исчерпывается одна из частей. После того как одна часть исчерпана, все оставшиеся элементы другой пересылаются в список вывода. Ситуацию, когда часть исчерпана, можно распознать различными спосо¬ бами. Способ распознавания использует некоторые важные характеристики Позиция Ключ Ввыод 1 1 1 (S1. 1) 2 2 2 (S1, 2) 3 5 3 (S2, 1) 4 7 4 (S2, 2) 5 8 5 (S1, 3) 6 (S2, 3) 1 3 7 (S1, 4) 2 4 8 (S1, 5) 3 6 9 (S2. 4) 4 9 10 (S2, 5) 5 10 Последовательность сравнений Позиции Ключи Пересылки Sl.l ; S2.1 (1 : 3) Sl.l Вывод 1 S 1,2 : S2.1 (2:3) SI,2 Вывод 2 Sl,3 : S2,1 (5:3) S2,1 Вывод 3 Sl,3 ; S2,2 (5:4) S2,2 Вывод 4 S1.3 : S2,3 (5: 6) Sl,3 Вывод 5 SI,4 : S2.3 (7:6) S2,3 Вывод 6 SI,4 : S2,4 (7:9) Sl,4 Вывод 7 SI,5 : S2,4 (8:9) SI,5 Вывод 8 — S2,4 Вывод 9 — S2.5 Вывод 10 S = qacTb Рис. 9.1. Слияние. алгоритма слияния. Если размер каждой части известен (или предварительно определен), то обнаружить, что часть исчерпана, можно любым приемом цик¬ лической проверки или подсчетом элементов. Процесс слияния, в котором каждая часть имеет фиксированную длину, называется прямым слиянием. Существует другой вариант, называемый естественным слиянием, в котором размер части не фиксирован, а распознавание того, что часть исчерпана, основано на анализе характеристик данных. Первым мы будем обсуждать прямое слияние, затем естественное. Читатель заметит сходство между этими двумя типами слияния и квадратичным выбором с предварительной сорти¬ ровкой. 9.2. Многопросмотровое двухпоточное прямое слияние В последующих разделах мы рассмотрим прямое двухпоточное слияние, опишем перемещение строк и производительность. 9.2.1. Организация начала слияния. На рис. 9.1 показано прямое двухпо- точное слияние из одного просмотра. Обычно слияние имеет несколько про¬
108 ГЛ. 9. ВНУТРЕННЕЕ СЛИЯНИЕ смотров. Идея слияния подразумевает многопросмотровый процесс, в котором при последовательных просмотрах части становятся все больше и больше до тех пор, пока заключительный просмотр не создаст часть, содержащую все элементы сортируемого списка. Необходимое для этого число просмотров за¬ висит от числа исходных частей и степени слияния. Длина исходной части может быть равна 1. На рис. 9.2 показан список из 16 элементов. Процесс слияния начинается с 16 частями, каждая длиной I. Области Области Номер Источ- Список вывода Источник Список вывода строки ник А 1. 3 3 1 U 2 А 1. 3 С 3 21 1 и 9 В 2. 15 15 2. 15 13 А 3. 12 11 3 U 4 3. 12 8 23 з и и В 4. 11 12 4. И 12 А б. 6 4 5 U 6 5. 6 2 25 5 U 13 В 6. 4 6 6. 4 6 А 7. 16 5 7 U 8 7. 16 14 27 7 U 15 В 8. 5 16 8. 5 16 А 9. 13 7 9 U Ю В 9. 13 D 7 22 2 (J Ю В 10. 7 13 10. 7 15 А 11. 8 8 11 U 12 11. 8 10 24 4 U 1* В 12. 10 10 12. 10 11 А 13. 2 1 13 U 14 13. 2 1 26 6 U 14 В 14. 1 2 14. 1 4 А 15. 14 9 15 U 16 15. 15 5 28 8 U Ю В 16. 9 14 16. 9 9 Рис. 9.2. Слияние, первый просмотр. Рис. 9.3. Слияние, формирование строк. На первом просмотре 16 исходных частей сливаются в восемь частей по два элемента в каждой, используя двухпоточное слияние. Существует множество способов объединения частей при слиянии. На рис. 9.2 сливаются части 1 и 2, 3 и 4, 5 и 6 и т. д. Иначе, начальный список можно было разбить на два подсписка: один — первая половина списка, дру¬ гой— вторая. На рис. 9.3 показаны подсписок А, состоящий из одноэлемент¬ ных частей с 1 по 8, и подсписок J3, состоящий из одноэлементных частей с9‘ по 16. В результате от слияния частей 1 и 9, 2 и 10, 3 и 11 и т. д. полу¬ чаются восемь частей. Обычно для обозначения упорядоченной части списка используют термин; строка. Строка — это набор элементов, о котором известно, что он упорядо¬ чен. На рис. 9.3 в областях С и D находятся по четыре строки, каждая из двух элементов. 9.2.2. Распределение строк. На рис. 9.3 при втором сравнении меж¬ ду Л и В сливаются элементы 2 и 10, и результат размещается в первых двух позициях второй половины области вывода, называемой областью D. Причины такого размещения объясняются свойством способа слияния, из¬ вестного как распределение. На рис. 9.3 область вывода разделена на две половины С и D точно так же, как входная область разделена на половины А и В. Эффективность слия¬ ния всегда выше тогда, когда в каждом входном подсписке число строк одно и то же. Это может быть достигнуто при помощи приема, называемого сбалансированным распределением, при котором одна слитая строка разме-
9.2. МНОГОПРОСМОТРОВОЕ ДВУХПОТОЧНОЕ СЛИЯНИЕ 109 щается в одном подсписке вывода, а ее преемница — в другом. В двухпоточ¬ ном слиянии эта процедура эквивалентна чередованию между областями вы- вода. На рис. 9.3 в силу чередования строки 21, 23, 25 и 27 находятся в С, Ввод Вывод Номер Номер Область строки Строка Область строки Строка Источник 21 3 А 31 3 21 U 22 13 7 23 8 13 12 15 25 2 33 1 25 U 6 2' 27 14 4 16 6 22 7 В 32 8 23 U 24 15 10 24 10 11 11 12 26 1 34 5 27 U 28 4 9 28 5 14 9 16 Рис. 9.4. Слияние, просмотр 2. а 22, 24, 26 и 28 — в D. (Обозначение строки состоит из двух цифр: первая — номер просмотра, на котором эта строка будет входной, — в данном случае просмотр 2, а вторая — порядковый номер их формирования.) Рассредоточе¬ ны вод Область Ввод Номер строки 31 33 32 34 Строка 3 7 13 15 1 2 4 6 8 10 11 12 5 9 14 16 Область Номер строки 42 Строка 3 7 8 10 11 12 13 15 1 2 4 5 6 9 14 16 Источник 31 U 32 33 U 31 Рис. 9.5. Просмотр 3. ние строк при фиксированном двухпоточном слиянии нередко является очень простым. При слиянии в общем случае алгоритм рассредоточения строк часто очень непрост и может существенно влиять на производительность слияния. 9.2.3. Последовательные просмотры. На рис. 9.3 при просмотре 1 число отрок сократилось с 16 до 8, а длина строк увеличилась с 1 до 2. Строки
110 ГЛ. 9. ВНУТРЕННЕЕ СЛИЯНИЕ находятся в областях С и D. На следующем просмотре будут сливаться С л D, используя А и В в качестве областей вывода. Первыми при просмотре 2 будут сливаться в А строки 21 и 22 в виде строки 31. Следующее слияние будет в В в форме строки 32. Просмотр за¬ кончится, когда все строки из С и D будут слиты. На рис. 9.4 показано положение в конце второго просмотра — четыре строки, каждая длиной 4. На просмотре 3 сливаются 31 и 32 в 41, 33 и 34 в 42. Длина каждой строки — восемь элементов, и есть всего две строки — одна в С и одна в О. Область Номер строки Строка Окончательный вывод Источник С 41 3 1 7 2 8 3 10 4 11 5 12 6 41 U 42 13 7 15 8 D 42 1 9 2 10 4 11 5 12 6 13 9 14 14 15 16 16 Рис. 9.6 Последний просмотр. Это — условие «последнего просмотра»: одна строка в каждой области. Сле¬ довательно, один единственный просмотр слияния сформирует одну упоря¬ доченную строку. Просмотр 3 и заключительный просмотр — просмотр 4 -- показаны на рис. 9.5 и 9.6 соответственно. 9.2.4. Вариант с меньшей памятью. Выполняя начальные слияния так, как показано на рис. 9.2, а не как на рис. 9.3, можно сократить необходимый размер дополнительной памяти для прямого двухпоточного слияния до об¬ ласти в половину длины исходного списка. То есть, сливая в основном смеж¬ ные элементы, можно сберечь память. На рис. 9.2 при слиянии строки 7 со строкой 8 верхняя половина началь¬ ной входной области фактически свободна. Слитые строки, начиная с 9 U Ю, можно разместить в этой области. Окончание первого просмотра показано на рис. 9.7. Второй просмотр можно продолжить, сливая 25, 26, 27 и 28 в свободной памяти. Память, освободившаяся за счет этих строк, используется для слияния 21 и 22, 23 и 24. Сокращение памяти достигается путем такой перестройки двух подсписков, при которой они не пересекаются и чередуются, как показано на рис. 9.2, где элементы с четными номерами считаются эле¬ ментами А, а элементы с нечетными номерами — элементами В. 9.2.5. Число просмотров, сравнений, перемещений. Число двухпоточных просмотров, необходимых для формирования из 5 строк одной строки, равно flog251 . В примере с 16 начальными строками, чтобы выполнить слияние, необходимо log2 16 = 4 просмотрев. Если N с самого начала равно S, то число просмотров можно положить равным f'log2/V"| •
9.2. МНОГОПРОСМОТРОВОЕ ДВУХПОТОЧНОЕ СЛИЯНИЕ 1Ц Число просмотров можно уменьшить, сократив число начальных строк* т. е. сделав 5 меньше N. Так поступают в некоторых эффективных методах Номер строки 25 26 27 28 Строка Номер строки Строка Снободны < 7 13 8 10 1 2 9 14 22 23 24 3 15 11 12 4 6 5 16 Рис. 9.7. Вариант слияния, использующий объем памяти, равный l,5Af. сортирозки отдельных частей или в алгоритме определения строк, похожем на тот, который будет описан в разделе 9.3.1. Уменьшение числа просмотров приводит к уменьшению числа сравнений в операции слияния. Число сравнений для прямого двухпоточного слияния в Максимальное Число Максимальное Число Длина число сравнений двухпоточных число строк строки за слияние слияний сравнений Просмотр 6 2 32 63 1 63 (последний) Просмотр 5 4 10 31 2 62 Просмотр 4 8 8 15 4 6J Просмотр 3 16 4 7 8 56 Просмотр 2 32 2 3 16 48 Просмотр 1 64 1 1 32 32 321 S = N = 64 N12 = 32 logs N = 6 log 2 (yV/2) = 5 N log2 N = 384 N log2 (7V/2) = 320 Рис. 9.8. Максимальное число сравнений за просмотр ДЛЯ 64-элемептного списка. литературе часто дается в виде N flog2An . Эта формула означает следую¬ щее: есть log2 N просмотров и в течение каждого просмотра каждый элемент, который присоединяется к формируемой строке, используется при сравнении. На каждом просмотре есть N перемещений, но не будет N сравнений. N [*log2 N"| , таким образом, представляет собой недостижимую верхнюю гра¬ ницу для числа сравнений. В общем случае при любом прямом двухпоточном слиянии, использующем строки равной длины, будет, самое большее, N — 21’ сравнений на просмотр,, где i—индекс просмотра, равный log2 N— Р, где Р — номер просмотра. За¬ метим, что i равно 0 для последнего просмотра и увеличивается с шагом 1 Для каждого предыдущего просмотра. На рис. 9.8 показан случай максималь-
112 ГЛ. 9. ВНУТРЕННЕЕ СЛИЯНИЕ ного количества сравнений на каждом просмотре для списка из 64 элементов. На последнем просмотре там выполняется N — 2° = 64 — 1 = 63 сравнения; на пятом просмотре — N — 21 = 62 сравнения и на остальных просмотрах /V — 22 = 60, N — 23 = 56, N — 24 = 48, N — 25 = 32. Рис. 9.8 показывает, что максимальное число сравнений не равно N flog2AC] = 384, но близко к нему. В качестве оценки числа сравнений при слиянии формула N flog2An приемлема и безопасна, если слияние начинается со строк длины 1. Если слияние начинается с более длинных строк, получить оценку числа сравне¬ ний несколько сложнее. Надо найти n°g2*Sl (числа строк), которое соответствует числу просмотров, и получить сумму сравнений по всем про¬ смотрам. В [30] показано, что наихудший случай числа сравнений в двухпоточном слиянии и теоретический минимум для сортировки N чисел разнятся очень незначительно. Например, для 100 элементов данных наихудший случай при двухпоточном слиянии равен 8967, а теоретический минимум — 8520. Таким образом, использование для числа сравнений формулы N flog2A^l оправдано. 9.3. Естественное двухпоточное слияние В последующих подразделах мы рассмотрим организацию естественного двухпоточного слияния, опишем перемещение строк и производительность. 9.3.1. Выявление и описание строк. Естественное (или неймановское) слияние отличается от прямого слияния тем, что оно пытается воспользовать¬ ся строками, которые уже есть в данных. Список на рис. 9.9 состоит из десяти начальных строк длины 1, 2 и 3. В таблице описания строк указаны их номера, начала и длины. Метод выявления строк выполняется на началь¬ ном просмотре данных, сравнивает каждый элемент с его преемником, вы¬ являет провалы (преемник меньше предшественника) и строит таблицу опи¬ сания строк вроде показанной на рис. 9.9. Этот процесс включает (N — 1) сравнений и создание таблицы описаний. Никаких перемещений входных данных не выполняется. Первый просмотр слияния заменяется этим процес¬ сом выявления строк. На последовательных просмотрах слияния адреса сравниваемых элементов обеспечивает таблица описания строки, которая также задает границы и длину строки. На рис. 9.10 просмотр описания строк выполняется иначе. Строки дли¬ ной 2 строятся группировкой в пары соседних элементов как в прямом, так и в обратном направлении. Те строки, у которых первый элемент меньше, яв¬ ляются D-строками, а остальные — А-строками *). Этот просмотр выявления строк является подготовительным для прямого слияния. Строки длины 2 строятся до слияния при помощи N/2 сравнений и N/2 обращений к таблице описания строк. Сравнение рис. 9.9 и 9.10 моментально показывает разницу между есте¬ ственным и двухпоточным слияниями. При естественном влиянии длину на¬ чальных строк можно определить, но не предсказать. Следовательно, зная *) От «descending» (англ.)—убывающий и «ascending» (англ.)—возра¬ стающий. (Прим. перев.)
9.3. ЕСТЕСТВЕННОЕ ДВУХПОТОЧНОЕ СЛИЯНИЕ ИЗ исходные данные, нельзя точно предсказать ни число строк, ни число про¬ смотров. На рис. 9.11, 9.12 и 9.13 показан процесс возможного слияния строк, изображенных на рис. 9.9. Заметим, что новые строки заполнярэт область 1. 2*. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. Список •} 10 ) 2 } S8L1 S9L2 1 14 9 Таблица описания строк > S10LI S= строка L=длина SlL2=cTpoKa 1 длины 2 Рис. 9.9. Описание естественных строк. SIL2 Номер Начало Длина 1 1 2 S2L1 2 3 1 S3LI 3 4 1 S4L1 4 5 1 S5L2 5 6 2 6 8 . 2 S6L2 7 10 3 8 13 1 9 14 2 S7L3 10 16 1 слияния с обоих концов. Таблица описания строк позволяет предсказать длину новых строк и размер области, которую они будут занимать. Алгоритм 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. Список 3 15 Таблица описания строк }А :?}■> ч}° '?}■> л* “}■> Рис. 9.10. Описание A-строк и D-строк. А 1 1 D 4 D 1 • D 8 D 10 А 1 " D 1 14 D 1 16 распределения строк строится по таблице описаний. Пространство памяти, необходимое для обычного слияния, такое же, как и для прямого слияния. 9.3.2. Естественное слияние без определения строк. Естественное слияние не обязательно опирается на таблицу списания строк или просмотр, опреде¬ ляющий строки. Рассмотрим процесс, который с самого начала выполняет
114 ГЛ. 9. ВНУТРЕННЕЕ СЛИЯНИЕ Вход Номер Область (с рис. 9.9) Область Позиция Выход строки Источник Длин 10 2 1 14 9 S = строк а Ь = длина } } 0 ) } } S1L2 С 1. 2. 3 5 21 si и S6 4 S2L1 3. 13 S3L1 4. 15 S4L1 5. 2 23 S3 и S8 2 S5L2 6. 7. 11 4 25 S5 U S10 3 S6L2 8. 9. 9 16 D 10. 1 24 S4 U S9 8 S7L3 11. 12. 6 14 S8L1 13. 7 22 S2 U S7 4 S9L2 14. 15. 8 10 S10L1 16. 12 Таблица описания строк Номер Начало Длина 21 1 4 22 13 4 23 5 2 24 10 3 25 7 3 Рис. 9.11. Естественное слияние с определением строк, просмотр I. Область Вход строки Позиция Выход строки Источник Длина C/D 3 21 1. 3 31 21 U 22 8 Номер Номер Вход строки Позиция Выход строки 3 21 1. 3 31 5 2. 5 13 3. 7 15 4. 8 2 23 5. 10 11 6. 12 4 25 7. 13 9 8. 15 16 9. 4 33 1 24 10. 9 6 11. 16 14 12. 1 32 7 22 13. 2 8 14. 6 10 15. 11 12 16. 14 Таблица описания строк Номер Начало Длина 31 1 8 32 12 5 33 9 3 25 23 U 24 Рис. 9.12. Естественное слияние с определением строк, просмотр 2.
9.3. ЕСТЕСТВЕННОЕ ДВУХПОТОЧНОЕ СЛИЯНИЕ 115 слияние без описания строк в списке, изображенном на рис. 9.14. Определим начало всего списка как первую позицию А, а последнюю ячейку списка как Вход для просмотра 3 3 5 7 8 10 12 13 15 4 9 16 1 2 6 11 14 Номер строки 33 32 Просмотр 3: Просмотр 4: Позиция Выход просмотра 3 — вход просмотра 4 Номер Выход строки просмотра 4 1. 1 41 1 2. 2 2 3. 3 3 4. 5 4 5. 6 5 6. 7 6 7. 8 7 8. 10 8 9. 11 9 10. 12 10 11. 13 И 12. 14 12 13. 15 13 14. 4 42 14 15. 9 15 16. 16 16 Таблица описания строк Номер Начало Длина 41 42 1 14 1 13 3 16 окончательный Рис. 9.13. Естественное слияние с определением строк, просмотры 3 и 4 первую позицию В. Это деление фактически разбивает список на два подспи¬ ска с неопределенным числом строк. Разделять именно так для того, чтобы зицня Вход Указатели Выход Номер строки 1. 3 <-А 3 21 2. 15 9 3. 12 <-А' 14 4. 11 15 5. 6 8 23 6. 4 11 7. 16 4 25 8. 5 5 9. 13 16 10. 7 13 24 11. 8 7 12. 10 6 13. 2 12 22 14. 1 <-В' 10 15. 14 2 16. 9 <-В 1 Рис. 9.14. Естественное слияние без определения строк, просмотр 1. избежать просмотра, определяющего строки, не обязательно, но это быстрый и разумный способ создать два входа для слияния. Этот способ используется в алгоритме 207 STRINGSORT («сортировка строк»)—обычном двухпоточ¬ ном слиянии, приведенном в Приложении А.
116 ГЛ. 9. ВНУТРЕННЕЕ СЛИЯНИЕ Процесс, показанный на рис. 9.14, опирается на понятие одиночного и двойного «провала». Элементы из А и В сравниваются при помощи соответ¬ ствующим образом продвигаемых указателей А и В и пересылаются в список вывода. Когда элемент из А меньше, он всегда пересылается в список вывода, а указатель передвигается. В списке вывода на рис. 9.14 в качестве четырех первых элементов новой строки показаны элементы 3, 9, 14, 15. Когда эти элементы попадают в спи¬ сок вывода, указатель А находится у позиции 3 (ключ 12). Указатель В на¬ ходится у позиции 14 (ключ 1). Но ми ключ 1, ни ключ 12 не могут попасть в строку, последним элементом которой является ключ 15, поскольку, чтобы попасть в строку, ключ должен быть не только меньшим из двух конкури¬ рующих элементов, но и большим самого последнего элемента строки. Таким образом, каждый попадающий в строку элемент должен при просмотре про¬ веряться дважды: первый раз определяется, что этот элемент меньше допу¬ стимого элемента в другом подсписке, и второй раз — что он не меньше по = следнего элемента строки. Если обнаружено, что элемент меньше последнего элемента строки, гово¬ рят, что выполнено условие провала. Условие провала вызывает переход всех элементов в другой подсписок до тех пор, пока снова не будет обнаружен провал. Когда это случается, выполняется условие двойного провала. Условие двойного провала означает, что не может быть добавлений в текущую строку, так как нет подходящих кандидатов. Слияние на рис. 9.14 помещает вторую строку (22) в конце области вы¬ вода. Эта строка строится не вниз от некоторой точки, вычисленной по таб¬ лице описания строк, а вверх от последней позиции. В ячейках с 16 по 13 области вывода находится строка длины 4, значения ключей которой возра¬ стают от ячейки 16. Это самый простой способ размещения строки, длина которой неизвестна. Для последующих просмотров алгоритма простого слия¬ ния возрастающие строки размещаются с головы списка, а убывающие (воз¬ растающие снизу вверх)—с хвоста. 9.3.3. Число просмотров, перемещений, сравнений. Цель естественного сли¬ яния— исключить лишние просмотры. Так поступают, поскольку не исключено, что во входных данных есть длинные естественные строки. В результате вы¬ явления этих естественных строк возможно сокращение просмотров данных по сравнению с методом, в котором последовательность длин строк фикси¬ руется без учета естественного упорядочения. При случайных данных можно сэкономить один просмотр. Ожидаемое число просмотров при естественном слиянии, таким образом, равно Г loga А71 — 1. Однако при данных с очень длинными естественными стро¬ ками будет значительно меньше просмотров. Без таблицы описания строк при естественном слиянии число сравнений ключей увеличивается, поскольку необходимо сравнивать с концом текущей строки. Это сравнение заменяет используемую при прямом слиянии проверку, не является ли конец строки границей. Сравнение ключей может оказаться существенно дороже, чем проверка границ. Некоторые авторы приписывают естественному слиянию 2 flog2(Af—1)1 сравнений из-за дополнительной про¬
9.4. ДАЛЬНЕЙШЕЕ ОБСУЖДЕНИЕ СЛИЯНИЯ 117 верки данных для входа в строку вывода. Это недостижимая верхняя гра¬ ница. Будет (приблизительно) N P°g2(W—1)1 сравнений при входе в строку, поскольку каждый элемент будет столько раз проверяться при каждом про¬ смотре. Однако число сравнений естественных элементов не возрастает, так что это число для худшего случая равно N pog2(N—1)1 + N pog2(W/2) —11 , если один просмотр экономится, и N pog2Wl -{- N f log2 (jV/2) 1 , если про¬ смотр не экономится. При прямом слиянии будет примерно N f log2 /V1 проверок конца строки. При любом определении предпочтительности одного подхода • перед другим решающим фактором является наличие на машине механизма, который обес¬ печивает более эффективную проверку конца строки, чем выявление провалов. Для внутреннего слияния преимущество естественного слияния перед пря¬ мым все-таки кажется надежным. При реализации эти способы равноценны; без какого бы то ни было конкретного анализа «рабочей длины» программист может выбирать любой из них, тщательно изучив, делают ли временные ха¬ рактеристики и всевозможные затраты, присущие его машине, какой-либо ме¬ тод процедурно быстрее. 9.4. Дальнейшее обсуждение слияния В следующих подразделах рассматриваются некоторые соображения, ко¬ торые еще не обсуждались. 9.4.1. Сортировка ключ-признак. Слияние обеспечивает идеальный случай для использования методов сортировки ключей. Область дополнительной па¬ мяти можно уменьшить до размеров, необходимых под ключи и адреса (или только адреса), а перемещение данных можно существенно сократить до вре¬ мени перемещения адреса или признака. Существует бесчисленное множество способов кодировки и подходов к реализации слияния как в форме записей, так и в форме признаков или адресов. Структуры, подобные таблице описа¬ ния строк, можно создавать для проведения слияния как в форме признаков, так и в форме записей. 9.4.2. Многопоточное слияние. Возможны слияния степени выше второй. Со списком из 16 элементов возможно трехпоточное, четырехпоточное слия¬ ние или слияние любой другой степени не выше 16. Эти слияния могут быть прямыми или естественными, с предварительной сортировкой или специализи¬ рованным первым просмотром определения строк или без них. На рис. 9.15 показано прямое четырехпоточное слияние для списка из 16 элементов. В область вывода (которая не обязательно больше, чем для Двухпоточного слияния) помещаются строки, сформированные четырехпоточ¬ ным слиянием из исходных одноэлементных строк входного списка. Слияние четырех строк, выполненное на первом просмотре, формирует одну упоря¬ доченную строку. Весь список, таким образом, упорядочивается за два про¬ смотра, использующих четырехпоточное слияние. Количество просмотров, необходимых для упорядочения списка, при ис¬ пользовании прямого М-поточного слияния равно pogM ЛП , если предпо¬ ложить, что первоначальная длина всех строк равна 1. Логарифм 16 по осно¬
118 ГЛ. 9. внутреннее слияние ванию 4 равен 2. Сокращение количества просмотров важно, поскольку оно в свою очередь сокращает количество перемещений данных до N fIog,wW| (часть которых может быть только перемещениями адресов или ключей). Сложности при использовании слияния больших степеней возникают из-за того, что команды сравнения на вычислительных машинах сравнивают за один раз по два элемента. Если же есть устройство, которое бы могло вы¬ полнять быстро М-поточные сравнения, то для М-поточного слияния потребо¬ валось бы столько же операций «сравнения», сколько и для двухпоточного, а использование М-поточного слияния было бы, несомненно, заманчивым. Хотя 13ИЦИЯ Вход Выход Номер строки 1. 3 3 21 2. 15 И 3. 12 12 4. 11 15 5. 6 4 22 6. 4 5 7. 16 6 8. 5 16 9. 13 7 23 10. 7 8 11. 8 10 12. 10 13 13. 2 1 24 14. 1 2 15. 14 14 16. 19 19 Рис. 9.15. Четырехпоточное слияние. Вход из 16 строк длиной 1; выход из четырех строк длиной 4. предлагались различные механизмы М-поточного сравнения, и М-поточное слияние, использующее такие устройства, было (причудливо) описано в лите¬ ратуре, таких устройств на самом деле нет, а реализация М-поточных слия¬ ний в основной памяти наталкивается на необходимость дополнительных ме¬ ханизмов управления программами для выполнения М-поточного сравнения. Под ними подразумеваются не только команды сравнения, но и организация подпрограмм для определения и построения таких циклов сравнений. Чтобы выбрать один наименьший элемент при М-поточном слиянии, нужно М — 1 сравнений. Максимальное число сравнений при М-поточном слиянии равно N (М — 1) Г logM/V“|. Способ, используемый для выполнения М-поточного слияния, не всегда столь же прост, как и М—1-поточный способ. В слияниях очень высоких степеней иногда бывает выгодно использовать какую-нибудь форму турнир¬ ной сортировки или любой другой эффективный метод для выбора следую¬ щего элемента формируемой строки. Ограничение на порядок слияния должно быть таким, чтобы сложность организации М-поточного слияния не превосхо¬ дила выигрыша при сокращении перемещения данных. 9.| 3. Оптимальная степень слияния, При слиянии любой степени от про¬ смотра к просмотру можно менять степень слияния из-за несбалансирован¬ ности рассредоточения строк или исчерпания подсписков. На рис. 9.16 опти¬
9.4. ДАЛЬНЕЙШЕЕ ОБСУЖДЕНИЕ СЛИЯНИЯ 119 мальная степень этого трехпоточного слияния действительно равна 3. Каж¬ дый просмотр сокращает число строк в 3 раза. Однако оптимальная степень слияния действительно равна фактической только тогда, когда исходное чис¬ ло элементов (или строк) в точности равно степени «поточности» слияния* Области: А В С D Е_ F_ Число строк 0(1) 9(1) 9(1) — - - 27 Просмотр 1 - - - 3(3) 3(3) 3 (3) 9 Просмотр 2 1 (9) 1 (9) 1(9) — - - 3 Просмотр 3 - - 1 (27) - - 1 Рис. 9.16. Совершенное слияние. Число перед скобками указывает количество строк в области; число строк в скобках указывает длину строк. Сначала все строки длины 1 (log3 27 = 3). На рис. 9.17 оптимальная степень слияния не равна 2. Возникают несбаланси¬ рованные случаи, и уменьшение строк от просмотра к просмотру не пропор¬ ционально степени слияния. Когда используется естественное слияние, а длины строк очень сильно изменяются, трудно оценить, какова же в действительности оптимальная сте¬ пень слияния. 9.4.4. Частичные просмотры. В тех слияниях, где отсутствовало равнове¬ сие, всюду до сих пор мы предполагали, что из одной области в другую пересылался экземпляр дополнительной строки. Можно организовать слияние так, чтобы это копирование выполнялось не всегда. Во внутреннем слиянии Обла сти А В С D Число строк Просмотр 1 6(1) 6(1) 3(2) 3(2) 12 6 Просмотр 2 2(4) 1(4) - - 3 Просмотр 3 - - 1 (8) 1 (4) 2 Просмотр 4 1 (2) - - - 1 Рис. 9.17. Несовершенное слияние (| log3 12 ) = 4). это сделать нетрудно. Альтернативой копированию является частичный про¬ смотр, где понятие «просмотра» ослаблено, и сортировка переходит не от просмотра к просмотру, а от этапа к этапу. Различие заключается в том, анализируется или нет весь список до начала нового просмотра (или этапа). Вернемся к рис. 9.12. Строка 33 — копия строки 25, которая создается в конце просмотра 2 и освобождает область С/D. Однако при других стратегиях управления памятью копировать эту строку было бы не обязательно. Ее можно было бы оставить там, где она есть, совсем не изменив характер по¬ следующих слияний. Поскольку она в равной степени доступна из любой позиции, ее перемещать абсолютно незачем. При этом слияния на рис. 9.1, п° правде говоря, не образуют просмотра, так как обрабатываются не все Данные. Частичный просмотр или этап завершен, и следующий начинается с состояния, изображенного на рис. 9.13, с той лишь разницей, что последо* пательность 4, 9, 16 расположена в другом месте. Принцип частичного просмотра можно использовать другим способом, ра¬ ботая с большим числом данных, чем те, что составляют просмотр. Напри- МсР, оставшаяся строка может быть слита со строкой, сформированной на
120 ГЛ. 9. ВНУТРЕННЕЕ СЛИЯНИЕ данном этапе. Теперь сами понятия просмотра и степени слияния становятся расплывчатыми. Четкий образ слияния, который был до этого, стал несколько размытым. Разработчик слияния вовсе не обязан жестко ограничивать каким- либо образом определение «просмотра» слияния; он волен по желанию изме¬ нять степень слияния от этапа к этапу и выбирать строки для слияния на любой удобной ему основе. Конструирование слияний очень гибко, даже если понятие «просмотра» жестко ограничить. 9.4.5. Дерево слияния. Дальнейшее обсуждение конструкции слияния тре¬ бует понятия дерева. О существовании таких деревьев, как на рис. 9.18, упо- / / / / 1 1 1 1 / / / / / / / / Рис. 9.19. Дерево прямого двухпоточного слияния из 16 элементов. миналось ранее. Это правильные деревья, несмотря на то, что число потом¬ ков, соответствующих одному узлу, может меняться. Бердж [4] дал интер¬ претацию деревьям, которой мы и будем следовать. В этом разделе мы сосре¬ доточим внимание на оптимизации перемещения данных, поскольку на каж¬ дое сравнение приходится одно перемещение (при сортировке записей). Читатель увидит, что любой способ оптимизации перемещения данных также оптимизирует и число сравнений. / 2 Рис. 9.18. Типы деревьев. Уровень
9.4. ДАЛЬНЕЙШЕЕ ОБСУЖДЕНИЕ СЛИЯНИЯ 121 Слияние можно представить в виде дерева, у которого старший узел со¬ ответствует строке, образованной слиянием его потомков. На рис. 9.19 изо¬ бражено дерево прямого двухпоточного слияния из 16 элементов. Число у каждого узла — это длина строки, соответствующей этому узлу. Каждый уровень на рис. 9.19 представляет один просмотр классического многопрссмот- рового внутреннего слияния. Вспомним понятие объема дерева из главы 4. Уровни дерева рис. 9.19 перенумерованы от 0 до 4, начиная с корневого узла, так же, как ранее мы нумеровали уровни двоичных деревьев. Здесь в качестве значения узла мы Уровень Рис. 9.20. Дерево трехпоточного слияния из 16 элементов. будем использовать длину строки, соответствующей этому узлу. Самый высо¬ кий уровень на рис. 9.19 — уровень 4. Номер наивысшего уровня равен числу просмотров, log2 N или log2 N' (N' — ближайшая большая степень 2). На рис. 9.19 изображено 16 концевых узлов со значением 1. Сумма этих значений на уровне 4 равна 16. Эта сумма набирается из длин строк, с которых начи¬ нается слияние на уровне 4. Произведение номера уровня (числа просмотров) на значение узлов (длину строк, участвующих в слиянии при просмотре, представленном номером уровня) равно числу перемещений элементов при этом слиянии. В виде формулы — N \og2 N или 16 X 4 = 64. Дерево дает нам графический эквивалент уравнения. На рис. 9.20 то же самое изображено для случая трехпоточного слияния. Есть 4 уровня, наивысший уровень — 3; f log3 16*] = log3 27 = 3. На уров¬ не 3 сливается 15 строк. Сумма их длин равна 15. Одна строка длины 1 ис¬ пользуется при слиянии на уровне 2. Всего перемещений строк будет ЗХ 15 + 2Х 1 =47. В этом случае Afflog3/V"| равно 16X3 = 48. Разница возникла в связи с исключением перемещения шестнадцатой строки путем задержки ее входа в слияние до второго уровня. В общем случае произведение номера уровня на Длину строк, входящих в слияние на этом уровне, равно сумме перемещений строк и является «объемом» дерева в этой интерпретации. 9.4.6. Оптимальные слияния. Пусть выполняется трехпоточное слияние строк заданной длины, изображенных на рис. 9.21. Используется схема слияния,
122 ГЛ. 9. ВНУТРЕННЕЕ СЛИЯНИЕ Строка Длина 1. 15 2. 3 3. 11 4. 6 5. 9 6. 41 7. 31 8. 27 9. 19 10. 61 11. 7 12. 8 13. 9 14. 21 15. 2 16. 14 17. 13 18. 17 Рис. 9.21. Строки в памяти. Уровень 3*314=942 Рис. 9.23. Другое трехпоточное просмотровое слияние.
9.4. ДАЛЬНЕЙШЕЕ ОБСУЖДЕНИЕ СЛИЯНИЯ 123 в которой 18 строк сливаются так, что строки с 1 по 6 образуют один подсписок, строки с 7 по 12 другой, а с 13 по 18 — третий. На рис. 9.22 показано дерево этого слияния. Все строки входят на одном и том же про¬ смотре и перемещаются трижды. Есть 314 элементов, которые перемещаются трижды, и, следовательно, для формирования одной строки слияние исполь¬ зует 942 перемещения. При слиянии на рис. 9.23 сливаемые строки выбираются в порядке их появления в списке на рис. 9.21. Слияние на рисунках 9.22 и 9.23 содержат одинаковое число перемеще¬ ний данных. Выбор строки по длине в просмотровом слиянии, где на каж¬ дом просмотре . обрабатываются все данные, не влияет на слияние. На число сравнений это также не влияет. Деревья, которые можно преобразо¬ вать одно в другое перестановкой концевых узлов, являются эквивалент¬ ными. Однако мы не можем сделать вывод, что выбор строки по длине никогда не влияет на слияние. Если некоторые строки не используются’ на каждом этапе слияния, то выбор как структуры дерева, так и определенных строк в каждом узле влияет на производительность. Рассмотрим еще раз слияние на рис. 9.23. Последний просмотр является скорее двухпоточным, чем трех¬ поточным. Каков же будет результат, если изменить схему слияния так, что¬ бы последним этапом было бы всегда слияние максимальной степени? Чтобы понять это, задержим вход в процесс слияния некоторых строк. Одна из форм такого слияния показана на рис. 9.24. Это слияние следует основному прин¬ ципу, по которому максимальная степень слияния используется на последних просмотрах так, чтобы самые длинные имеющиеся строки могли бы выгодно использоваться при слиянии максимальной степени. В результате число пере¬ мещений сокращается, поскольку не все строки сливаются одинаковое число раз. Но теперь становится очевидно, что если некоторые строки сливать чаще других, то желательно, чтобы строки, сливаемые реже, быди бы длиннее. Было бы выгодно переупорядочить строки. Деревья слияния не эквивалентны, когда перестановка концевых величин вызывает перемещение с уровня на уровень. Упорядочив список строк так, чтобы самые короткие строки слива¬ лись первыми, получим дерево, изображенное на рис. 9.25. Слияние на рис. 9.25 использует менее 800 перемещений данных, следуя принципам, обеспечивающим максимальную степень на последних этапах и вводящим строки в порядке длин. Управляя «несбалансированностью» и дли¬ ной строк, можно существенно сократить объем работы при слиянии. Цена такого сокращения, конечно, немалая. Чтобы построить дерево слияния, нуж¬ на сортировка длин строк, нужен и алгоритм планирования слияния. Такие затраты могли бы окупиться ■ при действительно массивном внутреннем слиянии. Оптимальное слияние (рис. 9.26) является развитием слияния, изобра¬ женного на рис. 9.25, в следующем направлении. После построения каждой новой строки она помещается в сортируемый список строк для слияния. На РИс- 9.25 только начальные строки вводятся в слияние по длине. Теперь осталась только одна возможность улучшить алгоритм, касающаяся работы
Уровень 124 ГЛ. 9. ВНУТРЕННЕЕ СЛИЯНИЕ Рис. 9.25. Упорядоченные строки в качестве входа для слияния.
10.1. РАСПРЕДЕЛИТЕЛЬНЫЕ СОРТИРОВКИ 125 со строками равной длины, когда одна является начальной, а другая по¬ строенной. Размещение составной строки перед исходной строкой той же длины приведет к минимизации числа уровней в дереве. Когда слияние выполняется на лентах или дисках, выбор строки не произволен. Физические характери¬ стики конструкции ленты и диска, ограничивающие рассуждения этого раздела, будут рассматриваться вместе с этими устройствами. Опти¬ мизация слияния такого типа суще¬ ственна для многоленточного или многодискового слияния, где бывает меньше устройств, чем строк при слиянии. Эти рассуждения применимы и к основной памяти, так как толь¬ ко там все строки одинаково доступны. При наличии очень большой не¬ посредственно адресуемой основной памяти такая оптимизация слияния может быть очень полезной. Число строк, участвующих в слияниях на этих устройствах, бывает достаточно значитель¬ ным, чтобы оправдать затраты. Глава 10. РАСПРЕДЕЛИТЕЛЬНЫЕ СОРТИРОВКИ 10.1. Распределительные сортировки В главе 1 было оговорено различие' между сравнительными и распреде¬ лительными (или классифицирующими) методами сортировки. В этой главе мы опишем ряд распределительных сортировок, а также связанные с ними проблемы и возможности. По своему характеру распределительные сортировки не являются мини¬ мальными по памяти. Поскольку они «распределяют» элементы по принимаю¬ щим областям на основе некоторых характеристик ключей, то под эти при¬ нимающие области необходимо выделить память, отличную от той, которая используется под исходный список. Объем памяти под эти области и потери при неправильном его распределении — вот в основном то, что надо учиты¬ вать при оценке этих методов. Исключением из общего правила является Двоичная поразрядная сортировка. Алгоритмы распределяющей сортировки одинаково применимы как к по¬ мещающимся, так и к не помещающимся в основной памяти входным спи¬ скам. Те алгоритмы, которые ранее рассматривались как внутренние, рас¬ сматриваются как таковые и здесь. Те, что вводились как внешние, изла¬ гаются и здесь как внешние. Логика процедур легко переносится с одних на ■Другие. Рис. 9.26. Дерево оптимального слияния.
126 ГЛ. 10. РАСПРЕДЕЛИТЕЛЬНЫЕ СОРТИРОВКИ Распределительные сортировки, в отличие от сравнительных сортировок, разделяются на блочные методы (интервальные методы) и поразрядные ме¬ тоды. В блочных сортировках ключ рассматривается как единое целое и рас¬ пределяется по интервалам, которые определяются так, чтобы обеспечить разумное разбиение списка на части. Поразрядные сортировки, распределяют элементы по принимающим областям на основе значений конкретных разря¬ дов ключа. Число принимающих областей и правила распределения зависят от основания системы счисления ключей. Со словом «распределение» связана одна трудность. В статистике поня¬ тие «распределение» относится к конкретным величинам, встречающимся в списке, их частоте и диапазону. В более общем смысле оно означает процесс рассредоточения элементов из одного места по нескольким местам. Поскольку оба значения этого термина имеют отношение к сортировке, то далее для статистического распределения элементов будет исполозоваться слово «частот¬ ность». 10.2. Двоичный поразрядный обмен: метод Основным алгоритмом внутренней распределительной сортировки являет¬ ся двоичный поразрядный обмен [15]. Этот метод основан на рассредоточе¬ нии ключей в соответствии с наличием 1 или 0 в двоичных разрядах ключа. Эффективность этого, метода зависит от возможности машины быстро и легко проверять двоичные разряды. На рис. 10.1 обычный список чисел представлен в десятичном и двоичном видах. Каждая двоичная позиция просматривается отдельно, начиная со стар¬ шего бита (крайний левый бит). Первый просмотр образует две части, у од¬ ной из которых все элементы имеют в старшем бите 0, а у другой I. Эти части строятся путем просмотра списка снизу вверх до тех пор, пока не бу¬ дет найден элемент с 0 в старшем бите. Затем выполняется просмотр сверху вниз до тех пор, пока не будет найден элемент с 1 в старшем бите, и эти два элемента меняются местами. Когда указатели встречаются, просмотр за¬ канчивается. Размер двух частей зависит от статистического распределения величин вокруг 2К, где К есть степень двойки, соответствующая первому двоичному разряду (старшему биту), используемому при просмотре. Величины, большие или равные 2К, будут иметь 1 в позиции /(-и степени, величины, меньшие 2\ - 0. На втором просмотре данных просматривается двоичная позиция справа от старшего бита, и из двух частей строятся четыре. «Нулевая» часть пре¬ образуется в две части, чьи первые биты равны 00 и 01 соответственно; «единичная» часть преобразуется в две части, чьи первые биты равны 10 и 11 соответственно. Этот процесс выполняется на каждом из /С + 1 просмотров; когда просмотрена последняя двоичная позиция, список упорядочен. 10.2.1. Пример. На рис. 10.2 показан первый просмотр поразрядного дво¬ ичного обмена. Сначала надо определить способ выделения старшего бита ключа. Машины с побитовой адресацией редки, но устройства, способные эффективно проверять биты, имеются на многих машинах
10.2. ДВОИЧНЫЙ ПОРАЗРЯДНЫЙ ОБМЕН: МЕТОД 127 Кроме способа выделения битов, в методе необходимы указатели на на¬ чало и конец списка. Первой операцией этого примера является проверка старшего двоичного разряда ключа из ячейки 11 списка: он равен 0. Поиск Десятичный Двоичный 3 ООН 11 1011 6 0110 4 0100 9 1001 5 0101 7 0111 8 1000 10 1010 2 0010 1 0001 Рис. 10.1. Десятичный список с двоичным эквивалентом. элемента для обмена начинается с вершины списка. Первый элемент с 1 в старшем разряде находится в ячейке 2. Содержимое ячеек 2 и 11 меняется Список Десятичный Двоичный Первый обмен Второй обмен 1. 3 ООН «-BEG 3 ООН 3 ООН 2. И 1011 —> 1 0001 1 0001 3. 6 0110 6 0110«- BEG 6 оно 4. 4 0100 4 0100 4 0100 О. 9 1001 9 1001 —> 2 0010 6. 5 0101 5 0101 5 0101 7. 7 0111 7 0111 7 0111 8. 8 1000 8 1000 8 1000 9. 10 1010 10 1010 10 1010 10. 2 0010 2 :0010<- END —> 9 1001. 11. 1 0001 <-END —->11 1011 11 1011 Конец просмотра Части * 1. 3 0311 1 —7 (2d) 2. 1 0001 8-11 (2) 3. 6 оно 4. 4 0100 5. 2 0010 6. 5 0101 7. 7 0111 <-END/BEG 8. 8 1000 9. 10 1010 10. 9 1001 11. 11 1011 * Число в скобках указывает следующий просматриваемый двоичный разряд. Рис. 10.2. Двоичный поразрядный обмен, просмотр 1. местами, и указатели продвигаются дальше. Состояние списка после первого обмена показано на рис. 10.2 в столбце «Первый обмен». Поиск снизу вверх теперь проверяет старший бит ячейки 10 списка и опять находит 0, таким образом, нужен еще один обмен. Возобновляется нисходящий поиск единицы в старшем бите. У ячейки 5 старший разряд
128 ГЛ. 10. РАСПРЕДЕЛИТЕЛЬНЫЕ СОРТИРОВКИ равен 1, выполняется обмен, как показано на рис. 10.2 под заголовком «Вто¬ рой обмен». Продолжается проверка снизу вверх. Следующий элемент с 0 в старшем разряде находится в ячейке 7. Однако выше в списке нет ячеек с 1 в стар¬ шем разряде. Поиск величины для обмена переводит верхний указатель в по¬ зицию нижнего указателя, оканчивая просмотр. Две части построены. Одна располагается с ячейки 1 до ячейки 7 и содержит элементы с нулевыми старшими битами. Другая располагается в ячейках с 8 по 11 и содержит элементы с 1 в старшем бите. Цель просмотра — отделить элементы с клю¬ чами, меньшими 8, от элементов с ключами, большими или равными 8. При После обработки После обработки частей 1- ■7 частей 8-11 Части * 1. 3 ООП 3 ООП 1-3(3) 2. 1 0001 1 0001 4-7 (3) 3. 2 0010 2 0010 8-11 (3) 4. 4 0100 4 0100 5. 6 оно 6 0110 6. 5 0101 5 0101 7. 7 0111 7 0111 8. 8 1000 8 1000 9. 10 1010 10 1010 10. 9 1001 9 1001 11. 11 1011 11 1011 * Число в скобках указывает следующий просматриваемый двоичный разряд. Рис. 10.3. Двоичный поразрядный обмен, просмотр 2. этом величина 2К используется как основа частей. Определения частей соби¬ раются в стек. Второй просмотр будет проверять следующий разряд и перестраивать каждую часть в две. Хотя последовательность обработки частей логически произвольна, про¬ дуктивнее выбирать часть так, чтобы все те части, у которых должен про¬ сматриваться один и тот же бит, обрабатывались прежде тех, у которых должен просматриваться бит правее. Причина важная: сокращение числа пере¬ настроек способа выбора бита. Этого можно достичь, организуя стек частей как список FIFO, а не LIFO. На рис. 10.3 показано окончание просмотра 2. Заметим, что метод строит две части из каждой исходной части в стеке. По¬ этому если все элементы в исходной части имеют одно и то же значение сортируемого бита, то автоматически создается пустая часть. Третий просмотр далее строит части, просматривая следующий разряд — разряд 3 (рис. 10.4). Просмотр части 1—3 порождает части 1—1 и 2—3. Просмотр части 4—7 порождает части 4—5 и 6—7. Просмотр части 8—11 порождает части 8—9 и 10—11. Пустая часть с рис. 10.3 отбрасывается. Четвертый просмотр оказывается последним, поскольку указатель битов достигает младшего бита ключа. На последнем просмотре можно отказаться от стекового механизма. Окончательно упорядоченный список можно легка разглядеть на рис. 10.4. Объем памяти, необходимый для определений частей, может расти до¬ вольно сильно: в общем случае максимально может потребоваться 2К—1 по-
10.2. ДВОИЧНЫЙ ПОРАЗРЯДНЫЙ ОБМЕН: МЕТОД 120 зиний. Если такого количества памяти под определения частей нет, то можно сократить требуемый объем, используя стек частей как стек LIFO и распла¬ чиваться перенастройкой при выборе бита. Этот способ уменьшает поле па¬ мяти примерно до К ячеек. 10.2.2. Число проверок и перемещений данных. На просмотре исчерпы¬ ваются все части, у которых просматривался один и тот же разряд. Число проверок на каждом просмотре равно N, так как между всеми частями рас¬ пределяется N элементов. Число просмотров равно числу двоичных разрядов, необходимых для представления наибольшего ключа. В данном примере было четыре просмот¬ ра, так как для представления 11 нужно четыре двоичных разряда. Число Вначале После просмотра 3 Части * 1. 3 ООП 1 0001 2. 1 0001 3 ООН 1-1 (4) 3. 2 0010 2 0010 СО 1 (N 4. 4 0100 4 0100 4-5(4) 5. 6 0110 5 0101 6-7 (4) 6. 5 0101 6 0110 8-9(4) 7. 7 0111 7 0111 10-11 (4) 8. 8 1000 8 1000 9. 10 1010 9 1001 10. 9 1001 10 1010 11. 11 1011 11 1011 * Число в скобках указывает следующий просматриваемый двоичный разряд. Рис. 10.4. Двоичный поразрядный обмен, просмотр 3. просмотров можно записать как К + 1 или flog2MAX“| + 1, где МАХ — са¬ мое большое значение в списке. Всего проверок будет N(K-\-\) или N( Гlog2 МАХ“| + 1). Вследствие обменов, характерных для этого метода, число перемещений данных зависит от их расстановки. Минимальное число обменов равно 0, а максимальное N(/C-f-l)/2. Ожидаемое число равно половине этого, или N (К+1)14. Часто в литературе коэффициент (/С+ 1) заменяют на число разрядов D (или битов Ь) и записывают число проверок как N-Dy а обменов как (N-D)l 4. 10.2.3. Двоичный поразрядный обмен и быстрая сортировка. Двоичный поразрядный обмен является распределительной версией быстрой сортировки. Значения просматриваемых двоичных позиций эквивалентны основам в быст¬ рой сортировке. Имеются ли тогда основания предпочесть быструю сортиров¬ ку двоичному поразрядному обмену или наоборот? Программист должен сделать выбор между N-D проверками и примерно 1.4AM0g2A/ сравнениями. В двух этих методах процессы управления на про¬ смотрах и между просмотрами настолько схожи, что их можно считать экви¬ валентными. Предположим, что имеется 1024 элементов для сортировки. Быстрая сортировка требует 14 336 сравнений (1.4 X 1024 X 10). Сколько же потребует двоичный поразрядный обмен? Это зависит от размера ключа. Если самый большой ключ занимает 36 битов (слово UNIVAC 1108), то потребу- 5 Г. Лорин
130 ГЛ. 10. РАСПРЕДЕЛИТЕЛЬНЫЕ СОРТИРОВКИ ется 31 744 проверки, и быстрая сортировка предпочтительнее. Если наиболь¬ ший ключ занимает только 13 битов, то число проверок битов меньше, чем ожидаемое число сравнений в быстрой сортировке. Если диапазон ключей достаточно мал, и двоичный поразрядный обмен кажется выгодным, то необходимо учесть относительную стоимость сравнения и проверки бита. Конечно, также учитывается кодирование вручную основ¬ ного цикла сравнений и процесса выбора бита для конкретной машины. Если машина не может эффективно обрабатывать двоичные строки переменной длины, поразрядный обмен может выполняться плохо. У программиста может быть достаточно информации о своих данных, чтобы он воздержался от выбора основы, используемого в поразрядном об¬ мене, и предпочел более сложный выбор основы, доступный быстрой сор¬ тировке. Двоичный поразрядный выбор, подобно быстрой сортировке, лучше ис¬ пользовать как комбинированный метод. Точно так же, как и в быстрой сортировке, процесс ускоряет использование просеивания для очень малых частей [24]. 10.3. Поразрядная сортировка: основной метод В упрощенной форме поразрядная сортировка аналогична процессу меха¬ нической сортировки перфокарт на ЭВМ. Область вывода делится на А «бун¬ керов» (также называемых «ведрами» или «карманами»). А соответствует числу значений, которые могут принимать символы ключей. Если известно, что все символы ключей — числа по основанию 10, то А равно 10. Для каж¬ дого символа должен быть свой бункер, т. е. А равно размеру алфавита, используемого для построения ключей. Просмотр в этом методе состоит из распределения элементов по бункерам на основе значения символа в проверяемой позиции, а затем «собирания» элементов для следующего просмотра. Распределение происходит символ за символом, от низших порядков к высшим так, что если ключи состоят из D символов, то будет D распределений и D собирающих просмотров, причем заключительный просмотр собирает элементы в упорядоченную последователь¬ ность. 10.3.1. Пример. На рис. 10.5 указано И трехзначных десятичных чисел; следовательно, А = 10, D = 3. Под распределение выделяются десять вы¬ ходных бункеров, помеченных 0—9. Начальный просмотр единичного разряда (самого правого) распределяет числа так, как показано на этом рисунке. В конце первого просмотра входная область пуста. В заданном бункере будет от нуля до N чисел, в зависимости от распределения цифр в позиции единиц. Перед вторым просмотром либо надо собрать числа из бункеров и возвратить их во входную область, либо иметь доступ к другому множеству бункеров. Если есть иное множество бункеров, то распределение может быть немед¬ ленно продолжено, и, таким образом, экономится просмотр данных, если же нет, то числа должны быть собраны. Процесс собирания идет от бункеров с малыми значениями к бункерам с большими значениями, при этом элементы из каждого бункера помещаются в сплошной список, упорядоченный по соот-
10.3. ПОРАЗРЯДНАЯ СОРТИРОВКА: ОСНОВНОЙ МЕТОД 131 ветствующей цифровой позиции. На рис. 10.6 показан список так, как он собран после первого просмотра. Когда сбор закончен, бункеры пусты, и вы¬ полняется новое распределение. 314 116 627 743 455 069 870 181 298 Список Бункеры 0 1 2 3 4 5 6 7 8 9 314 116 870 181 - 743 314 455 116 627 298 069 069 510 813 743 298 455 870 181 510 627 813 Рис. 10.5. Поразрядная сортировка, просмотр 1. Список I Бункеры 1 о 1 2 3 4 5 6 7 8 9 870 - 510 627 - 743 455 069 870 181 298 510 813 181 314 743 116 813 314 455 116 627 298 069 Рис. 10.6. Поразрядная сортировка, сбор и просмотр 2. Список Бункеры 0 1 2 3,4 5 6 7 8 9 510 069 116 298 314 455 510 627 743 813 813 181 870 Рис. 10.7. Поразрядная сортировка, сбор и просмотр 3. Второе распределение выполняется по разрядам десятков. Каждое число распределяется в бункер в соответствии со значением его цифры десятков. Состояние после этого распределения показано на рис. 10.6. Числа опять со¬ бираются в список, как показано на рис. 10.7. Этот список упорядочен по разрядам единиц и десятков. Третье и последнее распределение выполняется 5*
132 ГЛ. 10. РАСПРЕДЕЛИТЕЛЬНЫЕ СОРТИРОВКИ по разряду сотен. Сбор из этих бункеров образует упорядоченный список. Показанный процесс состоит из трех распределяющих и трех собирающих просмотров. 10.3.2. Распределение. Процесс распределения — это процесс определения нужной позиции для элемента и размещение его в этой позиции. Определение места, где именно должен находиться элемент, включает идентификацию раз- ряда для определения его бункера и обращение к индикатору, показываю¬ щему место следующей свободной позиции в выбранном бункере. Механизмом определения разряда может быть сравнение или вычисление. Сравнивающий механизм сравнивает разряд с возможными символами и на Таблица размещения бункеров Место Место бункера Счетчики бункера Имя бункера 1072 10000 3 0 1073 12000 6 1 1074 14000 7 2 1075 16000 4 3 1076 18000 3 4 1077 20000 5 5 1078 22000 4 6 1079 24000 6 7 1080 26000 2 8 1081 28000 1 9 1. Складываем цифру ключа с базой таблицы размещения; например, 1072+ 4=1076. 2. Содержимое 1076 дает начальный адрес бункера. 3. Счетчик в 1076 указывает первую свободную позицию 18003. Пример предполагает распределение однословных записей. Рис. 10.8. Вычисление адреса бункера и места в нем для размеще¬ ния элемента. основе успешного сравнения выбирает нужный бункер. Вычисляющий меха¬ низм пытается сформировать адрес бункера непосредственно по разряду. Если используется сравнивающий механизм, то при вычислении производительности сортировки надо учитывать число сравнений. Число сравнений зависит от At числа значений, которые могут появляться в позициях разряда, и организа¬ ции сравнений. Избежать сравнений можно, используя вычислительный способ идентифи¬ кации символа. На рис. 10.8 показано вычисление базовых адресов. Таблииа расположения бункеров, начинающаяся с ячейки 1072, содержит адреса каж¬ дого распределительного бункера и счетчик числа элементов в бункере. Каж¬ дая цифра складывается с базой таблицы, чтобы найти ячейку, содержащую базовый адрес нужного бункера. Счетчик числа элементов, уже находящихся в бункере, определяет место для нового элемента. Добавка к базовому ад¬ ресу бункера, естественно, строится так, чтобы представить фактические пре¬ делы адресного пространства. На рис. 10.8 предполагаются записи в одно
10.3. ПОРАЗРЯДНАЯ СОРТИРОВКА: ОСНОВНОЙ МЕТОД 133 слово. Если бы распределялись 10-словные записи, то поле счетчика для удоб¬ ства могло бы показывать 30. Сложение значений разрядов с адресами таблицы или счетчиков элемен¬ тов с адресами бункеров не должно зависеть ог программного сложения, если сортировка выполняется на машинах с индекс-регистрами и (или) косвенной адресацией. Общее число выполняемых в течение сортировки проверок разрядов за¬ висит от количества разрядов, необходимых для представления ключа. При D разрядах в ключе потребуется D распределении. Если используются сравне¬ ния, то число сравнений за просмотр равно N-D-F, где F — чйсло сравнений при любой схеме, используемой для определения нужного бункера. В против¬ ном случае было бы N-D вычислений адресов. 10.3.3. Память. Сортировщик перфокарт конструируется для небольшого алфавита, А = 10 или 12, что обычно соответствует десятичным цифрам. Алфавитные сортировки требуют дополнительных усилий. Поскольку вычис¬ лительная машина может иметь произвольное число бункеров, то теоретиче¬ ски может обрабатывать любой алфавит. Если алфавит большой, — например, буквенно-цифровой набор BCD*) имеет 64 символа — возникают проблемы в распределении памяти для бункеров. Сортировщик перфокарт обеспечивает фактически неограниченное количество памяти, так как можно удалять карты из карманов во время сортировки, и все стеки имеют неограниченные разме¬ ры. Вычислительная машина обязательно накладывает ограничения на размер области распределения. Если эта область расположена в основной памяти, то ограничением является доступный объем основной памяти. Если она рас¬ положена на дисках или барабанах, то ограничивающими факторами стано¬ вятся имеющееся пространство на этих устройствах и его доступность (по скорости). Попытки улучшить поразрядные методы в основном заключаются в сокращении объема требуемой памяти. Наиболее эффективный алгоритм распределения требует память для пред¬ ставления 2(A-TV) элементов. Позиция разряда может принимать А значений. Каждый из N элементов в заданной позиции может принимать любое из А значений. Следовательно, чтобы гарантировать, что бункер не будет пере¬ полняться, необходимо иметь бункера длины N для каждого из А значений, которое может стоять в позиции разряда. Однако наличие А-N полей памяти все же требует собирающего просмотра для очистки бункеров после каждого распределения. Этот собирающий просмотр ничего не дает для упорядочения Данных. Чтобы отказаться от него, нужна еще одна область распределения, также имеющая длину А-N. Имея меньше основной памяти, чем фактически необходимо, программист вынужден решать, как ее распределить. Если он кое-что знает о возможной частотности значений разрядов в данных, то может постараться для разных значений выделить области разной длины. Например, при сортировке конкретных имен можно выделить меньше памяти П°Д X, Z, Q. В литературе по информационному поиску есть некоторые мате¬ риалы по статистике появления букв в различных множествах, которые могут *) Система кодировки символов на ЭВМ. (Прим. перев.)
134 ГЛ. 10. РАСПРЕДЕЛИТЕЛЬНЫЕ СОРТИРОВКИ быть полезны для таких разработок. При этом подходе необходимо обеспе¬ чить какое-нибудь средство на случай переполнения бункеров. Есть одно очевидное средство для сокращения необходимой памяти — это распределение только признаков (или адресов). Оно не только сокращает объем памяти, необходимой под признаки (или адреса), но и сохраняет время для перемещения данных при распределении. Когда необходимого количества доступной памяти нигде поблизости нет, нужны более сложные процедуры. Одна из таких процедур — подсчет, который мы рассмотрим в следующем разделе. 10.3.4. Подсчет и вычисление адресов. Подсчет — это попытка сократить необходимую память путем определения диапазона и частоты значений в по¬ зиции каждого разряда. Результатом должно быть уменьшение дополнитель¬ ной памяти до разделов, необходимых для списка в целом (или признаков Слисок 314 Значение Счетчик 234 169 356 492 345 Рис. 10.9. Состояние счетчиков, младший разряд. Разряд Итоговая Счетчик сумма 116 1 1 0 2 16 069 2 1 1 1 14 743 3 2 2 1 13 298 4 2 3 2 12 455 6 2 4 2 10 870 6 2 5 2 8 181 7 1 6 2 6 510 8 1 7 1 4 627 9 2 8 1 3 813 9 2 2 Рис. 10.10. Итоговые суммы. списка), плюс ячейка счетчика для каждой величины. В приложении есть алгоритм MATH SORT, в котором используется этот подход. Мы используем область вывода длины N и область счета, содержащую счетчик для каждого символа, который может появиться в ключе. Просмотр входного списка проверяет позицию разряда каждого ключа и подсчитывает частоту появления каждого значения. На рис. 10.9 показано состояние счетчиков после начального подсчитывающего просмотра. Таблица счетчиков заполняется сложением значения позиции разряда с базовым адресом таб¬ лицы. После подсчета по таблице счетчиков подводится совокупный итог (рис. 10.10). Есть шестнадцать цифр разрядов, равных или больших 0, четыр¬ надцать цифр, равных или больших 1, десять цифр, равных или больших 4. Управление распределением происходит по значениям итоговой таблицы. На¬ пример, цифра 4 равна или меньше 10 чисел и больше 6 чисел. В списке вывода с разрядом 0 наверху числа, оканчивающиеся на 4, будут распола¬ гаться с ячейки 7 и ниже, так как над ними будет 6 чисел. Заметим, что
10.3. ПОРАЗРЯДНАЯ СОРТИРОВКА: ОСНОВНОЙ МЕТОД 135 позиция первого элемента, оканчивающегося на 4, равна BASE + N + 1 — CUM (4), то есть базовый адрес плюс длина списка плюс единица минус со- вокупный итог для цифры 4. На рис. 10.11 число 314 находится^ в позиции 7 (BASE равно 0). Это относительный адрес первой допустимой ячейки для цифры 4 в списке вывода. После размещения ключа совокупный итог умень¬ шается. При следующем появлении цифры 4 в качестве относительного адре¬ са будет вычислено 17 — 9 = 8. На рис. 10.12 показано уменьшенное значение Отсорти- TOSORT сим Счетчик ровано 314 0 16 1. 116 1 14 2. 069 2 13 3. 743 3 12 4. 298 4 10 5. 455 5 8 6. 870 6 6 7. 314 181 7 4 8. 510 8 3 9. 627 9 2 10. 813 11. 234 12. 169 N + 1- -CUM (4) = 13. 356 = 17- 10 = 7 14. 492 15. 345 16. Рис. 10.11. Распределение с исполь¬ зованием итоговой суммы. Отсорти- TOSORT CUM Счетчик ровано 116 0 16 1. 069 1 .14 2. 743 2 13 3. 298 3 12 4. 455 4 9* 3. 870 5 8 6. 181 6 6(17 — 6=11) 7. 314 510 7 4 8. 627 8 3 9. 813 9 2 10. 234 11. 116 169 12. 356 13. 492 14. 345 15. 16. * Используя уменьшение счетчика, для следующей цифры 4 имеем 17 — 9=8. Рис. 10.12. Измененная итоговая сумма. CUM(4) и размещение следующей цифры (6 от 116). Просмотр заканчивает¬ ся, когда размещен весь список. По завершении просмотра список упорядочен по номерам уже просмотренных позиций. Распределение выполняется из дру¬ гих областей, и, следовательно, собирающий просмотр не нужен. 10.3.5. Двоичная группировка. Если распределение бункеров под каждую величину приводит к слишком большому количеству бункеров или недопу¬ стимо малой длине бункера, то их длина может быть изменена путем сопо¬ ставления бункеру нескольких величин. При работе с лентами количество лент, необходимых для рассредоточения, можно сократить, записывая несколько величин на одну и ту же ленту. Расплата за такую группировку — допол¬ нительные просмотры. Каждый бункер группы должен все равно быть рас¬ пределен по отдельным бункерам. Разделение можно произвести при собираю¬ щем просмотре. Однако, по всей видимости, не стоит предпочитать этот способ способу подсчета, поскольку он не обеспечивает ни значительного сокращения памяти, ни достаточной защиты от переполнения бункера. Ю.3.6. Преобразования. У машин есть разные основания систем счисле¬ ния, разные коды для представления данных и разные упорядочивающие по¬ следовательности на основе этих кодов. Если надо применить поразрядную сортировку, то необходимо правильно представить ключи. Например, в двоич- Н°и Поразрядной сортировке следует позаботиться о том, чтобы чисто двоичная
136 ГЛ. 10. РАСПРЕДЕЛИТЕЛЬНЫЕ СОРТИРОВКИ строка представляла последовательность для машинных сравнений и чтобы правила представления отрицательных величин на этой машине позволяли обеспечить непрерывный переход от меньших чисел к большим. Программист должен решить, является ли преобразование различных ко¬ дов необходимым или желательным. Преобразование ключей, при котором происходит изменение основания системы счисления, часто используется для того, чтобы сократить количество бункеров, необходимых для представления цифр в системе с меньшим основанием, и, следовательно, с меньшим количе¬ ством цифр. Цена этому — дополнительные просмотры удлиненного ключа. В противоположность, можно увеличить основание системы счисления, чтобы сократить число просмотров за счет увеличения числа бункеров. 10.3.7. Сортировка «двуглавого змея». Характер времени доступа по внешним устройствам таков, что собирающие просмотры, которые могут быть вполне допустимыми во внутренней памяти, могут быть неприемлемыми, когда бункера расположены на устройствах ввода-вывода. Чтобы отказаться от собирающих просмотров, нужна другая область бункеров. На ленточной системе это означает, что потребуется 2А лентопротяжных устройств для сор¬ тировки ключей в системе счисления с основанием А. Таким образом, для десятичных ключей потребуется 20 лент или 20 областей на дисках. Как средство сокращения числа лент или областей можно использовать два спо¬ соба. Один, упомянутый ранее, является преобразованием ключей. Другой является развитием метода распределения и сбора, в котором требуется меньше 2А устройств. Сортировка методом «двуглавого змея» делает как то, так и другое [26]. Она несколько отличается от внешней поразрядной сорти¬ ровки с преобразованием ключей, но исключает собирающие просмотры и ис¬ пользует только (А + 1) ленту. Основание А можно изменить на какую-ни¬ будь величину R, чтобы приспособить к фактически доступному числу лент. Когда этот метод ориентирован на работу с лентами, он зависит от возмож¬ ности читать ленту в обратном направлении. От этой характеристики и про¬ исходит название метода. Выбор основания системы счисления для распределения зависит от числа доступных лентопротяжных механизмов (или числа бункеров при работе на внутренней памяти). В любой момент времени будет R устройств (R ^ Л), загружаемых с единственного устройства ввода. Если, например, есть шесть лент, то распределение будет происходить по основанию 5. Входные значения будут преобразовываться соответственно системе счисления, используемой при распределении, т. е. десятичный вход станет пятеричным. Позиционная система счисления приписывает каждой цифре d значение (с/+/?р), где р— позиция цифры; считая от самой правой цифры, р = 0, a RP — множитель цифры в р-й позиции. Таким образом, 314 в десятичной системе счисления есть 3 X W2 + 1 X Ю1 + 4 X 10°. Равное пятеричное число есть 2 X 53 + 2 X 52 + 2 X 51 + 4 X 5°, или 2224. Сначала данные считываются с входной ленты и распределяются по лен¬ там по самой старшей значащей цифре. На рис. 10.13 показан список в де¬
10.3. ПОРАЗРЯДНАЯ СОРТИРОВКА: ОСНОВНОЙ МЕТОД 137 сятичной и пятеричной системах счисления. На рис. 10.14 показано начальное распределение этого списка (и некоторые другие числа). Стрелками показано положение головки лентопротяжного устройства после распределения. После начального распределения происходит серия «расщеплений». Рас¬ щепляемая группа всегда состоит из величин с наибольшими ключами. Сле¬ дующее распределение расщепляет 74 (содержащую 4ХХХ) на меньшие груп¬ пы. Лента Тk становится входной, а лента Г/ (которая сначала была входной) становится лентой распределения и загружается элементами лент Т0 — Т3. Чтения и записи на Г4 и h теперь выполняются в обратном направлении. Десятичные Пятеричные Значения позиций: 100 10 1 125 25 5 1 3 1 4 2 2 2 4 0 6 9 0 2 3 4 2 9 '8 1 4 3 4 5 5 3 3 1 0 1 8 1 1 2 1 1 5 1 0 4 0 2 0 2 3 4 1 4 1 4 1 6 9 1 1 3 4 3 5 6 2 4 1 1 4 9 2 3 4 3 2 3 4 5 2 3 4 0 Рис. 10.13. Десятичные числа с пятеричным эквивалентом. Распределение по второй цифре образует группы 40ХХ, 41XX, 42ХХ, 43ХХ, 44ХХ на лентах Т0, Гг, Т3, Г/. Эти группы записываются на ленту впереди уже распределенных элементов, если таковые есть. Входная лента Г4 будет в состоянии загрузки, когда распределение закончится. На рис. 10.15(a) по¬ казано это распределение, подчеркнута позиция разряда, которая вызвала появление этого элемента на данной ленте. Следующее распределение будет расщеплять 44ХХ на 440Х, 44IX, 442Х, 443Х, 444Х. Это показано на рис. 10.15(b). Последующее распределение об¬ разует 4440, 4441, 4442, 4443, 4444. Далее расщеплений группы 444Х не будет. Все элементы этой группы собраны на Г/ и записаны в обратном порядке в виде убывающей строки 4444, 4443, 4442, 4441, 4440. Процесс расщепления начинается вновь с группы 443Х, которая расщепляется на 4434, 4433, 4432, 4431, 4430 и собирается на Г/ перед группой 444Х. Когда это сделано, начи¬ нает обрабатываться группа 442Х. По этой схеме — расщепление группы с левой ее стороны, пока не будет обработан весь ключ, до сбора и перехода к следующей по величине группе — процесс продолжается до тех пор, пока полная строка не будет собрана на Т/. Когда группа настолько мала, что может поместиться в памяти, этот процесс можно оборвать внутренней сортировкой. Например, группа 44ХХ может быть целиком упорядочена без дальнейшего расщепления, если она помещается в памяти, после ее распределения на Г/. Этот метод, хотя и описан как ленточный, более применим к дискам, поскольку ленты с обратной записью редки. Перемотка ленты равноценна просмотру списка вперед или назад. Информация, только что записанная в подсписок, всегда читается в обратном направлении. Запись продолжается
188 ГЛ. 10. РАСПРЕДЕЛИТЕЛЬНЫЕ СОРТИРОВКИ в том же направлении, что и ранее. Этот метод также может использоваться как внутренний. В ленточной или дисковой версиях количество распределений ключа за¬ висит от объема внутренней сортировки. Если внутренняя сортировка не вы- Начальный вход h Тх Т2 Тъ ТА Tj 0431 1211 2224 3310 4020 0234 1414 2143 3432 4131 1134 2411 4214 - < Считано <— 2340 4314 - < во время <— 4411 -I распределения 4431 «— 4422 4334 4303 4243 4121 4143 4034 4061 Замечание. Стрелки указывают положение текущего указателя списка. На лен¬ те—это головка чтения/записи. Рис. 10.14. Сортировка «двуглавого змея», начальный просмотр Го Т\ ^2 Т Т 'з 1А 7/ 0431 1211 2224 3310 - А 0234 1414 2143 3432 1 4061 1134 2411 4303 4122 А 4034 . 4143 2340 4334 , 4431 1 4020 4 4121 . 4243 1 4314 4 4411 4131 4 4214 4 а) Распределение второй цифры. то Т1 ^2 Т1 0431 1211 2224 3310 - А 0234 1414 2143 3432 1 4 4061 1134 2411 4303 4034 . 4143 2340 4334 4020 | 4121 4243 4314 , 4131 . 4214 I 4131 4 4411 4 4422 4 Ь) Распределение третьей цифры в 44ХХ. Замечание. Стрелки указывают направление. Выделены проверяемые цифры. Рис. 10.15. Второй просмотр сортировки «двуглавого змея». полняется, то ключ будет распределяться D — 1 раз, где D — количество цифр, необходимых для представления ключей в системе счисления по осно¬ ванию R. Если внутренняя сортировка есть, то ее эффективность зависит от того, насколько мала должна быть группа, чтобы ее можно было подвергнуть внутренней сортировке. Внутренняя сортировка сокращает количество про¬ смотров ключей, исключая распределение по последним разрядам.
10.4. ИНТЕРВАЛЬНАЯ СОРТИРОВКА 139 10.4. Интервальная сортировка Интервальная сортировка — аналог поразрядной сортировки — так же, как быстрая сортировка, является аналогом двоичной поразрядной сортиров¬ ки. Распределение основано на значении всего ключа, принадлежащего опре¬ деленному интервалу. Этот метод можно использовать и как внутренний, и как внешний с лентами или дисками. Особенно он интересен во внешнем окружении в качестве альтернативы внешнему слиянию. Этот метод должен разделять входные данные по нескольким бункерам, каждый из которых со¬ держит отдельный интервал ключей. Начальные группы расщепляются затем на все меньшие и меньшие до тех пор, пока список не станет упорядоченным или какая-нибудь сравнительная сортировка не упорядочит последние ма¬ ленькие группы. 10.4.1. Определение бункеров. Поскольку число просмотров зависит от числа бункеров, то хотелось бы иметь по возможности больше бункеров (ин¬ тервалов). «Степень распределения» (число бункеров) зависит от количества устройств или доступных областей. Если есть шесть лент, то одна будет вход¬ ной лентой, и распределение будет вестись по пяти направлениям. Надо установить, какое определение интервалов будет обеспечивать рав¬ номерное распределение, — от этого зависит эффективность метода. Если ин¬ тервалы были определены так, что три из пяти бункеров никогда не полу¬ чают элементов, то эффективное распределение будет двухпоточным. Чтобы правильно определить интервалы, нужны сведения о диапазоне величин и частотности их в сортируемом списке. Столь подробная информация о дан¬ ных имеется редко. Например, если есть 100 элементов с возможным диапа¬ зоном ключей от 1 до 1000 и пятью выходными бункерами, то интервалы 0—200, 201—400, 401—600, 601—800, 801—1000 могут быть, а могут и не быть приемлемыми и эффективными. Возможно, что у конкретного списка 63 ключа находятся в интервале 0—200, 250 — в интервале 201—400, 17 — в интервале 401—600 и т. д. При отсутствии такой информации надо обеспе¬ чить средство для ее получения в процессе сортировки; в противном случае следует избегать методов, чувствительных к частотности. Один метод вы¬ яснения частотности данных состоит в том, что входной файл просматри¬ вается при начальном просмотре и строится таблица интервалов. Создаются счетчики для отдельных интервалов, соответствующих значительно боль¬ шему числу бункеров, чем планировалось для распределения. В конце этого просмотра интервалы перестраиваются в новые так, что их границы охваты¬ вают примерно равное число элементов. На первом просмотре можно допустить плохое распределение, но затем Улучшить последующие просмотры. Для начального распределения могут ис¬ пользоваться совершенно произвольные интервалы, затем на основе собран- ных данных можно усовершенствовать определение интервалов. Ю.4.2. Пример: распределение на ленте. На рис. 10.16 даны трехзначные числа и их частотность по интервалам с шагом 200. На рис. 10.17 показано, Как Начальное распределение использует эти произвольные интервалы. Следующее распределение при просмотре частей разделяет элементы од- НОго интервала на меньшие интервалы. Для этого распределения границы
140 ГЛ. 10. РАСПРЕДЕЛИТЕЛЬНЫЕ СОРТИРОВКИ Список Частотность 184 352 376 505 604 0-200 21 388 369 742 482 256 201-400 29 672 523 351 440 973 401-600 20 634 666 279 298 278 601-800 18 154 574 148 830 795 801 -1000 12 116 104 469 293 287 312 659 327 970 441 265 201 163 507 243 492 069 947 372 751 570 194 032 759 889 212 137 554 240 798 198 303 199 570 078 222 858 335 757 354 842 637 212 412 619 417 698 258 957 685 921 127 637 177 537 651 718 497 230 288 328 397 248 783 024 197 941 181 626 152 878 065 068 707 003 Рис. 10.16. Список данных. Т1 1-200 Г2 201-400 о о 1 о -г ^4 601-800 184 388 534 672 154 312 492 666 116 265 570 659 198 212 417 637 197 222 551 718 194 328 523 742 069 352 574 637 194 309 598 759 137 201 469 757 127 393 554 783 065 397 497 626 148 376 505 707 163 351 482 604 032 279 440 795 199 327 507 751 181 335 570 798 177 212 412 619 073 258 441 685 024 248 537 <— 152 298 488 003 293 <— 372 210 230 256 278 267 243 354 чает 801-1000 842 921 878 858 941 947 868 830 970 957 973 889 Замечание. Стрелка обозна- указатель списка. На ленте — го- лоика чтения/записи. Рис. 10.17. Интервальная сортировка, первый просмотр.
10.4. ИНТЕРВАЛЬНАЯ СОРТИРОВКА 141 интервалов можно выбрать по таблицам разделенных интервалов или произ¬ вольно вычислить как одну пятую интервала первого распределения. В по¬ следнем случае на ленте 5 будут следующие новые интервалы: 801—840, 841—880, 881—920, 921—960, 961 —1000. Лента 5 читается в обратном на¬ правлении, а новые элементы помещаются на другие ленты за элемен¬ тами, распределенными на просмотре 1. По исчерпании Г5 элементы распреде¬ лены так, как показано на рис. 10.18. Следующее распределение будет основано на интервалах по одной пятой от 40. Распределение наибольших элементов (961 —1000), тех что на 7V про- Вход л Чтение 801 А до I 1000 ?! Т1 Т2 гз От первого 001 201 401 601 просмотра да Да да да 200 400 600 800 830 ^ 863 889 ^ 957 973 858 947 970 878 | 941 , 842 4 921 4 <— <— Лента Интервал Т1 801-840 Т\ 841 -880 Тг 881-920 Тг 921-960 Замечание. позицию. 961-1000 Вертикальные стрелки указывают направление, горизонтальные — Рис. 10.18. Перераспределение ленты 5. исходит с этими же границами. При вцутренней сортировке этого распреде¬ ления можно избежать, строку (973, 970) можно сразу записать на Т5. После внутренней сортировки или распределения окончательный список, упорядочен¬ ный по убыванию, начинается на Т*. Все группы, таким образом, сокращены и записаны на 7^, как показано на рис. 10.19. В конце этого процесса на Тъ получается убывающая строка. Возрастающую строку можно было бы полу¬ чить, если при втором разделении двигаться от меньших элементов к боль¬ шим. Схема от меньших к большим или от больших к меньшим необходима, так как окончательная выходная лента дублнруе;ся в виде ленты распреде¬ ления. При использовании (R + 2) лепт или распределении па дисках эта схема совершенно произвольна и может быть выбрана по характеристикам машины. 10.4.3. Просмотры и сравнения. Число просмотров зависит от степени распределения, от эффективности интервала и от размера групп, которые могут упорядочиваться заключительной сравнительной сортировкой. Число просмотров определяется последовательным делением N на степень распреде¬ ления. При этом делении получается либо 1, либо размер группы, которая может обрабатываться сравнительной сортировкой. Если эта сортировка обра¬ батывает группы по 100 элементов или меньше, а сортирует 50 000 элементов
142 ГЛ. 10. РАСПРЕДЕЛИТЕЛЬНЫЕ СОРТИРОВКИ с расщеплением по десяти направлениям, то первый просмотр распределения будет создавать группы по 5000 элементов, второй просмотр — группы из 500 элементов и третий просмотр — 50-элементные группы. Необходимы три распределяющих просмотра. Число сравнений при распределяющем просмотре зависит от метода, вы¬ бранного для нахождения соответствующего интервала. Поскольку этот метод Ti Т1 Т2 Tz Т4 h 830 Распреде¬ ление с Г4 Лента Интервал Tj 961-968 Tt 969-976 Г, 977-985 Г3 985-992 Tt 7\ 993-1000 Рис. 10.19. Распределение 961 — 1000 и сбор убывающей строки на Т$, работает со всеми ключами, сравнительные методы, как правило, будут ис¬ пользоваться чаще. Число сравнений зависит от точности алгоритма. Для рас¬ пределений малых степеней обычно будет использоваться простой (N—1)-спо- соб. Для распределений очень большой степени может быть эффективным log2 N-способ с древовидными структурами. 10.5. Вычисление адреса В этой главе, как и в главе 1, мы обсудили использование способа вы¬ числения величин, которые можно использовать в качестве адреса (или неко¬ торой его части) списка вывода. Если между значением ключа (или значением разряда ключа) и некоторой частью адресного пространства машины суще¬ ствует взаимнооднозначное соответствие, то адрес вычисляется просто; каж¬ дый элемент перемещается только один раз (из входного списка в список вывода), и нужно лишь достаточное количество памяти для хранения за¬ ключительного списка вывода. Если отображение адресов сложнее, то элементы должны перемещаться не один раз, и, следовательно, для метода необходимо больше рабочей па¬ мяти. Характер связи между ключами и адресами определяет сложность вы¬ числений адресов и возможность их непосредственного использования. Рента¬ бельность вычислений адресов как метода сортировки списка элементов зави¬ сит от диапазона, представления частотности значений ключей, а также от имеющихся методов преобразования этих величин в адреса [2, 19]. 10.5.1. Функция вычисления адресов. Основой вычисления адресов являет¬ ся функция, преобразующая ключи в адреса. В некоторых методах ключ рас- 868 858 878 842 970 973 889 957 947 941 921 973 I 970 | Сбор в убывающей последова¬ тельности
10.Б. ВЫЧИСЛЕНИЕ АДРЕСА 143 сматривается как единое целое, и над ним выполняется некоторая последо¬ вательность действий. Один из таких методов — деление на некоторое простое число и использование остатка как адреса. Другой метод — умножение (воз¬ ведение в квадрат) и усечение*). Некоторые методы строят адрес поразряд¬ но, создавая в итоге то, что представляет машинный адрес, другие преобра¬ зуют ключ из одной системы счисления в другую, в которой он будет адре¬ сом машины. Программист должен быть осторожным при выборе схем «перемешива¬ ния»**), так как некоторые из них в своем процессе не сохраняют относи¬ тельный порядок между ключами. Основными преимуществами перемешива¬ ния являются уникальность адресов и равномерность их распределения по Ключи Адреса 000000-300000 0- 1000 | 300001-700000 990001 -999999 Размещаемый ключ 376179 будет где-ни¬ будь между 1001 и 2000. Рис. 10.20. Преобразование ключа в адрес. имеющимся ячейкам. Поскольку поиск элементов данных можно выполнять при помощи такого же перемешивания, то строгий порядок часто не обяза¬ телен. В связи с этим программисту следует также подумать, есть ли реаль¬ ная необходимость сортировать данные, или достаточно создать способ их поиска. Если вероятность построения уникальных адресов при перемешивании мала, то для поддержки функции сортировки используются таблицы интер¬ валов. Использование таблиц интервалов вызвано необходимостью отыскивать подходящее место для элемента в некоторых видах поиска. Границы поиска зависят от пределов таблиц. На рис. 10.20 есть 10 000 адресов, распределен¬ ных по 10 группам ключей. В каждом интервале в ходе поиска внутри группы ключ должен найти соответствующее ему место. Очень часто метод перемешивания создает только группу адресов, из которой начинается поиск. При наличии очень хорошей функции сортировки по эффективности сор¬ тировка вычислением адресов равноценна однопросмотровому распределению. Однако, по мере того, как эта функция становится все менее и менее точной, этот метод приближается к методу вставки. При вычислении адресов ста¬ раются подобрать хорошую начальную точку для поиска места на основе не относительного значения, а отображения позиции. *) Имеется в виду отбрасывание младших разрядов результата. (Прим. иерее.) **) В отечественной литературе для этого понятия также используются ТеРмины «хеширование» и «функция расстановки». (Прим. перев.) 1001-2000 | 9001 -9999
144 ГЛ. 10. РАСПРЕДЕЛИТЕЛЬНЫЕ СОРТИРОВКИ 10.5.2. Поиск. На рис. 10.21 представлен список из 18 буквенных ключей. Каждая буква преобразуется в номер ее позиции в алфавите. Значение пози¬ ции единиц умножается на 1, значение позиции десятков на 10, значение позиции готен на 100 и т. д. Значения всех букв суммируются. Эта сумма округляется до числа из двух цифр (например, 1570 превращается в 16); в качестве адреса берется целая часть от половины результата. Недостаток такого вычисления адресов в том, что по набору из 18 ключей образуется только 11 разных адресов. Производительность метода перемешивания можно Был ли Список 100 10 1 Значения Адрес * построе ранее MZJ 13 26 10 1570 8 нет VQT 22 17 20 2300 12 » LZV 12 26 22 1482 7 » CXR 3 24 18 558 3 QTR 17 20 16 1916 9 ВАВ 2 1 2 212 1 СМВ 3 13 2 432 2 нет WTM 23 20 13 2613 12 да LVT 12 22 20 1440 7 » VWR 22 23 18 2433 12 » XLR 24 12 26 2546 12 да RVY 18 22 25 2045 10 нет TRV 20 18 22 2202 11 нет QMY 17 13 25 1855 9 да EXL 5 24 12 752 4 нет GQM 7 17 12 883 4 да HVO 8 22 15 1035 5 нет BAR 2 1 18 228 1 да * Адрес вычисляется округлением до ближайшей сотни с последующим делением на 200 для получения целого частного. Рис. 10.21. Преобразование буквенных ключей. увеличить, обеспечив дополнительное пространство памяти для списка вы¬ вода. Когда каждый адрес построен, пытаются разместить элемент. Ключи с MZJ по СМВ можно разместить непосредственно, поскольку адрес каждого ранее не создавался. (Определенная процедура проверяет, пуста ли ячейка с построенным адресом.) Список вывода, изображенный на рис. 10.22 после размещения СМВ, уже упорядочен, хотя и сильно разрежен. Список, расту¬ щий при сортировке вычислением адресов, по мере роста всегда будет упоря¬ доченным. Построение адреса для WTM вызывает трудность, так как ячей¬ ка 12 занята. Эта «коллизия» вынуждает к поиску ячейки для WTM. Значе¬ ния WTM и VQT (в ячейке 12) сравниваются. Поскольку WTM больше VQT, то поиск происходит в свободном пространстве памяти после ячейки 12. Пустая ячейка находится сразу—13. Такой же процесс выполняется для LVT. Ячейка 7 занята; LVT меньше LZV и место для нее находится сразу перед ячейкой 7, в ячейке 6. Ключ VWR обнаруживает VQT в ячейке 12. Он .старается отыскать место за ячейкой 12. Однако ячейка 13, во-первых, занята и, во-вторых, то, что там
10.5. ВЫЧИСЛЕНИЕ АДРЕСА 145 находится» — больше по величине, чем VWR. Этот ключ — WTM — надо пере¬ местить так, чтобы VWR можно было разместить в 13. Таким образом, после того, как элемент размещен, возможно придется переместить его, чтобы осво¬ бодить место для другого элемента. Размещение WTM включает поиск по свободным адресам, расположенным за тем адресом, из которого он должен быть перемещен. Если подходящий адрес занят, то элемент, который его за¬ нимает, и все элементы между ним и следующей свободной позицией должны быть перемещены. На рис. 10.23 список показан до и после размещения VWR. 1. 2. 3. ВАВ СМВ До размещения VWR После размещения VWR CXR 1. ВАВ ВАВ 4. — 2. СМВ СМВ 5. — 3. CXR CXR 6. — 4. — — 7. LZV 5. — — 8. MZJ 6. LVT LVT 9. QTR 7. LZV LZV 10. — 8. MZJ MZJ 11. — 9. QTR QTR 12. VQT 10. — — 13. — 11. — — 14. — 12. VQT VQT 15. — 13. WTM VWP 16. — 14. — WTM 17. — 15. — — 18. — 16. — — Рис. 10.22. Список 17. — — с рис. 10.21 после раз¬ мещения СМВ. 18. Рис. 10.23. Размещение VWR. Производительность вычисления адресов в основном зависит от частоты перемещения данных, которую можно контролировать в определенных пре¬ делах [6, 22]. Например, можно существенно повысить производительность, увеличив распределяемую память. Большие области памяти увеличивают ве¬ роятность того, что построенный адрес будет уникальным, и что, если колли¬ зия все же возникнет, то вблизи от того места, где она возникла, будет сво¬ бодное пространство. Рассмотрим наш пример с 36 ячейками памяти. Адре¬ сами могут быть усеченные значения из VALUE, но не деленные пополам. Тогда будет только два совпадающих адреса. Коллизий будет меньше, и не¬ обходимость перемещать элементы, когда коллизия все же возникает, умень¬ шится. После завершения распределения в зависимости от требований обра¬ ботки после сортировки может понадобиться алгоритм упаковки некоторых ключей. Размещение элементов, вступивших в коллизию, можно также отло¬ жить до последующего слияния. Применение столь заманчивого метода достойно изучения, если связь между ключами и адресами почти очевидна или легко выводится, либо когда можно выделить много памяти и времени на построение функции сортировки, ее тестирование и разумный анализ ее свойств. Однако случайный пользо- Ватель методов сортировки, вероятно, ограничит его применение ролыо вспо¬ могательного метода (например, в поразрядной сортировке).
146 ГЛ. 11. СРАВНЕНИЕ ВНУТРЕННИХ СОРТИРОВОК Глава 11. СРАВНЕНИЕ ВНУТРЕННИХ СОРТИРОВОК 11.1. Введение На рис. 11.1 представлен список разделов, где обсуждаются характери¬ стики производительности методов, рассмотренных в главах с 3 по 10 этой книги. У Холла [12] руководство для сравнения методов сортировки пред¬ ставляет таблица. Если нужна оценка времени работы сортировки, то эта Обсуждение Метод Г лава производительности Сортировка Шелла 3 3.4, 3.5, 11 Сортировка по дереву САСМ 143 5 5.2.3, 5.2.4 САСМ 245 5 5.3.3, 5.3.4 Центрированная вставка 6 6.4 Двоичная вставка 6 6.4 Быстрая сортировка 7 7.8 Квадратичный выбор 8 8.2.5 Слияния: двухпоточное прямо' 9 9.3.3 двухпоточное естественное 9 9.4.2 естественное 9 9.4.5 Двоичный поразрядный обмен 10 10.2.2 Распределение 10 10.3.2, 10.3.3 Сортировка «двуглавого змея» 10 10.3.7 Сортировка вычислением адреса 10 10.5.2 Рис. 11.1. К проверке производительности. таблица может быть полезной, однако следует иметь в виду следующие огра¬ ничения. 1. При большом слиянии ожидаемое число сравнений и перемещений данных могут выходить за указанную отметку. Даже незначительное смещение в частотности и расстановке может привести к существенным различиям в производительности. 2. Оценки памяти нельзя улучшить за счет элементов программного окру¬ жения или реализации. Использование сортировки с отделенными или неот¬ деленными ключами там, где можно выбирать, характер использования дан¬ ных непосредственно после сортировки, архитектура центрального процессо¬ ра — все это будет влиять на объем необходимой памяти. 3. Различные стили программирования и структуры данных будут влиять на время работы метода сортировки. Элементы организации просмотра, цикла, связи подпрограмм, действия с ключами и подпрограммы перемещения дан¬ ных будут определять, сколько фактически машинного времени тратится на сравнения или перемещения. Разработчик сортировки не должен поддаваться искушению принять ка¬ кой-либо из методов, описанных в этой книге, как единственный метод сор¬ тировки. Разумно всегда исследовать комбинированные методы. Помимо из¬ вестных комбинаций таких, как быстрая сортировка и просеивание, возможны многие другие, которые могут быть полезны в конкретных ситуациях. Любой метод, который постепенно увеличивает или уменьшает размер частей, еле-
11.2. ПРОСТЫЕ ПРИМЕРЫ 147 дует тщательно проверить на предмет разумной «критической точки» пере¬ хода к другому методу с дополнительными характеристиками. Очень быстрые сортировки для малых списков с каким-нибудь неизвестным упорядочением могут использоваться в комбинации с эффективным методом для случайных данных с большим N. Помимо поиска комбинации аналитику или программи¬ сту никогда не следует пренебрегать возможностью самому создать новый и лучший метод сортировки. 11.2. Простые примеры Для того чтобы лучше ощутить работу различных сортировок с разными данными, некоторые из сортировок, приведенных в приложении, «прогоня¬ лись» со списками данных разной длины и разными характеристиками. Чита¬ теля может заинтересовать цель и направление усилий в качестве миниатюр¬ ной модели того, что можно было бы предпринять, чтобы выбрать метод сортировки для разных данных. 11.2.1. Выбор сортировки. Процедуры на PL/1 были созданы для следую¬ щих алгоритмов: 1. Сортировка строк (естественное двухпоточное слияние). 2. Быстрая сортировка. 3. Сортировка Синглтона. 4. Сортировка Флойда по дереву. 5. Вариант Хиббарда сортировки Шелла. 6. Вариант Бутройда сортировки Шелла. 7. Челночная сортировка. Все эти алгоритмы были опубликованы и, кроме версии Хиббарда сор¬ тировки Шелла, напечатаны в СЛСМ*). Процедуры на PL/1, приведенные в приложении, следуют версиям, опубликованным на алголе. Эти программы сортировки, очевидно, неэффективны вследствие того, что в основном эти программы создавались для демонстрации и объяснения. На¬ пример, формальные вызовы процедур достаточно дороги в алголе и PL/1, и их использование было бы неестественно при кодировке указанных сортиро¬ вок. Однако этот факт не влияет на эксперимент, поскольку мы исследуем процедуры, реализующие методы, а не методы сами по себе. Это различие важно при оценке методов, которые примерно одинаково характеризуются по числу перемещений данных и сравнений. При исследовании самих методов надо было бы программировать так, чтобы во всех программах использовался унифицированный стиль использования подпрограмм и т. д. Семь выбранных сортировок реализуют только пять разных методов. Сортировка строк является естественным двухпоточным слиянием, опреде¬ ляющим начальные строки из разных концов списка. Она описана в главе 9. скоренная быстрая сортировка — это версия быстрой сортировки, опублико- Ванной в виде алгоритма 271 в С ACM. Она использует среднее значение части Данных как основу. Сортировка Синглтона, опубликованная как алгоритм в С ACM, является составной сортировкой, в которой используются *■) САСМ — Communications of the Association for Computer Machinery.
148 ГЛ. 11. СРАВНЕНИЕ ВНУТРЕННИХ СОРТИРОВОК просеивание для коротких частей и быстрая сортировка для более длинных частей. Используемая здесь критическая точка предложена Синглтоном, — де¬ сять элементов. Возможно, стоит поэкспериментировать с этой точкой. Важ¬ ной чертой этого метода является начальный подбор медианы в качестве основы порции данных. В том же духе как варианты одного и того же метода рассматриваются две версии сортировки Шелла. Они намного ближе друг к другу, чем две указанные версии быстрой сортировки, поскольку они одинаковы в обработке критического параметра — расстояния между элементами в течение каждого просмотра. Они различаются только в организации списка и управлении про¬ смотром. Сортировка Флойда по дереву не представляет оптимальную форму тур¬ нирной сортировки, поскольку турнир, не использующий вспомогательную адресную память, не будет столь эффективен, как метод, использующий эту память. Однако сортировка Флойда является любопытным минимальным по памяти алгоритмом. Сортировка Шелла включена в этот список, как наилуч¬ ший из «основных» методов — вариант просеивания. Включение этого метода дает образец, который позволяет судить о значении улучшений «новых» спо¬ собов (особенно сортировки Шелла). 11.2.2. Данные. Эти сортировки прогонялись со списками данных трех размеров—100 элементов, 1000 элементов и 5000 элементов. В каждом слу-' чае единичным элементом данных была 32-битовая запись «в одно слово», в котором запись и ключ были одинаковыми. Каждая сортировка, каждый список прогонялись с данными, имеющими следующие характеристики: 1. Случайность: список был построен при помощи RANDU — стандартного генератора случайных чисел, имеющегося в библиотеке SSP IBM 360. 2. Повторяемость: в данных есть устойчивая тенденция к повторяемости. 3. Упорядоченность: список уже упорядочен. 4. Чередование: четные элементы образуют возрастающую строку, нечет* ные — убывающую. 5. Отсортированность по половинам: первые N/2 элементов и последние NJ2 элементов были отсортированы. Проверка на повторяемость определяет чувствительность к дублирова¬ нию, порядку и рабочей длине. Проверки на чередуемость и отсортирован¬ ность по половинам определяют чувствительность к рабочей длине и по¬ рядку. Это только два из многих способов, которыми в файле можно пред¬ ставить неслучайность. Они приведены здесь как пример чувствительности, которую можно искать при тестировании алгоритма сортировки. 11.2.3. Проверки. Для сравнительных прогонов отобранных алгоритмов использовалась система IBM 360/50, с операционной системой OS/360 Re¬ lease 21 и версией PL/1 5—1. Все прогоны выполнялись на «пустой» машине (т. е. не в мультипрограммном режиме), так что можно было подсчитать все различия между временем центрального процессора и общим затраченным временем. Каждая из семи отобранных сортировок была связана с драйвером, кото¬ рый выполнял следующие функции в следующей последовательности:
11.2. ПРОСТЫЕ ПРИМЕРЫ 149 1. Вызов генератора случайных чисел для построения 100 чисел. 2. Вызов сортировки для упорядочения построенных чисел. 3. Вызов сортировки для упорядочения упорядоченного списка, создан¬ ного на шаге 2. 4. Построение «располовиненных» данных, меняя местами нижнюю и верхнюю половины упорядоченного списка. Вызов сортировки для упорядоче¬ ния этого списка. 5. Построение чередующихся данных путем перестановки чисел с нечет¬ ными номерами. Вызов сортировки для упорядочения этого списка. 6. Вызов генератора случайных чисел для построения списка с усиленным дублированием путем сужения диапазона значений ключей до половины по¬ строенных значений. Вызов сортировки для упорядочения этого списка. 7. Повторение шагов 1—6 для 1000 чисел. 8. Повторение шагов 1—6 для 5000 чисел. При помощи встроенной в PL/1 функции TIME для каждого вызова за¬ писывалось время входа и выхода из сортировки. Общее время и время центрального процессора отличались на величину, необходимую для обра¬ ботки прерываний по истечении кванта времени*), возникающих через каж¬ дые 200 мс. Поскольку эта микросекундная задержка возникает пять раз в секунду, ее воздействие минимально и легко учитывается в результате. 11.2.4. Результаты. В таблице на рис. 11.2 приведены результаты прого¬ нов названных алгоритмов. Еще раз предупреждаем читателя, что эта таб¬ лица отражает только относительную производительность запрограммирован¬ ных алгоритмов на описанных данных. Можно указать некоторые общие вы¬ воды об эффективности, присущей каждому из этих методов при сортировке признаков, но для того, чтобы эти выводы были квалифицированными, необ¬ ходимо детально рассматривать сами программы. Использование обращения к процедурам, как в сортировке по дереву (TREESORT 3), безусловно, уве¬ личивает время работы программы и является единственным примером зави¬ симости от кодировки и компиляции. Каждый элемент таблицы нормализован так, чтобы основная единица времени (1.0) равнялась времени, необходимому версии Синглтона быстрой сортировки для упорядочения 100 случайных чисел. Все остальные указанные времена являются множителями этой величины. Например, алгоритм Сингл¬ тона требует в 14 раз больше времени для упорядочения 1000 случайных чи¬ сел, чем для упорядочения 100 чисел. Челночная сортировка для упорядоче¬ ния 1000 случайных чисел расходует в 721.8 раза больше времени, чем сортировке Синглтона нужно для упорядочения 100. Просмотр показателей, относящихся к одному методу, позволяет оценить эффективность этого метода для разных состояний данных с заданным чис¬ лом элементов. Например, при 100 элементах версия Синглтона, по-видимому, не чувствительна к повторяемости, но реагирует как на полностью упорядо¬ ченный, так и на чередующийся список. *) Средство, позволяющее предотвратить «захват» центрального процес¬ сора одной задачей. По истечении кванта времени процессор освобождается и становится доступным другой задаче. (Прим. перев.)
150 ГЛ. 11. СРАВНЕНИЕ ВНУТРЕННИХ СОРТИРОВОК Просмотр показателей «сверху-вниз» позволяет оценить (1) относитель¬ ную эффективность каждого метода при различных значениях N и (2) отно¬ сительную эффективность самих методов. Например, версия Синглтона сор¬ тирует список из 5000 случайных элементов в 85.7 раза дольше, чем список из 100 случайных элементов. Челночная сортировка сортирует 5000 случайных Исходный список: N случай¬ ный упоря¬ дочен¬ ный упорядо¬ ченный по половинам чере¬ дую¬ щийся с по¬ вторе¬ нием Сортировка Синглтона 1 100 1-0 0.7 0.9 0.7 1.0 (САСМ 347) 1000 14.0 7.3 8.8 8.5 14.0 5000 85.7 43.2 52.5 49.2 84.4 Ускоренная сортировка 1 100 1.3 0.8 1.3 0.8 1.3 (САСМ 271) 1000 18.8 13.8 16.2 13.3 20.5 5000 121.1 73.2 91.5 75.4 120.3 Древовидная сортировка 2 100 2.6 2.7 2.6 2.5 2.5 (САСМ 245) 1000 34.3 37.9 36.2 36.5 36.3 9000 220.8 230.8 222.5 221.9 220.7 Сортировка Бутройда 3 100 2.0 1.0 1.7 1.5 1.8 (САСМ 201) 1000 36.9 6.5 24.0 24.8 35.7 5000 270.3 105.8 159.0 152.5 266.7 Сортировка Хиббарда3 100 2.2 1.3 2.6 2.6 2.5 (опубл. в САСМ 6, 1000 32.3 20.8 36.2 36.5 36.3 май 1963) 5000 509.0 131.8 222.5 221.9 220.7 Сортировка строк 4 100 4.7 2.7 2.8 4.7 4.7 (САСМ 207) 1000 58.7 26.0 29.7 58.0 58.7 5000 354.6 129.9 148.3 347.8 354.5 Челночная сортировка 100 7.0 0.3 7.3 7.3 6.7 {САСМ 175) 1000 721.8 1.8 726.1 725.5 712Д 5000 18 375.5 9.0 18 120.6 * * 1 Вариант быстрой сортировки. 4 Слияние. 1 Турнирная сортировка. 5 Просеивание. 3 Вариант сортировки Шелла. * Не получено. Рис. 11.2. Относительные скорости сортировки. элементов более чем в 1600 раз (11837.5/7) дольше, чем список из 100 слу¬ чайных элементов. На рис. 11.3 указан список методов, упорядоченных по «эффективности», которая определяется делением нормализованного времени сортировки слу¬ чайного списка на N и умножением на 100. Результат дает нормализованное время, необходимое каждому методу на обработку одного элемента. Этот список показывает, что каждый метод эффективнее для малых N (N = 100 и данные случайны), но некоторые методы и при N= 1000 эффективнее, чем другие при N = 100. По рис. 11.2 и 11.3 можно сделать наряду с другими следующие выводы: 1. Никогда не используйте простое просеивание для очень больших слу¬ чайных списков. Используйте этот метод только тогда, когда есть основания ожидать почти полного упорядочения с самого начала. 2. Методы можно закодировать так, чтобы они были нечувствительны к повторяемости. Только программа Хиббарда сортировки Шелла существенно
11.2. ПРОСТЫЕ ПРИМЕРЫ 151 реагирует на увеличение повторяемости, используйте это свойство при боль¬ ших N. 3. Различные кодировки одного и того же метода будут вести себя по- разному. Обратите внимание на разницу между версиями Бутройда и Хиб¬ барда сортировки Шелла при 5000 случайных элементах. 4. Методы проявляют различную чувствительность к разным характери¬ стикам данных. Например, сортировка по дереву (TREESORT 3) и сортиров¬ Метод Размер Время на один Номер списка элемент 1. Сортировка Синглтона 100 1.00 2. Ускоренная сортировка 100 1.30 3. Сортировка Синглтона 1000 1.40 4. Сортировка Синглтона 5000 1.71 5. Ускоренная сортировка 1000 1.88 6. Вариант Бутройда сортировки Шелла 100 2.00 7. Вариант Хиббарда сортировки Шелла 100 2.20 8. Ускоренная сортировка 5000 2.42 9. Сортировка по дереву TREESORT 3 100 2.60 10. Сортировка по дереву TREESORT 3 1000 3.43 11. Вариант Бутройда сортировки Шелла 1000 3.59 12. Вариант Хиббарда сортировки Шелла 1000 4.23 13. Сортировка по дереву TREESORT 3 5000 4.41 14. Сортировка строк 100 4.70 15. Вариант Бутройда сортировки Шелла 5000 5.40 16. Сортировка строк 1000 5.87 17. Челночная сортировка 100 7.00 18. Сортировка строк 5000 7.09 19. Вариант Хиббарда сортировки Шелла 5000 10.18 20. Челночная сортировка 1000 72.18 21. Челночная сортировка 5000 367.51 11.3. Классификация методов по эффективности при сортировке случг ного списка чисел. ка Шелла не реагируют в противоположность другим методам на отсорти- рованность списка по половинам. С другой стороны, построчная сортировка не реагирует на чередование в списке. Плохая производительность сортировки по дереву (TREESORT 3) и сор¬ тировки строк удивляет так же, как и разница в производительности между реализациями Хиббарда и Бутройда (САСМ 201) сортировки Шелла. Воз¬ можным объяснением такого поведения построчной сортировки является то, что она выбирает строки из начала и конца списка. Такой выбор не является хорошим для этого метода, поскольку нельзя получить длинных естественных строк из нижней части списка. Производительность сортировки по дереву (TREESORT 3) может умень¬ шаться из-за обращения к процедурам. Различия между двумя формами сор¬ тировки Шелла могут возникать из-за разницы в выражениях, используемых Аля вычисления расстояния, или из-за разной чувствительности к упорядоче¬ нию и повторяемости. Анализ этих алгоритмов не является целью данной главы. Техника эксперимента, полученные результаты и возникшие вопросы лишь подчеркивают те предупреждения (о сравнении сортировок), какие были сделаны в гл. 1 и в начале этой главы.
Часть II ВНЕШНЯЯ СОРТИРОВКА Глава 12. ЭТАП СОРТИРОВКИ ПРИ ВНЕШНЕЙ СОРТИРОВКЕ 12.1. Внешняя сортировка Когда список сортируемых данных слишком велик, чтобы поместиться в основной памяти, забот у разработчика сортировки существенно прибавляется. Проблемы возникают, начиная с написания хорошей подпрограммы и до определения правильного равновесия между программой в целом и всеми сопутствующими характеристиками ввода-вывода, центрального процессора, разбиения на блоки и буферизации, передачи данных между компонентами программы. Эффективность процесса сортировки должна измеряться общим количеством времени, необходимого для чтения, сортировки и записи всех эле¬ ментов данных, поскольку собственно алгоритм упорядочения определяет время лишь частично [4]. Наиболее общей формой внешней сортировки является сортировка-слия¬ ние. Сущность этой процедуры составит содержание этой и последующих глав. Альтернативой является распределительная сортировка, использующая устройства, как указывалось в главе 10. Будущее, возможно, положит конец явным внешним методам благодаря использованию «виртуальной памяти», ко¬ торая рассматривается в главе 20. 12.2. Сущность сортировки-слияния Процесс сортировки-слияния состоит из двух основных этапов — этапа сортировки и этапа слияния [18]. Этап сортировки обычно выполняется пер¬ вым, чтобы распределить частично упорядоченные записи по семейству лент или областей на дисках, которые потом последовательно обеспечат вход для слияния. На этапе сортировки (или распределения) за один раз читается столько данных, сколько может поместиться в имеющейся памяти, после чего в па¬ мяти некоторым способом строятся упорядоченные строки данных. Эти строки переписываются из памяти в соответствии с алгоритмом распределения, соз¬ данным специально под нужное слияние. В большинстве алгоритмов все дан¬ ные просматриваются на этапе сортировки до слияния. В начале слияния есть семейство строк, распределенных по устройствам. Последующее слияние формирует единую упорядоченную строку. На рис. 12.1 графически пред¬ ставлен весь этот процесс.
12.2. СУЩНОСТЬ СОРТИРОВКИ-СЛИЯНИЯ Назначение этапа сортировки — сократить число просмотров слияния. Зтап сортировки связан с внешним слиянием так же, как предварительная внутренняя сортировка связана с внутренним слиянием. На операцию слия¬ ния влияют следующие характеристики этапа сортировки: 1. Число строк, созданных на этапе сортировки. 2. Длина строк и все ли они имеют одинаковую длину. Просмотр Ввод сортировки Вывод с? « Случайный ввод» Просмотр слияния Упорядоченные страны от < Q- сортировки Упорядоченные строки от первоао просмотра слияния У пор я до ченныв строки от предыдущего просмотра слияния Сорти¬ ровка “П 1 -о -о -о Упорядоченные строки распределены по т устройствам 1/т упорядоченных строк в т раз большей длины 1/т упорядоченных строк в /7? раз большей длины > 1 строка Рис. 12.1. Процесс сортировки-слияния. 3. Характеристики разбиения на блоки тех данных, которые были запи¬ саны при сортировке. 4. Распределение строк по устройствам, объем памяти на устройствах, карактеристики каналов. Основная цель разработки сортировки-слияния — уравновесить время эта¬ пов сортировки и слияния так, чтобы минимизировать время работы всей про¬ цедуры упорядочения. Эта цель не всегда достигается оптимизацией либо этапа слияния, либо этапа сортировки. Только анализ сложных взаимосвязей Между характеристиками и требованиями сортировки и слияния даст сба¬ лансированную и эффективную сортировку-слияние. На этапе сортировки могут выполняться разные побочные действия. Обыч¬ ными функциями этапа сортировки являются переупаковка ключей и общее Переупорядочение данных для удобства слияния. Могут вводиться функции,
154 ГЛ. 12. ЭТАПЫ ПРИ ВНЕШНЕЙ СОРТИРОВКЕ которые не связаны с сортировкой. При некоторых характеристиках системы, возможно, следует отступить от концепции эффективности этапа сортировки ради создания программы, которая в качестве результата просмотра данных строит многочисленные строки вывода. Среди таких функций, не относящихся к сортировке, могут быть предварительное редактирование данных и выдача сообщений об ошибках, распечатка данных, распечатка с подсчетом или рас¬ пределение по критерию, не связанному с сортируемыми ключами. Малая эффективность этапа сортировки компенсируется возможностью избежать до¬ полнительных просмотров данных. Ценность этих функций зависит от сущно¬ сти прикладной системы; решения, принимаемые при разработке приложений, выходят за рамки рассуждений, связанных только с эффективностью сорти¬ ровки. 12.3. Элементы этапа сортировки Множество вопросов и взаимосвязей, которые учитываются при разра¬ ботке сортировки, неисчерпаемо. Основными являются следующие: 1. Выбор метода сортировки. 2. Определение алгоритма распределения. 3. Определение метода связи между сортировкой и выводом. 4. Определение метода связи между сортировкой и вводом. 5. Определение распределения памяти для сортировки, ввода и вывода. 6. Определение влияния изменений на шагах 1—5 на время сортировки. 7. Определение влияния изменений на шагах 1—5 на время слияния. Шаги 6 и 7 являются продолжением процесса оценки на шагах 1—5. Вопрос управления памятью, возникающий как таковой на шаге 5, более или менее непосредственно влияет на все шаги и является той точкой, в которой сходятся многие факторы. В разделе 12.4 рассматривается шаг 5, в разде¬ лах 12.5 и 12.6 — шаги 3 и 4, в разделе 12.7 обсуждается шаг 2 и в раз¬ деле 12.8 — шаг 1. Поскольку все факторы взаимозависимы, то комментарии о взаимосвязях между этими шагами даны во всех разделах. 12.4. Управление памятью: число и длина строк Имеющаяся память должна быть разделена между вводом, выводом и сортировкой. На память претендуют: 1. Процедуры сортировки. 4. Области сортировки. 2. Процедуры ввода. 5. Области ввода. 3. Процедуры вывода. 6. Области вывода. Решающими факторами при определении желательного размера области сортировки являются влияние этого размера на длину строки, которая может быть построена, скорость этапа сортировки и воздействие на слияние. Чтобы определить, как длина строки влияет на слияние, необходимо знать степень и «тип» слияния, а также число записей в файле. Эта информация позволит определить, какой длины должна быть строка, чтобы достичь различных уровней слияния. На рис. 12.2 показано количество строк разной длины, по¬
12.4. УПРАВЛЕНИЕ ПАМЯТЬЮ: ЧИСЛО И ДЛИНА СТРОК 155 строенных для трехпоточного слияния 50 000 элементов. Из этого примера следует, что в целях эффективности не обязательно создавать строки макси¬ мально возможной длины. Поскольку количество просмотров при слиянии равно f\og2(NIs) ~\ у где s — длина строки, то строки длины 8 и строки дли¬ ны 20 требуют по 8 просмотров слияния. Для построения строк длины 8 памяти требуется меньше, и ее можно сохранить для того, чтобы с пользой Длина строки Количество строк Количество просмотров 2 25000 10 4 12500 9 8 6250 8 10 5000 8 12 4166 8 14 3570 8 16 3125 8 18 2777 8 20 2500 8 25 2000 7 30 1666 7 40 1250 7 50 1000 7 68 729 6 80 625 6 100 500 6 150 333 6 200 250 6 250 200 5 Рис. 12.2. Длина и число строк, а также число просмотров при сбалансиро¬ ванном двухпоточном слиянии 50 000 элементов. использовать еще где-нибудь в качестве буфера ввода-вывода или рабочей памяти для быстрого не минимального по памяти метода. Точное число сортируемых элементов часто неизвестно, и число создавае¬ мых строк необходимо оценить. Эта оценка является основой для проекти¬ рования сортировки. Нельзя разумно выбрать размер области сортировки без предположения о характеристиках слияния, которые в свою очередь полу¬ чаются из предположений о совокупности строк. Этап сортировки можно спроектировать так, чтобы получать по возмож¬ ности максимально длинные строки или чтобы выполнять его наиболее эффек¬ тивным способом. Максимально длинные строки получаются при минимизации блоков и областей буферизации, что обеспечивает наибольшую область сор¬ тировки. В другом случае, на машине с независимым вводом-выводом, сор¬ тировка может быть «сбалансирована» (оптимизирована по производительно- сти) за счет сокращения памяти под область сортировки, увеличения размера блоков и расширения буферизации. Характеристики машины, влияющие на выбор при проектировании, включают следующее: 1. Время, необходимое для создания строк разной длины при разных алг°ритмах сортировки. 2. Относительные скорости центрального процессора и ввода-вывода, воз¬ можность совмещения их работы.
156 ГЛ. 12. ЭТАПЫ ПРИ ВНЕШНЕЙ СОРТИРОВКЕ 3. Возможность чтения по цепочке малыми блоками (могут ли короткие строки быть связаны позднее?). 4. Реально доступная максимальная степень слияния. Помимо ожидаемых характеристик слияния, размер области сортировки зависит от следующего: 1. Размера записи (сколько записей помещается в памяти? — 8К памяти при 100-символьных записях не равны 8К памяти при 1000-символьных за¬ писях) . 2. Требований алгоритма сортировки (минимальный или не минимальный по памяти метод). 3. Длины строк, которые используются сортировкой (можно ли строить более длинные строки при меньшей памяти?). Некоторые алгоритмы сортировки могут формировать строки, превышаю¬ щие размер области сортировки. Точная длина строки непредсказуема, она зависит от естественного упорядочения в данных. Если не обязательно точно знать длину строки, то можно получить значительный выигрыш, используя алгоритм сортировки, при котором строки могут достигать длин, примерно равных удвоенному числу записей в области сортировки, при этом необходи¬ мая память увеличивается весьма незначительно [7]. 12.4.1. Управление памятью, ввод и вывод. Область памяти, необходимая для ввода и вывода, определяется при выборе метода сортировки и области сортировки. При этом обязательно должны быть учтены следующие фак¬ торы: 1. Характеристики разбиения на блоки как при вводе, так и при выводе. 2. Временная зависимость между сортировкой и вводом-вызодом с точки зрения возможностей эффективного их совмещения при различной глубине и способах буферизации. 3. Время, сэкономленное при оптимизации совмещения на распределяю¬ щем просмотре, равно как и время, потерянное при слиянии из-за более ко¬ ротких строк. Часто размер блока ввода неподвластен разработчику сортировки. Раз¬ мер этого блока определяет объем памяти, необходимой для хранения вводи¬ мых данных, и влияет на пригодность использования буферов при вводе. Размер блоков вывода влияет на использование памяти точно так же, как на ее использование влияет размер блоков ввода. Размер блока вывода определяет пригодность или полезность буферизации, вывода. Число записей определяет, когда можно начинать процесс записи. Длина блока вывода определяется требованиями проекта слияния. Блок, создаваемый на этапе сортировки, должен быть наиболее эффективным для слияния. Наиболее эффективна такая длина блока, которая в рамках разум¬ ных ограничений на производительность устройств ввода-вывода обеспечи¬ вает наилучшее совмещение операций на этапе слияния. Память, выделяемая для ввода и вывода, зависит от относительной ско¬ рости вычислений, чтения и записи на этапе распределения и от характери¬ стик машины. Если в системе, используемой для сортировки, нет возможно¬ стей для совмещения операций, то под сортировку можно отдать всю память. Последовательность действий программы состоит в следующем: ввести дан¬
12.4. УПРАВЛЕНИЕ ПАМЯТЬЮ: ЧИСЛО И ДЛИНА СТРОК 157 ные в память, отсортировать и затем записать сформированную строку, используя удобный для слияния размер блока. Если есть машина с независимым вводом-выводом (впредь мы будем предполагать, что имеем дело с системами, которые могут по крайней мере чнтать-записывать-вычислять), то обязательно возникает вопрос о глубине буферизации. Соотношение скорости сортировки и ввода-вывода определит, каким может быть уровень буферизации, подходящий для данной сортировки. Установление нужного уровня буферизации зависит от того, будет неблаго¬ приятное влияние на длину строки наносить ущерб слиянию или нет.' По¬ скольку память для буферизации выделяют из области сортировки, то строки Ввод Число записей 50 000. Длина записи 100 символов Число записей в блоке при вводе 20 Число блоков 2 500 Размер блока 2 000 символов Время считывания блока 50 мс Вывод Число записей в блоке при выводе 10 Число блоков 5 000 Размер блока 1 000 символов Время записи блока 30 мс Время внутренней обработки Сортировка 80 записей 100 мс Сортировка 30 записей 35 мс Сортировка 20 записей 15 мс| Объем доступной памяти Общий 10 000 Для процедур 2 000 Распределяется 8 000 Рис. 12.3. Конфигурация сортировки 50 000 записей. будут короче и многочисленнее. Если вследствие увеличения совокупности строк потребуются дополнительные просмотры, то это повредит слиянию. Рассмотрим один способ организации этапа сортировки для файла из 50 000 записей, который показан на рис. 12.3. Планируется, что блоки ввода будут содержать по 20, а блоки вывода — по 10 записей. Даны разные вре¬ менные характеристики сортировки и оценки распределяемой памяти. На рис. 12.4 для сортировки выделено 8000 ячеек; совмещение ввода-вывода в системе не используется. Общее время этапа распределения будет равно сУмме времен чтения, записи и вычислений. Схема обработки состоит в сле¬ дующем: четыре блока считываются в память, сортируются и затем записы- вается восемь коротких блоков для слияния. Время, затраченное на обработ- КУ> при которой строятся 625 строк, равно 337,5 с. При другом подходе, показанном на рис. 12.5, память разделяется на Четыре области по 2000 символов. В каждый момент времени сортировка Работает только с одной областью. Другие области доступны для ввода и °Да. Каждый буфер один раз служит в качестве области сортировки,
158 ГЛ. 12. ЭТАПЫ ПРИ ВНЕШНЕЙ СОРТИРОВКЕ а в остальное время — в качестве одной из областей ввода-вывода. Выбор длины 2000 определяется размером блока ввода. Если достижимо полное сов¬ мещение операций, то время всей обработки будет равно наибольшему из времен чтения, записи или вычислений. На рис. 12.5 видно, что наибольшим является Предполагается, что минимальному по памяти алгоритму сортировки до¬ ступно 8000 символов (80 записей). Время чтения: 2500 блоков по 50 мс на каждый = 125с Время записи: 5000 блоков по 30 мс на каждый = 150 с Время сортировки: 625 строк из 80 записей по 100 мс на каждую строку = 62,5 с 337,5 с Ввод | | | I | | м Сортиродка |—| Запись I—I—I -f- Н Нет совмещения ввода-вывода, 625 строк из 80 записей обработано за 837,5 с. Рис. 12.4. Сортировка 50 000 записей в 8000 ячейках. Предполагается, что минимальному по памяти алгоритму сортировки вы¬ делена 2000-символьная область. Три другие 2000-символьные области заре¬ зервированы для буферизации ввода-вывода. Время чтения: 2500 блоков по 50 мс на каждый = 125 с Время записи: 5000 блоков по 30 мс на каждый = 150 с Время сортировки: 2500 строк из 20 записей по 15 мс на каждую строку =37,5 с Время работы (если время записи непрерывно) =150 с 1 2 3 4 5 6 Ввод | 1 | 1 1 1 1 12 3 4 5 Сортиробка | 1 1 - -f.—| 1 12 3 4 Запись | 1 1 1 1 Замечание. Числа над сегментами представляют отдельные стро¬ ки. Строка 1 записывается, пока строка 2 сортируется и т. д. За 150 с про¬ изводится 2500 строк записей по 20 записей каждая. Рис. 12.5. Сортировка записей в четырех областях по 2000 ячеек. время записи. Если процесс записи всех блоков может выполняться непре¬ рывно, т. е. без периодов времени, когда записывать нельзя, то вся обработка будет занимать 150 с. Если же при записи будут задержки, вызванные при¬ остановками записывающего просмотра, то обработка займет больше времени. На рис. 12.4 и 12.5 представлены диаметрально противоположные с точки зрения совмещения операций чтение-запись схемы. Первая строит минималь¬ ное число строк ценой потери совмещения; последняя строит намного больше строк, но достигает равновесия ввод-вывод-центральный процессор на этапе
12.4. УПРАВЛЕНИЕ ПАМЯТЬЮ: ЧИСЛО И ДЛИНА СТРОК 159 сортировки. Если 187 с, сэкономленных на рис. 12.5, не будут потеряны, т. е. слияние дополнительных строк потребует не более 187 с, то схема на рис. 12.5 лучше. На рис. 12.2 показано (для трехпоточного слияния) 8 просмотров 2500 строк и 6 просмотров 625 строк. Время каждого просмотра слияния определит, займут дополнительные просмотры слияния 187 с или нет. 12.4.2. Выравнивание производительности буферизацией. Схема чередую¬ щихся областей буферизации, описанная в связи с рис. 12.5, является весьма гибким и широко распространенным способом буферизации. Способность си¬ стемы буферизации динамически перераспределять области памяти между функциями на основе их текущей потребности, является важным свойством. На рис. 12.6 показаны различные способы использования буферов. Каждая перестановка А, В, С эквивалентна любой другой. Истинное влияние буферизации проявляется тогда, когда отдельные функ¬ ции различаются по времени. Время для чтения или записи блока на магнит¬ ную ленту обычно одно и то же, но время для сортировки списка записей Буфер 1 2 3 4 (A) R R S W R — чтение (B) R S W W S —сортировка (C) R S S W W —запись Рис. 12.6. Различные допустимые схемы буферизации. почти всегда разное. Если время, необходимое для сортировки элементов, определяется методом с ожидаемым числом сравнений 1.4 P°g2 W| и макси¬ мальным числом сравнений N(N—1)/2 (например, для упорядоченного спи¬ ска при быстрой сортировке), то время сортировки может возрастать вдвое даже при списках умеренной длины. Сортировка некоторых блоков будет за¬ нимать больше времени, чем их чтение или запись. Если это действительно так, то этап сортировки становится критичным по вычислениям. Если сортировка блока (или блоков) требует много времени, то ввод новых блоков может быть задержан из-за отсутствия свободного буфера ввода. Считывание блоков будет приостановлено до тех пор, пока сортировка не освободит буфер. В свою очередь продолжение сортировки будет задер¬ жано из-за отсутствия в памяти блоков для сортировки. Когда процесс за¬ писи окончен, совместная задержка чтения и сортировки может привести к отсутствию блока, пригодного для записи, и процесс записи должен будет ждать до тех пор, пока таковой не появится. Если процесс записи является ограничивающим фактором, то его время ожидания прибавляется к общему времени, затраченному на обработку. Стратегия буферизации состоит в опре¬ делении числа буферов и распределении их таким образом, чтобы минимизи¬ ровать задержки. Например, добавив буферов ввода, можно избежать задер¬ жек сортировки и записи и, следовательно, существенно повлиять на время обработки. Однако, увеличение числа буферов должно быть оправдано, по¬ скольку это может сократить размеры буфера и области сортировки. Схема чередующихся буферов эффективна при любом их числе. Суще- У*от другие схемы, в которых определяется конкретное число буферов боче?’ конкРетное число буферов вывода, а оставшаяся память считается ра- и областью. При такой буферизации с фиксированными функциями
160 ГЛ. 12. ЭТАПЫ ПРИ ВНЕШНЕЙ СОРТИРОВКЕ элементы физически перемещаются между буферными областями через рабочее поле. Это увеличивает время внутренней сортировки, поскольку теперь оно включает физическое размещение записей в области сортировки. Стоит ли использовать чередующуюся буферизацию или же буферизацию с фиксированными функциями — здесь решающим является вопрос о коли¬ честве буферных областей. Как правило, используются два буфера для ввода, два для вывода и некоторая рабочая область, однако это не гарантирует отсутствия задержек или «сбалансированности» этапа сортировки. 12.5. Взаимосвязь сортировки и вывода При обсуждении управления памятью мы делали некоторые предполо¬ жения о характеристиках сортировки и данных, пересылаемых между обла¬ стями ввода, вывода и сортировки. До сих пор единицей обмена между вво¬ дом-выводом и сортировкой был блок. Области сортировки определялись как блоки или как совокупности блоков, и сортировка «выпускала» полностью от¬ сортированные строки в область вывода в конце сортировки. Но единица об¬ мена является конструкторским решением, одним из аспектов взаимосвязи между сортировкой и вводом-выводом. Некоторые сортировки последователь¬ но увеличивают упорядоченный список (например, сортировки выбором дей¬ ствуют так, а быстрая сортировка—нет). Если сортировка имеет такую ха¬ рактеристику, то можно пересылать данные из области сортировки в область вывода до того, как список будет упорядочен полностью. Когда элемент об¬ работан*), его всегда можно переслать в область вывода. Сглаживающий эффект буферизованной операции усиливается тем, что пересылка записей область вывода зависит не от скорости упорядочения всего блока или обла¬ сти сортировки (строки), а только от скорости определения места одного эле¬ мента в упорядоченной строке. Запись (а не блок или буфер) как единицу обмена наиболее естественно рассматривать в случае фиксированного назначения буферов. Естественный механизм взаимодействия — это физическая пересылка записи из области сортировки в область вывода. Однако, использовать именно этот механизм не обязательно. Архитектура подсистемы ввода-вывода может обеспечивать дру¬ гой способ. Поле памяти, выделенное для ввода-вывода, не обязательно должно быть сплошным. На уровне записей могут использоваться разновид¬ ности чередования буферов. Адреса обработанных элементов, пригодных дня вывода, могут быть записаны в накопительный список. Блок вывода сформи¬ рован, когда в этом списке накопится достаточно элементов. Программа вы¬ вода под управлением накопительного списка собирает записи из разных ячеек памяти и образует на некотором устройстве непрерывный блок вы¬ вода. Когда процесс записи закончен, ячейки, ранее занимаемые записями, освобождаются от сортировки. пере \ еСТЬ к0Г,Д'а опРед'елено его место в упорядоченной строке. (Прим‘
12.6. ВЗАИМОСВЯЗЬ СОРТИРОВКИ И ВВОДА 161 12.6. Взаимосвязь сортировки и ввода Единицей обмена между вводом и сортировкой также может быть блок, несколько блоков или отдельная запись. Интерфейс между вводом и сорти¬ ровкой особенно интересен потому, что он связан с длиной строки и способом сортировки, известным как замещение. Сортировки выбором обрабатывают элементы по порядку по одному за один раз. Если вместо того, чтобы за¬ менять победителя фиктивной величиной или укорачивать список, программа заменяет этого победителя новым элементом, то число элементов в строке может быть больше числа элементов в области сортировки. В. этом случае Область ввода 15 15 16 17 18 19 20 Область сортировки Область быдода 27 13 14 25 17 15 Рис. 12.7. Элементы из входного блока заменяют победителей по мере их выбора. единицей обмена между вводом-выводом и сортировкой обязательно бывает элемент, а не блок. На рис. 12.7 показана область сортировки, содержащая 20 записей, после того, как она заполнена первый раз. Буферная область /2 содержит записи блока ввода; буферная область Л получает новый блок ввода. Области Wi u ^2 предварительно пусты. Сортировка выбирает ключ 1 из позиции 11 как наименьший в списке и Пересылает соответствующую запись в область Wi. Позиция, освобожденная 0т записи с ключом 1, теперь заполняется некоторой записью из буфера вво¬ да. В эту только что освобожденную позицию из буфера ввода пересылается Следующая доступная запись — первая запись в /2. Следующий цикл сорти- Р°вки обрабатывает преобразованный список. Для пересылки в Wi будет выбрана запись с ключом 2. Эта запись будет заменена в ячейке 7 следующей 3аписыо из буферов I — записью с ключом 4. б Г. Лорин
162 ГЛ. 12. ЭТАПЫ ПРИ ВНЕШНЕЙ СОРТИРОВКЕ Теперь единицей обмена между вводом и сортировкой стала запись. Форма обработки строки 5, пока считываются блоки строки S + 1, нарушена, а обработка строки и ввод-вывод для нее могут идти параллельно. Нет такого продолжительного промежутка времени, чтобы функция сор¬ тировки была «закрыта» для связи. Если сортировка на рис. 12.7 хорошо сбалансирована, то когда бы запись ни пересылалась на выход, для нее всегда есть замена в буфере, и когда бы ни заканчивался процесс записи, всегда имеется буфер, наполненный готовыми записями. Размеры блоков ввода и вывода не связаны с размером области сорти¬ ровки потому, что единицей обмена является запись. При этом, хотя длина строки и связана с размером области сортировки, но вследствие замен она не равна количеству элементов в этой области. Физическая пересылка записей из буфера ввода в область сортировки может быть заменена на «чтение вразброс», аналогичное процессу «накопи¬ тельной записи». В каждый-момент времени список свободных ячеек для ввода и список ячеек области сортировки динамически определяют область ввода и область сортировки. Когда процесс записи закончен, его список мож¬ но сделать доступным в качестве списка считывания. Как и в случае естественного слияния, необходимо обеспечить, чтобы эле¬ мент, слишком маленький для данной строки, не попал в эту строку. Допу¬ скается, чтобы наименьший элемент в области сортировки был меньше по¬ следнего элемента в строке вывода. Есть метод, который связан со старшим разрядом всех ключей. Этот разряд можно установить так, чтобы изъять эти ключи из текущей строки. Установка этого разряда происходит при поступле¬ нии элемента в область сортировки и при условии, что этот элемент меньше элемента, расположенного в данный момент в конце строки. Все элементы с таким значением старшего разряда не используются при выборе элементов для текущей строки. Процесс построения строки продолжается до тех пор, пока в области сортировки все элементы не станут непригодными. Тогда по¬ строение старой строки прекращается, значение старших разрядов изменяется, и начинается построение новой строки. Длина строки зависит от доли посту¬ пающих элементов, которые меньше предшествующих ключей. Чем больше область сортировки, тем больше допустимое отклонение малых ключей. Таким образом, длина строки зависит от размера области сортировки. При сортировке с заменой получаемые строки, очевидно, будут неодина¬ ковой длины. Будет некоторый разброс длин строк около предполагаемой длины, равной удвоенному числу элементов в области сортировки. Изменение длины строк не будет отрицательно влиять на слияния на лентах и некото¬ рые слияния на дисках, они могут работать очень хорошо даже и с более длинными строками. Некоторые слияния на дисках, однако, не допускают изменений длины из-за трудностей при распределении памяти (см. сортировка выбором с заменой, раздел 12.8). 12.7. Распределение Среди прочего на этапе сортировки необходимо определить схему разме¬ щения строк по устройствам. Характер алгоритма сортировки определяется видом и количеством устройств, используемых для слияния, возможностями
12.7. РАСПРЕДЕЛЕНИЕ 163 передачи данных (структурой каналов) системы и тем, имеют ли строки оди¬ наковую длину. Распределение строк на ленте при любой схеме слияния заданной степени включает выбор устройств ввода-вывода для получения строк в соответ¬ ствии с назначениями данного слияния. Есть два основных типа алгорит¬ мов — сбалансированные и несбалансированные. Сбалансированное распреде¬ ление размещает равное количество строк на каждой ленте или области диска (барабана). Несбалансированное распределение размещает строки так, чтобы достичь «идеального уровня». Понятие идеальных уровней будет описано в связи с каждым типом несбалансированного слияния; в общем случае, иде¬ альный уровень — это такое распределение строк, которое позволит несбалан¬ сированному слиянию работать без изменения алгоритма слияния от просмо¬ тра к просмотру. Сбалансированные слияния являются горизонтальными; несбалансирован¬ ные слияния бывают либо горизонтальными либо вертикальными. Горизон¬ тальное распределение размещает нужное число строк на каждом устройстве, последовательно перебирая устройства, так что каждое устройство постепенно приближается к своей цели. Вертикальное распределение сначала приводит одно устройство к его цели, затем другое и т. д. по очереди. Последователь¬ ные строки, как правило, записываются на одно и то же устройство. Произ¬ водительность горизонтального или вертикального распределения частично за¬ висит от характеристик машины, связанных с очень специальными деталями компонент конфигурации подсистемы ввода-вывода. Например, на машине, которая может выполнять запись параллельно, горизонтальное распределение может записывать первые блоки одной строки совместно с записью послед¬ них блоков другой. Встречаются системы, на которых последовательные процессы записи на одно и то же лентопротяжное устройство или с одним и тем же синхрониза¬ тором включают небольшие задержки. На таких системах переключение лент может устранить эту задержку. Однако, есть системы, на которых последо¬ вательные процессы записи протекают быстрее из-за отсутствия старт/стопных операций между этими процессами; на таких системах увеличение количества блоков, записываемых последовательно на одну и ту же ленту, будет пре¬ имуществом. Огромную важность в отношении горизонтального и вертикального рас¬ пределений при несбалансированных слияниях на лентах представляет степень риска, с которой этот метод может не достичь идеального уровня. Цена, какую придется платить, если этот уровень не будет достигнут, будет ме¬ няться в зависимости от конкретного распределения строк, согласно соответ- ствующей схеме горизонтального или вертикального распределений. Распределение на диске или на барабанах — существенно более сложная процедура нежели распределение на лентах потому, что алгоритм распреде¬ ления в этом случае должен, помимо устройства, выбирать для каждой строки к°нкретное поле памяти на устройстве. н *2.7.1. Изменение и расширение строк. При построении строк фиксирован- Длины специальный механизм разметки начала и конца строки не нужен. 6*
164 ГЛ. 12. ЭТАПЫ ПРИ ВНЕШНЕЙ СОРТИРОВКЕ Для выявления новых строк в системе можно использовать счетчик блоков или счетчик записей, не зависящий от представления самой строки. Если строки разной длины, то нередко, хотя вовсе и не обязательно, после последней записи строки записывается признак конца или признак на¬ чала в начале строки. В другом случае новую строку с ленты можно распо¬ знать путем сравнения записи, поступающей в память с предшествующей записью и принятия требуемых мер к новой записи, если она меньше пред¬ шествующей. Наличие признаков конца строки или их отсутствие определяет возмож¬ ность применения метода распределения, называемого расширением строки. В тех случаях, когда допускаются строки разной длины, можно увеличи¬ вать длину строки, если у нее нет признака конца. При каждом поступлении новой строки ее первая запись сравнивается с последними записями других строк. Если у какой-либо строки последний элемент меньше первого элемента Та Тл Гз Si (9-481) S2 (2-517) S3 (41-119) SW6-211) Se (53-71) Se (16-374) ST (19-55) Sm (23-61) S9 (8-141) Первый элемент новой строки: 57 Рис. 12.8. Расширение строки. новой строки, то для формирования одной удлиненной строки эта строка мо¬ жет быть продолжена за счет конкатенации с новой строкой. На рис. 12.8 указаны три ленты, на каждой по три строки. Первый и последний ключ каждой строки известны. Эти строки распределены горизон¬ тально: Sif S2, S3, S4, S5, S6, S7, S8, So. Первый элемент строки S2 меньше последнего элемента строки Si, а первый элемент строки S3 меньше послед¬ них элементов строк Si и S2; первый элемент строки S4 меньше последних элементов строк Sif S2 и S3, и т. д. Пока ни одну построенную строку рас¬ ширять нельзя. Однако у следующей строки первый элемент будет иметь ключ 57. Если бы не было возможности расширения строк, была бы сфор¬ мирована строка Sio. Однако просмотр последних элементов всех имеющихся строк показывает, что ключ последнего элемента строки S7 меньше 57, и, следовательно, эта строка может быть расширена, а построение строки Sю отложено. Эффективность расширения строки частично ограничена числом «доступ¬ ных» строк. В слиянии, изображенном на рис. 12.8, доступными являются строки S7, Ss и S9. Ни одна другая строка не может быть расширена потому, что она физически недоступна. Если есть несколько подходящих строк (на¬ пример, если бы на рис. 12.8 расширяющим ключом был бы 67, а не 57), то можно расширять первую подходящую строку или строку, у которой раз¬ ность между последним элементом и новым элементом наименьшая. Таким образом, если бы первый новый элемент был бы 67, а не 57, то скорее сле¬ довало бы расширять строку S8, а не S7. Б случае дисков или барабанов, хотя теоретически доступно намного больше строк (все строки равнодоступ¬ ны), стратегия распределения памяти может серьезно препятствовать исполь¬ зованию расширения.
12.8. ХАРАКТЕРИСТИКИ СОРТИРОВКИ 165 12.8. Характеристики сортировки Наиболее широко используемым методом внутренней сортировки, кроме случая очень малой памяти, является выбор с заменой [20]. Этот метод турнирного типа был описан в гл. 5. Каковы же те свойства, которые делают эту сортировку столь привлека¬ тельной? Их список подскажет критерий, который можно использовать при выборе сортировки для окружения, предшествующего слиянию, а также даст описание свойств этого метода. 1. Связь с вводом-выводом. Поскольку данный метод является одним из методов выбором, он обрабатывает по одному элементу на каждом цикле. Следовательно, как время до отсылки элемента на выход, так и время, пред¬ шествующее освобождению позиции в буфере ввода, являются минимальными. Кроме того, поскольку время выбора записи фиксировано и предсказуемо, можно сделать анализ уровней буферизации. 2. Число сравнений. Число сравнений для выбора N победителей (раз¬ местить все элементы файла по строкам в турнире размера F) без учета под¬ готовки турнира приблизительно равно W Pog2/H + Поскольку в дереве есть f log2 F~\ уровней, то выбор элемента-победителя будет включать flog2 F*] сравнений плюс одно сравнение при включении в строку, итого flog2 F“| +1 сравнений для выбора одного победителя. Таким образом, время определения победителя является минимальным не только с точки зрения того, когда он передается на выход, но и с точки зрения продолжительности «цикла». Скорость метода сортировки тем не менее важна для сортировки, пред¬ шествующей слиянию. Желательно, чтобы время построения строки было меньше времени чтения или записи строки для того, чтобы сохранить про¬ смотр критичным по вводу-выводу. 3. Перемещения при сортировке. В течение сортировки запись переме¬ шается только один раз; все остальные перемещения являются перемещения¬ ми признаков или адресов. Однако здесь есть некоторая зависимость от реа¬ лизации. Запись может перемещаться дважды: из буфера ввода в область сортировки и из области сортировки в буфер вывода. С другой стороны, если использовать процесс накопительной записи и чтение вразброс, то записи не будут перемещаться совсем. Если используется схема чередующихся буферов, то область сортировки и память, используемая для представления дерева, располагается в отдельной рабочей области вне области буферизации. 4. Использование памяти. По существу, данный метод является сорти¬ ровкой ключей. Существуют разные способы представления древовидных •структур и организации сравнений в древовидных структурах. Пусть задано определенное количество памяти для области сортировки, из чего необходимо вычесть память для представления турнира. Например, предположим, что Нам выделено 10 000 ячеек на машине, ориентированной на символьную обра- ботку, и даны 100-символьные записи. Турнир из 100 записей уже организо- *ать нельзя. Предположим, что каждый узел дерева представлен двух¬
166 ГЛ. 12. ЭТАПЫ ПРИ ВНЕШНЕЙ СОРТИРОВКЕ адресным пакетом, а длина каждого адреса—три символа, то есть нужна шесть символов. (Эти адреса являются: один — адресом пакета адресов сле¬ дующего уровня, другой — адресом проигравшего на этом уровне.) При этом остается место для турнира только из 94 записей — это довольно незначитель¬ ные накладные расходы для данного метода. (Об организации турнира см. раздел 5.4.1.) 5. Длина строки. Длина строки неопределима и зависит от упорядочен¬ ности в данных. Первая строка, порождаемая выбором с заменой, будет, как правило, длиной 1.7F, последующие строки — 1.9F, ожидаемая длина 2.OF до¬ стигается очень быстро. Для выбора с заменой характерна большая длина строки при небольшом числе сравнений, что и делает его столь интересным и широко популярным [8, 15, 26]. 12.8.1. Выбор сортировки. Рассмотрение характеристик выбора с заменой прояснило сущность этого метода. Однако этот метод не является универ¬ сальным. В случае малой памяти предпочтительными могут оказаться другие Поточность Число строк 23456 1 024 10 7 5 5 4 2 043 11 7 6 5 5 4 096 12 8 6 6 5 Рис. 12.9. Влияние длинных строк. методы. Часто вместо выбора с заменой используются методы двоичной вставки, просеивания и внутреннего слияния. В определенной степени играет роль исторически сложившееся предпочтение, но нашего внимания заслужи¬ вает возможность того, что «очаги сопротивления» могут иметь рациональную основу. Рассмотрим вопрос о числе сравнений при формировании строки. Для строки длиной 20 выбор с заменой выполнит 100 сравнений. Просеивание, если воспользоваться приближением (Л/2 — N)/4, выполнит 95 сравнений. Два¬ дцать — очень небольшое количество элементов в строке, но не для машины, вмещающей 16 000 символов. При малых списках разница в числе сравнений является минимальной, и очень часто издержки, связанные с более сложными методами (такими, как сложные адресные вычисления и управление просмо¬ тром) могут быть неприемлемыми. В случае небольшой памяти использование просеивания вместо выбора с заменой требует тщательного исследования. Вопрос о длине строки может тем или иным образом способствовать ис¬ пользованию выбора с заменой, но есть нокоторые соображения, которые могут сделать этот метод невыгодным. При двухпоточном слиянии выбор с заменой за счет длинных строк может сэкономить один просмотр. Для очень больших файлов это может быть несущественно. Посмотрите на рис. 12.9. Имея 50 000 записей и область сортировки, вмещающую 20 записей, метод без замен построит 2500 строк, метод с заменой — примерно 1250. Эта раз¬ ница сократит количество просмотров с 12 до И, давая экономию менее 10 процентов при двухпоточном слиянии. Если же есть какие-нибудь дополни¬ тельные затраты, связанные с распределением длинных строк, то преимуще¬ ство длинных строк вполне может стать эфемерным. Более того, с ростом
13.1. СБАЛАНСИРОВАННОЕ СЛИЯНИЕ НА ЛЕНТАХ 167 .степени слияния исчезает уверенность, что можно будет сэкономить просмотр. В данном примере, при четырехпоточном и шестипоточном слияниях просмотр сэкономить не удастся. Таким образом, нельзя сделать вывод о том, что вы¬ бор с заменой сокращает время слияния. Бывают случаи, когда характеристики чтения, записи и вычислений не¬ существенны. Несущественность может проистекать из конструкции малой вычислительной системы или из-за того, что ресурсы, выделяемые сортировке, .не обеспечивают параллельного чтения и записи. Эти замечания должны убедить читателя в том, что не надо автомати¬ чески использовать выбор с заменой, несмотря на его прекрасные и важные ■свойства. На малых машинах может заслуживать внимания более простой метод, быстрее (или так же быстро) обрабатывающий небольшие списки без ущерба для слияния. 12.9. Заключительные замечания Среди пользователей обычной причиной создания внешней сортировки яв¬ ляется то, что сортировки, предоставляемые изготовителями или поставщика¬ ми программного обеспечения, неприменимы по тем или иным причинам, свя¬ занным с исходными данными или конфигурацией конкретной вычислительной установки. На создание сортировки-слияния пользователя толкает наличие в его наборе данных характеристик, не допускаемых средствами пакета сорти¬ ровки, или предполагающих использование специальных методов, не преду¬ смотренных в арсенале возможностей пакета. Поэтому создание специальной сортировки может быть целесообразным или даже необходимым. Проект есть все. Часто там, где создаются программы, недооценивают проектирование, а сразу приступают к созданию программы. Эта тенденция «смертельно* опасна при создании сортировки. Проект должен включать не только описание системы, но и обзор возможных альтернатив, и обоснование выбора. При проектировании этапа сортировки для сортировки-слияния чем боль¬ ше можно узнать о слиянии, тем лучше. Если описание слияния можно за¬ кончить до того, как будут приняты окончательные решения об этапе сорти¬ ровки, то задача создания хорошего этапа сортировки значительно облегча¬ ется. Важность знания характеристик устройств, диапазона степеней слияния, размеров блоков и схем слияния подчеркивалась при обсуждении длины строки и производительности, которые можно ожидать от конкретных страте¬ гий управления памяти. Глава 13. СЛИЯНИЕ НА ЛЕНТАХ 13.1. Сбалансированное слияние на лентах Первая строка на рис. 13.1 показывает состояние сортировки-слияния в к°нце распределяющего просмотра. Распределение происходило с ленты 0 на Пол°вину доступных для сортировки лентопротяжных устройств по девять
168 ГЛ. 13. СЛИЯНИЕ НА ЛЕНТАХ строк на каждое. Количество лентопротяжных устройств часто в литературе обозначается через /г, а сбалансированное слияние называется (6/2)-поточным слиянием. Номинальная степень слияния равна /г/2. 27 строк, полученных при распределяющем просмотре, могут быть как разной, так и одинаковой длины. Считается, что они имеют длину L, где L — номинальная длина исходных строк. 27 начальных строк составляют 27L сли¬ ваемых элементов. Окончательная строка, полученная при слиянии, будет строкой длины 27L. Процесс слияния заключается в объединении строк в меньшее число более длинных строк до тех пор, пока не будет получена одна строка, содержащая все элементы. Количество необходимых для этого просмотров разно flog™ S’] , где т — степень слияния, а 5 — число исходных строк. Трехпоточное слияние 27 строк требует log3 27 или 3 просмотров. Просмотр 1 сокращает число строк до девяти. Поскольку длина каждой вновь сформированной строки равна 3L, то девять построенных строк по- прежнему будут содержать 27L элементов исходных строк. Число строк к концу просмотра будет равно следующей меньшей степени «поточности» слия¬ ния, а длина строк будет равна следующей большей степени «поточности» слияния, умноженной на L. На рис. 13.1 показаны 27, 9, 3 и 1 строка на разных этапах; длины строк равны L, 3L, 9L и 27L. Если число исходных строк не кратно степени слияния, то эти отношения являются приблизитель¬ ными. Длина строки в любой момент слияния равна сумме длин всех строк, которые были объединены в эту строку. При трехпоточном слиянии три стро¬ ки объединяются в одну строку. Если строки неодинаковой длины и/или по¬ рядок слияния не постоянен, то, чтобы определить длину строки, получаемую при слиянии, надо просуммировать длины всех сливаемых строк. На рис. 13.2 начальное распределение показано значительно подробнее. Строки записываются на ленты 3, 4 и 5. Каждое число на рис. 13.2 — это номер начальной строки. Первый просмотр слияния объединяет строки 1, 2 я 3 в строку А длины 3L на ленте 0. Аналогично строки 4, 5 и 6 объединяются в строку В на ленте 1, а строки 7, 8 и 9 — в строку С на ленте 2. В конге первого просмотра девять строк с А по /, каждая длиной 3L, будут содер¬ жать все записи на лентах 0, 1 и 2. Ленты 3, 4 и 5 будут пустыми. Распределение новых строк происходит по тому же алгоритму, что и распределение исходных строк. Строки, слитые вместе, являются «следую¬ щими» строками, доступными (в физическом смысле) для головок считывания лентопротяжных устройств. Можно использовать расширение строк и преимУ' щество естественного порядка в данных. Можно построить одну строку мень¬ ше, чем за flogmS"| просмотров, если максимально использовать эти способы на хорошо упорядоченных данных. На рис. 13.3 после каждого номера строки в скобках указаны первый и последний ключи этой строки. «Несчастный слУ' Го 7\ Тл Гз Т\ Т, Просмотр 1 Просмотр 2 Просмотр 3 Ввод — - 9 (L) 9 (L) 9(1) 3 (3L) 3 (3L) 3 (3L) — — — — — - 1 (91) 1 (9L) 1 (9 L) - - 1 (27 L) Рис. 13.1. Итог сбалансированного слияния.
13.1. СБАЛАНСИРОВАННОЕ СЛИЯНИЕ НА ЛЕНТАХ 169 чай» при построении строк: каждая строка на ленте начинается с ключа, пре¬ восходящего последний ключ предшествующей строки на этой ленте. Проверка обнаруживает, что каждая лента содержит одну упорядочен¬ ную последовательность, и что на лентах, действительно, есть только три .строки, а не 27. Слияние, которое распознает «провалы»» и продолжает фор¬ мирование строки до тех пор, пока не будет больше подходящих элементов То тх тг 7з тк г5 • - - - 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 Просмотр 1 А (1, 2, 3) В (4, 5, 6) С (7, 8, 9) - - — D (10, 11, 12) Е (13, 14. 15) F (16, 17, 18) G;(19, 20, 21) Я(22, 23, 24) / (25, 26, 27) Просмотр 2 — - - J {А, В, С) К (D, Я, F) L(G, Н, /) Просмотр 3 — - - М (/, К, L) - - Рис. 13.2. Сбалансированное слияние рис. 13.1 по строкам. Го Тх Tt п Т 4 т5 1 (17-81) 2 (11-91) 3(73-111) 4(86-121) 5(93-171) 6 (136-183) 7(127-141) 8(172-214) 9 (185-212) 10 (149-183) 11 (215-282) 12 (217-281) 13 (197-214) 14 (283-361) 15 (287-311) 16(219-279) 17 (362-380) 18 (371-416) 19 (311-367) 20 (381-411) 21 (448-463) 22 (373-411) 23 (417-511) 24 (469 -510) 25 (521-596) 26 (561-611) 27 (571 -623) Рис.. 13.3. Естественное слияние можно сократить на один просмотр. ^каждая входная лента начинается с ключа меньшего, чем последний эле* мент), может построить одну строку за один просмотр. 13.1.1. Перемотка. В конце просмотра головки считываиия/записи вход¬ ных лент располагаются непосредственно за последним считанным блоком. Головки считывания/записи выходных лент располагаются непосредственно за последнием записанным блоком. Все ленты «размотаны», и в системе, которая читает только в одном направлении, необходима перемотка. Время перемотки между просмотрами слияния различно для разных сортировок и разных си¬ стем. Общее количество времени, необходимое для перемотки, зависит от сле¬ дующих факторов. Г Количество данных на ленте. Разные устройства управления лентами тРебуют разного количества ленты для представления одного и того же ко¬ личества данных. Емкость ленты зависит от плотности упаковки и скорости Перемещения ленты. Разбиение на блоки также влияет на емкость, так как 10110 определяет, какое пространство займут межблочные промежутки.
170 ГЛ. 13. СЛИЯНИЕ НА ЛЕНТАХ Пространство между блоками очень сильно изменяется в зависимости от имеющихся лентопротяжных устройств. 2. Скорость перемотки. Некоторые лентопротяжные устройства перематы¬ вают ленту с такой же скоростью, с какой они пишут или читают, а некото¬ рые могут перематывать с намного большей скоростью. Те устройства, у ко¬ торых есть высокоскоростная перемотка, могут притормозить в некоторый момент и далее перематывать ленту со скоростью чтения/записи. 3. Возможность распараллеливания. При заданном числе лентопротяжных устройств количество устройств, одновременно выполняющих перемотку в разных системах, будет разное. Их число не обязательно будет равно числу устройств, которые могут читать или писать одновременно. В худшем случае за один раз • может перематываться только одна лента. Это означает, что общее время перемоток между просмотрами равно сумме времен всех пере- йоток. На вычислительных системах достаточно часто устройства могут вы¬ полнять перемотку параллельно. Число параллельно выполняемых перемоток изменяется от системы к системе в зависимости от размещения управления перемоткой. Если управление находится в самом лентопротяжном устройстве, то каждое устройство способно независимо выполнять перемотку. Если упра¬ вление перемоткой находится в устройстве управления, и нет специального «двойственного» контура, то устройство управления может перематывать одну ленту. Если управление перемоткой располагается в канале, то на этом ка¬ нале может перематываться одна лента. Если управление находится в цен¬ тральном процессоре, то центральный процессор может перематывать одну ленту. 13.2. Обратное сбалансированное слияние Если лентопротяжные устройства способны читать в обратном направле¬ нии, то необходимость перематывать ленты между просмотрами слияния от¬ падает. В настоящее время обратное чтение является стандартной возмож¬ ностью, и сбалансированное слияние на лентах подразумевает его использова¬ ние. На рис. 13.4 показано распределение 27 строк. Каждая из лент Тз, Г4 и Г5, на которые загружаются выходные строки, установлена так, как показано стрелкой. Ленты Т\ и Г2 при распределении не используются, предполагается, что они находятся в исходном положении в точке загрузки. Лента Г0 уста¬ новлена на конец данных. Статус Го, исходной ленты ввода, представляет особую проблему. Если исходные данные должны быть сохранены (неплохая мера предосторожности), то То должна быть изъята и заменена, если только сортируемый файл не на много меньше по сравнению с емкостью ленты. В этом случае пространство на Г0, расположенное за исходным файлом, можно использовать без опаски (без угрозы «переполнения») для оставшегося слияния. Если лента Г0 долж¬ на использоваться как пустая (исходные данные теряются), ее всегда надо будет перематывать. Это только один пример перемотки при слиянии. Все строки на Тз — Г5 возрастающие, они построены так, что значения ключей элементов возрастают от начала строки к ее концу. Можно построить строку, упорядоченную по убыванию. Если мы поэлементно читаем возра-
13.2. ОБРАТНОЕ СБАЛАНСИРОВАННОЕ СЛИЯНИЕ 171 ■стающие строки в обратном направлении, то можно построить убывающую строку из сливаемых величин. Механизм сравнения, связанный с внутренними .операциями слияния, в качестве победителей выбирает не меньшие ключи, Тг т4 Ts 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 —> —> —> Замечание. БР = точка загрузки (Load Point) Рис. 13.4. Расположение лент. .а большие. По окончании слияния строк 25, 26 и 27 на Г2 находится убываю¬ щая строка. Обратное чтение и прямая запись продолжаются при слиянии следующей ■совокупности строк — строк 22, 23 и 24. К концу второго просмотра все строки являются убывающими. На рис. 13.5 показано состояние системы к концу данного просмотра. На этом этапе Т0, 7\ и Т2 будут заполнены, а Г3, Т4 и Тъ надо будет вернуть в исходное состояние. Обратное чтение восста¬ новило пространство, которое использовалось строками, записанными на т0 Т\ 7\ Тг Т\ П А (25, 26, 27) В (22, 23, 24) С (19, 20, 21) —> —*► —* D (16, 17, 18) Е (13, 14, 151 (10, 11, 12) 0(7, 8, 9) Я(4, 5, 6) /(1,2,3) Рис. 13.5. Первый просмотр в обратном направлении (убывающие строки). Т’з —Г5. Заметим, что строка А теперь состоит из строк 25, 26 и 27, так как 'С них началось обратное чтение. После того как ленты Т3 — Т5 возвращены в исходное положение, в те¬ чение следующего просмотра на них можно писать в прямом направлении. Ленты Т0, Ti и Т2 заполнены убывающими строками. Они будут читаться в обратном направлении на следующем просмотре слияния. Строка, записан¬ ная в прямом направлении как убывающая, в обратном направлении чита¬ ется как возрастающая; таким образом, следующий просмотр слияния будет формировать возрастающие строки. В общем случае, если исходные строки записаны при распределяющем просмотре как возрастающие, то просмотры влияния с нечетными номерами будут формировать убывающие строки, а просмотры с четными номерами — возрастающие. На рис. 13.6 показано слия¬ ние, строки которого, формируемые на каждом просмотре, помечены как воз¬ растающие (А) или убывающие (D). Рис. 13.6 иллюстрирует одну проблему, характерную для обратного слия¬ ния на лентах. Заключительный просмотр строит убывающую строку, которая "Должна быть скопирована на другую ленту. Это требование добавляет еще
172 ГЛ. 13. СЛИЯНИЕ НА ЛЕНТАХ один полный просмотр к этапу слияния. Если слияние критично по вводу-вы¬ воду, то этот просмотр будет столь же длительным, как и остальные [10, 29]. Потребность в заключительном переставляющем просмотре может быть удовлетворена заранее на этапе слияния. Если число строк и способ слияния известны, то можно вычислить, будет ли число просмотров четным или не¬ четным. Если ожидается четное число просмотров, то последний просмотр построит возрастающую строку. Если известно, что исходные строки являются возрастающими и ожидается нечетное число просмотров, то последний про¬ смотр сформирует убывающую строку. В случае нечетного числа просмотров. То 7\ Т\ Гз Т\ 7\_ — — — 9 (А) 9 (А) 9 (Л) Просмотр 1 3(D) 3(D) 3(D) — — — Просмотр 2 — — — 1 (Л) 1 (Л) I (Л) Просмотр 3 — — 1 (D) — — — Рис. 13.6. Направленность строк. перемотка до первого просмотра слияния обеспечит возрастающую заклю¬ чительную строку. В другом случае изменить направленность упорядоченности строк может распределяющий просмотр. Если надо, чтобы при трехпоточном слиянии 27 исходных строк заключительная строка была возрастающей, то распределяющий просмотр создаст 27 убывающих строк. Первый просмотр слияния сократит их число до девяти возрастающих строк, второй просмотр слияния создаст три убывающие строки, и последний просмотр сформирует одну возрастающую строку. Успех этого способа зависит от возможности прогнозировать число просмотров. 13.3. Несовершенное сбалансированное слияние Случается, что число строк, построенных на распределяющем просмотре, не кратно степени слияния. На рис. 13.7 при 30 исходных строках будет f log3 30"! =4 просмотра. Поскольку каждый просмотр перемещает каждую строку, то при слиянии будет перемещено 120 длин строк. Число Конец перемещенных Напра- просмотра 7о Г| Г? 7\ Т. Г- длин строк вленность 0 10 (D) 10(L) 10(D) - — - А 1 - — — 4 (3D) 3 (3D) 3 (3D) 30 D 2 2f1(9L) 1(9L) 1(9L) - 30 Л 11 (3D) 3 — — 1 (21D) 1 (9D) 30 D 4 1 _____ зо А Рис. 13.7. Сбалансированное слияние, неустойчивое распределение (З3 < 30 < < З4, 4 просмотра). Можно несколько повысить производительность слияния за счет выявле¬ ния специальных случаев и выполнения частичных просмотров. Рассмотрим сначала выявление специальных случаев. На рис. 13.7 один из них встре¬ чается при просмотре 3. После слияния двух строк длины 9L и одной строки длины 3L в строку длины 211, на Т0 остается строка длины 9L. Как пока*
13.3. НЕСОВЕРШЕННОЕ СБАЛАНСИРОВАННОЕ СЛИЯНИЕ 173 зано на рисунке, эта строка копируется на Т4. Однако копирования можно избежать, так как эта строка вполне может остаться на То до заключитель¬ ного просмотра слияния. Особенность этого случая состоит в том, что коли¬ чество строк, существующих в момент, когда сформирована строка длиной 21L, меньше степени слияния, и можно сразу выполнять заключительный просмотр. Количество перемещений строк сокращается до 111, а просмотр 3 является частичным. Обратное чтение может усложнить стратегию частичного просмотра. Если строки, которые должны «оставаться на месте», имеют обратный порядок (как на рис. 13.7), то надо установить считывающие головки так, чтобы кгждая строка имела тот же порядок, что и все остальные строки. Это можно Число Конец перемещенных просмотра 7\ Т\ Гз Т\ Т\ Т* длин строк 2 2 (I №) йо!) Гт I Z I 1 (3L) «Заключи- 1 (9 L) 1 (9L) - 1 (12L) - тельного» 1 (ЗОЕ) (3 строки) Рис. 13.8. Заключительные частичные просмотры до однопоточного слияния сделать надлежащим количеством считываний в обратном направлении или перемоткой к краю строки в нужном направлении. Такая настройка может сделать эту стратегию невыгодной. Заметим также, что на машине с двумя каналами возникают серьезные препятствия при чтении с Т0 и записи на Т2. Можно усилить стратегию частичного просмотра, подсчитывая все время количество оставшихся строк и сливая лишь столько строк, сколько нужно, чтобы количество получаемых строк было равно степени слияния. На рис. 13.8 показаны состояния лент в конце второго просмотра рис. 13.7. Двухпоточное слияние строки с Т2 со строкой длины 3L, c Т0 сокращает совокупность строк до трех. Это приводит к состоянию, отмеченному «окончание» на рис. 13.8, когда число строк равно порядку слияния. Заключительное трехпоточное слия¬ ние создаст одну строку. Суммарная длина перемещенных строк равна 102. Как и ранее, если используется обратное чтение, то направление перевернутых строк должно быть изменено. По суммарной длине перемещаемых строк это г подход всегда будет по крайней мере столь же хорош, как и показанный на рис. 13.7. Альтернативой условию отслеживания состояний в конце слияния яв¬ ляется настройка слияния вначале. Она включает серию копирований, слияний и перемоток с целью перемещения некоторых строк для того, чтобы их число стало кратно степени слияния до начала полных просмотров слияния. Этот подход в общем случае является наиболее мощным. Рассмотрим рис. 13.9, на котором показана настройка частичных просмотров. Мы не утверждаем, что эта настройка является наилучшей в данном случае; тем не менее мы пока¬ зываем ее, чтобы проиллюстрировать сам принцип. В этом примере предпо¬ лагается, что ленты читаются только вперед. Сначала сливается по одной Строке с каждой ленты. При этом возникает состояние, изображенное в пер- Вой строчке рис. 13.9. Теперь осталось 28 строк. — 12 (слияние TJTs) 30 . Просмотр 2 сокращен
174 ГЛ. 13. СЛИЯНИЕ НА ЛЕНТАХ Дальнейшее слияние строки с Гз и строки с Т2 порождает строку на 7*4 и сокращает число строк до 27. Настройка слияния для создания этих 27 строк потребовала 7 перемещений строк. В третьей строчке рисунка пока¬ зан результат возобновления трехпоточного слияния. Трехпоточное слияние с Г0, 71! и Д на ^ выравнивает все обычные входные ленты. С этого момента выполняется обычное трехпоточное слияние. Постепенное развитие слияния показано в последующих строчках на рис. 13.9. В процессе построения единой строки суммарная длина перемещенных строк оказалась равной лишь 97 дли¬ нам строк. Эту меру эффективности слияния можно выразить иначе — при Номер строчки 7* Т\ Тг П Т1 Ts Число перемещенных длин строк Суммарная длина переме¬ щенных строк Частичный 0. 10 10 10 - - - 0 0 просмотр 1 1. 9 9 9 1 (3) - - 3 3 2. 9 9 8 0 1 (4) - 4 7 3. 8 8 8 0 0 1 (6) 6 13 Частичный 4. 7 7 7 1 (3) - 1 (6) 3 16 просмотр 2 5. 6 6 6 1 (3) 1 (3) 1 (6) 3 19 6. 5 5 5 2(3) 1 (3) 1(6) 3 22 7. 4 4 4 2(3) 2(3) 1 (6) 3 25 8. 3 3 3 2(3) 2(3) 1 (6), 1 (3) 3 28 9. 2 2 2 3(3) 2(3) 1 (6), 1 (3) 3 31 10. 1 1 1 3(3) 3 (3) 1 (6), 1 (3) 3 34 11. - - - 3 (3) 3(3) 1 (6). 2 (3) 3 37 Просмотр 1 12. - - - 3 3 3 - 37 13. 1 (12) - - 2 2 2 12 49 14. 1(12) 1 (9) - 1 1 1 9 58 15. 1(12) 1 (9) 1 (9) - - - 9 67 Просмотр 2 16. 1 (30) 30 97 Рис. 13.9. Подготовительный частичный просмотр. Числа в скобках указы¬ вают длину строк. слиянии каждая исходная строка перемещается 3.23 раза, а не 4. Следова¬ тельно, этот метод эффективнее. Частичные просмотры пытаются сместить количество просмотров от flog2Aq ближе к log2 М. Заметим, что обратное чтение не слишком услож¬ няет рис. 13.9, где То, Тi и Т2 читаются в обратном направлении при форми¬ ровании строки на Тз. Эта строка может потом читаться в обратном направ¬ лении вместе с Т2 для формирования строки на П. Новая строка на Г4 может читаться в обратном направлении вместе с Т0 и 7\ при формировании строки на Г5. Все строки, формируемые в течение двух частичных просмотров, яв¬ ляются убывающими. Никаких изменений направления упорядоченности строк не требуется (строчка 12), однако в этом примере заключительная строка получается убывающей. 13.4. Неустойчивое сбалансированное слияние Сбалансированное слияние можно выполнять с нечетным числом лент. Распределение происходит на (/г/2) + 1 лентах, после чего (/г/2) + 1 лент
13.5.* РАССУЖДЕНИЯ О ПРОЕКТИРОВАНИИ СЛИЯНИЯ 175 сливаются на /г/2 лент. На следующем просмотре /г/2 лент будут сливаться на (W2) + 1 лент, и последующие просмотры слияния будут менять входные и выходные ленты таким же способом. 13.5. Рассуждения о проектировании слияния Проектирование слияния — более сложное дело, нежели проектирование распределяющего просмотра. Особенности аппаратуры и конструкции про¬ граммы имеют такое влияние на проект слияния, что теоретически превосход¬ ное слияние может работать хуже плохого. Например, на любой машине шестипоточное слияние, требующее меньше просмотров и перемещений дан¬ ных, фактически может работать дольше, чем четырехпоточное слияние с теми же самыми данными. Причина кроется в характере подсистемы ввода- вывода, размерах памяти и специфике системы команд. Искусство проектиро¬ вания слияния включает достижение равновесия целого ряда основных фак¬ торов (которые по своей природе не поддаются совместной оптимизации) и огромного числа менее существенных факторов, которые обычно влияют на производительность очень незначительно, но которые при известных условиях могут приподнести крайне неприятные сюрпризы. Основными вопросами про¬ ектирования являются следующие. 1. Схема слияния. Здесь мы должны выбрать внутренний алгоритм, кото¬ рый будет использоваться для объединения составных входных строк в вы¬ ходные строки. Этот процесс по сути является процессом сортировки и в нем используются методы внутренней сортировки. В случае сортировки на лептах, где степень слияния обычно лежит в диапазоне от 2 до 20 (а чаще всегс от 2 до 10), вполне достаточно основных алгоритмов сортировки, поскольку в такой схеме не так много элементов. Время выбора элемента для строки вывода важно, потому что онс влияет на равновесие между внутренними операциями и операциями ввода- вывода, а также на способность системы работать с лентами на полной ско¬ рости. Степень слияния влияет на скорость внутренних операций, так ка* она определяет, сколько элементов будет использоваться при сравнении дл* выбора очередного элемента строки. 2. Степень слияния, разбиение на блоки и буферизация. Теоретически, чем больше степень слияния, тем оно предпочтительнее. Однако тонкости внутрен¬ них возможностей машины, организация подсистемы ввода-вывода и доступ ная память могут создать условия, в которых предпочтительным окажете* слияние небольшой степени. Выбор степени слияния иллюстрирует некоторые взаимосвязи между фак торами, которые следует учитывать при проектировании слияния. Минималь¬ ное время работы просмотра слияния равно времени записи на устройства: НЫвода, когда они работают непрерывно на полной скорости. Условие кри¬ тичности по записи можно полностью сохранить при слиянии степени т, не Нельзя сохранить при слиянии степени m + 1 или m + 2. Дополнительная ра бота, связанная с обработкой дополнительных входных строк, увеличива* вРемя сравнения, может сделать просмотр слияния критичным по вычисле¬ ниям и привести к перерывам в записи, задерживая окончание просмотра.
176 ГЛ. 13. СЛИЯНИЕ НА ЛЕНТАХ Связь между степенью слияния и свойствами слияния зависит от способ¬ ности центрального процессора сохранять слияние любой степени критичным по записи. При слиянии большой степени допустимо увеличение времени слия¬ ния на каждом просмотре, потому что оно может компенсироваться сокра¬ щением числа просмотров. Три просмотра по десять минут каждый предпо¬ чтительнее четырех просмотров по восемь минут. Однако с ростом степени слияния число просмотров может не сокращаться. В особенности это так, если увеличение степени невелико (1 или 2, например). На рис. 13.10 для числа Поточность Число строк 2 3 4 5 6 7 8 9 10 100 7 5 4 3 3 3 3 3 2 200 8 5 4 4 3 3 3 3 3 300 9 6 5 4 4 3 3 3 3 400 9 6 5 4 4 4 3 3 3 500 9 6 5 4 4 4 3 3 3 1 000 10 7 5 5 4 4 4 4 2 000 11 7 6 5 5 4 4 4 3000 12 8 6 5 5 5 4 4 4 000 12 8 6 6 5 5 4 4 5 000 13 8 7 6 5 5 5 4 6 000 13 8 7 6 5 5 5 4 7 000 13 9 7 6 5 5 5 5 8 000 13 9 7 6 6 5 5 5 9 000 14 9 7 6 6 5 5 5 10 000 14 9 7 6 6 5 5 5 Число просмотров=рогпоточность S'] Например, для S = 100 и поточности = 2 число просмотров = | Iog2 1001=7, для S = 100 и поточности = 7 число просмотров = | log7 100] = 3. Рис. 13.10. Поточность слияния. строк от 100 до 10 000 указано количество просмотров, необходимое для вы¬ полнения слияний степеней от 2 до 10. Обратите внимание на то, что эффект от увеличения степени слияний от 6 до 10 даже при малом количестве строк падает. Сортировка 10 000 эле¬ ментов, которые можно разбить на 100 строк, при слияниях степени 5, 6, 7, 8 и 9 занимает одинаковое количество просмотров. Выбор степени слияния следует рассматривать в свете количества ожидаемых строк и времени, ко¬ торое потребуется центральному процессору для выполнения слияний разных степеней. Степень слияния связана с разбиением на блоки и буферизацией. Каждой входной строке должна сопоставляться область в памяти, достаточно большая для того, ч7обы вместить по крайней мере одну запись из этой строки. Обычно, поле памяти, сопоставляемое входной строке, таково, что вмещает по крайней мере один блок. Для заданного количества памяти при определен¬ ной степени слияния может понадобиться сократить размеры блоков и на¬ оборот. Совокупности больших блоков могут считываться или записываться за меньшее время. Степень слияния должна быть выбрана так, чтобы время, нужное для записи всех блоков на каждом просмотре, не перекрывало время, сэкономленное за счет числа просмотров слияния.
13.6. МОДЕЛЬ ВВОДА-ВЫВОДА ПРИ СЛИЯНИИ 177 Буферизация обязательна, если работа центрального процессора должна быть совмещена с работой ввода-вывода, а просмотр слияния является кри¬ тичным по записи. Степень слияния влияет на объем памяти, выделяемой для буферизации. Разбиение на блоки, степень слияния и уровни буферизации — это три наиболее важные элемента проекта слияния, коль скоро основное ре¬ шение о типе слияния уже сделано. Способы буферизации и влияние недо¬ статочной буферизации будут рассматриваться в следующих разделах. 3. Алгоритм слияния. Алгоритм слияния определяет конкретный .способ чтения и записи при слиянии. Способы распределения, выбор конкретных строк для объединения с другими, регулировка степени слияния в течение процесса слияния, использование алгоритмов частичных просмотров, — все эго следует учитывать. При слиянии на лентах алгоритмом может быть один из основных способов слияния: сбалансированный, многоэтапный, каскадный, осциллирующий. Как только определен основной способ, разрабатывается стратегия частичного просмотра и определяются особые случаи. Прекрасный список факторов, определяющих производительность слияния, впервые дал М. А. Готц в своем письме к редактору САСМ в 1964 году [28]. Мы воспроизводим этот список здесь. 1. Количество лентопротяжных устройств. 2. Объем основной памяти. 3. Фиксированный или переменный размер записи, длина записи. 4. Выбранный способ внутренней сортировки. 5. Независимость каналов чтения и записи. 6. Буферизация. 7. Предполагаемый объем данных. 8. Длина исходных строк. 9. Распределение строк. 10. Время обработки в сравнении с временем чтения-записи. 11. Время перемотки в сравнении с временем чтения-записи. 12. Скорость чтения, время переключения с записи на чтение, скорости канала и фиксированного устройства, время переключения с одного устрой¬ ства на другое на одном канале. 13. Возможность чтения в обратном направлении. 14. Характеристики процессора машины (например, чтение вразброс, на¬ копительное записывание, индексация, косвенная адресация, прерывания). 15. Межблочные промежутки на ленте, старт-стопное время. Готц указал, что для заданного слияния могут быть существенными либо лишь один или дв'а фактора, либо все и что «эти факторы проявляют слож¬ ное взаимодействие, оценка которого требует непростых средств. Плюс ко всему, некоторые факторы зависят от данных». 13.6. Модель ввода-вывода при слиянии и характеристики системы На каждом просмотре слияния обычно записывается и считывается оди¬ наковое количество данных. При сбалансированном слиянии строки записы¬ ваются циклически по лентам вывода. Чтение выполняется, когда надо
178 ГЛ. 13. СЛИЯНИЕ НА ЛЕНТАХ добавить входных строк. В течение просмотра имеется &/2 входных лент и одна лента вывода. При наиболее эффективном просмотре слияния запись будет выполняться непрерывно и параллельно со всеми операциями считыва¬ ния и внутренними операциями. При (/г/2)-поточном слиянии, каждая лента ввода добавляет примерно одинаковое количество входных данных. Если т = &/2, то каждая лента ввода добавляет l/m-ю часть строки вывода. Это условие не выполняется, когда некоторые локальные «прогоны» вызывают неравномерность вклада от¬ дельных строк ввода в отдельные строки вывода, но оно будет выполняться в течение просмотра, на котором каждая лента ввода добавляет l/m-ю часть выходных данных. Для того чтобы быть уверенным, что чтение ^никогда не будет задержано и процесс записи ему никогда не помешает, нужна система с (/г/2) + 1 независимыми каналами для лентопротяжных устройств, поскольку в каждый момент времени потенциально активны {k/2) + 1 лент. Можно очень близко подойти к идеальной производительности, имея только два ка¬ нала. Поскольку каждая лента считывает l/m-ю часть данных, то время чтения строк ввода со всех лент примерно равно времени записи всех строк. Считывания с каждой ленты будут чередоваться, и каждая лента будет ис¬ пользовать канал для чтения l/m-ю часть всего времени. Полудуплексная система с двумя каналами позволит эффективно выполнять слияние. Однако, в силу потенциальной неравномерности добавления элементов от разных строк, возможно, потребуется параллельное чтение. В этом случае вероятны задержки при чтении, которые могут привести к задержкам при последующей записи. Эта проблема сбалансированного чтения обсуждается далее в связи с буферизацией. Ввод-вывод обременяет центральный процессор во-первых, управлением подсистемой ввода-вывода и, во-вторых, конфликтами в памяти. Минимальное время, какое центральный процессор может посвятить управлению вводом- выводом на однопроцессорной системе, равно времени для посылки команды ввода-вывода и управляющего списка каналу плюс время отклика на пре¬ рывания ввода-вывода. Малые системы требуют для поддержки ввода-вывода больше времени центрального процессора, чем большие системы, так как пути передачи данных для ввода-вывода и команд центрального процессора ис¬ пользуются в режиме разделения, а цепи центрального процессора нужны для функций ввода-вывода. Когда ввод-вывод активен, выполнение команды центральным процессо¬ ром задерживается из-за конфликта в цикле памяти. Пересылка символов между вводом-выводом и памятью «сталкивается» с передачей команд и опе¬ рандов центральному процессору. При активном вводе-выводе программа центрального процессора выполняется медленнее. Это должно быть учтено при оценке совмещения и сбалансированности центрального процессора и ввода-вывода. На системах, у которых нет двух полудуплексных каналов, сбалансиро¬ ванное слияние не может работать оптимально. На одноканальной машине каждое считывание будет задерживать запись и каждая запись будет задер¬ живать считывание. Чтение-вычисление или запись-вычисление — это наилуч¬ шее, что может быть достигнуто. Общее время слияния не будет оцениваться
13.7. ВЛИЯНИЕ БУФЕРИЗАЦИИ НА СЛИЯНИЕ 179 временем записи; оно будет равно сумме времен записи и чтения. Если совмещение невозможно, то время просмотра будет равно сумме времен чте¬ ния, записи и вычислений. На системе с двумя каналами следует позаботиться, чтобы распределение строк избегало помех чтения-записи. На каждом просмотре ленты ввода и ленты вывода должны быть на разных каналах. Если это не сделано (или не может быть сделано), то производительность слияния снизится из-за по¬ мех чтению-записи. 13.7. Влияние буферизации на слияние Влияние буферизации на производительность слияния можно показать при помощи «микроскопического» анализа слияния. Предположим, что у нас есть двухканальная система и использованное ранее трехпоточное слияние. Ячейка памяти О 1 ООО 2 000 3 000 4 000 5 000 6 000 7 000 8 000 Управление вводом-выводом, разбиение на блоки и разблокировка, процедура сортировки, включая рабочую память для сортировки 9 000 10 000 11 000 Блок ввода 1 161 119 111 83 78 77 64 68 57 52 Лента А Блок ввода 2 226 211 192 181 131 123 98 97 81 56 <— В Блок ввода 3 77 71 68 63 61 59 51 48 45 43 С Блок ввода 45 43 31 29 26 17 91 —> D 10 элементов на один блок Замечание. Выделенные элементы используются при текущем сравнении. Рис. 13.11. Влияние буферизации на слияние. Нет параллельных операций. В некоторой точке процесса память распределена так, как показано на рис. 13.11. Двенадцать тысяч слов памяти отведено для слияния и 8000 — Для процедур. Форма буфера — это десять записей по 100 слов каждая. Есть три ленты ввода и 3000 слов, начинающихся с ячейки 8000 и выделенных для Бьода. Дополнительные 1000 слов выделены для формирования блока вывода, процедура сортировки следит за указателем на «текущую запись» в каждом блоке ввода. * Текущая запись на рис. 13.11 показана в виде элемента в этом блоке, выделенного полужирным шрифтом. Процесс сортировки включает перенос ключа из блока ввода в область сортировки и сравнение его со всеми клю¬ чами, уже расположенными там. Наименьший из ключей выбирается в ка¬ честве победителя, а запись, содержащая этот ключ, пересылается из своего блока ввода в блок вывода. Указатель текущей записи продвигается в блоке
180 ГЛ. 13. СЛИЯНИЕ НА ЛЕНТАХ победителя, и новый ключ передается из него в область сортировки. Когда в блоке вывода скапливается 10 записей, начинается процесс записи. Когда из блока ввода выбрано 10 записей, начинается считывание нового блока. К моменту, соответствующему рис. 13.11, в блоке вывода накопилось уже семь записей. Текущий элемент каждого из первых двух блоков является первой записью; в третьем блоке ввода — это третья запись. Сортировка сравнивает ключи этих трех записей, выбирает ключ 48 и пересылает третью запись из третьего блока ввода в блок вывода. Указатель записей третьего блока ввода устанавливается на ключ 51 и процесс продолжается. Ячейка памяти 0 ) Процедуры 8000 | 9000 ) Блок ввода 1 161 119 111 83 78 77 64 58 57 52 10 000 11 ООО 12 000 13 000 14 000 Блок ввода 2 226 211 192 181 131 123 98 97 81 56 Блок ввода 3 78 71 68 63 61 59 51 48 45 43 Блок вывода 2 63 61 59 58 57 56 Лента А Блок вывода 1 52 51 48 45 43 31 29 26 17 Замечание. Элементы, выделенные полужирным шрифтом, ::сп ользуются при текущем сравнении. Рис. 13.12. Вывод при удвоенной буферизации. Лента Е загружается из блока 1, в то время как блок 2 заполнен. Операции записи и вычисления совмещены. Слияние на рис. 13.11 препятствует значительному совмещению операций по следующим причинам. 1. Пока блок вывода строится, считывание невозможно, потому что больше нет памяти для ввода. Не произойдет и запись, так как блок для этого еще не укомплектован. 2. Пока записывается блок вывода, нельзя ни сортировать, так как неку¬ да поместить выбранную запись, ни читать, так как нет свободной памяти. 3. Совмещение возможно только в том случае, если выходной буфер бу¬ дет исчерпан как раз в тот момент, когда блок вывода будет заполнен. Не¬ хватку областей буферизации можно компенсировать способностью системы совмещать чтение-запись-вычисление. Дополнительный буфер вывода позволил бы совместить процессы записи и сортировки. Если легкодоступной памяти для дополнительного буфера нет, то нужны компромиссы между буфером и размером блока, буфером и степенью слияния, буфером и памятью для про¬ цедур. На piiv. i3.12 показаны блоки, запись в один из которых протекала па¬ раллельно с заполнением другого. Если второй блок вывода становится пол¬
13.8. БУФЕРИЗАЦИЯ ПРИ ВВОДЕ 181 ным как раз тогда, когда закончена запись в первый блок, то можно пол¬ ностью совместить запись и вычисления. Если второй блок вывода заполнен раньше, чем первый, то центральный процессор будет ждать окончания про¬ цесса записи. Однако дополнительная буферизация наверняка достигнет своей цели — сохранения вывода непрерывным. Наличие побочных эффектов зависит от трехстороннего отношения запись-чтение-вычисление, которое мы рассмо¬ трим позднее. Если второй блок вывода не заполнен до окончания записи блока 1, то в процессе записи возникнет период ожидания. Если временные отношения между выбором записи центральным процессором и вводом-выво¬ дом таковы, что этот процесс в своей основе постоянно критичен по работе центрального процессора, то ничего нельзя сделать для того, чтобы процесс записи не прерывался. 13.8. Буферизация при вводе Полное представление о поведении сортировки требует рассмотрения той ее части, которая связана с чтением. Когда блок ввода исчерпан, должен быть считан следующий блок, и пока выполняется чтение, сортировка не мо¬ жет продолжаться. Простой центрального процессора при считывании попол¬ нения может не позволить сохранить процессы записи непрерывными. Запись прекратится из-за недоступности блоков, и время слияния увеличится. Обычное решение проблемы хронической задержки чтения и возможной задержки записи состоит в удвоенной буферизации каждого входа, но этому решению сопутствуют две другие проблемы. Удвоенная буферизация может оказаться невозможной из-за отсутствия памяти для удваивания числа обла¬ стей ввода или же, если память для буферизации нельзя получить без силь¬ ных потерь в размере блоков или степени слияния. Кроме того, удвоение буферизации может ничего не дать из-за скорости исчерпания блоков ввода, когда в данных есть определенные особенности. Однако достаточный объем памяти и немного везения могут дать хорошие результаты. На рис. 13.13 показаны дополнительные буфера-дублеры. Отличие от рис. 13.12 состоит только в том, что для каждой входной строки в памяти есть дополнительный блок. Важно запомнить, что если ленты Л, В и С со¬ единены с памятью одним каналом в силу либо архитектуры системы либо ее конфигурации, то читаться в одно и то же время может только одна из них. В ближайшее время дополнительные записи с ключами 64, 68, 71 и 75 образуют блок вывода 2. В это же время блок ввода 4 будет исчерпан и получит другой блок с ленты В. При считывании с ленты В сортировка мо¬ жет продолжаться, используя парный буфер (блок 3) с ленты В. Цель удвоенной буферизации — избежать задержек при сортировке и записи. Средство устранения задержек должно гарантировать, что каждая строка ввода всегда может быть представлена в памяти. Однако эта цель не Всегда может быть достигнута. Способ выбора элементов из входных строк Может приводить к неравномерному исчерпанию буферов ввода. Способ ис¬ черпания блоков ввода и, следовательно, способ считывания будет разным, если 20 последовательных записей выбираются из одной и той же строки, или Же если выбранные записи поступают из всех строк.
182 ГЛ. 13. СЛИЯНИЕ НА ЛЕНТАХ Если одна строка исчерпывается, в то время как другая остается нетро¬ нутой, то может оказаться невыполнимой достаточно быстрая перезагрузка буферов-дублеров при помощи операции чтения, и при сортировке может воз¬ никнуть задержка. Эта трудность может повлиять (а может и не повлиять — в зависимости от процесса записи) на соотношение времени центрального про¬ цессора и ввода-вывода. Если строки исчерпаны равномерно, то задержки все же возможны (на двухканальной машине), поскольку читать в одно и то же Ячейка памяти О 8000 9009 10 000 11 000 '12 000 13 000 15 000 16 000 17 000 * Блок ввода 1 ** Блок ввода 2 161 119 111 83 78 77 64 58 57 52 ^ Лента д 320 315 310 271 239 237 214 197 181 171 ) ч ** Блок ввода 3 226 211 * Блок ввода 4 75 71 192 181 68 63 131 61 123 59 97 48 81 45 ^ 1 Лента В 43 Г ч * Блок ввода 5 ** Блок ввода 6 84 88 87 116 115 110 100 85 96 84 94 83 93 82 92 80 91 78 I Лента С 90 j ч Блок вывода I Блок вывода 2 92 51 48 43 63 31 61 29 59 26 58 17 Лента D 57 56 J >■ Замечание. Элементы, выделенные полужирным шрифтом, используются при текущих сравнениях. * — активный блок ввода ** — блок ввода-дублера Рис. 13.13. Ввод с удвоенной буферизацией. Совмещение чтения-записи- вычислений. время более одной ленты будет нельзя. Время для выполнения трех считыва¬ ний может превышать время, необходимое сортировке для исчерпания всех блоков-дублеров. Однако обычно изменения способа выбора при сортировке таковы, что удваивание буферизации все же достигает своей цели в течение всего просмотра. Фрэнд [14] установил, что абсолютную гарантию от «зависания при чте¬ нии» может дать только (/+1) буфер для каждой из I входных лент. Эта конфигурация обеспечивает непрерывное чтение в течение просмотра и га¬ рантирует, что оно не станет источником задержки. Бывают системы с динамической буферизацией, которые пытаются ими» тировать удвоенную буферизацию или пытаются превзойти удвоенную буфе¬ ризацию с меньшим числом буферов, чем идеальные (/2 +/). Основным спо¬ собом является разделение буферов и некоторая форма предварительного выбора или прогнозирования [11]. При основном предварительном выборе каждому файлу выделяется буфер, а один дополнительный плавающий буфер совместно используется всеми. При считывании блока его последний элемент всегда сравнивается с последними элементами всех остальных. Блок с наш
13.9. УЧЕБНЫЙ ПРИМЕР СЛИЯНИЯ 18а меньшим последним элементом исчерпывается первым. Пока он исчерпыва¬ ется, в плавающий буфер считывается следующий блок из файла, чей теку¬ щий блок будет исчерпываться следующим. В любой момент времени есть k/2 + 1 буферов ввода; каждому файлу в любой момент времени соответ¬ ствует два буфера. При определенных условиях k/2 + 1 буферов ввода могут полностью имитировать удвоенную буферизацию. Однако этот способ неэффективен, когда есть тенденция к одновременному исчерпыванию нескольких буферов. На рис. 13.14 путем предварительного выбора определено, что А будет исчер¬ пан первым, а следующий блок считан (или считывается) в область предвари¬ тельного выбора. Уже до исчерпания блока А(п), блок А(п-{- 1) будет в па¬ мяти, и чтение «зависать» не будет. Если за один раз устойчиво исчерпы¬ вается один блок, то предварительный выбор будет работать хорошо. Однако Блок А {п) Блок В (/г) Блок С (п) Блок предварительного выбора A(ti+ 1) 2 5 3 8 4 6 7 9 Рис. 13.14. Предварительный выбор. на рис. 13.14 В и С будут исчерпываться вместе. Даже если предварительно выбранный блок для В будет считан вовремя, то будет перерыв для введения замещающего блока для С. Такой блок имелся бы, если бы запасные блоки имелись для всех строк ввода. Производительность предварительного выбора можно повысить, прибли¬ жая число предварительно выбираемых блоков к числу блоков, используемых при удвоенной буферизации. Весьма успешно такой подход разделения буфе¬ ров можно использовать для усиления удвоенной буферизации. Обычным способом является приписывание каждой строке ввода двух буферов. Располо¬ женная за ними совокупность из (/г/2) — 1 разделяемых буферов (или столь¬ ких, сколько можно предоставить) помогает поддерживать чтение непрерывным и тем самым избегать задержек чтения, которые, в конечном итоге, ведут к за¬ держкам записи. Если в системе читать параллельно, то за счет этого можно повысить производительность, совмещая какую-то часть считывания данных И обеспечивая более быструю реакцию на исчерпание нескольких блоков. 13.9. Учебный пример слияния На рис. 13.15 приведены характеристики файла, для которого надо спроектировать слияние. Этот пример покажет процесс выбора разных ха¬ рактеристик разделения на блоки и уровней буферизации для слияния. 1. Определим пробную степень слияния. Это наименьшая степень из тех, при которых число просмотров для ожидаемого числа строк будет минималь¬ ным. На рис. 13.16 показано вычисление количества просмотров для пяти-, Четырех- и трехпоточных слияний, когда ожидаемое число строк равно 500. Поскольку при каждом сокращении степени слияния добавляется еще один просмотр, то рассматривать следует как пяти-, так и четырехпоточное Слияние. Если для сворачивания строк при использовании четырех- и
184 ГЛ. 13. СЛИЯНИЕ НА ЛЕНТАХ пятипоточного слияний требуется одинаковое число просмотров, то использо¬ вать следует четырехпоточное слияние. 2. Зададим распределение памяти. Для каждой исследуемой степени слияния установим баланс разбиения на блоки и буферизации при различных предположениях о буферизации. На рис. 13.17 и 13.18 показаны рабочие Характеристики файла Число лент 10 Максимальная степень (fe/2) 5 Число элементов 50 ООО Длина элемента 100 слов Память 20 ООО слов Рабочая память 10 000 слов Длина строки после этапа сортировки 100 элементов Рис. 13.15. Рабочая карта для проектирования слияния. карты для четырех- и пятипоточного слияний соответственно. Для каждого предположения о буферизации вычислены количество буферов, размер блока, число блоков, время ввода-вывода блока и время ввода-вывода при про¬ смотре, а также общее время слияния. Расширенная схема буферизации включает два блока вывода, удвоенную буферизацию для каждой лепты ввода и дополнительные плавающие буферы. Сравнение этих двух рисунков показывает, что при всех уровнях буферизации пятипоточное слияние пре-' восходит четырехпоточное. Заметим, однако, что при размере блока в Шаг 1. Ожидаемое число строк = Количество элементов данных : длина строки=» 500 строк Шаг 2. При максимальной степени слияния будет Iog5 500= 4 про¬ смотра -Шаг 3. При уменьшенной степени слияния будет log4 500 = 5 про¬ смотров Шаг 4. При уменьшенной степени слияния будет Iog3 500= 6 про¬ смотров Вывод: рассматриваем 5- и 4-поточные слияния. Рис. 13.16. Пробная степень слияния. 1400 символов четырехпоточное слияние с предварительным выбором превос¬ ходит по производительности пятипоточное с минимальной буферизацией. В прошлом на некоторых системах размеры блоков фиксировались. Некото¬ рые современные устройства имеют характеристики, которые делают опреде¬ ленные размеры блоков предпочтительными. Например, размеры блоков на дисках в одну дорожку или половину дорожки. Исходные временные предположения для рабочих карт состоят в том, что слияние является критичным по вводу-выводу и достигается полное совме¬ щение. При минимальной буферизации эта комбинация условий невозможна. Лучшее временное предположение при минимальной буферизации состоит в том, что нет совмещения при чтении-записи, — условие, которое удваивает время просмотра и слияния. Только расширенная буферизация при исполне¬ нии будет близко подходить к вычисленным временным характеристикам. Коррективы в предварительный выбор и удвоенную буферизацию должен вносить разработчик, руководствуясь собственным мнением и тем, что он знает о данных.
13.9. УЧЕБНЫЙ ПРИМЕР СЛИЯНИЯ 185 Мини¬ мальная (/г/2) + 2 С предвари¬ тельным выбором (А/2) + 3 С удвоенной буферизацией к Л-2 Расши¬ ренная ЗА/2 6 7 10 12 1600 1400 1000 800 3125 3572 5000 6250 37 33 25 21 115,6 117,8 125,0 131,3 578,0 589,0 625,0 656,5 1156,0 736,2 687,5 656,5 Рабочая память = 10 000 Предположения буферизации Количество буферов Размер блока, округленно 1 Количество блоков Время блока на ленте (мс)2 Время просмотра (с) 3 Время слияния (с) 4 Время слияния (с), 5 просмотров5 > Размеры блоков округлены до ближайших 100 слов, так как они содержат 100-словные записи целиком. Размер блока = 10 ООО/количество буферов. 2 Включая время включения, равное 5 мс. Скорость пересылки = 50 ООО слов в се¬ кунду. 3 Предполагается полное совмещение чтения-записи-вычислений. Время просмотра 5* *= время блока на лентеХколичество блоков. 4 Предполагается полное совмещение чтения-записи-вычислений. Время = время про- смотраХчисло просмотров. 3 Предполагается наибольшее возможное совмещение чтения-записи-вычислений. Пересмотр «несерьезного фактора» оправдывается следующим: 1) Минимальная буферизация предполагает, что время работы = время чтения+ + время за шеи; 2) Расширенная буферизация предполагает полное совмещение; 3) Удвоенная буферизация предполагает 10%-ю задержку при чтении; 4) Буферизация с предварительным выбором предполагает 25%-ю задержку при чтении. Рис, 13,17. Рабочая карта для 4-поточного слияния: k!2 = 4. Рабочая память = 10 000 Предположения буферизации Мини- С предвари- С удвоенной Расширен- мальная тельным буферизацией ная (/г/2)+ 2 выбором А+ 2 3 А/2 (А/2) + 3 Количество буферов 7 8 12 15 Размер блока, округленно1 1400 1200 800 600 Количество блоков 3572 4167 6250 8333 Время блока на ленте (мс) 2 33 29 21 17 Время просмотра (с)3 115,6 120,8 131,3 141,6 Время слияния (с) 4 462,4 433,2 525,2 566,4 Время слияния (с), 924 604,0 577,7 566,4 5 просмотров 6 1 Размеры блоков округлены до ближайших 100 слов, так как они содержат 100-слов- ные записи целиком. Размер блока = 10 000/количество буферов. 2 Включая время включения, равное о мс. Скорость пересылки = 50 000 слов в се¬ кунду. 3 Предполагается полное совмещение чтения-записи-вычислений. Время просмотра = ** время блока на лентеХколичество блоков. 4 Предполагается полное совмещение чтения-записи-вычислений. Время = время про- СМотРаХчисло просмотров. 0 Предполагается наибольшее возможное совмещение чтения-записи-вычислений. Пе¬ ресмотр «несерьезного фактора» оправдывается следующим: 1) Минимальная буферизация предполагает, что время работы = время чтения+ +время записи; 2) Расширенная буферизация предполагает полное совмещение; 3) Удвоенная буферизация предполагает 10%-ю задержку при чтении; 4) Буферизация с предварительным выбором предполагает 25%-ю задержку при чтении. Рис. 13.18. Рабочая карта для 5-поточного слияния: к!2 = 5.
186 ГЛ. 13. СЛИЯНИЕ НА ЛЕНТАХ 13.10. Заключительные комментарии Несколько важных вопросов слияния мы еще не затронули, и среди них следующие: 1. Различие между «последним просмотром» и всеми остальными просмо¬ трами слияния. 2. Контрольные точки слияния. 3. Прогнозирование заключительной ленты вывода. 4. Многоленточная сортировка-слияние. 13.10.1. Последний просмотр. Когда число оставшихся строк становится равным либо меньшим степени слияния, достигается условие последнего про¬ смотра. Последний просмотр слияния обычно считается специальным этапом процесса сортировки-слияния. Как правило, последний этап отвечает за интер¬ фейс с пользователями и последующими программами обработки. Он должен разблокировать и перестроить записи; часто он может передавать специаль¬ ные сообщения, которые могут быть с успехом сформированы в процессе •создания физически упорядоченного файла. Разблокировать и перестраивать записи надо всегда, когда для удобства слияния меняются размеры блока. Размер блока, оптимальный для данного слияния, не всегда может быть эффективным для сортировки-слияния и мо¬ жет быть не тем размером, который пользователь ожидает получить в итоге. В изменении формата записей нет ничего необычного. Перед тем, как записи покинут процесс сортировки-слияния, их формат должен быть изменен так, как желает пользователь. 13.10.2. Контрольные точки. В конце каждого просмотра слияния все дан¬ ные располагаются в двух местах — на новых лентах вывода и на лентах, которые образовывали вход для данного просмотра. Входные ленты формаль¬ но считаются исчерпанными в том смысле, что для формирования слияния с них уже все считано, но не стерто. Если их сняли и заменили другими лен¬ тами, то они становятся контрольной точкой слияния. Слияние можно возоб¬ новить с того просмотра, который использовал снятые ленты как входные, если их установить заново. Решение о сохранении лент зависит от длитель¬ ности времени просмотра. Процедура контрольной точки имеет определенную продолжительность, и время, которое она сохраняет, должно быть больше времени, которое она занимает. На больших системах с очень гибкими схемами распределения необяза¬ тельно снимать и вновь ставить ленты до того, как начнется следующий просмотр. Сортировка может исключать такие устройства ввода, и занимать устройства, на которые предварительно были установлены чистые ленты. Пока идет запись на чистые ленты, контрольные ленты снимаются. Этот процесс занимает значительно меньшее время, чем при задержке слияния для уста¬ новки лент. Если из сортировки можно обратиться к операционной системе за перераспределением, то весь процесс будет очень плавным. Рента¬ бельность этого подхода зависит от компромисса между использованием при слиянии всех доступных лент и минимизацией стоимости контрольных точею
13.10. ЗАКЛЮЧИТЕЛЬНЫЕ КОММЕНТАРИИ 187 Если ленты используются в обратном направлении, то, возможно, сле¬ дует устанавливать контрольные точки после того, как ленты ввода будут прочитаны в обратном направлении и будут располагаться около точки за¬ грузки. Когда эти ленты устанавливаются вновь, строки выглядят как убы¬ вающие, но возобновленный просмотр может писать строки вывода как убывающие и не допускать серьезных издержек. Обычным требованием является отключение исходных лент для сохране¬ ния начальных данных. Обращение с ними ничем не отличается от обращения с другими контрольными точками. 13.10.3. Заключительная лента вывода. Обычно сортировка-слияние ука¬ зывает пользователю, где располагается его бобина с упорядоченной лентой. Сколь много потребуется сделать, зависит от того, насколько неукоснительно пользователь настаивает на том, чтобы итоговая бобина располагалась на конкретном лентопротяжном устройстве. Нетрудно сделать так, чтобы итого- •вый выход располагался на одной из двух возможных лент. Алгоритм рас¬ пределения для любого просмотра одинаково легко может строить последова¬ тельности как Т1, Г2, Тз, так и 73, Г2, Ти так и Г2, Г3) ^ и т. д. На послед¬ нем просмотре для вывода используется только одна лента, и ею может быть любая из имеющихся лент. Трудность заключается в том, что не всегда можно предсказать с абсолютной достоверностью, будет ли четным или не¬ четным число просмотров. Если же число просмотров предсказать можно, то исходное распределение можно настроить так, чтобы можно было выбрать определенную совокупность из (/г/2) лент вывода, а внутри этой совокупности легко выбрать заданную ленту. Если же число просмотров предсказать нельзя, то правильнее будет использовать естественное слияние и расширение строк, копировать при необходимости заключительную строку на нужную ленту. 13.10.4. Многоленточная сортировка-слияние. Есть два случая, когда необ¬ ходимо рассматривать сортировку данных, которые не помещаются на одной бобине. Один возникает, когда данные превышают объем одной бобины, но помещаются на (/е/2) промежуточных бобинах, а многоленточный характер ввода и заключительного вывода обеспечивается простым способом распре¬ деления устройств [6]. Когда исчерпана первая лента, устанавливается вто¬ рая, или, если есть еще одно лентопротяжное устройство, то адрес устройства ввода изменяется так, чтобы обращаться к этому дополнительному устрой¬ ству. Поскольку данные не будут опять записываться на одну ленту до за¬ ключительного просмотра, то до этого просмотра процесс сортировки-слияния протекает обычно. Другой случай возникает, когда данных слишком много, чтобы охватить Их одной сортировкой-слиянием. В этом случае выполняются раздельные сор- тировки-слияния, и отсортированные подфайлы сливаются вместе. Конструк¬ ция этого слияния следует принципу, рассмотренному в главе, посвященной инутреннему слиянию. Конструкция минимального дерева для строк перемен¬ яй длины и для степеней слияния разной длины полностью применима к многоленточному слиянию.
188 ГЛ. 14. МНОГОЭТАПНОЕ СЛИЯНИЕ НА ЛЕНТАХ Глава 14. МНОГОЭТАПНОЕ СЛИЯНИЕ НА ЛЕНТАХ 14.1. Введение Метод сбалансированного слияния степени k/2 требует k лент. В каждый момент времени активны (/е/2) -f- 1 лент: /г/2 считываются и одна записы¬ вается, а (6/2) — 1 простаивают. Изменение логики слияния может повысить интенсивность использования лент. В семействе «несбалансированных» слия¬ ний сделана попытка достигнуть степени слияния, большей чем /г/2, считывая в одно и то же время более /г/2 лент, используя до k — 1 входов и один выход. Такие несбалансированные слияния (которые отличаются друг ог друга диапазоном степеней слияния, фактически используемых при слиянии) образуют непрерывную цепочку: на одном конце находится многоэтапное слияние, которое поддерживает количество лент ввода постоянным и равным (fr—1): на другом — каскадное, которое использует k—1, k — 2, k — 3, k—(k—1) лент ввода в течении разных этапов просмотра сортировки. Между этими экстремальными случаями располагается множество «компро¬ миссных» слияний, которые различаются числом входов, используемых на каждом просмотре. Эффективность несбалансированных слияний относительно друг друга и сбалансированного слияния зависит от k, количества строк, архитектуры ис¬ пользуемой машины и множества других факторов. Сравнительные замечания сделаны при описании каждого метода (многоэтапного в этой главе, каскад¬ ного и компромиссного в следующей), обзор методов дан в главе 17. 14.2. Многоэтапное слияние с прямым чтением на трех лентах Если просмотр внутреннего распределения размещает восемь строк на ленте Ti и пять строк на ленте Тг, то возможно следующее слияние: Этап То 7*1 Т2 0 8 5 1 5(2£.) 3 — 2 2(2 L) — 3(3 L) 3 — 2(5 L) 1 (3L) 4 1 № 1 (5L) — 5 — — 1 (13L) Это поэтапное слияние с частичными просмотрами, известное как «много¬ этапное с тремя лентами» [16]. Выполнение трехленточного слияния заклю¬ чается в циркуляции строк по ленте, исчерпанной на предыдущем этапе, до тех пор, пока не будет исчерпана одна из двух текущих лент ввода. Для оптимального слияния строки должны иметь форму последовательностей чи¬ сел Фибоначчи. 14.2.1. Просмотр распределения: последовательности Фибоначчи. Обрати¬ те внимание, что в предыдущем примере число строк S = 13. При этом рас¬ пределении восемь строк размещается на одной ленте, а пять строк на дрУ'
14.2. СЛИЯНИЕ С ПРЯМЫМ ЧТЕНИЕМ НА ТРЕХ ЛЕНТАХ 189 гой. Эти числа входят в последовательность Фибоначчи, в которой каждое значение равно сумме двух предыдущих. 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144... —-это стандартная последовательность чисел Фибоначчи. При любом файле просмотр распределения пытается разместить заданное число строк по двум лентам так, чтобы количество строк на них было равно двум предшествую¬ щим числам Фибоначчи, т. е. если S = 13, то будет пять и восемь строк соот¬ ветственно. После распределения каждый этап слияния уменьшает количество строк до двух следующих чисел Фибоначчи: (5,3), (3,2), (2, 1), (I, 0) до тех пор, пока записи не будут упорядочены. Всегда, когда окончательное число строк на двух лентах распределения равно двум последовательным «числам Фибоначчи, многоэтапное слияние достигает «идеального уровня». Ввод Распределение Фибоначчиев уровень S Г* Тх Т2 1 0 1 1 1 2 1 1 2 2 3 2 1 3 3 5 3 2 4 5 8 5 3 5 8 13 8 5 6 13 21 13 8 7 21 34 21 13 8 34 55 34 21 9 55 Рис. 14.1. Трехленточное многоэтапное слияние, идеальные Фибоначчиевы уровни. Если мы знаем заранее, что S — это число Фибоначчи, мы можем предва¬ рительно вычислить, сколько строк надо разместить на каждой ленте при распределении. Если же мы не знаем S, то' все равно можем попытаться достичь последовательности чисел Фибоначчи, строя промежуточные последо¬ вательности этих чисел по ходу ввода. Эта процедура строит идеальные Уровни для разных значений S, как показано на рис. 14.1. Если S — не число Фибоначчи, то вход будет исчерпан прежде, чем будет достигнут по¬ следний идеальный уровень и понадобится настройка многоэтапного процесса, ■о чем будет сказано позднее. При этом не имеет значения, на какой ленте ■больше строк, поскольку на идеальном уровне допустима любая перестановка чисел Фибоначчи. Правила вычисления для размещения строк на каждой ■ленте даны в разделе 14.3. 14.2.2. Просмотр слияния. На рис. 14.2 в первой строчке показано, как 21 игрока распределена на двух лентах. Поскольку 21 является числом Фибо¬ наччи, то распределение 13 и 8 строк образует идеальный уровень. Остальные СтРочки этого рисунка показывают просмотры этого слияния, при котором ^роки переходят с двух лент на третью, все время сохраняя идеальные Уровни. Поскольку на каждом шаге исчерпывается только одна из лент СЛияния, то каждый этап, за исключением последнего, является частичным. На каждом этапе многоэтапного слияния исчерпывается лента с
190 ГЛ. 14. МНОГОЭТАПНОЕ СЛИЯНИЕ НА ЛЕНТАХ наименьшим числом строк. В конце каждого этапа перематываются только что исчерпанная лента и только что заполненная лента вывода. Это гарантирует, что на следующем просмотре все ленты будут читаться в прямом направле¬ нии. Форма совмещения такова, что машина, способная совмещать чтение- запись-вычисления, может эффективно выполнять слияние (с ограничением, которое будет указано позднее). Поскольку это слияние на каждом этапе перемещает не все строки, то его эффективность проследить нелегко. Все строки в файле перемещаются только Число переме- )СМОТр То Т\ т. Число строк Текущая длина щенных , строк - 13 (L) 8 (L) 21 1 - 1 8(2L) 5 (L) — 13 2 16 2 3(2L) — 5(3 L) 8 3 15 3 — 3 (5L) 2(3 L) 5 5 15 4 2 (8L) 1 (5L) — 3 8 16 5 1 (8 L) — 1 (13L) 2 13 13 6 — 1 (21L) — 1 21 21 96 Число перемещенных длин строк Число строк =-|^- = 4.6 просмотров данных, эффективная степень слияния* Рис. 14.2. Трехленточное многоэтапное слияние, эффективная степень слияния. ка просмотре распределения и последнем этапе слияния. С учетом того, что при сбалансированном слиянии степень сокращения строк равна /г/2, а число просмотров слияния равно f“log^2 S~], не так-то просто описать многоэтап¬ ное слияние. По «эффективной степени» многоэтапного слияния есть уже масса теоретических работ. Гилстэд [17] подсчитал, что при неограниченном числе строк и любом количестве лент максимальная эффективная степень многоэтапного слияния равна 4. Это означает, что многоэтапное слияние на любом просмотре никогда не будет сокращать число строк менее, чем до 1/4 числа строк ввода. Очень полезным способом для вычисления эффективности слияния является деление общего числа строк, просматриваемых при слиянии, на число исходных строк. Частное равно числу просмотров данных. На рис. 14.2 приведены вычисления, которые показывают, что для слияния на этом рисунке требуется 4.6 просмотров данных. Необходимые вычисления иг громоздки даже при большом количестве лент и строк и обеспечивают каче¬ ственную картину многоэтапного слияния, которую можно использовать для его сравнения с другими методами. 14.3. Многоэтапное слияние с большим числом лент Многоэтапное слияние можно использовать с любым количеством лент. Последовательности чисел Фибоначчи надо обобщить на различные S и k с целыо определения идеальных уровней для этих случаев. Это обобщение применимо также и для 6 = 3. Дано k лент и 5 исходных строк:
14.3. МНОГОЭТАПНОЕ СЛИЯНИЕ С БОЛЬШИМ ЧИСЛОМ ЛЕНТ 191 1. Распределим одну строку на любую из k—1 лент. (Лентой ввода является 6-ая лента.) Распределим дополнительную строку на любую, но одну ленту. 2. Определим ленту «приращения». Эта лента имеет наибольшее коли¬ чество строк. Чтобы сформировать следующий уровень, добавим на все остальные ленты, кроме ленты приращения, число строк, равное числу строк этой ленте. Если одинаковое количество строк имеют несколько лент, то выбор ленты приращения произволен. 3. Повторим шаг 2 до полного исчерпания ленты ввода. Для удобства программирования обычно надо иметь правило для расформирования связей при выборе ленты приращения. Мы используем правило, согласно которому 70 Т\ 7^ Гз Т\ Число строк Уровень ~7 0 0 0 ! \ О I 1 1 1 1 * 4 I + 1 + 1 -М - I 2 2 2* 1 7 2 +2 +2 - +2 4 4 2 3 13 3 +4 - +4 + 4 1 8 * 4 6 7 25 4 +8 +8 +8 I 8 12 14 15 49 5 * Лента приращения Рис. 14.3. Распределение многоэтапного слияния (k = 5). ленты сопоставляются столбцам рабочей карты, и выбирается самая правая лента. Пример этой процедуры (рис. 14.3) показывает, как она работает при 6 = 5 и 5 = 49. Данные на рис. 14.3 могут быть собраны в обобщенные по¬ следовательности Фибоначчи, где каждая последовательность из четырех чи¬ сел трактуется как группа: (О, 0, 0, 1), (1, 1, 1, 1), (2, 2, 2, 1), (4, 4, 2, 3), (8, 4, 6, 7), (8, 12, 14, 15), ... Каждая группа из k — 1 элемента является идеальным уровнем. Она об¬ разуется добавлением максимального элемента из предшествующей группы к 6 — 2 не максимальным элементам этой же группы. Это правило работает при любых k ;> 2; таким образом N Последовательности Фибоначчи Ссылки 3 (0, 1), . (1, 1), (2, 1), (2, 3), (5, 3), ... Рис. 14.1 4 (0, 0, 1), (1, 1, 1), (2, 2, 1), (4, 2, 3), (4, 6, 7), 5 (П , 13, 7), (24, 13, 20), ... Рис. 14.7 6 (0, 0. 0, 1), (1, 1, 1, 1), (2, 2, 2, 1), (4, 4, 2, 3), ... Рис. 14.3 (0, 0, 0, 0, 1), (1, 1, 1, 1, 1), (2, 2, 2, 2, 1), (4, 4, 4, 2, 3) ...
192 ГЛ. 14. МНОГОЭТАПНОЕ СЛИЯНИЕ НА ЛЕНТАХ Другим способом вычисления значения i-й группы в последовательности Фибоначчи из k—1 элементов является сложение k—1 предшественников. Таким образом, при k = 5 пятый идеальный уровень равен 25 +13 + 7 + 4 = 49. / Метод приращения предпочтительнее потому, что он обосабливает текущее состояние каждой ленты, которое необходимо как основа для подсчета. После того, как просмотр распределения достигнет идеального уровня на k—1 лентах, просмотр слияния движется в обратном направлении по обоб¬ щенным последовательностям Фибоначчи до тех пор, пока останется только Число перемещенных 7j 7\ Т\ 7^ 7j Число строк длин строк — 8 (L) 12 (L) И (L) 15 (L) 49 - * 8 (4L) — 4 (L) 6 (L) 7 (L) 25 32 4(4 L) * 4 (7L) — 2 (L) 3 (L) 13 28 2 (4L) 2(7 L) * 2 (13L) — 1 (L) 7 26 1 (4L) 1 m 1 (13L) * 1 (25L) — 4 25 * Лзнта вывода для этапа. 1 49 160 3.26 просмотров данных. Рис. 14.4. Этап слияние для строк, распределенных на рис. 14.3. одна строка. И опять-таки, перестановка любого идеального уровня является идеальным уровнем. (Сравните последовательность для k = 3 вверху с рис. 14.1. Этот факт полезен, когда по каким-либо причинам желательно ис¬ пользовать определенную ленту на определенном канале в определенное время.) Таким образом, на рис. 14.3 любое распределение, которое создает 8, 12, 14 и 15 строк на k—1 лентах слияния, является приемлемым. Заметим, что следующим идеальным уровнем для k = 5 является S = 49. Для того чтобы многоэтапное слияние было эффективным, любой файл (49 < S < 94) необходимо настроить. На рис. 14.4 показан этап слияния для распределе¬ ния, изображенного на рис. 14.3. Каждый этап этого слияния поднимает на¬ чальный уровень до следующего «идеального» уровня, а число строк умень¬ шается в обобщенной последовательности Фибоначчи. На рис. 14.4 имеется пять частичных просмотров, эквивалентных 3.26 полным просмотрам данных. 14.4. Распределение при прямом многоэтапном слиянии При многоэтапном слиянии есть два способа распределения начальных строк: «вертикальный» и «горизонтальный». Вертикальное распределение до¬ водит по очереди каждую ленту до нужного уровня. Горизонтальное распре¬ деление доводит постепенно до нужного уровня все ленты, размещая каждый раз по одной строке на каждую ленту. Есть много модификаций этих спосо¬ бов распределения, которые влияют на производительность многоэтапного слияния. Достичь идеального уровня удается достаточно редко, при этом важ¬ но фактическое распределение строк сразу после исчерпания ввода. Фактиче¬ ское количество длин строк, перемещаемых при слиянии, зависит от конкрет¬ ного размещения строк, которое образует несовершенное распределение.
14.4. РАСПРЕДЕЛЕНИЕ ПРИ ПРЯМОМ СЛИЯНИИ 193 Алгоритм распределения для многоэтапного слияния должен определять, сколько строк надо разместить на каждой ленте, чтобы достичь следующего уровня. Он также должен регистрировать распределение строк так, как оно фактически выполнялось. Число строк, помещаемых на каждую ленту для достижения следующего уровня, не зависит от того, распределяются ли стро¬ ки горизонтальным или вертикальным способом. На распределяющем просмотре устанавливаются два счетчика, которые представляют каждую ленту при слиянии. Один («идеальный» счетчик) пред¬ ставляет число строк на ленте, необходимых для следующего уровня; другой («фактический» счетчик) представляет число строк на ленте. Вначале идеаль¬ ные счетчики устанавливаются равными 1. Если ввод исчерпан до того, как достигнут первый совершенный уровень (по одной строке iia каждой ленте), то слияние всех имеющихся строк образует упорядоченную строку за один просмотр, фактически являющийся «последним просмотром». Когда исходные строки распределены, алгоритм регулирует идеальные счетчики каждой ленты. Алгоритмы всегда определяют «следующий» уровень для всех лент, но конкретная расстановка строк на новом уровне будет из¬ меняться. Факторы, влияющие на алгоритм, включают желание предсказать заключительную ленту вывода и возможность использования обратного чте¬ ния при просмотрах слияния. Для вертикального распределения, описанного Рейнольдсом [37], харак¬ терно то, что на любом идеальном уровне лента с наибольшим числом строк имела наибольшее число строк и на предыдущем уровне. Более того, на лю¬ бом уровне лента с наименьшим числом строк была таковой и на предыду¬ щем уровне. На рис. 14.5 показана эта взаимосвязь, а также предложен механизм для работы со счетчиками. После того, как начальный уровень — 1,1,1 — установлен, можно строить следующий уровень, добавляя Тi по оче¬ реди на каждую из оставшихся лент, для того, чтобы образовать новую сумму для Т1, Г2, ..., Tk-i. Лента Тi на любом уровне имеет наибольшее число строк (и всегда является лентой приращения), а лента Tk~i всегда имеет наименьшее число строк. Когда уровень сформирован, как показано на рис. 14.5, то достигается он либо вертикальным, либо горизонтальным рас¬ пределением. Другой механизм формирования идеальных счетчиков, описанных в раз- Деле 14.3, изменяет ленту приращения от уровня к уровню (см. рис. 14.6). Ои подробно описан Мендозой [35]. На рис. 14.7 показан последовательный переход от уровня 13, 11, 7 к уровню 24, 20, 13 при вертикальном и горизонтальном распределениях. Изме¬ ненное горизонтальное распределение дает другой новый уровень, который эк- В1,валентен перестановке данного нового уровня. Решающей разницей между распределениями является положение строк На лентах, когда идеальный уровень не может быть достигнут. Идеальный УР°вень не достигнут, если ввод исчерпан, а положение строк на лентах иа- ^одится на рис. 14.7 между 13, И, 7 и 24, 20, 13. Если идеальный уровень ■j. ~ ^0стигнут, то для многоэтапного слияния нужен какой-то способ настрой- Таким способом может быть частичный просмотр или использование фик- величин. Частичные просмотры пытаются переместить и объединить ^ г* Лорин
194 ГЛ. 14. МНОГОЭТАПНОЕ СЛИЯНИЕ НА ЛЕНТАХ строки так, чтобы вернуться к ранее достигнутому совершенному уровню. Фиктивные величины создают впечатление, что совершенный уровень достиг¬ нут, добавляя строки длины 0. Мендоза и Рейнольдс подробно описали алгоритмы частичных просмртров для различных промежуточных состояний. В общем случае настройки для т0 Т\ т, Тз То Тх То Тг I 1 1 1 I 1 1 1 2 2 1 2 2 1 4 3 2 4 2 3 7 6 4 4 6 7 13 11 7 11 13 7 24 20 13 24 13 20 Уровень г + 1: Т\ = ТХ + Т2\ Т2=ТХ + Гз; 7'з = 7,1+°- Tk-\=TX• Рис. 14.5. Распределение Рейнольдса. Рис. 14.6. Распределение Мендозы. Вертикальнее распределение То Т, т2 Т3 Число строк Комментарии I 13 11 7 31 I 24 11 7 42 Тй на следующем уровне I 24 20 7 51 Ти Т2 на следующем уровне I 24 20 13 57 Все на следующем уровне Горизонтальное распределение Та Т i Т2 Тз Число строк Комментарии I 13 11 7 31 I 14 12 8 34 Каждая лента увеличивается на 1 I 19 17 13 49 Тз полна I 22 20 13 55 Т2 полна I 24 20 13 57 Тз полна Альтернативное горизонтальное распределение То Т, Т2 Тз Число строк I 13 11 7 31 I 13 24 20 57 Рис. 14.7. Вертикальное и горизонтальное распределения. горизонтальных состояний обеспечивают более эффективные слияния. (В этой книге они не описаны.) Использование фиктивных величин стало общеприня¬ тым в силу его эффективности и простоты. 14.5. Фиктивные величины Можно сделать вид, что идеальный уровень уже достигнут. Псевдоиде- альный уровень внешне выглядит так же, как и в момент исчерпания. Этот метод называется методом фиктивных величин [37]. Фиктивными величинами являются строки, которые представлены только внутренними счетчиками. По¬ чти с любым фактическим распределением можно обращаться как с идеаль¬ ным уровнем, используя внутренние счетчики. Однако конкретная обработка счетчиков фиктивных величин в конечном итоге влияет на производительность
14.5. ФИКТИВНЫЕ ВЕЛИЧИНЫ 195 многоэтапного слияния. Метод фиктивных величин работает как с горизон¬ тальным, так и с вертикальным распределением, но наиболее эффективное его использование приводит к «смешанному распределению», при котором некото¬ рые строки распределяются горизонтально, а некоторые вертикально. На рис. 14.8 показано окончание распределения и набор соответствующих Фиктивных величин. У каждой ленты есть счетчик фиктивных величин, значе¬ ние которого равно разнице между фактическим числом строк на ленте и чис¬ лом строк, необходимых для идеального уровня. Эти счетчики можно устано- То 7\ 7\ J 1 Т\ I 8 16 15 4 12 идеальный — 8 12 10 9 7 фактический 0 4 5 5 5 фиктивный Рис. 14.8. Счетчики фиктивных величин. вить, сычитая фактические счетчики из идеальных счетчиков или сохраняя во время исполнения счетчик строк, который также размещается на ленте. Когда строка с некоторой ленты должна быть включена в слияние, мно¬ гоэтапное слияние проверяет счетчик фиктивных величин этой ленты. Если он равен 0, то лента обрабатывается обычным образом. Если этот счетчик не равен 0, то он уменьшается на 1, но никаких операций ввода-вывода с этой лентой не выполняется. По мере ТОГО, как счетчики достигают 0, все больше Реально Фиктивные величины Число переме¬ щенных длин Т0 г, т2 Г3 Т» т, 7% Ту т2 Гз ТА т, строк 0 8 12 10 9 7 _ 0 4 5 5 5 4 (L) 4 12 10 9 7 0 0 0 1 1 1 4 4(L) \ 3 11 10 9 7 0 0 0 1 1 1 2 1 (2L) J 0 0 0 0 0 0 4 (L) ) 1 (2L) } 0 8 7 6 4 15 3 (5L) ) 21 Рис. 14.9. Слияние с фиктивными величинами. и больше лент поставляет реальные строки для слияния. При этом все счет¬ чики фиктивных величин необязательно очищаются за один просмотр. На рис. 14.9 идеальный уровень— (8, 16, 15, 14, 12) —не достигнут. Из¬ начально, Т1 — единственная лента без фиктивных величин. С Тt на Т0 копи¬ руется некоторая строка, а все остальные счетчики уменьшаются на 1. Этот процесс как бы сливает строки длины 0 с лент Т2 — Тъ со строками длины L с ленты Т1. После того, как все повторится четыре раза, на Го будет четыре строки длиной по 1, а счетчики фиктивных величин лент Тг — Т5 будут равны 1, 1 соответственно. Поскольку счетчик фиктивных величин ленты !Тг Равен 0, то теперь она начинает поставлять для слияния реальные строки. Когда при слиянии строк с Т\ и Т2 будет сформирована строка длины 2Lf Все счетчики фиктивных величин станут равными 0. В это время все ленты Начнут поставлять для слияния реальные строки. Рис. 14.9 показывает, что ^стоящий совершенный уровень— (8, 8, 7, 6, 4) достигается тогда, когда Тi °Уста. Была'перемещена 21 строка.
196 ГЛ. 14. МНОГОЭТАПНОЕ СЛИЯНИЕ НА ЛЕНТАХ Конкретное распределение в момент исчерпания влияет на производитель- ность, равно как и на способ использования счетчиков фиктивных величин. Один способ управления фиктивными величинами называется выравниванием. Цель — распределить фиктивные величины так, чтобы их количество на каждой ленте было как можно ближе друг к другу. Для достижения этой цели алгоритм распределен.11 я изменяется так, чтобы лента, требующая наи¬ меньшего увеличения для достижения следующего уровня, не получала строк до тех пор, пока счетчики фиктивных величин других лент не уменьшатся до ее значения. Результат выравнивания — сведение к минимуму копирования строк и частичного слияния за счет замены копирования и частичных слияний пере¬ мещением фиктивных величин. Предпочтение одной расстановки уровня перед другой зависит от необходимости управлять распределением фиктивных ве¬ личин от уровня к уровню. Другой причиной выбора конкретной расстановки является необходимость выбора конкретной заключительной ленты вывода. При многоэтапном слиянии окончательная упорядоченная строка всегда бу¬ дет размещаться на той ленте, у которой было нечетное число строк или не¬ четная сумма строк и фиктивных величин в конце распределения. Управляя распределением так, чтобы на каждом уровне на нужной ленте вывода было нечетное число строк, можно обеспечить размещение упорядоченных данных на нужной ленте. Однако, на каждом (k—1)-м уровне все ленты содержат нечетное число строк. Для того, чтобы прогнозировать заключительную ленту вывода, необходимо исключить эти «тотально нечетные» уровни как недопу¬ стимые, и объявить последующий уровень очередным идеальным. 14.6. Обратное многоэтапное слияние Желание избежать перемоток и воспользоваться обратным чтением лент приводит к основательным изменениям многоэтапного слияния. Чтобы цели¬ ком включить новое требование, необходимо развить алгоритм распределения. _Го т, 7j 13Л ИЛ 7 А 7D 8Л 4Л О Рис. 14.10. Обратное чтение. Соответствующее размещение фиктивных величин становится значительно бо¬ лее тонким. Можно изменить поведение сортировки, используемой для созда¬ ния исходных строк. 14.6.1. Распределение. Первый просмотр слияния на рис. 14.10 создаст семь строк на То. Если не делать перемоток после начального распределения, то на первом этапе ленты Т4, Т2 и Т3 будут читаться в обратном направле¬ нии до тех пор, пока не исчерпается лента 7Y Строки, сформированные на То, обязательно будут убывающими. По завершении этого этапа строки на Тi ч Т2 будут исходными строками, упорядоченными по возрастанию, и слияние нельзя будет продолжать. Для того, чтобы выполнить обратное многоэтапное слияние, алгоритм сор¬ тировки и распределения должен распознавать направление строк. Для вы*
14.6. ОБРАТНОЕ МНОГОЭТАПНОЕ СЛИЯНИЕ 197 п0ЛНения слияния необходимо достигать каждого уровня, имея только одну ленту с нечетным числом строк, и изменять направление строк на каждой ленте. Строка, размещаемая первой на ленте, на которой будет нечетное чис¬ ло строк, должна иметь нужное окончательное направление. Размещение 7, 6, 4? показанное на рис. 14.11, удовлетворяет этим требованиям, А соответ¬ ствует возрастающим строкам, D — убывающим. Числа, следующие за А и D, То т, т2 Т3 ДСП D02 D03 £>04 А05 А 06 А07 £>08 £>09 D010 АОП А012 А013 £>014 £>015 А016 А017 7 6 4 Рис. 4.11. Изменение направления строк. указывают порядок размещения строк. Это распределение предполагает, что желаемой лентой вывода будет ТПервыми сливаются строки Л17, Л16 и Л12 и формируют убывающую строку на Т0. Это слияние показано на рис. 14.12. Первая цифра каждой строки указывает просмотр, на котором Т0 г. Тг т3 Комментарии — Л01 D02 £>03 £>04 А05 АОб А07 £>08 D09 £>010 A0U А012 А013 D014 Исходный D015 А016 А017 (7, 6, 4) То Т\ Т2 То £>101 (17, 10, 12) А01 D02 0 Конец первого этапа АЮ2 (15, 14, 9) D04 А05 £>103 (13, 11, 6) А07 Л104 (10, 8, 3) (4, 3, 2) То Г| Т 2 То D101 А01 0 D201 (104, 7. 5) Конец второго этапа Л102 Л202 (103, 4, 2) (2, 2, 1) £>201 Конец третьего этапа £>101 0 D302 (102, 202, 01) (1, 1. 1) А401 (101, 301, 201) Рис. 14.12. Обратное многоэтапное слияние. °на была создана. Числа в скобках показывают строки-компоненты. Это слия- иие похоже на прямое многоэтапное слияние характеристиками просмотра, роста строк и сворачивания строк. Оно отличается только требованием изме- ^ния направления строк и обязательным требованием четно-нечетного рас- пРеделения. 14.6.2. Размещение фиктивных величин. Поскольку ленты будут читаться Как вперед, так и назад, то группировка длинных или коротких строк в
198 ГЛ. 14. МНОГОЭТАПНОЕ СЛИЯНИЕ НА ЛЕНТАХ начале или в конце ленты (важная при чтении ленты в прямом направлении) теряет значение. Можно игнорировать эту деталь и обрабатывать фиктивные величины так, как будто они находятся в начале лент; таким образом, счи¬ тается, что фиктивные величины всегда предшествуют сливаемым строкам. Но этот подход не дает оптимального многоэтапного слияния. При оптимальном размещении фиктивных величин для многоэтапного слияния с обратным чтением фиктивные величины «разбрасываются» по ленте так, что они занимают те позиции строк, которые используются наиболее ча¬ сто, при этом настоящие строки занимают те позиции, которые реже исполь¬ зуются при слиянии. Создание алгоритмов распределения для такого подхода является актуальным направлением работ специалистов данной области. За¬ интересовавшемуся читателю будет полезна статья Шелла [40]. 14.6.3. Длина строк. Если для создания начальных строк используется внутренняя сортировка выбором с заменой, то изменение направления строк может отрицательно повлиять на длину строк и, следовательно, при¬ вести к большому количеству строк. Степень влияния направления на количе¬ ство строк зависит от алгоритма распределения и упорядочения данных. Ко¬ роткие строки (ближе к 1.5F, чем к 2F, где F — количество элементов в тур¬ нире) получаются потому, что изменение направления строк делает каждую строку, по существу, начальной строкой. Алгоритм распределения будет опре¬ делять частоту изменения направления и, следовательно, частоту появления короткой строки. Строго вертикальный алгоритм будет изменять возрастаю¬ щие и убывающие строки так, что каждая строка сменит направление. При горизонтальном алгоритме, как правило, будут последовательности строк одинакового направления. Это явление демонстрирует последовательность чи¬ сел на рис. 14.2. 14.7. Внутреннее влияние многоэтапного слияния Номинально слияние степени k — 1 имеет следующее влияние на внутрен¬ нюю организацию этапа слияния: ' 1. Механизм сравнения будет использовать скорее k— 1, чем /г/2 элемен¬ тов. Для выбора следующего члена строки вывода потребуется больше вре¬ мени сравнения. 2. Для ввода-вывода потребуется больше памяти. Только для работы по¬ требуется как минимум k—1, а не /г/2 полей памяти для блоков; для того, чтобы обеспечить блоком-дублером каждый вход, потребуется 2k — 2, а не k буферных областей. С другой стороны, упадет скорость исчерпывания, и мож¬ но будет использовать метод предварительного выбора. Если из-за требова¬ ний больших блоков для слияния степени k— 1 придется сократить буфериза¬ цию ниже уровней эффективности или уменьшить размер блоков, то произ¬ водительность конкретного многоэтапного слияния, если оно будет перемещать меньше данных, серьезно упадет. При большом количестве лент и памяти умеренного размера зачастую возможно, что сбалансированное слияние, даже когда оно перемещает больше данных, будет превосходить по производитель¬ ности многоэтапное слияние в силу своих намного более умеренных требова-
14.9. ГИБКОСТЬ ИСПОЛЬЗОВАНИЯ ЛЕНТ 199 14.8. Подсистема ввода-вывода и многоэтапное слияние Возможности подсистемы ввода-вывода имеют серьезное влияние на при¬ годность многоэтапного слияния для системы. Необходимо, чтобы подсистема ввода-вывода была в состоянии обеспечить k— 1 вводов и один вывод на лен¬ ты. На машинах с одним каналом производительность многоэтапного слияния не представляет особенной проблемы, так как совмещение чтения-записи все равно невозможно. На системах с двумя каналами будут чередующиеся задержки чтения- записи при использовании многоэтапного слияния, поскольку на таких систе¬ мах нет никакой гарантии, что при чтении ленты ввода не произойдет кон¬ фликта с процессом записи. При распределении k — 1 лент ввода по двум каналам очень велика вероятность того, что считываться будет лента, распо¬ ложенная на том же канале, что и лента вывода. Системы, которые спон¬ танно определяют свободный канал для устройств или обеспечивают допол¬ нительные пути передачи данных, свободны от этого недостатка. 14.9. Гибкость использования лент Модификации распределения строк, которые рассматриваются в этом раз¬ деле, не являются центральными в многоэтапном слиянии. Однако, они могут быть полезны для программиста, который создает свое многоэтапное слияние с учетом конкретных данных. 14.9.1. Ухищрения. В интересах эффективности системы, пользователю может понадобиться вести какие-нибудь протоколы на этапе распределения. На системе с шестью лентами для распределения строк ему будет доступно скорее четыре, а не пять лент. Однако, пользователь хочет в течение слияния полностью использовать преимущество системы с шестью лентами. Этот слу¬ чай показан на рис. 14.13. Лента 0 являетсд лентой ввода. Лента 1 выделена Т\ Тл Тз Т\ Тл 7j FPOC FPOC 0 2(1. 1) 0 0 1 1 0 1 5 FPOC 2(1. 2) 2 2 2 9 FPOC 5 (3, 2) 4 4 4 17 FPOG Ю (6, 4) 7 8 8 33 4 6 7 8 Рис. 14.13. Ухищрение. 8 Под «собственный код первого просмотра» FPOC и используется для вывода, Не связанного с сортировкой. Распределение строк организовано так, как будто доступны все пять лент вывода. Однако одна из лент несет двойную нагрузку: она содержит свои Сгроки и строки для ленты, которая недоступна при распределении. Если нет 0гРаничений, например, связанных с выбором заключительной ленты вывода, т° лента, несущая двойную нагрузку, должна соответствовать лентам с наи- Меньшим числом строк. При этом копирование после окончания этапа распре- ^еления минимально. Когда лента 1 (рис. 14.13) становится доступной для Слияния, строки с Тг копируются на 7\, и можно выполнять соответствующее
200 ГЛ. 16. КАСКАДНОЕ И КОМПРОМИССНОЕ СЛИЯНИЯ НА ЛЕНТАХ пятипоточное слияние. При обратном многоэтапном слиянии необходимо поза¬ ботиться о правильном направлении строк. Если идеальный уровень не до¬ стигнут, выполняется копирование и расставляются фиктивные величины для представления любой формы исчерпывания, которая может возникнуть, если все ленты получали строки. 14.9.2. Освобождение ленты на последнем просмотре. Требование, анало¬ гичное требованию при использовании лент на первом просмотре, может воз¬ никать и на последнем. Пользователь может захотеть использовать все ленты с полной выгодой как при распределении, так и при слиянии до последнего То Т1 Тг Тг ТА г5 0 1 1 1 0 1 0 2 2 2 1 1 2 4 4 3 3 Распределение 0 6 4 8 7 7 4 2 0 4 3 3 2 0 2 2 1 1 Слияние 1 1 1 1 0 0 0 0 0 0 X 1 Последний просмотр Рис. 14.14. Раннее высвобождение. просмотра, где он хочет иметь дополнительную ленту для «собственного кода последнего просмотра» (LPOC). На последнем просмотре он может выбрать ленту по своему усмотрению. Распределение настраивается так, чтобы лента, которая должна быть пустой к началу последнего просмотра, была бы исчерпана к этому времени. Ни одна строка не попадает на эту ленту, когда установлен первый уровень распределения. В течение слияния на этой ленте не будет хватать одной строки, и следовательно, она будет исчерпана к последнему просмотру. На рис. 14.14 показано раннее высвобождение. 14.9.3. Восстановление. После каждого этапа можно устанавливать точ¬ ки восстановления, снимая ту ленту, которая была исчерпана в конце этапа и заменяя ее новой лентой. Если на следующем этапе возникает отказ, требую¬ щий повторного исполнения, то установка сохраненной ленты и возврат остальных лент на прежние позиции вернет процесс в состояние, соответ¬ ствующее началу этого этапа. Глава 15. КАСКАДНОЕ И КОМПРОМИССНОЕ СЛИЯНИЯ НА ЛЕНТАХ 15.1. Введение Каскадное слияние формально является (k—1)-поточным слиянием и во многом схоже с многоэтапным слиянием. С точки зрения практики разница между ними в том, что каскадное слияние более мощно при большом коли¬ честве лент, а многоэтапное — при малом. Каскадное слияние изначально было
16.2. КАСКАДНОЕ СЛИЯНИЕ С ПРЯМЫМ ЧТЕНИЕМ 201 задумано как метод с обратным чтением лент, но пригодна и версия с пря¬ мым чтением. Описание этого метода, следуя порядку изложения многоэтап¬ ного слияния, начнем со случая прямого чтения. 15.2. Каскадное слияние с прямым чтением: распределение и слияние Идеальные уровни каскадного слияния для трехленточиой системы иден¬ тичны идеальным уровням многоэтапного слияния, которое было описано в главе 14. При большем количестве лент обобщение последовательности Фибо¬ наччи, которое определяет идеальные уровни для каскадного слияния, отли¬ чается от такового для многоэтапного слияния. На рис. 15.1 показан идеальный уровень для каскадного слияния на че¬ тырех лентах. Опишем кратко, как получить идеальный уровень. На этапе 1 Число перемещенных Т0 Т\ Гг Т\ Число строк Этап длин строк — 14 11 6 31 0 6 (3L)R 8 5 °R 19 1 18 6 (3L) 3 °R 5 (2L)R 14 2 10 6 (3L) 0R 3(L)r 5 (2L)R 14 3 3 31 Частичный Степень Число просмотр слияния строк 1 k — \ 6 2 k — 2 5 3 Л-3 3 Рис. 15.1. Один проход каскадного слияния (R — перемотка). выполняется трехпоточное слияние 6 строк степени k—1. Когда Т3 исчер¬ пана, она перематывается, и в качестве этапа 2 выполняется двухпоточное слияние степени k — 2 пяти строк. Когда Т2 исчерпана, она перематывается и происходит однопоточное слияние (степени k — 3 или этап копирования) на Т2. Когда этот этап (3) завершен, то уже достигнут новый идеальный уро¬ вень, а данный просмотр закончен. «Просмотр» каскадного слияния состоит из последовательности этапов. Каждый этап имеет собственную степень слия¬ ния. Первый этап имеет степень k—1, а последующие этапы имеют степени ^ — 2, k — 3 ... до последнего этапа, копирование (которое может быть опу¬ шено) завершает этот просмотр. Каждый этап завершается исчерпанием лен¬ ты ввода. После перемотки опустошенная лента используется на следующем этапе для вывода. Лепта вывода на каждом этапе также перематывается. Каждый просмотр состоит из k — 1 этапов. Каждый этап требует двух пере¬ моток, так что при каждом просмотре выполняется 2(k—1) перемоток. Пе¬ ремотка исчерпанной ленты должна быть закончена до начала следующего этапа, так как на следующем этапе она будет лентой вывода. Это время Перемотки всегда добавляется к общему времени слияния. Ленту вывода любого этапа можно перемотать в течение следующего этапа, поскольку она Не используется. Эту дополнительную перемотку всегда можно совместить. Это слияние, несмотря на то, что его номинальная степень равна k—1, не выдерживает эффективной степени слияния, равной k—1. От количества лв»т и конкретной совокупности строк зависит, где на отрезке между 6/2 и
202 ГЛ. 15. КАСКАДНОЕ И КОМПРОМИССНОЕ СЛИЯНИЯ НА ЛЕНТАХ к—1 будет лежать «степень» каскадного слияния. Эта степень зависит от доли строк, вовлекаемых в (k—1)-поточное слияние, (k — 2)-поточное слия¬ ние и т. д. Эти доли, естественно, зависят от того, с какого уровня начи¬ нается просмотр. Этот метод, как правило, мощнее при большой совокупно¬ сти строк. Скорость сворачивания строк в этом методе всегда больше, чем у сбалансированного слияния. Для каскадного слияния характерно неболь¬ шое число просмотров данных. Бывают совокупности строк, которые требуют одинакового числа просмотров, как при том, так и при другом методе, но, когда число строк становится существенно большим, число просмотров при каскадном слиянии начинает уменьшаться по сравнению со сбалансированным слиянием. 15.3. Уровни каскадного слияния Для построения уровней распределим k — 1 строк по столбцам, которые представляют одно лентопротяжное устройство ввода и k — 1 лентопротяжных устройств вывода. Возьмем первую ленту распределения Т\. Каждый после¬ довательный уровень получается суммированием строк. 1. Тi(L 1) = TiL T2L ТзЬ Тk-iL. 2. Ti(L 1) = ТiL -\-TzL T^L Тk-гL. 3. Tk-i(L+ 1)= TtL Здесь L — текущий уровень, a L + 1 — следующий желаемый уровень. Равенство 1 означает, что число строк на Тi на следующем уровне каскад¬ ного слияния равно сумме всех строк на лентЗТ на данном достигнутом Уровень То Г2 Г3 Число строк 1 1 1 1 3 2 3 2 1 6 3 6 6 3 14 4 14 И 6 31 5 31 25 14 70 6 70 56 31 157 а) Идеальный уровень Уровень Т\ т2 Тг 2 1 + 1 + 1 1 + 1 1 3 3 + 2+1 3 + 2 3 4 6 + 5 + 3 6 + 5 6 5 14+11+6 14+11 14 6 31 + 25+ 14 31 + 25 31 Ь) Формирование уровня Рис. 15.2. Уровни каскадного слияния. уровне. Равенство 2 означает, что число строк на 7^ на следующем уровне равно сумме строк на всех лентах на данном достигнутом уровне, за исклю¬ чением последней ленты. При каждом суммировании исключается по одной ленте до тех пор, пока на последней ленте на следующем уровне не будет такого же числа строк, как и на Ti на предыдущем уровне. На рис. 15.2, а) изображены идеальные уровни для четырехленточного каскадного слияния. На рис. 15.2, Ь) даны компоненты строк каждой ленты.
15.4. ОБРАТНОЕ КАСКАДНОЕ СЛИЯНИЕ 203 соответствующие равенствам 1, 2 и 3. На рис. 15.3 показано, как были бы слиты 190 строк при каскадном слиянии на шести лентах. Идеальные уровни это- го распределения равны 55, 50, 41, 29, 15. Меньшие уровни можно обнаружить Т0 Т\ 7\ Ts Т\ Г5 Число строк — 55 50 41 29 15 190 15 (5L) 40 35 26 14 0 5-поточное 15 (5L) 26 21 12 0 14 (4L) 4-поточное . 15 (5L) 14 9 0 12 (3L) 14 (4L) 3-поточное 15 {Ы) 5 0 9(2L) 12 (3L) 14 (4L) 2-поточное 15 (5L) 0 5 (L) 9 12 14 (4L) 55 Копирование или пе¬ ремотка 10 (5L) 5 (15L) 0 4 (2L) 7(3L) 9 (4L) 5-поточное 6(5 L) 5 (15L) 4 (14L) 0 3 (3L) 5(4L) 4-поточное 3(5 L) 5 (15L) 4 (14L) 3M2L) 0 2(4L) 3-поточное 1 (5L) 5 (15L) 4 (14L) 3 (12L) 2 (9L) 0 2-поточное 0 5 (15L) 4 (14L) 3 (12L) 2 (9L) 1 (5 L) 15 Копирование или пе¬ ремотка 1 (55L) 4 (15L) 3 (14L) 2 (12L) 1 (9 L) 0 5-поточное 1 (55L) 3 (15L) 2 (14L) 1 (12L) 0 1 (50L) 4-поточное 1 (55L) 2 (15L) 1 (14L) 0 1 (41L) 1 (50L) 3-поточное 1 (55L) 1 (15L) 0 1 (29L) 1 (41L) 1 (50L) 2-поточное 1 (55L) 0 1 (15L) 1 (29L) 1 (41L) 1 (50L) 5 Копирование или пе¬ ремотка 0 1 (190L) 0 0 0 0 1 Последний просмотр - 55 50 41 29 15 190 15 0 5 9 12 14 55 0 5 4 3 2 1 15 1 0 1 1 1 1 5 0 1 0 0 0 0 1 Замечание. Подчеркнутые ленты либо являются лентами вывода, либо исклю¬ чаются из этапа. Рис. 15.3. Каскадное слияние 190 строк. ь краткой сводке просмотров. Каскадное слияние будет поочередно проходить через каждый из этих идеальных уровней. В конце любого просмотра самые Короткие строки будут располагаться на топ ленте, на которой меньше всего Ci рок. Способность этого метода интенсивно просматривать строки объясняется тем, что разрыв между уровнями в этом методе намного больше, чем разрыв между уровнями в многоэтапном слиянии. Чтобы определить новый уровень, нУжно больше дополнительных строк, и любое заданное число строк будет сдито за меньшее количество просмотров. 15.4. Обратное каскадное слияние Разница между каскадными слияниями с обратным и прямым чтением н°велика. Вместо перемотки применяется движение ленты в обратном на¬ бавлении. Пока сортировка не закончится, перемотка не выполняется. В за¬
204 ГЛ. 15. КАСКАДНОЕ И КОМПРОМИССНОЕ СЛИЯНИЯ НА ЛЕНТАХ висимости от характеристик перемотки и изменения направления движения, можно значительно увеличить эффективность. Недостатком метода является возможность создания заключительной строки в неправильном направлении. Этот недостаток можно преодолеть либо путем обязательного копирования, либо гарантируя, что всегда будет четное число просмотров. Гарантируя чет¬ ность числа просмотров (как это сделано в пакете сортировки SODA для UNIVAC III), можно серьезно повлиять на способ распределения. Рис. 15.4 иллюстрирует просмотр каскадного слияния с обратным чте¬ нием, указывая, где изменяется направление движения лент. Заметим, что перевернутые строки в течение просмотра вторично не используются. После То Т\ г2 Тг т% Ть Изменение направления _ 15 А 14 А 12 А 9А ЬА Все, Т0 перематывается 5Р \0А 9 А 7 А 4 А 0 Го, Ть 5D 6 А ЬА 3 А 0 АР Ть, Г, 5 D 3 А 2 А 0 3D AD Гз, ТА 5 D \А 0 2D 3D AD 2*. Ть 5D 0 1D 2D 3D AD Ти Tt Рис. 15.4. Обратное каскадное слияние, один просмотр (А — возрастающая строка, D — убывающая строка). начального распределения строк направление движения всех лент изменяется, и ленты читаются в обратном направлении. Впоследствии направление дви¬ жения лент изменяется после того, как они исчерпываются, и после того, как они получают строки. Этап заключительного копирования является необяза¬ тельным и зависит от затрат на него на используемой аппаратуре. Направле¬ ние оставшейся строки может быть с успехом изменено при помощи пере¬ мотки. 15.5. Распределение строк при каскадном слиянии Размещение строк для каскадного слияния может быть вертикальным, горизонтальным или смешанным; настройка между уровнями может происхо¬ дить при помощи частичных просмотров или фиктивных величин. Если идеаль¬ ный уровень не достигнут, то издержки при каскадном слиянии обычно боль¬ ше, чем при многоэтапном. 15.5.1. Настройка при помощи фиктивных величин. Метод фиктивных ве¬ личин может быть применен к каскадному слиянию. Настройка фиктивными величинами перемещает строки для достижения идеального уровня. По этой причине выбор горизонтального или вертикального распределения, а также соответствующих распределений между уровнями не влияет на производи¬ тельность слияния. На рис. 15.5 показано вертикальное распределение, кото¬ рое пытается достичь уровня 14, 11, 6 на трех лентах вывода. Исчерпание наступает после распределения 24 строк. Последним был достигнут уровень 6, 5, 3. Вертикальное распределение «загоняет» Тi на следующий уровень, но исчерпание ввода наступает после записи двух строк на ленту 2. Фиктивные величины с D0 по D3 показаны сбоку от распределений на лентах. В примере
15.5. РАСПРЕДЕЛЕНИЕ СТРОК ПРИ КАСКАДНОМ СЛИЯНИИ 205 р2 = 4 и Z>3 = 3, чтобы дотянуть распределение до нужного уровня. Чтобы вернуться к предыдущему уровню б, 5, 3, настройка продолжается таким же образом, как и в методе фиктивных величин для многоэтапного слияния. Строчка 2 на рис. 15.5 показывает перемещение строк с Тi (соответ¬ ствующих слиянию Т1, D2, D3) на То. Когда будут скопированы три строки с этой ленты, счетчики фиктивных величин у всех остальных лент уменьшатся на 3, в результате чего D3 (соответствующая Г3) станет равной 0. Строчки 3 и 4 на рис. 15.5 показывают состояние строк после слияния 7\, £2? Тз на Т0. Это двухпоточное слияние, которое захватывает только одну строку, поскольку D2 станет равной 0 после слияния одной строки. Строчки 5. 6 и 7 показывают трехпоточное слияние, которое продолжается до тех пор, Число Цель Т0 14 т, 11 тг 16 тя Число строк перемещенных строк Do л, Dt D3 1. - 14 7 3 24 - 0 0 4 3 2. 3 (L) 11 7 3 3 0 0 1 0 3. A P(L) 4. 1 1 (2 L) 10 7 2 2 0 0 0 0 5. f3 (L) 6. 6 < 1 (2L) 7. Ь (3L) 8 5 0 6 8. 6 3 0 5<2L) 10 9. 6 0 3 (L) 5(21) 3 24 Рис. 15.5. Настройка фиктивными величинами. пока Тз физически не исчерпается. Строчки 8 и 9 показывают обычные (k — 2) и (k — 3) этапы этого процесса, в конце которого достигается уро¬ вень 6, 5, 3. Если используется метод фиктивных величин, то при любом распределе¬ нии строк между уровнями, перемещений данных включает один полный просмотр данных для достижения совершенного уровня. Таким образом, если распределение 6, 5, 3 обычно сводится к одной строке за три просмотра, то любое число строк между 14 и 31 потребует четырех просмотров. 15.5.2. Частично-просмотровое, парно-просмотровое распределение. Инте¬ ресный и эффективный, хотя и несколько сложный, подход для распределения при каскадном слиянии был создан для пакета сортировки SODA (Sequential Ordering of DAta) для UNI VAC III. Он рассматривается здесь, потому что алгоритм частичного просмотра для каскадного слияния ранее не был опубли¬ кован в широкой литературе. Этот метод пытается преодолеть следующие два недостатка метода фик¬ тивных величин: 1. Метод фиктивных величин нечувствителен к направлению строк, и для того чтобы достичь нужного пользователю упорядочения (возрастающего или Убывающего), может потребоваться заключительный копирующий просмотр. 2. Метод фиктивных величин перемещает все строки на достигнутый иде¬ альный уровень. Частичный просмотр может уменьшить влияние несовершен- н°г° уровня.
206 ГЛ. 15. КАСКАДНОЕ И КОМПРОМИССНОЕ СЛИЯНИЯ НА ЛЕНТАХ Этот метод основан на горизонтальном распределении и определении це¬ лей промежуточных распределений, достигаемых с помощью групп строк, называемых «слоями» [31]. 15.5.2.1. Послойное распределение. Слой — это совокупность строк, распределяемая таким образом, что пара частичных просмотров слия¬ ния сведет фактическое число строк к уровню каскадного слияния. То Т\ Тг Тг Используемый слой Слой - 3 2 1 * (1)2, 2, 1 1. 5 4 2 1 (2)2, 1, 1 2. 7 6 3 1 (3)1, 1. 0 3. 9 8 4 1 4. 11 9 5 2 5. 13 10 о 2 С. 14 11 6* 3 * Идеальные уровни Рис. 15.6. Послойное распределение. На рис. 15.6 приведен пример послойного распределения. Процесс опреде¬ ления слоя рассматривается в следующем разделе. Это распределение пропу-. скает уровень 6, 5, 3 и сразу переходит от уровня 3, 2, 1 к уровню 14, 11, 6. Данная схема гарантирует, что всегда будет четное число просмотров, и устраняет необходимость в заключительном копирующем просмотре. Слои обеспечивают механический способ перехода к разным идеальным уровням. На рис. 15.6 указано количество строк на каждой ленте после распреде¬ ления ранее определенных слоев. Слой 1 распределялся трижды (строчки 1,2,3 на рис. 15.6), слой 2 — дважды (строчки 4, 5) и слой 3 один раз (строчка 6). При слиянии максимальной (k—1) степени, будет k—1 уникальных слоев. Поэтому на рис. 15.6 есть три слоя: 2,2,1; 2,1,1; 1,1,0. Количество использований слоя на каждом уровне определяется числом строк на каждой ленте на предыдущем уровне. Лента 1 (лента с наибольшим числом строк) определяет, сколько раз будет использован слой 1; лента 2 определяет число использований слоя 2; а лента (k—1) определяет число использований слоя (k—1). Количество удачно распределенных слоев опре¬ деляет число строк, которое надо переместить с каждой ленты на частичном просмотре. 15.5.2.2. Вычисление слоев. При построении уровней будем обо¬ значать: i — номер слоя, / — номер лентопротяжного устройства, и /*, / — при¬ ращение /-й ленты на t-м слое. На рис. 15.6 U — 2,2,1 *); /1,3 = 1, т. е. уро¬ *) Здесь, видимо, имеется в виду lit 1 = 2; /1,2 = 2; U, 3 = 1. (Прим, пере в.)
15.5. РАСПРЕДЕЛЕНИЕ СТРОК ПРИ КАСКАДНОМ СЛИЯНИИ 207 вень 1—2,2,1; приращение Г3 на слое 1 равно 1, k — число лентопротяжных, устройств. Ниже приведен алгоритм вычисления слоев. DO i = 1, k — 1; DO / = 1, k— 1; A = min (k — 1, k — /, k — /'); IF i = j THEN I (i, j) = A — 1; ELSE /(/, j) = A' END; END; i / (ft-D (ft-/) (ft-/) 1 1 4 4 4 3 * 1 2 4 4 3 3 1 3 4 4 2 2 1 4 4 4 1 1 2 1 4 3 4 3 2 2 4 3 3 2* 2 3 4 3 2 2 2 4 4 3 1 1 3 1 4 2 4 2 3 2 4 2 3 2 3 3 4 2 2 1 * 3 4 4 2 1 1 4 1 4 1 4 1 4 2 4 1 3 1 4 3 4 1 2 1 4 4 4 1 1 0* r ( min (ft — 1, , ft-/, ft — /), если i Ф /; LiJ-\ min (ft — 1, , ft — /, ft —/)—1, если /-/. Слой 1 : 3, 3, 2, 1 Слой 2 : 3, 2, 2, I Слой 3 : 2, 2, 1, 1 Слой 4 : 1, 1, 1, О * /--=/ Рис. 15.7. Построение слоев (6 = 5). То Т\ п Тг Та I i 1 1 1 4 3 2 1 Основной уровень 4Хслой 1 + 12 12 8 4 Слой 1 : 3, 3, 2, 1 16 15 10 5 Слой 2 : 3, 2, 2, 1 3Хслой 2 + 9 6 6 3 Слой 3 : 2, 2, 1, 1 25 21 16 8 Слой 4 : 1. 1, 1, 0 2Хслой 3 + 4 4 2 2 29 25 18 10 *Хслой 4 + 1 1 1 0 30 26 19 10 Идеальный уровень» Рис. 15.8. Распределение уровней.
208 ГЛ. 15. КАСКАДНОЕ И КОМПРОМИССНОЕ СЛИЯНИЯ НА ЛЕНТАХ Внутренний цикл управляет одним слоем для (k— 1) лент. Внешний цикл охватывает (k—1) слой. Значения U, / при k = 5 показаны на рис. 15.7. Эти значения потом ис¬ пользуются при достижении идеального уровня, число строк, уже расположен¬ ных на лентах с 1 по (k—1), указывает, сколько раз использовался слой. На рис. 15.8 показан результат использования этих слоев. 15.5.2.3. Алгоритм частичного просмотра. По окончании распределения строк, если совершенный уровень не был достигнут, то на всех лентах будут «лишние» строки. Общее количество строк на каждой ленте равно числу строк на последнем достигнутом идеальном уровне («нелишние» строки) плюс определенное число лишних строк. На каждом распределенном Межуровневое распределение слов Лента Слои Используется Лишние на Т^ Изъято с Т ^ 1. 2, 2, 1 14 40 54 2. 2, 1, 1 6 34 40 3. 1. 1, о 0 20 20 Распределение Го г, г2 Г3 I 14 11 6 Последний идеальный I +40 +34 + 20 Лишние (новые) 54 45 26 Исчерпание Рис. 15.9. Распределение 125 строк. слое i «нелишняя» строка (принадлежащая предыдущему идеальному уров* кю) с ленты i перемещается первым частичным просмотром вместе со всеми лишними строками. На рис. 15.9 показано распределение входа из 125 строк для четырехленточной системы. Это неидеальная совокупность строк. Она больше 70, но меньше 157 (см. рис. 15.2). 40 лишних строк попадают на Тt в результате того, что слой 1 использовался 14 раз, а слой 2 — 6 раз. 34 лишних строки создаются на Т2 так же, как и 20 лишних строк на Тз- Число изъятых строк (см. «Изъято с Ti» на рис. 15.9) равно сумме лишних строк и использованных уровней. На рис. 15.10 показаны частичные просмотры. На частичном просмотре 1 начальное трехпоточное слияние изымает все лишние строки с 7’3. (С нее изы¬ маются только лишние строки, потому что третий слой ни разу не использо¬ вался. После этого направление движения Т3 изменяется для получения строк от двухпоточного слияния, которое изымает все нужные строки с Т2. (См. рис. 15.9.) К настоящему моменту с Т2 изъято сорок строк.) Направление движения Т2 изменяется, чтобы получить с 7\ оставшиеся строки. Там оста¬ лось 14 нелишних строк. В общем случае, на частичном просмотре 1 слияние (k — 1)-й степени на Т0 исчерпывает счетчик «изъятых строк» на Тk-\. Эта лента затем изменяет направление движения, чтобы получать строки от слия¬ ния (k — 2)-й степени до тех пор, пока счетчик «изъятых строк» на Ть-г не будет исчерпан и т. д. Счетчик «изъятых строк» равен сумме изъятых лиш¬ них и нелишних строк. Строки, записанные в течение частичного просмотра, являются убывающими строками. На лентах, отличных от исчерпанных лент ввода, будет смесь из возрастающих и убывающих строк.
15.5. РАСПРЕДЕЛЕНИЕ СТРОК ПРИ КАСКАДНОМ СЛИЯНИИ 209 Частичный просмотр 2 должен достичь предыдущего уровня. Это делается перераспределением убывающих строк. Слияние степени k — 1 на ту ленту, на которой нет убывающих строк, очищает одну ленту с убывающими стро¬ ками и приводит одну ленту к идеальному уровню. На рис. 15.10 лента Тi получает строки от трехпоточного слияния, чтобы получить 14 возрастающих строк. Исчерпываемой лентой с убывающими строками является 7Y Эта лен¬ та теперь будет получать строки от двухпоточного слияния. Когда двухпоточ¬ ное слияние закончено, идеальный уровень достигнут, и все строки являются Частичный просмотр Г0 Т\ г2 г, 0 54 А 45Л 26Л 1 20D (3L) 34 А 25Л 6Л Строки в 3-поточном слиянии па Го. Изъято 20 лишних строк с Г3, Тъ Тх 20О (3L) 14 А 5Л 6Л 20 Строки в 2-поточном слиянии на Гл. Изъято 14 лишних и 6 нелишних строк с Г2. Изъ¬ ято 20 лишних строк с Тх 20О (3L) 0 < 5 II4DJ Г 6Л | 1 20О (2L) у 14 строк копируются на Гг. Изъятие 14 нелишних строк с Г, 2 60 (3L) 14Л (6L) 5Л 6Л 3-поточное слияние 14 убы¬ вающих строк на Т\ 0 0 14Л (6L) I 5Л \ \ 6Л (5L)У 6Л 2-поточпое слияние убываю¬ щих строк на Г2 Рис. 15.10. Частичные просмотры. Изъятие и возвращение строк. возрастающими. Число этапов, перераспределяющих убывающие строки, за¬ висит от начального распределения. В этом примере каждый частичный просмотр перемещает 114 длин строк. Четыре дополнительных обычных каскадных слияния доведут общее число Алин перемещенных строк до 728. При методе фиктивных величин шесть просмотров переместили бы 750 длин строк. Если лишних строк существенно меньше, чем нелишних, то эффективность частичного просмотра падает. Наилучшими случаями для метода частичных просмотров являются те, при которых идеальные уровни превышаются отно¬ сительно небольшим числом строк. На рис. 15.11 показан случай, в котором Достигнуто значительное сокращение перемещения строк. 15.5.3. Пары просмотров. Копирующего просмотра можно избежать, если сАелать число просмотров четным. Когда метод парных просмотров объеди¬ няется с методом частичных просмотров, возможна значительная экономия ПеРемещения строк. В методе пар частичных просмотров все идеальные уров- Hl1, получаемые при нечетном числе просмотров, рассматриваются, как не¬ реальное межуровневое распределение. При использовании послойного Распределения, уровни соответствующие нечетным просмотрам даже не
210 ГЛ. 15. КАСКАДНОЕ И КОМПРОМИССНОЕ СЛИЯНИЯ НА ЛЕНТАХ возникают. Правильное направление гарантируется не за счет полного копи¬ рования данных, а за счет настройки частичными просмотрами. Если слияния и копирование требуют одинакового времени, то способ парных просмотров, очевидно, предпочтительнее. При любом слиянии, если просмотры слияния занимают больше времени, чем копирование, то сокраще¬ ние перемещения строк может быть невыгодным. Например, если просмотры Число строк То Г, Тг Тз Tj Состояние 85 I 30 26 19 10 Последний идеальный 103 36 32 23 12 Исчерпывание a) Семейство строк. 1. Слой 1 : 3, 3, 2, 1. 2. Использование слоя 1 : 2 раза. 3. Изымаются лишние строки (103-85) : 18 раз. 4. Изымаются нелишние строки (число использований слоя): 2 раза. ■ 5. Всего перемещений во время частичного просмотра: 20X2 = 40. 6. За 4 полных просмотра строки перемещаются: 412 раз. 7. Всего перемещений: 452. 8. Всего перемещений с использованием метода фиктивных величин 515 (пять просмотров). b) Краткий итог частичного просмотра. Рис. 15.11. Успешный частичный просмотр. слияния строго критичны по вычислениям, то копирование может быть пред¬ почтительнее, даже если перемещается больше строк. При каскадном слиянии можно также предсказать число просмотров и, если надо, изменить направле¬ ние начальных строк. 15.6. Длина строки В отличие от многоэтапного слияния, каскадное слияние не влияет отри¬ цательно на ожидаемую длину строки при сортировке выбором с заменой. При выборе с заменой всегда следует сравнивать число строк, которые будут созданы, когда строки имеют длину 2, с числом строк, имеющих длину 1.5. Возможно, что дополнительные строки вызовут при многоэтапном слиянии больше просмотров и, следовательно, будет больше перемещений данных даже при той конфигурации лент, которая, казалась бы, более эффективна для многоэтапного слияния. 15.7. Внутреннее влияние каскадного слияния Внутреннее влияние у каскадного слияния такое же как и у многоэтап¬ ного. Имея k — 1 потоков на входе, надо предвидеть возможное отрицательное влияние этих потоков на размер блока, буферизацию и последующее совме¬ щение. Поскольку по мере уменьшения степени слияния число сравнений со- кращается, то скорости центрального процессора и ввода-вывода не будут оставаться стабильными в течение слияния. (k—1)-поточное слияние можег быть критичным по вычислениям, но критичность ввода-вывода может быть достигнута при степени слияния, равной (k — 2), или меньшей.
16.10. КОМПРОМИССНЫЕ слияния 211 15.8. Подсистема ввода-вывода Каскадное слияние, как и «несбалансированное» слияние, зависит от.воз¬ можности подсистемы ввода-вывода поддерживать одновременно ввод-вывод в несбалансированной форме. На сбалансированных системах с двумя кана¬ лами каскадное слияние не будет работать эффективно. 15.9. Дополнительные замечания На рис. 15.12 приведена таблица, отражающая мощность каскадного слияния в отношении просмотра строк. При указанном числе лент указанное число строк может быть сокращено за указанное число просмотров. Если ис¬ пользуются фиктивные величины или копирование, то, когда число просмо¬ тров, указанное на рис. 15.12, нечетно, нужен дополнительный просмотр. Все Число лент 3 4 5 6 7 8 9 10 1 просмотр 2 3 4 5 6 7 8 9 2 просмотр 3 6 10 15 21 28 36 45 3 просмотр 5 14 30 55 91 140 204 290 4 просмотр 8 31 85 190 371 658 1,086 1,865 5 просмотр 13 70 246 671 1,547 3,164 5,916 11,372 6 просмотр 21 157 707 2,353 6,405 15,106 31,938 68,764 7 просмотр 34 343 2,032 8,272 26,585 72,302 173,322 416,834 8 просмотр 55 773 5,859 29,056 110,254 345,775 >Ш >1М 9 просмотр 89 1732 16,866 92,091 457,379 >Ш 10 просмотр 144 3894 48,570 318,671 >Ш Рис. 15. ,12. Каскадное слияние, мощность просмотра строк. строки в пределах диапазонов данного столбца сливаются за такое количе¬ ство просмотров, какое необходимо для слияния следующего большего числа. Для способа парных частичных просмотров это не так. 15.9.1. Ухищрение и раннее высвобождение. Для распределения можно использовать меньше лент, чем требуется для слияния. Дополнительные стро¬ ки перекладываются в конец одной ленты и копируются оттуда, когда рас¬ пределение закончено, и для слияния становится доступной дополнительная лента (ленты). Читатель может обратиться к главе 14. Можно также высво¬ бодить одну ленту до последнего просмотра, не размещая строки на ней до тех пор, пока слияние не будет передано второй паре просмотров. 15.9.2. Восстановление. Окончание этапа обратного чтения является есте¬ ственной точкой восстановления для каскадного слияния. В этот момент только что исчерпанная лента находится в точке загрузки и, если ее снять, содержит запись только что перемещенных строк. Неполадки на следующем этапе можно устранить, вновь установив и переставив другие ленты. Снятие лснты в конце ка и того прохода дает возможность восстановления любого просмотра. 15.10. Компромиссные слияния В широкой литературе первое упоминание о существовании семейства слияний, из которых многоэтапное и каскадное представляют предельные слу- Чаи» обычно приписывают Д. Е. Кнуту. В письме к редактору Communications
212 ГЛ. 15. КАСКАДНОЕ И КОМПРОМИССНОЕ СЛИЯНИЯ НА ЛЕНТАХ о» the ACM в октябре 1963 года Кнут [30] описал и дал пример «компро¬ миссного» слияния. Это название отражает то место, какое это слияние зани¬ мает между предельными случаями, которыми являются многоэтапное и кас¬ кадное слияния. Эта «промежуточность» вытекает из формы этапов слияния, выполняемых в течение просмотра слияния. У многоэтапного слияния степени k — 1 на один частичный просмотр приходится один этап. У каскадного — на один просмотр приходится k — 1 отдельных этапов. Компромиссное слияние — это такое слияние, у которого на один про¬ смотр приходится больше одного, но меньше k — 1 этапов. При любом зна¬ чении k — 1 с k > 4 между каскадным и многоэтапным слияниями будет не Число переме¬ щенных длин Гп Т\ т2 Гз т< т. строк Этап - 44 40 36 25 13 - I 13 (5L) * 31 27 23 12 0 65 1 5-поточный 13 (5L) * 19 15 11 0 12 (4L) * 48 2 4-поточный 13 ,5L) * 8 4 0 11 (3L) * 12 (4L) * 33 3 3-поточный 11 9 (5L) 4 0 4 (14L) * 7 (3L) 8(4 L) 56 1 5-п оточи ы ii 5 (5L) 0 4 (13L) * 4 (14L) * 3(3 L) 4(4 L) 52 2 4-поточньш 2(5 L) 3 (17L) * 4 (13L) * 4 (14L) * 0 1 (4 L) 36 3 3-поточный 111 1 (5L) 2(12 L) 3 (13L) 3 (14L) 1 (48L) * 0 48 1 5-поточный 0 1 (12 L) 2 (13L) 2 (14L) 1 (48L) * 1 (44L) * 44 2 4-поточный 1 (39L) * 0 1 (131) 1 (14L) 1 (48L) * 1 (44L) * 39 3 3-поточный IV (последний) 1 (158L) 158 579 • Ленты, не участвующие в слиянии. 579 Число эффективных просмотров да иных = -у^-= 3.7. Рис. 15.13. Компромиссное слияние с тремя этапами. одно компромиссное слияние. Их будет много. Предельным случаем является слияние только с единственным, например, четырехпоточным этапом; есть слияние с четырехпоточным и трехпоточным этапами, слияние с четырехпо¬ точным, трехпоточным и двухпоточным этапами, слияние с четырехпоточным, трехпоточным, двухпоточным и однопоточным этапами. Частичность каждого просмотра является общей чертой компромиссного и многоэтапного слияний. Однако при компромиссном слиянии перемещается больше строк — условие, которое при некоторых значениях k и N приводит к большей эффективности, чем у многоэтапного слияния. Аналогично, для не¬ которых значений k и N больше строк перемещается при слияниях высоких степеней, приводя к большей эффективности, чем у каскадного слияния. На рис. 15.13 показано компромиссное слияние с тремя этапами и k = 6. Определение идеальных уровней будет дано в следующем разделе. Процесс слияния идентичен каскадному с той лишь разницей, что просмотр заканчи¬ вается до того, как перемещены все данные. 15.10.1. Распределение строк. Построение идеальных уровней для компро¬ миссных слияний отражает их промежуточное место между многоэтапным и
15.10. КОМПРОМИССНЫЕ слияния 213 каскадным слияниями. Вычисление числа строк для каждой ленты при одном количестве лент будет выполняться так, как если бы распределение выполня¬ лось для каскадного слияния, а при другом — так, как если бы распределение выполнялось для многоэтапного слияния. Рассмотрим рис. 15.14, где для совокупностей из 4, ... 9 лент показаны значения (k—1) = М, минимальная степень (W), и количество этапов (Р). ряд простых взаимосвязей очевиден. Количество этапов на одном просмотре равно разности между числом лент в системе и желательной минимальной по¬ точностью слияния, P = k—W. В свою очередь минимальная поточность слияния для просмотра равна разности между числом лент в системе и жела¬ тельным количеством этапов W = k — Р. В течение каждого просмотра компромиссного слияния некоторые ленты будут исчерпываться, а некоторые нет. При каскадном слиянии исчерпываются все ленты, при многоэтапном — только одна. Ленты, которые исчерпываются в течение просмотра, получают строки так, как если бы выполнялось каскад¬ ное слияние. В течение просмотра будут исчерпываться Р лент, и, следова¬ тельно, Р лент будут получать строки как при каскадном слиянии. М — Р лент не будут исчерпываться и будут получать строки так, как если бы вы¬ полнялось многоэтапное слияние. На рис. 15.15 (в строчке 1) показано начальное распределение (k—1) строк, общее для всех слияний степени (k— 1). Есть семь лент, и минималь¬ ная степень слияния должна быть 4. Таким образом, на один просмотр слия¬ ния приходится три этапа, и три ленты будут получать строки, как при кас¬ кадном слиянии. При распределении для каскадного слияния лента 1 на любом уровне со¬ держит число строк, равное сумме всех строк на предыдущем уровне; Т2 со¬ держит на каждом уровне число строк, равное сумме всех строк на предыду¬ щем уровне без учета ленты с наименьшим числом строк; Tk-i (лента с наи¬ меньшим числом строк) на любом уровне содержит количество строк, равное числу строк на ленте с наибольшим числом строк на предыдущем уровне. Вторая строчка рис. 15.15: Т4, Тъ и Те — те три ленты, которые будут исчерпаны на первом просмотре слияния. Они получают строки, как при каскадном слиянии. В третьей строчке рис. 15.15 показан идеальный уровень Для каскадного слияния, который был бы достигнут, если бы каскадное рас¬ пределение было бы продолжено. В четвертой строчке показан идеальный Уровень, который был бы достигнут, если бы распределение выполнялось под многоэтапное слияние. Ленты с 1 по 3 для нового уровня строки не получают. Это те ленты, к°торые не будут исчерпаны и которые будут получать строки как при рас¬ пределении для многоэтапного слияния. Число строк на последней ленте, по¬ дучающей строки как при каскадном слиянии, представляет «базу», на ко¬ брой вычисляются количества строк для остальных лент. На рис. 15.15 ба¬ зовой лентой является 7Y Пятая строчка на рис. 15.15 показывает (справа Палево), что число строк на Т3, Т2 и Ti равно сумме базового числа и Те, Т5 и ^4 на предыдущем уровне. В общем случае: 1- Последней лентой, получающей строки как при каскадном слиянии,. нвляется Tw.
214 ГЛ. 15. КАСКАДНОЕ И КОМПРОМИССНОЕ СЛИЯНИЯ НА ЛЕНТАХ Общее количество лент к Число лент распределения М Минимальная степень W Этапы Р 3 3 1 Многоэтапное 3 2 2 3 1 3 Каскадное 4 4 1 Многоэтапное' 4 4 3 2 з) ► Компромиссное 4 1 4 Каскадное 5 5 1 Многоэтапное 5 4 21 I 5 3 3 \ Компромиссное 5 2 4 J 1 5 1 5 Каскадное 6 6 1 Многоэтапное 6 5 1} | 6 6 4 3 3 ! 4 I Компромиссное 6 2 sj 1 6 1 6 Каскадное 7 1 Многоэтапное 6 2 5 3 4 4 . Компромиссное 3 5 2 6 1 7 Каскадное 8 8 1 Многоэтапное 8 7 2 8 6 3 8 5 4 8 4 5 • Компромиссное 8 3 6 8 2 7 . 8 1 8 Каскадное Рис. 15.14. Компромиссные слияния. Го Г1 То Т 1 3 TATw) г5 гб 1. 1 1 1 1 1 1 1 з 1 2 1 1 3/ 6 5 4 з 2 1 4. 2 2 2 2 2 1 5. 4 4 4 з 2 1 6. 4 4 4 з 2 4 7. 4 4 4 з 8 4 8. 4 4 4 12 8 4 9. 4 4 13 12 8 4 10. 4 14 13 12 8 4 11. 15 14 13 12 8 4 ;] многоэтапное Уровень 1 Каскадное для Г4 —Г- Следующее каскадное Следующее многоэтапное Уровень 2, компромиссное T^L3 = T\Li - Т\L-2 + T2L2 --TiU+To^+TJ T3L3 = T^L3 + ^ 3 + TbLi > многоэтапное з + TiL2 ) уровень 3 компромиссное ( T6L3 = 1 < T5L3 = 7 I T<L3 = 1 ( T3L3 = TiL3 s T2L3 = T<L3 I T,L3 = T,L3 T,L, } каскадное Рис. 15.15. Распределение для компромиссного слияния.
15.10.' КОМПРОМИССНЫЕ СЛИЯНИЯ 215 2. Число строк на Tw есть базовое число, которое будет использоваться для вычисления совокупности строк для всех лент слева от Tw. 3. Число строк на лентах справа от Тт на предыдущем уровне добавля¬ ется к Tw для того, чтобы определить количество строк слева от нее. На рис. 15.15 в пятой строчке Tw — это Г4 с тремя строками. Следова¬ тельно, второй уровень для 73 — Tw + (Тб на уровне 1) = 3 + 1 = 4; второй уровень для Т2 — Tw + (Т5 на уровне 1); и для Т1 — это Tw + (Та на уровне 1). Аналогично, для уровня 3 Tw — это Т4 с 12 строками. Чтобы вычислить число строк для Ти Т2, Тз на уровне 3, складываем 12 с совокупностями строк на Г4, 75, Те на уровне 2. Новый уровень показан в одиннадцатой строчке рис. 15.15. Сходство с многоэтапным распределением заключается в добавлении одной величины по всей совокупности лент. В результате этих вычислений должно сократиться То - Т\ Т1 Тг т< Т 5 То - 15 14 13 12 8 4 Начало 4 * 11 10 9 8 4 0 6-поточное Просмотр 1 4 * 7 6 5 4 0 4* 5-поточное 4 * 3 2 1 0 4 * 4 4-поточное 3 2 1 0 1 * 3 3 б-поточное Просмотр 2 2 1 0 1 * 1 * 2 2 5-поточное 1 0 1 * 1 * 1 * 1 1 4-поточное 0 1 0 0 0 0 0 б-поточное Окончание ** Лента не участвует в слиянии либо является лентой вывода. Рис. 15.16. Компромиссное слияние из трех этапов. число строк на тех лентах, которые не будут исчерпаны в течение начального просмотра слияния. Строчки с шестой по одиннадцатую на рис. 15.15 пока¬ зывают построение уровня 3 для каждой ленты. Ленты с 6 по 4 — это те ленты, которые получают строки как при каскадном слиянии. Ленты с 3 по 1 получают приращение как при многоэтапном слиянии. На рис. 15.16 показано слияние, которое бы получилось, если бы формирование строк прекратилось в Данный момент. На каждом просмотре было бы по три этапа, а минималь¬ ная поточность слияния — 4. В Приложении С приведен на PL/1 алгоритм вычисления идеальных Уровней для всех (k—1)-поточных слияний, которые исчерпывают вход до слияния. Этот алгоритм отличается от того, что было сказано в этом разделе, только тем, что значение Ру представленное переменной PHASES, на 1 мень- Ше> чем Р на рис. 15.14. PHASES=0— это многоэтапное распределение; phases = (М — 1)—каскадное. Интересная деталь, которая видна на РИс- 15.14, так же, как и в алгоритме, состоит в том, что и при k— 1 этапах, и при k — 2 этапах будет каскадное распределение, поскольку устраняемый Зтап —. это этап копирования при значении k — 2.
216 ГЛ. 16. ОСЦИЛЛИРУЮЩЕЕ И ПЕРЕКРЕСТНОЕ СЛИЯНИЯ 15.10.2. Обратное компромиссное слияние. Для выполнения обратного ком¬ промиссного слияния надо либо копировать строки со всех неисчерпанных лент в течение просмотра, либо перематывать все неисчерпанные ленты. На эффективность процесса влияют характеристики системы. Надлежащее раз¬ мещение фиктивных величин может ослабить это условие. Глава 16. ОСЦИЛЛИРУЮЩЕЕ И ПЕРЕКРЕСТНОЕ СЛИЯНИЯ 16.1. Введение Методы слияния на лентах, которые рассматривались до сих пор, выпол¬ няют слияние лишь после того, как просмотр распределения сформирует все входные данные в строки. В этой главе будут описаны два метода слияния, в которых формирование строк и слияние строк сменяют друг друга по мере исчерпывания входных данных. Эти два метода — осциллирующий и пере¬ крестный. Оба метода являются «несбалансированными» и достигают степе¬ ней слияния значительно больших, нежели 6/2. Оба метода применимы как с дисками, так и с лентами. 16.2. Осциллирующее слияние Осциллирующее слияние первоначально было задумано как полностью зависящее от возможности обратного чтения, и это предположение упрощает описание этого метода [41]. Первая операция распределения строит k — 2 возрастающих строк. Лента ввода содержит оставшиеся строки; одна лента пуста. Когда k — 2 возрастаю¬ щих строк созданы, выполняется (k — 2)-поточное слияние, которое из k-—2 строк формирует одну убывающую строку. Затем с ленты ввода распреде¬ ляется еще k — 2 строк. Одна из этих возрастающих строк помещается на ту ленту, на которой расположен результат предыдущего слияния. Так посту¬ пают для того, чтобы следующее (k — 2)-поточное слияние поместило убы¬ вающую строку длины k — 2 на другую ленту. Когда второе слияние закон- чено, распределяется еще k — 2 строк и выполняется третье слияние. К этому времени строки длины k — 2 распределены по k — 2 лентам. Теперь выпол¬ няется слияние второй степени. Это слияние образует строку длины (k — 2)2. Кратко осциллирующее слияние можно описать следующим образом: 1. Распределить k — 2 строк по k — 2 лентам. 2. Выполнить слияние степени k — 2, формируя строки длины (k — 2). 3. Повторить 1. и 2. k — 2 раз. 4. Выполнить слияние степени k — 2, формируя строки длины {k — 2)а- 5. Повторить шагиТ—4. k — 2 раз. 6. Выполнить слияние степени k — 2, образующее строки длины (6 — 2)3> 7. Повторить шаги 1.—6. k — 2 раз. 8. Повторять распределение и слияние таким способом до тех пор, пока не будут исчерпаны входные данные.
16.2. ОСЦИЛЛИРУЮЩЕЕ СЛИЯНИЕ 217 Слияние с обратным чтением может создавать убывающую заключитель¬ ную строку, которую, возможно, придется скопировать для того, чтобы сде¬ лать из нее возрастающую, если таковую требует последующее применение. На рис. 16.1 показан процесс осциллирующего слияния в тот момент, когда уже выполнено слияние степени k — 2 второго уровня. К этому времени выполнено первое слияние третьего уровня, и сформирована строка длины ^ 2)3. Теперь этот процесс начинает распределение строк еще раз. 16.2.1. Характеристики и мощность слияния. В течение всех этапов слия¬ ния степень слияния равна (k — 2). Размер строк возрастает по степеням (it —2). В примере с пятью лентами на рис. 16.1 размеры строк после не¬ скольких слияний разных уровней будут равны 3, 9, 27. Число просмотров данных равно f log k-2 S'] . При распределении два¬ дцати семи строк по трем лентам, как в данном примере, данные будут про¬ сматриваться трижды (log3 27). (Двухпоточное сбалансированное слияние, использующее ленты Тi — Г4, для тех же самых данных потребовало бы пяти просмотров.) Если идеальные уровни не достигнуты, то слияния на более высоких уровнях будут иметь меньшую степень и будут создавать более короткие строки. Выбор лент для распределения произволен при условии, что та лента, на которой размещались строки от последнего слияния, должна получить строку при новом распределении. Поразительной характеристикой этого метода является количество изме¬ нений направления движения лент, выполняемых в течение всего процесса. Каждый этап слияния изменяет направление перемещения ленты, требуя, что¬ бы лентопротяжное устройство изменило режим работы, положение считы¬ вающей головки и подготовилось к считыванию. После распределения k — 2 строк направление движения всех лент должно быть изменено для того, чтобы выполнить (k — 2) -поточное слияние первой степени. После слияния они должны изменить свое направление еще раз для того, чтобы получить новые строки. Каждая лента дважды меняет направление движения в течение каж¬ дой последовательности распределения и слияния первой степени. Число этих изменений в течение всего процесса, естественно, определяется количеством Данных. Осциллирующий и перекрестный — это единственные методы, в ко¬ торых число изменений направлений движения столь велико и во много раз превосходит эту характеристику других методов (из которых самым близким будет каскадное слияние). На машине, которая не имеет возможности совме¬ щать изменения направления движения и которая тратит значительное время на изменение направления движения, большое число изменений направления Движения может быть серьезным препятствием для производительности. 16.2.2. Осциллирующее слияние с прямым чтением. На системах без обрат¬ ного чтения или с очень плохими характеристиками изменения направления Движения, но хорошими характеристиками перемотки (перемотка совмещается с большим количеством считываний) разумно использовать версию осцилли¬ рующего слияния с прямым чтением [25]. Ленточная система должна уметь Че-Редовать чтение и запись на одну и ту же ленту. На многих ленточных Системах такое чередование чревато опасностью, что очередное записывание Уничтожит существующую запись.
218 ГЛ. 16. ОСЦИЛЛИРУЮЩЕЕ И ПЕРЕКРЕСТНОЕ СЛИЯНИЯ Я о. § о СЯ сч | о — g 1 as о. я и к я ч (X и *-4 *4 со СО Q Q Q Q Q Q — о 2- о — л ч а о Q Q —' о — о 2 2 * * ^ >2 СО со со со 9 9 9 9 •2 2- 2 2 2 2 2 0 (N 1 1 * Лй Я я <У а) ч; ч; ч; ч: S.S 0 <М I 1 * J* S я V 0J 5 е Я О) <и н Ч а <и * 2 ^ 5 а, я * й Q Q Q Q ч; ч; El 2 >» а. я я о О я а. о я д Et
16.2. ОСЦИЛЛИРУЮЩЕЕ СЛИЯНИЕ 219 На рис. 16.2 показано слияние с прямым чтением. Читателю рекомен¬ дуется следить за изложением по этому рисунку. Начальное распределение имеет степень k—1, а последующие — k — 2, поскольку исключается лента, с0Держащая длинную строку, сформированную слиянием. Обычно за распре¬ делением каждой строки следует перемотка, так что перемотку лент можно, как правило, совместить с процессом записи следующей строки. Слияние сте- 1И £ — 2 из примечания 2 образует длинную строку, размещаемую на Т4 за Т\ Т-i Тл Т/i Комментарии j \* 1 * 1 * 1 1. Распределение к — 1 строк на 1\ — Т4. Определение Т\. Т2. Г3. Звездочками отмечены точки загрузки на ленте в конце распределения или слияния. О* 0* 0* 1 * 2. Слияние степени k — 2 на Г4. Перемотка всех лент. Б скобках указана длина строк 1* 1* 1 1* 3. Распределение к — 2 строк на Т\ через Г3. Пере- 1 (3; мотка Т% и Т2. Обращений к Г4 нет. О* 0* 1 * 0* 4. (k — 2)-поточное слияние с Тх, Г2, Г4 на 7V Перемот- 1 (3) 1 (3) ка всех лент. На Т4 образуется свободная позиция. 1 * 1 1 * 1 * 5. Распределение k—2 строк на Т\, Т2, Г4. Перемотка 1 (3) 1 (3) Т\ и 7Y Заметим, что новая строка занимает сво бодную позицию на Г4. О* 1* 0* 0* 6. к — 2-поточное слияние на Т2. Перемотка всех лент. 1 (3) 1 (3) 1 (3) Позиции на Г3 и Г4 становятся свободными. 1 1 * 1 * 1 * 7. Распределение к — 2 строк на Tlt Т3у Г4. Перемотка 1 (3) 1 (3) 1 (3) Г3 и 7Y 1 0 0 0 8. [k — 2)-поточное слияние на Тх. Имеется /г —I строк 1 (3^ 1 (3) 1 (3) 1 (3) нужной длины. Перемотка отменяется. Считываю¬ щие головки на Т2—Т4 в этот момент находятся перед длинной строкой. 1* 0* 0* 0* 9. {к — 2)-поточное слияние второго уровня на Т\. Пе- 1 (3) ремотка всех лент. 1(9) 1*1 1 1 10. Распределение к — 2 строк и т. д. 1 (3) 1(9) Рис. 16.2. Прямое осциллирующее слияние. короткой строкой. Теперь эта лента слияния перематывается. После распре¬ деления степени k — 2 короткая строка на 7Т участвует в слиянии степени ^ — 2 с новыми строками, оставляя свое место свободным. Данный метод за¬ висит от использования этого свободного пространства. Если при прямой осцилляции использовать выбор с заменой, то надо ограничить размер строк с тем, чтобы все строки помещались в освобожденном поле. Каждое слияние Степени k — 2 первого уровня оставляет одну распределенную строку метро¬ вой, размещая длинную строку за ней. В ходе распределения и слияния Уступает момент, когда начинается второй уровень степени k — 2 (см. ком¬ ментарий 9 на рис. 16.2). Этот момент наступает после k— 1, а не k — 2 цик- ЛОв распределения. При слиянии задержки из-за перемотки ограничены одной длиной строки П°СЛе каждого слияния степени k — 2 первого уровня и к — 2 длинами строк ^Ля Слияния второго уровня. План слияния на рис. 16.2 (как у Готца) миними- ^иРУет время перемотки и задержки из-за них. Реализовать осциллирование ВиДе метода с прямым чтением более простым способом обычно нельзя.
220 ГЛ. 16. ОСЦИЛЛИРУЮЩЕЕ И ПЕРЕКРЕСТНОЕ СЛИЯНИЯ 16.2.3. Длина строки и внутреннее влияние. Схема осциллирующего ели-* яния влияет на распределение строк разными путями. Поскольку сливается лишь k — 2 строк, то имеется незначительное ослабление требований к па¬ мяти относительно разбиения на блоки и буферизации. Однако, эта выгода перекрывается характером взаимодействия между слиянием и распределением. При попытке разместить в памяти поле, необходимое для сортировки, плюс код программ слияния и распределения размер строк будет ограничен. Аль¬ тернативой является повторное использование одних и тех же блоков вну¬ тренней памяти для фрагментов кода слияния и распределения. Решение об ограничении размера области сортировки или повторном использовании памя¬ ти от этапа к этапу — это компромисс, который необходимо исследовать при каждой реализации на любой системе. Надо оценить общую задержку при сортировке из-за издержек на повторное использование памяти и сравнить ее с увеличением просмотра данных вследствие создания более коротких, а следовательно, и более многочисленных строк. Если использовать сортировку выбором с замещением, то ее влияние становится довольно сильным. Для того, чтобы сохранить ожидаемую длину строк близкой к удвоенному числу элементов в области сортировки, необхо¬ димо поддерживать и пополнять турнир. Когда турнир восстанавливается после слияния, то его первая строка имеет длину, примерно равную 1.7 обла¬ сти сортировки. Начинать турнир после каждого слияния первого уровня надо будет так, чтобы одна строка из k — 2 имела длину 1.7 области сор¬ тировки. В худшем случае последняя строка распределения будет иметь длину, равную лишь 1.0 области сортировки, поскольку замена не может быть применена, пока область турнира используется для слияния. При каждом распределении k — 2 строк, одна будет иметь длину 1.7 области сортировки, а одна — 1.0 области сортировки. Таким образом, этот метод будет поро¬ ждать больше строк, чем эквивалентные каскадный и многоэтапный с пря¬ мым чтением. Безусловно, аналогичная проблема есть и у обратного много¬ этапного слияния. Использование памяти не спасает от «разлива» турнира, поскольку любой турнир в памяти обязательно будет меньше турнира, который используется при каскадном, многоэтапном или сбалансированном слияниях. 16.2.4. Восстановление. Точка восстановления вводится всякий раз, когда на одной ленте собираются все данные, распределенные до этого момента. Этот момент наступает на любом уровне при первом слиянии. Сортировка может быть «возвращена» к последней единой последовательности, и от этой точки вход может быть перераспределен. Более редкие точки восстановления можно определить, восстановив состояние, предшествующее последнему слия¬ нию первого уровня или последнему (k — 2)-поточному слиянию любого уров¬ ня. Повторение этого слияния и распределения с этой точки может компенси¬ ровать восстановление. 16.3. Перекрестное слияние Перекрестное слияние — это метод, пригодный как для дисков (бараба¬ нов), так и для лент с обратным чтением. Насколько известно автору, един¬ ственной реализацией этого метода в серийно поставляемом пакете сортиров¬
16.3. ПЕРЕКРЕСТНОЕ СЛИЯНИЕ 221 кИ является дисковый метод для сортировки в OS/360. Этот метод также эффективен как ленточный метод и может быть описан среди слияний на лентах. Подобно осциллирующему слиянию, этот метод зависит от чередова¬ ния формирования и слияния строк. Однако, эти методы различаются формой слияния. В настоящее время есть мало материала по сравнению и анализу эффективности перекрестного и осциллирующего слияний. 16.3.1. Перекрестное слияние на лентах. Этот метод сначала распределяет слева направо k — 2 строк по k — 2 лентопротяжным устройствам. Когда fi — 2 строк распределены, выполняется слияние степени k — 2 для того, что¬ бы сформировать строку длины к — 2. Этот процесс чередования .распределе- ния и СЛИЯНИЯ выполняется k - - 2 раз до тех пор, пока k — 2 строки ДЛИНЫ Го Тх г2 Г, Г, Строки 1. / 0 1D (3L) ID (3L) ID (3L) Базовый уровень (уро¬ вень 1) 9 2 1 1 0 1 Распределение к— 2 3. 0 1D (3L) ID (3L) ID (3L) ID (3L) Слияние степени /г — 2. Первая строка уровня 2 12 4. 1 1D (3L) 1 ID (3L) ID (3L) 1 ID (3L) Распределение k — 2 5. 0 ID (3L) ID (3L) ID (3L) ID (3L) ID (3L) Слияние степени k—2 Вторая строка уровня 2 (теперь доступно k — 3 строк уровня 2) 15 6. 1Л (9L) 0 ID (3L) ID (3L) & —3 строк на уровне 2 сливаются с 1 строкой на уровне 1 Рис. 16.3. Перекрестное слияние. & — 2 не будут распределены по рабочим лентам. Это положение, называемое «базовым уровнем», достигается точно так же, как и в осциллирующем слия¬ нии. Первая строчка на рис. 16.3 показывает состояние слияния при форми¬ ровании исходного базового уровня. При достижении базового уровня вместо (к — 2)-поточного слияния вто¬ рого уровня, как в осциллирующем методе, в перекрестном методе возобнов¬ ляется формирование строк. Основная цель этого метода — как можно доль¬ не задержать формирование и слияние длинных строк. По существу каждое слияние — это частичный просмотр, который использует только часть строк с ленты ввода. После того, как первый базовый уровень достигнут, распределяются и сливаются к — 2 строк (вторая и третья строки на рис. 16.3) для того, чтобы сформировать строку такой же длины, как и строки базового уровня. Эта Сгрока размещается за строкой базового уровня. Возобновляется распределе- Нис строк (четвертая строчка рис. 16.3), и, когда k — 2 строк распределены, ^полняется еще одно слияние исходных строк (пятая строчка рис. 16.3). -• этот момент строки по лентам распределены так: 0, 1,2, 2. Получено усло- *Ие Для еще одного слияния. Это условие состоит в том, что сформировано
222 ГЛ. 16. ОСЦИЛЛИРУЮЩЕЕ И ПЕРЕКРЕСТНОЕ СЛИЯНИЯ k — 3 строк длины базового уровня, которые готовы к слиянию со строкой базового уровня. Частичное слияние, указанное в шестой строчке рис. 16.3 образует первую строку длины (k — 2)2. Новый базовый уровень будет до- стигнут тогда, когда сформировано k — 2 строк длины (k — 2)2. Рис. 16.3 подсказывает, что будет три процесса слияния. Один — осцилли¬ рующее слияние, зключающее k — 2 распределений k — 2 строк и k — 2 слия¬ ний степени k — 2, которые устанавливают первый базовый уровень. Другой процесс слияния, распределение и слияние исходных строк выполняется k — 3 раз, чтобы достичь состояния, указанного в пятой строчке. Этот процесс рас¬ пределения-слияния начинается, как только достигнут базовый уровень, и продолжается до тех пор, пока не будут сформированы k — 3 строк нового уровня. Когда условие, указанное в пятой строчке, достигнуто, выполняется частичное слияние, показанное в шестой строчке. Это слияние выполняется всегда, когда еще не достигнут базовый уровень, но есть k — 3 строк, длины которых равны длинам последних базовых строк, сформированных распреде¬ лением и слиянием более низкого уровня. Выбор лентопротяжных устройств для размещения строк является основ¬ ным для этого метода и не всегда очевиден. Этот метод не похож на другие методы тем, что решающим здесь является порядок и расстановка уровней строк по конкретным лентам данной совокупности лент. Тот процесс, который устанавливает первый базовый уровень, распреде¬ ляет строки «слева направо» и сливает их на ленту, расположенную справа от (k — 2)-й распределенной строки. Первые строки распределяются по лен¬ там с 1 по k — 2, а первая длинная строка образуется на ленте k—1. Сле¬ дующая распределяемая строка размещается на ленте k—1, а последующие дополнительные строки размещаются на 7Т, Гг, ... и т. д. Лента (k—l)-fl заворачивается, чтобы стать лентой 1. В то время, когда установлен первый базовый уровень, внутренний ука¬ затель, называемый здесь указателем слияния, указывает на последнюю ленту, которая получала строки в течение (k — 2)-поточного слияния, установившего этот базовый уровень. На рис. 16.4, который частично дублирует рис. 16.3, показано распределение этого базового уровня и значение указателя слияния (МР). Последней лентой, получавшей строки, была Г2. Теперь начинается процесс второго слияния. Распределением строк и слиянием управляет указатель, который здесь называется DM-указателем, из¬ начально установленный равным МР. Во время первого распределения DM устанавливается равным МР для каждой последовательности из /г — 3 рас¬ пределений k — 2 строк. На рис. 16.4 первая строка помещается на Г2. После этого DM уменьшается так, чтобы строки размещались справа налево. Вторая строчка рис. 16.4 показывает распределение строк на Г2, Г4 и Г4. На Г3 будет объединение строк. В третьей строчке показано это слияние. Четвертая и пя¬ тая строчки показывают распределение и слияние еще одной совокупности строк. DM изначально равно 3, таким образом, строки распределяются по Тз, Г2, Ti и сливаются на Г4. В шестой строчке основной цикл уже закончен, для слияния со строкой предыдущего уровня есть k — 3 строк подходящей длины. Выполняется про* смотр частичного слияния.
16.3. ПЕРЕКРЕСТНОЕ СЛИЯНИЕ 223 Есть две формы частичного слияния. При одной из них строки сливаются да ленту слева от МР, при другой строки сливаются на ленту справа от МР. Есть переключатель направлений, установленный сначала (шестая строчка) для слияния налево. По этой причине строки длины 9 следуют на Тt. Когда есть несколько последовательных частичных слияний, как это может про¬ изойти на более поздних этапах слияния, направления чередуются. Начальное частичное слияние после серии распределений и слияний всегда происходит налево. После частичного слияния определяют, следует ли сразу выполнять Указа¬ тель слия¬ ния (МР) Указатель распределения слияния (DM) Пере¬ ключе¬ ния направ¬ ления То Т\ Т2 To TA 1. 2 — I I 0 1D (3L) ID (3L) ID (3L) Базовый уровень 2. 2 2 (2, 1, 4, U3) * I 1 ID (3L) ID (3L) ID (3L) Распределение 1 1 к — 2 3. 2 3 I 0 ID (3L) ID (3L) ID (3L) Слияние степени ID (3L) k — 2 4. 2 3(3, 2, 1, U4) I 1 ID (3L) ID (3L) ID (3L) Распределение 1 ID (3L\ 1 k — 2 5. 2 4 I 0 ID (3L) 1 ID (3L) ID (3L) Слияние степени ID (3L) ID (3L) k — 2 6. 2 4 <— I 1Л (9L) 0 ID (3L) ID (3L) k — З строк на уров¬ не 2 сливаются с уровнем 1 7. 3 3 (3, 2, 1, U 4) I 1Л (9L) 0 ID (3L) ID (3L) ID (3L) 8. 3 4 (4, 3, 2, U 1) I 1Л (9L) 0 ID (3L) ID (3L) \D (3L) ID (3L) 9. 3 4 <— I 1Л (9L) 1Л (9L) 0 ID (3L) 10. 4 4 (4, 3, 2, U1) I 1Л (9L) 1Л (9L) 0 ID (3L) 1D (3L) 11. 4 1 (1, 4, 3, U 2) I 1Л (9L) 1Л (9L) 0 ID (3L) ID (3L) ID (3L) 12. 4 1 <— I 1Л (9L) 1Л (9L) 1Л (9L) 0 ♦ U-объединение, «слияние с» Рис. 16.4. Использование лент при перекрестном слиянии (k — 2 = 3; k — 3 = 2). еще одно слияние. Частичное слияние выполняется в том случае, если базо- вый уровень еще не достигнут, но есть k — 2 лент со строками, длина кото¬ рых равна длине строк предыдущего уровня. В противном случае МР продви¬ нется на единицу, и выполняется последовательность распределение-слияние. присваивается новое значение МР (см. седьмую строчку), и начинается Распределение. Седьмая и восьмая строчки показывают k — 3 слияний начальных строк, достигнуто условие для частичного слияния: базовый уровень не достигнут, Но есть строки, длина которых подходит для слияния. Частичное слияние идет Налево, на Т2. К концу этого слияния условия для непосредственного продол¬ жения не достигнуты, МР и DM регулируются, и опять начинается процесс Распределения-слияния. Десятая и одиннадцатая строчки показывают его
224 ГЛ. 17. ОБЗОР СЛИЯНИЯ НА ЛЕНТАХ производительность. Двенадцатая строчка показывает последующее частичное слияние, которое формирует новый базовый уровень. По мере продолжения процесса на лентопротяжных устройствах создают¬ ся строки разной длины. Когда данные исчерпаны, (k — 2)-поточное слияние формирует заключительную строку. Во время слияния, в зависимости от рас¬ пределения строк и их направления, может возникать необходимость в ча¬ стичных просмотрах. 16.3.2. Сравнение с осцилляцией. При больших совокупностях строк дан¬ ный метод будет превосходить по производительности осциллирующий, по¬ скольку будет просматривать длинные строки меньшее число раз. При очень маленьком числе строк уменьшения перемещения строк не бу¬ дет, поскольку имеющиеся уровни будут недостаточными для того, чтобы частичные слияния были эффективны. При двадцати семи строках на пятп- лснточной системе оба метода дадут одинаковый результат. При 100 строках на системе с шестью лентами перекрестный метод переместит примерно па 10 процентов меньше строк. Этот метод никогда не будет хуже осциллирую¬ щего. Поэтому при больших совокупностях строк ему следует отдать предпо¬ чтение. Влияние длины строки и количества строк на оба метода одинаково. Глава 17. ОБЗОР СЛИЯНИЯ НА ЛЕНТАХ 17.1. Введение Осторожность, с которой надо браться за обзор слияния на лентах, не может быть чрезмерной. Нет «самого лучшего» слияния на лентах, хотя лите¬ ратура буквально кишит взаимоисключающими утверждениями. Большинство серьезных исследований свойств слияний и условий, которые влияют на про¬ изводительность, обескураживающе формальны, и, следовательно, недоступ¬ ны для многих рядовых пользователей. В этом разделе мы попытаемся опи¬ сать рабочие характеристики основных слияний на лентах, а также те харак¬ теристики данных и аппаратуры, к которым эти слияния чувствительны. Кроме этого будут сделаны некоторые общие утверждения о производитель¬ ности. Основные положения слияния на лентах можно сформулировать в виде двух вопросов: (1) Сколько данных перемещает слияние? (2) Сколько вре¬ мени требуется слиянию, чтобы переместить их? Часто затраченное время можно сократить, увеличив перемещение данных, если характеристики аппа¬ ратуры самой системы позволяют высокоэффективное перемещение данных. Например, мы уже видели, что из-за особенностей разбиения на блоки, буфе- ризации и характеристик внутреннего сравнения слияние на четырех лентах может быть производительнее слияния на шести лентах. Для проектирования слияния необходимы две совокупности сведений. Одна — о данных, которые будет обрабатывать слияние, и об аппаратуре, на которой оно будет работать. Другая — совокупность критериев, по который сравниваются между собой методы слияния, степени слияния одного и т°г°
17.3. ПРОИЗВОДИТЕЛЬНОСТЬ слияния 225 jge метода, частичные просмотры или способы настройки. В этом обсуждении, которое начинается с описания критериев слияния, скорее намечены направле¬ ния исследований слияний, чем сделаны заключения о производительности. 17.2. Критерии слиянии Обычными критериями слияния являются: (1) число этапов; (2) эффек¬ тивная степень слияния; (3) объем перемещаемых данных. Число этапов слия¬ ния важно потому, что с окончанием каждого этапа связана функция времен¬ ных затрат. Необходимо учитывать время и количество перемоток и’измене¬ ний направления движения. Аналитик должен быть очень осмотрительным, делая вывод о том, что эффективность слияния, которое кажется предпочти¬ тельным, компенсирует межэтапные издержки слияния. «Эффективная степень слияния» не всегда позволяет интуитивно оценить необходимое число этапов слияния и часто опирается на теоретические обобщения, которые не учиты¬ вают фактического числа перемещаемых строк в конкретных совокупностях строк или конкретных системах. Числу просмотров данных автор отдает предпочтение как наиболее по¬ лезному и вычислимому критерию преимущества одного слияния или схемы слияния перед другими. Число просмотров данных равно числу записей, пере¬ мещаемых слиянием, деленному на число записей в файле. Этот критерий существует в разных формах [12, 13]. С ним тесно связано понятие «числа перемещений строк». Когда длина каждой строки фиксирована и равна длине всех других строк, подсчет общего числа перемещений строк дает совершенно точное выражение числа просмотров данных при слиянии. Если строки раз¬ ной длины, то подсчет числа перемещений строк даст приемлемую аппрокси¬ мацию перемещенных данных. Методы внутреннего слияния заменой, которые приводят к строкам переменной длины, как правило, не порождают строки с резко изменяющейся длиной. Критерий просмотрев данных часто указывают п виде «числа просмотров на строку» — количество перемещений строки в те¬ чение слияния. 17.3. Факторы, влияющие на производительность слияния Ряд факторов, связанных с данными и аппаратурой, влияет на характери¬ стики слияния, связанные с просмотрами данных. Факторы, связанные с дан¬ ными, перечислены ниже: 1. Объем входных данных. 2. Число порожденных строи. 3. Знание числа строк. 4. Связь между распределением и слиянием. 5. Метод естественного слияния й/или метод расширения строк. 6. Структура данных. Каждый из этих факторов будет влиять на объем данных, перемещаемых Сиянием. Факторами, связанными с аппаратурой, которые влияют на объем ПеРемещаемых данных (в противоположность количеству времени, необходи- МомУ Для перемещения этих данных), являются число лентопротяжных Устройств (определяющее поточность слияния) и размеры памяти. 8 Г. Лорин
226 ГЛ. 17. ОБЗОР СЛИЯНИЯ НА ЛЕНТАХ 17.3.1. Объем входных данных. Один просмотр 160 000 записей из пятиде- сяти слов каждая переместит больше данных, чем десять просмотров 10 000 двадцатисловных записей. Кроме того, объем данных разными путями влияет на планирование слияния. Использование метода (k—1)-й степени может стать невозможным, если объем данных вызывает «переполнение» лент. По¬ скольку в течение процесса слияния (или даже распределения) данные на k — 1 лентах располагаются как правило неравномерно, то вероятность того, что на одну ленту будет записано слишком много данных, возрастает. В се¬ рийно поставляемых пакетах сортировки можно выбирать между многоэтап¬ ным и несбалансированным слияниями, одним из параметров этого выбора служит объем данных. Но даже при сбалансированном слиянии есть опас¬ ность переполнения. В некоторых случаях на последних просмотрах может возникнуть преждевременное накопление записей на ленте. Например, на ше¬ стиленточной системе при 100 строках и отсутствии частичных просмотров на предпоследнем просмотре на одну ленту будет попадать 89 процентов дан¬ ных. Однако в общем случае опасность переполнения при сбалансированном слиянии меньше. Если объем данных таков, что одной ленты ввода и одной ленты вывода недостаточно, то решения, принятые при проектировании, будут влиять на просмотр данных. Если исследователь выяснит, что дополнительная лента требуется лишь для исходных и результирующих данных, то он может при¬ нять решение выполнять слияние с максимальной поточностью, затрачивая время на установку новой ленты ввода и новой ленты вывода. Однако ом может ограничить степень слияния для того, чтобы менять ленты при вводе и заключительном выводе. В зависимости от числа строк и конкретных сте¬ пеней слияния при уменьшении степени слияния может возрастать число про* смотров данных [18]. Случается, что объем данных слишком велик для одной сортирован слияния. В этих случаях разделяют файл, к каждой части применяют сорти¬ ровку-слияние и «сливают» заключительные ленты вывода. Если разные сор¬ тировки-слияния строят заключительные строки разной длины, то существует стратегия слияния, позволяющая минимизировать работу по заключительному слиянию. Применяют оптимальные слияния, описанные в гл. 9. 17.3.2. Число порождаемых строк. Конкретное число построенных строк влияет на эффективность слияния. Некоторые слияния, которые «обычно» не столь эффективны при заданном числе лент, как другие, при очень малом или очень большом числе строк могут стать эффективнее. Слияния, описанные в этой книге, чувствительны к числу строк, а кроме этого, к появлению определенных чисел — к так называемым совершенным распределениям. Чувствительность к совершенным числам может быть пони¬ жена методами частичных просмотров. Однако, слияние, которое «обычно» ме¬ нее эффективно, чем другие при данном числе лент, может стать эффективнее, если его совершенные уровни распределены по этому числу лент. Реакция слияний на «плохие» уровни различна. Сбалансированное слияние будет тра¬ тить дополнительный полный просмотр данных, если эффективная степень слияния не достигнута, а частичные просмотры не используются. Каскадное слияние также может понести значительные потери при несовершенных уров'
17.3. ПРОИЗВОДИТЕЛЬНОСТЬ слияния 227 кях. Издержки многоэтапного слияния при несовершенных уровнях меньше. По отношению к другим методам относительная эффективность многоэтап¬ ного слияния при несовершенных уровнях выше, если число строк невелико. Рассмотрим 20-ленточную систему со 145 начальными строками. Для упо¬ рядочения файла сбалансированное слияние потребует flogio 145*1 == 3 про¬ смотров данных. Многоэтапное слияние упорядочит эти данные за 2.54 про¬ смотра. Несмотря на то, что теоретически эффективность сбалансированного слияния при k = 20 выше, многоэтапное слияние оказывается более эффек¬ тивным, потому что в данном случае у него совершенный уровень, тогда как для сбалансированного слияния 45 — это плохой уровень. Важность частич¬ ных просмотров для сбалансированного слияния можно проиллюстрировать тем, что при частичных просмотрах оно может упорядочить 145 строк за 2.36 просмотров данных. При 100 строках, образующих совершенный уровень для сбалансированного слияния, это слияние превосходит по производитель¬ ности многоэтапное: 2.00 просмотров данных против 2.37 просмотров. Можно привести аналогичный пример сравнения для многоэтапного и каскадного слияний. На восьми лентах каскадное предпочтительнее много¬ этапного при 145 строках, а многоэтапное предпочтительнее каскадного при 45 строках. В общем случае, в силу своей способности просматривать строки, каскадное слияние более эффективно при большом числе строк, тогда как многоэтапное эффективнее при меньшем их числе. Для достижения нового уровня при каскадном слиянии надо обработать намного больше строк, и эта тенденция становится особенно ярко выраженной на высоких уровнях. Одна¬ ко и при меньших совокупностях строк бывает, что каскадное слияние пред¬ почтительнее. Это случается тогда, когда уровни очень близки к совершенным уровням каскадного слияния. При плохом уровне каскадного слияния умень¬ шению числа перемещаемых строк могут способствовать методы частичных просмотров. При большом количестве лент число строк, при котором каскад* ное слияние становится предпочтительным, намного меньше. При малом коли¬ честве лент (например, k — 4) многоэтапное слияние превосходно во всех отношениях. 17.3.3. Знание числа строк. Знание числа строк позволяет выбирать ме¬ тод слияния более осознанно. Помимо того, что число строк влияет на эф¬ фективность слияния, у точного предвидения есть и другие преимущества. Если число просмотров известно или может быть оценено на основе ожидае¬ мого числа строк, то направление исходных строк можно выбрать так, чтобы избежать просмотров копирования при каскадном, сбалансированном или осциллирующем слияниях. При каскадных слияниях число просмотров необ¬ ходимо знать при любом алгоритме определения формы возрастающих и убы¬ вающих строк во избежание перемоток или копирования неисчерпанных лент. Число строк можно определить, если знать количество сортируемых эле¬ ментов, используемый метод внутренней сортировки и размер рабочей обла¬ чи, выделяемой под внутреннюю сортировку. Цена этого может быть высо¬ кой, включая отказ от методов замещения или расширения строк. Если из¬ вестно число строк, то после того, как они сформированы, создать слияние — Дело техники. Трудности при этом проистекают из-за того, что решения, отно- СяШиеся к разбиению на блоки, уже сделаны алгоритмом распределения, а 8*
228 ГЛ. 17. ОБЗОР СЛИЯНИЯ НА ЛЕНТАХ форма убывающих и возрастающих строк уже установлена. Однако, разбие¬ ние на блоки можно изменить на первом просмотре слияния или любом ча¬ стичном просмотре, необходимом для подготовки выбранного слияния. 17.3.4. Число строк, создаваемых при замещении. Исследование относи¬ тельных достоинств любого из способов слияния должно учитывать, ЧТО при использовании выбора с замещением обратное многоэтапное, осциллирующее и перекрестное слияния порождают больше строк. Осциллирующее слияние предпочтительнее каскадного потому, что между уровнями оно способно просматривать больше строк. При наличии настраи¬ вающего просмотра для совокупности от 8 до 11 лент осциллирующее слия¬ ние может быть и не производительнее каскадного, если появление дополни¬ тельных строк приводит к дополнительному просмотру слияния. При дей¬ ствительно большом количестве лент, например, таком, как k = 20, влияние дополнительных строк отсутствует, и с точки зрения просмотра данных осцил¬ лирующее слияние является наилучшим методом, но до тех пор, пока сово¬ купность строк не станет достаточно большой, чтобы стало оправданным использование перекрестного слияния. Обобщение числа дополнительных строк, порождаемых при осциллирующем слиянии, которое использует выбор с за¬ меной, было получено Готцем в виде [2 (£ — 2) l(2k — 5.3)] — 1 процент дополнительных строк [25]. Обратное многоэтапное слияние весьма чувствительно к появлению до¬ полнительных строк. Ожидаемый размер строки при выборе с замещением после изменения направления равен, как показал Кнут, (1.5 X размер турни¬ ра). Алгоритм горизонтального распределения минимизирует увеличение числа строк, строя как можно больше строк в одном направлении. Однако при ма¬ лом количестве лент, при котором, очевидно, предпочтительным является многоэтапное слияние, увеличения числа строк может оказаться достаточно, чтобы разумнее стало рассматривать прямой многоэтапный или какой-либо другой метод. Стимулом для обратного многоэтапного слияния является устранение неоднократных перемоток. Альтернативой является использование многоэтап¬ ного слияния степени, меньше максимальной, которое может совместить пере¬ мотку со слиянием и, таким образом, поглотить время перемотки. Эта степень слияния равна k — 3, а ленты, перематываемые в течение этапа (исчерпанная лента и лента для получения строк), используются на следующем этапе для вывода и ввода. 17.3.5. Естественное слияние. Во всех утверждениях, основанных на прин¬ ципе перемещения данных, предполагается непосредственное слияние. Говоря, что сбалансированное трехпоточное слияние требует трех просмотров для 27 исходных строк, имеют в виду, что последовательно будут образованы девять строк длины 3, три строки длины 9 и одна строка длины 27. 27 исходных строк вполне можно преобразовать в одну строку за один просмотр, если используется естественное слияние, и в данных есть достаточная упорядочен¬ ность. Утверждения о просмотре данных указывают наихудший случай при использовании естественного слияния и расширения строк.
Число строк для заданного количества лент k 17.3. ПРОИЗВОДИТЕЛЬНОСТИ слияния 229 21 О Ю О CD , 23 £3 ю to £2 42 ^ 00 10 05 i n so С Ю - М ^ rti — Cl ю о о g. - (М Tf 21 о ю о со о>| 00 | 00 g S $ 2 §8 Я (М О 05 СП со н ю - СО tsCOOOO^fDNlO 00 I CD 3? cr CD S' CD c4 00 CO Ю jB 05 •*f 05 CO 05 3 05 CD UO 05 s CO CO t-. CO О irt —<t CD —J CD —; 00 <M О ^ oi <м' СО СО, V Ю* CD -Tfcoocjcotoo | СО CD <М Ю ~н <N X! а X X Я о ^ н CD| — -(SWlOrt1® СО О 't Ю (М со -< (С (О О S —. СО <М CD —■ s Ю N ю 5 N (О СО N О О (О СО 00 О) W 00 (М 05 -1 o4co“^4t^oJ‘t',*?o'oo'co46o 3 СО* со TJ* Tt< ID lO 05 rj i'» i-- — ID 05 CM H w ■? O) Ol CM — 05 05 S о Он С - S О] h CO 30 CO » ci oi CO CO <?’ ^ Ю «О (J N CO I.o 05 5 В ! со со 1 К a* ID| 2 g: CD N M 05 CO о CO id CD (N N О 00 00 oo 03 Ю CO о ■5J* CO Ю & Ю Ю CD, CO fe Ю о 1 iD Ю CO s CD rf —i О N « CO M ~ ^ 2 3 £ £ i 3 % § 8. sag jj § I «Ч t; e? я со 3 * 8 I ” u О S< со, 3 2 8 .1 0,-HMC0'fc0!DN000>O ei c OCO^^OltOCOO Is- Ю н -и N СО СО V Ю О Ю N ^ л! сЛ i rt rrt СЧ СО Ю 00 CO T-н Ol CO LO CO (MC0^irtC£>t^C00>O
230 ГЛ. 17. ОБЗОР СЛИЯНИЯ НА ЛЕНТАХ 17.3.6. Структура данных. На объем данных, просматриваемых при слия. нии, влияют разные структурные характеристики. Имеет ли запись фиксиро. ванную или переменную длину? Увеличивает ли распределяющий просмотр размер записи за счет добавления управляющих полей? Выдает ли он корот- кие строки или наполняет блоки фиктивными величинами или строками с фиктивными элементами [22]? Основной размер записи влияет на такие вещи как разбиение на блоки, буферизация и размер области сортировки и, следо. вательно, влияет на основные параметры процесса сортировки-слияния. 17.4. Аппаратура и слияние Для разработчика слияния важны характеристики аппаратуры, перечис¬ ленные Готцем (см. гл. 12). Ниже перечислены основные вопросы, которые должен решить разработчик: 1. Каково влияние размера памяти на критичность слияния разных сте¬ пеней по вводу-выводу или работе центрального процессора? Ограничены ли Просмотры к Строки Сбаланси¬ рованное Осцилли¬ рующее Каскадное Многоэтапное 6 37 4 3 3 2.7—3.2 86 5 4 4 3.2—3.7 144 5 4 4 3.7—4.3 250 6 4 5 со "d* 1 со 425 6 5 5 4.3-4.8 863 7 5 6 4.8-5.3 1296 7 6 6 СП со 1 сл 00 10 37 3 2 2 2.0 —2.6 86 3 3 3 2.6—3.1 144 4 3 3 СО со 1 со 425 4 3 4 3.6-4.1 1296 5 4 4 4.6—5.1 Замечание. При сортировке файла, состоящего из 100 ООО 100-сим» вольных записей, в 40 000-символьной рабочей области (средней для малых машин) будет сформировано не более 250 строк до слияния на лентах. Рис, 17.2. Некоторые примеры сравнений просмотров данных. разбиение на блоки и буферизация (k—1)-поточным слиянием или выбором конкретной степени слияния так, что циклы слияния не будут критичными по вводу-выводу или же будут работать столь медленно, что понадобятся дополнительные более быстрые просмотры? 2. Какова схема подсистемы ввода-вывода? Какой вид совмещения чте¬ ния-записи доступен? Будет ли слияние степени k — 1 вызывать помехи и за¬ держки? 3. Каковы характеристики перемотки и изменения направления движения- Возможны ли одновременные высокоскоростные перемотки? Какова истинна^1 цена изменения движения ленты при чтении? Ответы на эти вопросы будут влиять на решения об использовании кас¬ кадного, осциллирующего, сбалансированного или многоэтапного слияний либо в прямом, либо в обратном направлениях. Они также влияют на выбор
18.1. ХАРАКТЕР УСТРОЙСТВ 231 подходящей степени слияния при заданном методе. Более «тонкие» характе¬ ристики будут влиять на выбор алгоритма распределения; например, будут ли вдержки в канале или при синхронизации способствовать или препятство^ вать вертикальному или горизонтальному распределениям. 17.5. Сравнения слияний На рис. 17.1 дана сводка просмотров данных при многоэтапном, каскад¬ ном, осциллирующем и сбалансированном слияниях для разных значений k и разных совокупностях строк [5, 28]. Частичные просмотры не предполагаются. Значения для сбалансированного и осциллирующего слияний даны в виде формул, а для многоэтапного и каскадного в виде таблицы. На рис. 17.2, чтобы проиллюстрировать некоторые формы поведения, приведены некоторые значения, выбранные из рис. 17.1. Глава 18. СОРТИРОВКИ С ПРОИЗВОЛЬНЫМ ДОСТУПОМ 18.1. Характер устройств Запоминающие устройства произвольного доступа, вопреки своему назва¬ нию, характеризуются временными задержками при доступе, которые различ¬ ны по продолжительности. Время задержки включает время поиска и время задержки при вращении*). Время поиска — это время физического перемеще¬ ния механизма считывания-записи. Время задержки при вращении — это вре¬ мя, необходимое для установки вращающейся поверхности в надлежащую позицию под ожидающим механизмом считыванця-записи. Читатель, знакомый с дисками и барабанами, может пропустить раздел 18.2. 18.1.1. Время поиска. Время поиска возникает тогда, когда есть несколь¬ ко узлов считывания-записи и несколько адресуемых частей на записывающих поверхностях, и, следовательно, необходимо перемещение узлов считывания- записи в надлежащие позиции. Необходимое для перемещения время зависит 0т того, на какое расстояние по адресуемой дорожке на записывающей по- верхности должен быть перемещен этот механизм. Как правило, время поиска Смеряется в миллисекундах. Разработчик слияния обязательно должен учитывать перемещение штан- Ги **) как фактор, влияющий на производительность. У каждого типа устройств *) В качестве синонимов этих терминов в отечественной литературе чи- Татель может встретить термины «время подвода» и «время поиска» соот- Ветственно. (Прим. перев.) • ) В данном случае, штанга — это рычаг, к которому крепятся узлы тывания-записи и который перемещает эти узлы над поверхностью диска. перев.)
232 ГЛ. 18. СОРТИРОВКИ С ПРОИЗВОЛЬНЫМ ДОСТУПОМ есть своя кривая времени доступа, свое минимальное, максимальное и среднее время. Для определения точного времени поиска при перемещении ца разные расстояния надо обращаться к руководствам по данному устрой¬ ству. Поскольку время поиска имеет столь большое значение, следует уделять много внимания увеличению количества данных, доступного головке считы¬ вания-записи в каждой конкретной позиции. Одним из способов достижения этого является увеличение плотности записи на поверхности диска. Другим важным средством организации современных дисковых систем, которое уве¬ личивает объем доступных данных без перемещения штанги, является понятие цилиндра, которое требует несколько узлов считывания-записи, перемещаемых всех вместе над поверхностями пакета дисков. Этот комплект головок считы¬ вания-записи крепится к одной штанге. Такая организация эффективно увели¬ чивает размер дорожки, делая доступными за одно перемещение штанги сразу несколько дорожек — «цилиндр» — на каждой отдельной поверхности. Хотя для перехода от дорожки к дорожке внутри цилиндра электронной аппаратуре требуется определенное время для переключения головок, но оно мало по сравнению с временем поиска. Объем данных, доступный штанге без физического поиска, можно увеличить за счет увеличения размера пакета. Несмотря на то, что головок несколько, штанга рассматривается как единич¬ ное устройство, потому что в каждый момент времени читает только одна головка. Параллельное считывание и запись на разные поверхности одного и того же цилиндра не встречаются. Конструкций дисковой памяти существует множество и некоторые из них представляют в настоящее время лишь исторический интерес. Самые ранние дисковые устройства для обслуживания всего пакета имели одну штангу, поэтому к времени поиска добавлялось время на перемещение от поверхности к поверхности. В некоторых устройствах была сделана попытка повысить производительность, используя несколько штанг. Штанга, ближе всего распо¬ ложенная к нужному месту, перемещалась туда под управлением програм¬ миста. Современные многоштанговые устройства обеспечивают доступ к памяти большей емкости, связывая с одним устройством несколько пакетов. У каж¬ дого пакета есть своя штанга и данные на одном накопителе доступны только для штанги этого накопителя. Адресация включает обращение к накопителю, поверхности и дорожке. Такие устройства способны выполнять параллельно несколько поисков. Насколько полно эта возможность реализована на топ или иной системе, зависит от возможностей устройств управления, каналов и архитектуры системы ввода-вывода. (Подробнее об этом сказано в раз- деле 18.1.4.) Время поиска может возникать и в очень больших системах на бараба¬ нах, таких как семейство барабанов Fastrand на UNIVAC. Барабаны этого семейства обеспечивают память колоссальной емкости и предназначены ДлЯ поддержки больших баз данных (нетипичное использование барабанов)- Каждый барабан семейства Fastrand II содержит 192 дорожки, которые (за¬ служиваются 64 головками считывания-записи. Для того чтобы обратиться * барабану, необходимо установить головки над требуемыми дорожками. Б°е
18.1. ХАРАКТЕР УСТРОЙСТВ 233 головки смонтированы в виде единого комплекта и перемещаются вместе. Независимое перемещение одной головки невозможно. Головки этого устрой¬ ства полностью аналогичны головкам считывания-записи, укрепленным на одной штанге, перемещающейся над поверхностью диска. В системе Fastrand можно выбрать совокупность из 24 дорожек, назы¬ ваемых Fastband. Каждой из этих дорожек сопоставлена головка считывания- записи, и при обращении к этим дорожкам не возникает времени поиска. В системе Fastrand возможно подключение независимых барабанов через единственное устройство управления. Перемещения могут выполняться парал¬ лельно на восьми независимых устройствах. Читателям, особенно заинтересо¬ ванным в сортировке на Fastrand, следует обратиться к документации этого устройства. Описание Fastrand приведено здесь, как пример системы на бара¬ банах, имеющей время поиока. 18.1.2. Время задержки при вращении. И дискам, и барабанам свойствен¬ на задержка при вращении, т. е. период времени, в течение которого головка считывания-записи, установленная над нужной дорожкой, должна ждать, пока определенная позиция для считывания записи не окажется под ней. Задержка при вращении зависит от скорости вращения диска или барабана и от орга¬ низации данных. Скорость вращения существенно изменяется в зависимости от устройства. Барабан основной памяти на 5000 слов на машине Solid-State фирмы UNIVAC вращается со скоростью 17 500 об./мин. Барабаны средней величины, такие как IBM 2303, или UNIVAC FH-432, или FH-1782, как пра¬ вило, вращаются значительно медленнее. FH-1782 (объемом в два миллиона 36-разрядных слов) вращается со скоростью 1800 об./мин. Очень большие барабаны вращаются еще медленнее, например, Fastrand II имеет скорость вращения 870 об./мин. Задержки изменяются от нуля до полного оборота. Часто время задерж¬ ки при вращении указывают в виде минимального, максимального и среднего времени. Среднее время обычно берется как среднее арифметическое от ми¬ нимального и максимального времени. На некоторых барабанах используется идея Fastrand — введение допол¬ нительных головок для «быстрых» дорожек. Для таких дорожек время досту¬ па уменьшается пропорционально числу головок. Обычно это число равно че¬ тырем. На барабане с максимальным временем доступа 20 мс. (полный обо¬ рот) дорожка с четырьмя головками будет иметь максимальное время досту¬ па 5 мсек, и среднее время доступа 2.5 мс. Все, что было сказано о задержке при вращении для барабанов, пол¬ ностью относится и к дискам. Максимальное, минимальное и среднее время зависит от устройства. Для всех устройств с перемещающимися головками время доступа равно сумме времени поиска и времени задержки при вра¬ щении. 18.1.3. Другие устройства. На современных системах есть и другие цик- лические запоминающие устройства, но непосредственно при сортировке они Попользуются не часто. Если данные, расположенные на лентопротяжном Устройстве или других накопителях, должны быть переупорядочены, то обыч¬ но Делают так, что они «просачиваются» на быстрые устройства заранее, до Начала сортировки слияния.
234 ГЛ. 18. СОРТИРОВКИ С ПРОИЗВОЛЬНЫМ ДОСТУПОМ 18.1.4, Системы. Запоминающие устройства произвольного доступа по. мимо задержек вследствие поиска и вращения подвержены, подобно другим устройствам ввода-вывода, задержкам, вызванным устройством управления каналом и центральным процессором. Влияние этих задержек зависит от архитектуры и конфигурации самой системы. Архитектура определяет, сколь много может быть сделано параллельно, а конфигурация — какова та степень параллельности, какую можно достигнуть в конкретной системе. Соображе- ния, используемые здесь, почти те же, что приводились в связи с обсужде¬ нием слияния на лентах. Однако, здесь есть несколько новых деталей, кото- рые стоит рассмотреть. 18.1.4.1. Одно устройство. В самой простой конфигурации, где в качестве сортирующего устройства могут использоваться диск или барабан, есть только одно запоминающее устройство. На нем происходят все считыва¬ ния и записи. Такая конфигурация не позволяет совмещать на этом устрой¬ стве поиск с другим поиском или любой другой операцией ввода-вывода. Минимальное время слияния будет равно сумме времени считывания, записи и задержек при вращении. При такой конфигурации основной задачей про¬ ектирования должно быть сокращение времени поиска до возможных пре¬ делов. 18.1.4.2. Несколько устройств. В системе может быть набор из нескольких независимых накопителей. При этом можно проводить ^-поточное слияние на k накопителях подобно тому, как оно выполнялось на лентах. Время поиска, возникающее из-за перемещения механизма считывания-записи от одной строки ввода к другой, исчезает. В течение этапа механизм вывода планомерно перемещется над поверхностью. Огромное влияние на производительность сортировки имеет способ под¬ ключения нескольких устройств к системе. Архитектура и конфигурация устройств управления и каналов будет определять возможность совмещения времени поиска и времени задержки при вращении, а также возможность параллельного считывания данных. Можно каждое устройство подключить к отдельному устройству управления, а каждое устройство управления к от¬ дельному каналу, гарантируя таким образом совмещение считывания-записи. Чаще несколько накопителей соединяются с одним устройством управления, и это устройство может иметь канал в монопольном владении. В некоторых системах устройство управления имеет доступ к нескольким каналам. Коль скоро есть возможность для совмещения считывания-записи, то дополнитель¬ ный канал не нужен. Как и в случае лент, при наличии нескольких путей передачи данных при считывании и записи возможны исключительно резкие улучшения. Такое же значение, как число каналов и устройств управления, имеет место, где выполняются те или иные функции — правила взаимодействия 8 подсистеме ввода-вывода. Один канал, который может передавать адрес ДлЯ поиска на устройство управления и затем обслуживать другое устройство Д° тех пор, пока не будет выполнен поиск, может работать с эффективностью нескольких каналов, которые «запирают» устройство на все время поиски* Точно так же и устройство управления, которое может запустить пойск на
18.2. ОСНОВНЫЕ ПРИНЦИПЫ СЛИЯНИЯ 235 одном устройстве, затем освободиться и запустить поиск на другом, может быть столь же эффективно как и несколько устройств управления. Для того, чтобы выявить имеющиеся возможности для совмещения, разработчик дол¬ жен скрупулезно изучить интерфейсные характеристики канала, устройства управления и подключаемого устройства. 18.2. Основные принципы слияния Слияние на диске можно охарактеризовать следующим образом: 1. Оно может иметь степень, равную числу строк: 5 строк могут участво¬ вать в однопросмотровом S-поточном слиянии. 2. Оно может выбирать конкретные строки для использования на любом конкретном этапе слияния и произвольно переопределять степень слияния от этапа к этапу. 3. На него может влиять время поиска. Это обстоятельство может сде¬ лать теоретически оптимальные формы слияния неэффективными. Таким образом, минимизация времени поиска является основной целью проектирования. Там, где есть поиск, слияние, которое перемещает больше Область 1 Область 2 Область 3 > К области 3 > К области 1 Рис. 18.1. Сбалансированное слияние на диске. Первое перемещение из обла¬ чи 1 в область 3. Просмотр 1 заканчивается, когда строки из области 2 пере¬ местятся в область 1. Данных, может быть производительнее, поскольку время, затраченное на поиск, рачительно меньше. Скорость передачи данных на дисках очень велика, ^тройство IBM 2314 может передавать 312 000 символов в секунду. Чтение л°ка из 1000 символов на IBM 2314 занимает около 3 миллисекунд. Сред- ре время поиска плюс время задержки вследствие вращения равно 87.5 мил- екУнд. Налицо большая разница между данным случаем и случаем с Лентопротяжным устройством, где время поиска (т. е. время запуска) по-
236 ГЛ. 18. СОРТИРОВКИ С ПРОИЗВОЛЬНЫМ ДОСТУПОМ рядка 5—10 миллисекунд, а чтение 1000 символов занимает около 11 милли секунд. • 18.2.1. Сбалансированное слияние. Разнообразные элементы проектиро вания слияния будут рассматриваться на примере сбалансированного слия пия — метода, который получается из сбалансированного слияния на лентах Для демонстрации будет взято устройство с одним диском. Метод сбалансированного слияния на дисках включает определение чис ла рабочих областей на диске. Если выделяется три области, то строки рас пределяются некоторым способом по двум из них. Таким образом, когда ввод закончен, две области содержат все строки, а одна область пуста. Затем строки из одной области объединяются друг с другом при m-поточном слия* нии в пустую область. Когда это слияние закончено, сливаются строки из другой области в область, освободившуюся при первом слиянии. Всякий раз есть область, которая не получает строки. Просмотр слияния заканчивается, Область 1 Область 2 Область j А) *-16 L hi В) 76L 16 L С) 16L WL -32L (Вывод) Рис. 18.2. Просмотр 2 и последний просмотр сбалансированного слияния на диске. когда строки каждой области, которая вначале получала строки, будут слиты в другую область. На рис. 18.1 показано исходное распределение и просмотр сбалансирован¬ ного слияния, использующего три области. Степень слияния, в примере рав¬ ная 4, выбрана произвольно. Последовательность из четырех четырехпоточных слияний 16 строк из области 1 образует в области 3 четыре строки длины 4, а область 1 оставляет пустой. Строки из области 2 можно затем слить в об¬ ласть 1. В конце этого просмотра области 1 и 3 содержат строки длины 4, а область 2 пуста. Первый просмотр этого слияния закончен, так как файл данных перемещен полностью. В конце просмотра существующие состояния определяют необходимость дополнительного просмотра такого типа. Если общее количество строк мень¬ ше, чем степень слияния, то последнее слияние между областями образует одну строку. Если число строк больше степени слияния, то необходим допол¬ нительный промежуточный просмотр. На рис. 18.2 показаны окончание про¬ смотра 1, дополнительный промежуточный просмотр 2 и заключительный про¬ смотр. Заключительный просмотр отличается от промежуточного тем, 11Т° строки из разных областей объединяются в упорядоченную строку. Степень заключительного слияния равна числу оставшихся строк.
18.2. ОСНОВНЫЕ ПРИНЦИПЫ СЛИЯНИЯ 237 18.2.2. Поиск при сбалансированном слиянии: слияние внутри одной об¬ ласти. Перемещение штанги минимизирует скорее слияние внутри одной об¬ ласти, чем между областями. В течение слияния надо пытаться сократить как число перемещений штанги, так и их протяженность. Если для каждой области поле выделяется в виде цилиндра, то все стро¬ ки одной области доступны для штанги считывания-записи без поиска. Если нужно несколько цилиндров, то перемещение штанги все же ограничено опре¬ деленным числом цилиндров (например, двухцилиндровая область). Если же все строки помещаются в один цилиндр, то все считывание строк для слияния выполняется без поиска независимо от вклада отдельных строк, ввода в стро¬ ку вывода. При выполнении слияния с одной штангой надо перемещать штангу так, чтобы записи шли в соседний цилиндр. Эффективность при этом сильно падает, но перемещение штанги все же меньше, чем при слиянии между областями. При слиянии внутри одной области степень слияния не зависит от коли¬ чества областей, выделенных под строки. Над строками одной области можно проводить слияние любой степени. Точная степень слияния выбирается с целью уравновесить перемещение данных и время доступа путем управления числом выполняемых поисков и указывает ту память, какую можно использо¬ вать под блоки, образуемые из каждой строки ввода. 18.2.3. Степень слияния. Минимальный объем перемещений данных дости¬ гается при наибольшей степени слияния. На гипотетической системе с пол¬ ностью произвольным доступом к любым данным и без ограничений на объем памяти наилучшая степень слияния всегда есть наибольшая, а самая лучшая стратегия — это сливать все строки за один просмотр [9, 27]. При обсуждении слияния на лентах нам были хорошо известны те огра¬ ничения на степень слияния, которые накладывают машины. На слияние на дисках влияют, и даже с большой силой, те же самые ограничения. Ниже пе¬ речислены факторы, влияющие на степень слияния: 1. Размер основной памяти. 2. Среднее время поиска. 3. Время передачи данных. Размер основной памяти является решающим фактором для выбора сте¬ пени слияния. При любом заданном количестве памяти пространство, какое может быть занято под любую строку, зависит от степени слияния. Как пока¬ зано на рис. 18.3, при 16-поточном слиянии максимальное число записей, ка¬ кое получается из каждой строки и может разместиться в основной памяти, Равно 6, тогда как при двухпоточном слиянии там может поместиться 50 за¬ писей. Число записей, на которое можно разбивать одну строку — это размер блока, который можно сопоставить данному слиянию. Размер блока определяет число блоков, необходимых для формирования С1Роки. Число блоков, приходящихся на одну строку, определяет время до- СтУпа, поскольку обмен осуществляется блоками. Экономии в просмотрах дан- НЬ1Х 33 счет слияния высоких степеней противостоит возрастающая вероят- н°сть увеличения числа поисков, которая оказывает решающее влияние на Слияние.
238 ГЛ. 18. СОРТИРОВКИ С ПРОИЗВОЛЬНЫМ ДОСТУПОМ На рис. 18.3 показано общее число обращений к блокам, необходимое для разных степенен слияний при сворачивании 16 строк в одну строку. Для того чтобы определить наиболее подходящую степень для слияния 16 строк, надо найти такую степень слияния, при которой сумма времени передачи данных и времени поиска минимальна. Сте- Размер пень блока 1 Число Количество блоков обращений в строке2 при слия¬ нии между областями 3 Число слияний между областями за просмотр Число обращений к блоку за просмотр 3 Всего Число обращений просмо- к блоку 4 тров данных5 16 6 84 1344 1 1344 1344 1 8 12 42 336 2 672 1344 2 4 25 20 80 4 320 640 2 2 50 10 20 8 160 640 4 Замечания. 1 Число записей, помещающихся в памяти одновременно. Для этого примера, когда для ввода доступно 10 ООО символов памяти, а записи состоят из 100 символов, в любой момент времени в памяти может быть 100 записей. При 16 строках ввода в любой момент времени в памяти может быть 6 записей от каждой строки. Это вычисляется делением степени слияния на число записей в памяти. 2 Число блоков для формирования строки длиной 500 записей. Имеется 16 начальных строк или 8000 общих записей. Таким образом, каждая строка содержит 500 записей. 3 Слияние между областями — это одно m-поточное слияние т строк в области вы¬ вода. При одном просмотре 16-поточного слияния происходит одно 16-поточное слияние и 84X13 обращений к блокам. Для перемещения файла просмотру двухпоточного слияния надо 8 двухпоточных слияний. Число обращений за одно слияние между областями = тХ Хчисло блоков в строке. Число обращений за просмотр = число обращений за однослияниё между областями Хчисло слияний между областями за просмотр. * 16-поточное слияние имеет один просмотр, двухпоточное — четыре и т. д. Общее число обращений = число просг^РТровХэдсдр обращений за просмотр. 6 Файл перемещается на каждом просмотре. Рис. 18.3. Размеры блоков при слиянии разных степеней с указанием соот¬ ветствующего числа обращений к данным и просмотров данных. Для подсчета времени разных слияний надо знать, сколько будет про¬ смотров и сколько времени займет каждый из них. Расчет времени для четы¬ рех слияний, указанных на рис. 18.3, дан на рис. 18.4, где общее время вклю¬ чает лишь время чтения и поиска блоков. На устройстве с одной штангой т Всего обращений Время доступа, мс 1 Число считанных записей 2 Время чтения, мс Место Общее время (поиск-чтение) 16 1 344 16 800 8 000 5 280 2 22 080 8 1 344 16 800 16 000 10 560 3 27 360 4 640 8 000 16 000 10 560 1 18 500 2 840 8 000 32 000 21 120 4 29 120 Замечания. 1. Число обращенийх12п5 мс за доступ для данного примера. 2. Время чтения=0.66 мс на 100-символьную запись. Рис. 18.4. Временные характеристики разных слияний; быстрое обращение. добавилось бы время записи, и между каждым считыванием и записью по¬ явилось бы время поиска. Вычисления на рис. 18.4, хотя и упрощенные, по¬ казывают, что число просмотров данных и количество обращений работают друг против друга.
13.2, ОСНОВНЫЕ ПРИНЦИПЫ слияния 239 Наилучшим рассматриваемым слиянием для данного примера является четырехпоточное. Следующим наилучшим является 16-поточное, а самым пло- хим — двухпоточное. На 16-поточное влияет время обращения. На двухпоточ¬ ное влияет время считывания. На этот результат воздействуют такие параметры, как время доступа, время считывания, отношение между ними и размер памяти. Решающим для данного результата является предположение о 12.5 миллисекундном среднем времени считывания. Если отношение времени обращения и времени поиска иное, то и резуль¬ таты будут иными. На рис. 18.5 даны те же условия, что и на рис. 18.4, с одним исключением: время обращения равно 87.5 мс. Двухпоточное слияние теперь на втором месте. Сравнивая рис. 18.4 и 18.5, можно увидеть взаимо¬ связь между слиянием и влиянием параметров. Не всегда ясно, что следует использовать в качестве оценки времени об¬ ращения. Публикуемые средние времена обращения, как правило, весьма за¬ нижены. Если под рукой есть какая-то информация о размере файла и имею¬ щемся пространстве на диске, то можно получить улучшенную оценку среднего времени обращения. Если на 200-дорожечной поверхности используется только 10 дорожек, то опубликованные средние времена обращения дают очень гру¬ бые оценки. В мультипрограммной сред© или любой другой, где сортировка те¬ ряет контроль над штангой, лучше использовать весьма осторожные цифры. т Всего обращений Время доступа, мс1 Число считанных записей Время чтения, мс Общее место Время 16 1 344 117 600 8 000 5 280 3 122 800 8 1 344 117 600 16 000 10 560 4 128 160 4 640 56 000 16 000 10 560 1 66 560 2 640 56 000 32 000 21 120 2 77 120 Замечание. 1 Число обращений X 87.5 мс для данного примера. Рис. 18.5. Временные характеристики разных слияний; медленный доступ. 18.2.4. Выбор степени слияния. Здесь описывается конструкция слияния, при которой на каждом этапе за фиксированное число полных просмотров перемещаются все данные. Выбор степени слияния для таких конструкций наиболее изящно изложен Блэком [3], у которого, по существу, заимствован материал последующих разделов. Данное изложение, несмотря на то, что оно не исчерпывает всех аспектов оптимизации, позволяет понять основной под¬ ход к этой проблеме. Формально время слияния равно сумме времен всех просмотроз. Время просмотра зависит от степени слияния и влияния этой степени на производи¬ тельность машины. Машинные параметры — время обращения, время передачи Данных и размер памяти — можно связать одной величиной, своей для каж- Д°п конкретной конфигурации системы. Эта единая величина представляет гРубое, но приемлемое средство для оптимизации слияния. На рис. 18.6 ука¬ зано отношение времени поиска к времени считывания ALPHA для разных Рззмеров памяти на IBM 360 и скоростей передачи данных и времени обра- ■ .*йия для диска IBM 2311. Время считывания получается умножением ско¬
240 ГЛ. 18. СОРТИРОВКИ С ПРОИЗВОЛЬНЫМ ДОСТУПОМ рости считывания символа на число символов, необходимых для заполнения имеющейся памяти. С ростом памяти отношение времени поиска к времени считывания уменьшается, и за время поиска можно считывать больше данных. Значения отношения ALPHA зависят от скорости передачи данных в подсистеме ввода-вывода, используемого значения среднего времени поиска и размера заполняемой памяти. Для вычисления отношений можно использовать среднее время поиска. Если у исследователя есть основания использовать другое число, он, безусловно, может его использовать. Отношение ALPHA используется для построения формальной оценки до¬ стоинства просмотра в предположении совмещения считывания-записи-вычпс- лений и ограничения ввода-вывода. Оценка достоинства любого просмотра Размер памяти, байты Время чтения, мс ALPHA (поиск-задержка)/чтение 1000 6.6 13.25 10 000 66 1.33 20 000 132 0.66 30 000 198 0.44 40 000 264 0.33 50 000 330 0.26 100 000 660 0.13 250 000 * 1 650 0.05 500 000 3 300 0.03 1 000 000 6 600 0,01 Замечание. Скорость передачи данных на IBM 2311 = 156 кбайт; время поиска + + время оборота для IBM 2311=87.5 мс. Скорость передачи одного байта —около 6.6 мкс. Рис. 18.6. Вычисление ALPHA для дискового файла IBM 2311. есть (ALPHA Хш)+1- Число просмотров зависит от т обычным образом. Чем больше т (степень слияния), тем меньше число просмотров. Общее вре* мя слияния равно к £ (ALPHA х mi) + 1, где k — количество просмотров. Это число равно просто сумме времен всех просмотров. Это соотношение строится за несколько простых шагов. Первый опреде¬ ляет, каков допустимый диапазон значений k (количества просмотров). Если использовать максимальную степень слияния, то будет лишь один просмотр. Если использовать минимальную степень (т = 2), то число просмотров будет равно fl°g2 51 , где S — число строк. Этот набор значений k относительно мал. Для совокупности из 1000 строк k может изменяться от 1 до 10. Зная диапазон значений ку можно вычислить для каждого k соответ¬ ствующую степень слияния: mk — S. На рис. 18.7 показаны вычисленные степени слияния для 128 строк. Что(>ы
просмотров k Степень слияния 18.2. ОСНОВНЫЕ ПРИНЦИПЫ СЛИЯНИЯ 241 с К I V S 1 «531 л к 35 Я £33 u5s й м Я о х о. V Н _ о ° Ohs ЧО у «ВО !Г S с О S Ч о а ° * а tT* cs — ю со сч oi О си н N S -i О Ю Ю JO СО N СО « —« СО ft л N "t СО N Ри О ю U 00 00* 1-м СО ^ N СО N К а, М М СО ^ W (О N w со (О м ю а -м —. CD СО СО СО Ю ^ Ю т}< — <М СМ —' — —■ N N (N W N - 00 - N О оо <М Ф ^ СО СО N а) х Н cd о « О /1» си £ н л о a оо £<n о *-* ЙР (N СО ^ Ю (О N + Й 55 К К к <и К СВ 0) й> К Н <и О — н _1_ ° CQ т и о о а , :Г а н ' —■ н о 2 a О о ~ ' О I-* ХХ^с _ I £ X 2 2 | . ч I а а й 5 1 \ . = S = у Пии I Замечание. 1. (ALPHAXm)+ 1 = (0.13X128)+ 1 = 17.64. Ри-с. 18.9. Итоговые подсчеты для определения степени слияния (ALPHA=0.13).
242 ГЛ. 18. СОРТИРОВКИ С ПРОИЗВОЛЬНЫМ ДОСТУПОМ выполнить это слияние за семь просмотров, достаточно взять степень слия¬ ния, равную 2 (27 = 128); чтобы выполнить это слияние за шесть просмотров, нужна степень слияния, равная 3 (З6 > 128); и т. д. Точное значение подходящей степени слияния не обязательно должно быть целым числом. Однако слияния нецелых степеней невозможны (хотя результат слияния в терминах сворачивания строк может быть и нецелым). Таким образом, в большинстве конструкций слияния должно быть несколько слияний степени, меньшей максимальной. Следующим шагом при проектиро¬ вании слияния должно быть определение необходимого числа этих слияний более низкого уровня. На рис. 18.8 для каждого k показано суммарное число //2-поточных и (т—1)-поточных слияний, необходимых для сворачивания 128 строк. Ради стабильности используются лишь слияния степеней т и (т—1). Таким образом, общее время слияния равно сумме времен т-поточ- иых и (т— 1)-поточных просмотров. Заключительный шаг в определении степени слияния состоит в использо¬ вании информации, указанной на рис. 18.8, для определения времени про¬ смотра файла. Минимальное значение этого соотношения укажет подходящую степень слияния. На рис. 18.9 видно, что одно 12-поточное слияние образует 11 строк (10 длины 12 и одну длины 8), следующее за ним 11-поточное слияние является оптимальной конструкцией для 128 строк при ALPHA = 0.13. Читатель заметит, сколь сильно этот результат зависит от ALPHA. Значения ALPHA определяют подходящие конструкции слияний на основе взаимосвязи между размером внутренней памяти, размером всей памяти и скоростями ввода-вывода данных. Теперь давайте применим этот способ к более раннему примеру. Если мы используем 10 000 символов (как на рис. 18.3) и временные характери¬ стики IBM 2311 (как на рис. 18.6), то значение ALPHA будет равно 1.33. Столь большое значение ALPHA заставляет нас предположить, что более выгодными будут слияния малых степеней. В самом деле, на основе рис. 18.4 т— 1 Просмотры 1 16 15 1 16-поточное 2 4 3 2 4-поточное 3 3 2 3 3-поточное, 2-поточное 4 2 1 4 2-поточное Рис. 18,10. Применение метода Блэка к примерам на рис. 18.3, 18.4 и 13.5 (ALPHA 5= 1.33; число строк= 16). и 18.5 мы ожидаем, что оптимальной степенью слияния будет 4. Рисунки 18.10 и 18.11 подтверждают, что оптимальным является четырехпоточное слияние* равно как и относительное расположение двух-, четырех- и 16-поточных слия¬ ний. Поскольку данная конструкция слияния исключает следование двухпо¬ точного слияния за восьмипоточными, то восьмипоточное слияние не учиты¬ вается при сравнении.
18.2. ОСНОВНЫЕ ПРИНЦИПЫ СЛИЯНИЯ 243 18.2.5. Переменная степень слияния. Если отказаться от условия постоян¬ на степени слияния, станут приемлемыми намного больше конструкций слияния. Для 16 строк приемлемой становится конструкция, включающая рссьми- и двухпоточные слияния (которые использовались на рис. 18.3 и ис 18.4, но были исключены из последнего раздела). Конструкции с постоянной степенью слияния, однако, будут оптимальны лишь тогда, когда оптимальна конструкция MINB. Конструкция MINB — это k 1 2 3 4 т 16 4 3 2 Число просмотров степени т 1 2 2 4 ‘ m — 1 15 3 г I Число просмотров степени 0 0 1 0 т-1 (ALPHAXm) + 1 22.28 6.32 4.99 3.66 (ALPHAX(m-l))+ 1 - - 3.66 - Сумма просмотров степени т 22.28 12.64 9.98 14.64 Сумма просмотров степени - - 3.66 - т-1 Общее число просмотров 22.28 12.64 13.64 14.64 Рис. 18.11. Метод Блэка, продолжение (ALPHA = 1.33). слияние, у которого число поисков за весь цикл слияния минимально. MINR — это конструкция слияния, в котором за весь цикл слияния просматривается минимальное число записей. Величина константы ALPHA определит выбор между конструкциями MINB и MINR на основе размера памяти, времени поиска и времени передачи. Если оптимальны конструкции MINR, то в пре¬ делах отобранного максимального слияния всегда предпочтительнее слияние самой большой степени (иначе упомянутое свойство M1NR теряется). Если оптимальны конструкции MINB, то желательность сохранения степеней слия¬ ния почти одинаковыми объясняется тем, что конструкции типа описанных в разделе 18.2.4 в этом случае будут предпочтительнее других. Выбор сте¬ гни слияния путем вычисления ALPHA и использования формулы (ALPHA X т) + 1 Даст великолепный результат в тех случаях, когда выпол¬ няются полные просмотры слияния. 18.2.6. Частичные просмотры. Задана совокупность теоретически равно¬ доступных строк. Как надо спроектировать слияние, чтобы свернуть их в одну СтРоку за минимальное время? На рис. 18.12 показана некоторая совокупность СтРок различной длины (вверху) и оптимальное слияние этих строк (внизу). Каждое трехпоточное слияние (степень слияния выбрана из соображений, Указанных в предыдущих разделах) помечено одной из букв от Л до £, а в столбцах показаны списки строк после данного слияния. Строки, взятые в скобки, построены данным слиянием. У этого слияния есть два важных свойства: К Самые короткие строки сливаются первыми. 2. У последних слияний степень слияния всегда максимальна. Тот, кто читает эту книгу последовательно, увидит здесь применение к°нцепции дерева в том виде, как она излагалась в разделе 9.4.5. При нали-
244 ГЛ. 18. СОРТИРОВКИ С ПРОИЗВОЛЬНЫМ ДОСТУПОМ чин запоминающих устройств произвольного доступа, понятие оптимального слияния имеет большие возможности. Эффективность слияния с рис. 18.12 показана на рис. 18.13 и рис. 18.14. На первом показано сбалансированное трехпоточное слияние совокупности строк с рис. 18.12 без какого-либо упоря. дочения строк по длине (вверху) и более сбалансированное слияние (внизу), Список после Список строк (Л) (В) (С) (D) (В) в порядке первого второго третьего четвертого пятого записи слияния слияния слияния слияния слияния 19 26 29 38 81 19 27 34 52 99 26 28 36 67 (157) 27 29 38 81 28 34 52 (99) 29 36 67 34 (38) (81) 36 52 52 67 67 Замечание. Новые строки в скобках. Перемещение строк Ввод Вывод 19 U 19 38 26 U 27 U 28 81 29 (J 34 U 36 99 52 U 67 U 38 157 81 U 99 U 157 _337 712 Рис. 18.12. Оптимальное слияние (новые строки заключены в скобки). На рис. 18.13 внизу показана обработка строк от коротких к длинным. Разница между этими двумя слияниями не столь значительна, как между первым сбалансированным слиянием и оптимальным деревом. Возможности оптимального слияния показаны на рис. 18.14. При десяти строках в опти¬ мальном дереве перемещений данных на 15 процентов меньше, чем в сбалан¬ сированном. Таким образом, на последнем просмотре необходимо сохранить максимальную степень — это решающий фактор в использовании преимуще¬ ства длины строк. Заметим, однако, что если строки равной длины, а их число есть степень степени слияния, то между оптимальным слиянием и сба¬ лансированным слиянием разницы нет. На рис. 18.15 показан интересный результат применения частичных на¬ страивающих просмотров при сбалансированном слиянии. Верх, идентич¬ ный верху рис. 18.14 показывает, что сбалансированное слияние можно пре'
18.2. ОСНОВНЫЕ ПРИНЦИПЫ СЛИЯНИЯ 245 образовать в оптимальное при помощи частичного просмотра, который сокра¬ щает число строк до некоторой степени его слияния. Дерево такого слияния является оптимальным. Частичный настраивающий просмотр преобразует сба¬ лансированное дерево в «наилучшее» дерево, обеспечив максимальную сте- пень слияния на последнем просмотре. В общем случае, частичный настраи¬ вающий просмотр сможет преобразовать сбалансированное слияние степени т 337 273 310 в Дерево наилучшего перемещения строк (оптимальное дерево), если число строк немного превышает точную степень. На рис. 18.15 внизу частичный настраивающий просмотр выполняется над первыми двумя строками. Форма этого дерева такая же, как и у оптимального дерева на рис. 18.12. Из-за Размеров строк число перемещаемых записей иное. В худшем случае для этого множества строк сбалансированное слияние переместит 793 строки Частичный просмотр сливал бы строки длины 52 и 67). В лучшем случае Пришлось бы переместить 712 строк. Число строк, используемых на частичном просмотре, или степень первого Сияния при оптимальном дереве, дается Буржем (и другими) в следующем виде; 1- Степень частичного слияния равна оптимальной степени, если (число °трок — 1) mod (оптимальная степень—1)=0 (Ато&В — это остаток от де- Ления А на В).
246 ГЛ. 18. СОРТИРОВКИ С ПРОИЗВОЛЬНЫМ ДОСТУПОМ 2. Степень частичного слияния равна ((число строк — 1) mod (оптимальная степень—1))+1 в противном случае, т. е. степень частичного слияния равна остатку плюс 1. Например, при 11 исходных строках и степени слияния 3 нет остатка от деления 10 (число строк—1) на 2 (степень слияния—1), следовательно, 100 80 Число 220 перемещённых данных 100 '70 90 260 перемещенных банных Рис. 18.14. Оптимизация слияния максимизацией степени слияния последнего просмотра. степень частичного слияния также равна 3. При 10 строках, однако, частич¬ ное слияние имело бы степень 2, так как ((9mod2) + 1) равно 2. Вывод, который можно сделать из этого раздела, состоит в том, что если размер строк достаточно стабилен, то сбалансированное слияние с настройкой частичными просмотрами является прекрасной аппроксимацией слияния, опти¬ мального с точки зрения перемещения записей. 18.2.7. Оптимизация поиска: чередование. Средство для управления вре¬ менем поиска предоставляет чередование, которое размещает компоненты строк таким образом, что время поиска становится минимальным. При последовательном распределении блоки строк по мере построения записываются в сплошное поле памяти. При распределении с чередованием при записи строки между блоками оставляются зазоры. Эти зазоры исполы
18.2. ОСНОВНЫЕ ПРИНЦИПЫ СЛИЯНИЯ 247 з\-ются под блоки других строк, таким образом, блоки одной строки физи¬ чески следуют за блоками другой или дорожка, заполненная блоками одной перемещённых данных Рис. 18.15. Использование частичных-просмотров для оптимизации сбалансированного слияния. строки, следует за дорожкой, заполненной блоками другой. Если размер бло¬ ка равен размеру дорожки, то между чередованием блоков и дорожек нет Разницы. «Ширина» чередования может изменяться. Слияние степени 10, на¬ пример, не обязательно будет чередовать блоки всех десяти строк, оно может чередовать и меньшими степенями. В основе разумного объяснения чередования лежит характер процесса слияния. Блоки строк выбираются по одному по мере исчерпания. В качестве развития замысла — блок строки 1 исчерпывается прежде исчерпания блока строки 2 и т. д. — хотелось бы получать блоки из разных строк при минималь- н°м перемещении штанги. «Случайность» данных влияет на чередование. Поскольку при записи од- н°й строки необходимо оставлять зазоры заданного размера, то надо заранее 311ать длину строки. Необходимость знать длину строки приводит при рас¬ пределении к использованию внутренней сортировки, которая строит более Короткие строки фиксированной длины, или к усечению всех строк до задан- 251 719 13/ 337 Число
248 ГЛ. 18. СОРТИРОВКИ С ПРОИЗВОЛЬНЫМ ДОСТУПОМ иого размера, возможно 2F, где F — число записей в рабочей области. Более короткие строки искусственно дополняются фиктивными величинами до нуж- ной длины. Влияние усекающего выбора с заменой на строки не слишком велико, однако в течение всего процесса слияния надо знать размеры строк. Если размер блока меньше размера дорожки, то при чередовании возни¬ кает одна трудность. В течение процесса слияния может случиться так, что первый процесс записи будет использовать не первую физическую позицию дорожки. Без использования форматирующих методов, открывающих доступ на уровне записей, потери памяти на одной дорожке могут быть значитель¬ ными. Один из способов нахождения начальной позиции состоит в выделении под первый блок всей дорожки, в которой записан этот блок. Это, в действи¬ тельности, определяет формат дорожки, который потом используется при об¬ ращении к конкретным позициям. Могут возникать значительные дополни¬ тельные затраты на записи. На устройствах с заранее определенным форма¬ том эта проблема проще. Чередование строк полезно всегда, когда степень слияния больше желае¬ мого числа штанг считывания-записи. Чередование можно использовать при сбалансированном слиянии, как это было описано в этом разделе, или при других конструкциях слияния, в которых число рабочих областей или штанг не связано со степенью слияния. Еще одной проблемой чередования является трудность выполнения под¬ готовительных частичных просмотров. Решением этой проблемы, которое к тому же позволяет ограничить длины исходных строк, может служить за¬ держка чередования до тех пор, пока не будут построены все строки. Строки можно распределять последовательно. Можно построить указатель для пред¬ ставления места и длины. Зная число и длину строк, можно выбрать опти¬ мальный формат чередования. 18.2.8. Запись на место. В случае одного накопителя чередование не ре¬ шает одной проблемы — взаимного влияния чтения и записи в течение про¬ цесса слияния. Штанга должна сдвигаться при записывании и возвращаться при считывании. Метод, позволяющий сократить время перемещения штанги, состоит в том, чтобы записывать элементы строк вывода сразу туда, откуда они потом будут считываться. При использовании этого метода говорят, что происходит запись на место. Этот метод можно применять вместе с чередо¬ ванием, используя такую специальную схему считывания и записи, что каж¬ дая операция ввода-вывода является последовательностью считывания-записи. Поскольку согласно схеме считываний вновь сформированные строки записы¬ ваются по всему множеству строк ввода, то они не обязательно соприка¬ саются. При использовании этого метода аппаратура, по-видимому, потре¬ бует применения метода сцепления блоков. В силу прерывистости строк, образующихся в процессе записи на место, естественно использовать этот метод вместе с чередованием, пытаясь сокоа- тить время считывания-поиска и при этом устранить время записи-поиска- Поля, освобождаемые последовательными считываниями, при использования чередования будут, как правило, непрерывными и свободными для болыпи* записей на место. Подробности ускорения чередования процессов считывания и записи связаны с методами буферизации или распределения, применяемый
18.2, ОСНОВНЫЕ ПРИНЦИПЫ СЛИЯНИЯ 249 таким способом, чтобы гарантировать наличие записанного блока всякий раз, когда возникает считывание. С записью на место связана одна трудность — обязательно нужен какой- нибудь механизм для расстановки контрольных точек. 18.2.9. Несколько штанг. Существует множество подходов к различным способам использования нескольких штанг, которые различаются определе¬ нием областей и их использованием на разных устройствах. Полезность того или иного метода частично зависит от количества доступных устройств. Если есть много независимых устройств, то, может быть, эти устройства следует использовать как последовательные, наподобие лент. Перекрестный метод уместен тогда, когда оптимальная степень слияния невелика. Если она не превосходит число штанг, то можно выполнить лентоподобное слияние с од¬ ной областью на каждом устройстве. Ввод происходит с (k—1)-го устрой¬ ства на k-e устройство. После того как позиции начала строк определены, поиск не возникает. Процесс записи можно совмещать с процессом чтения, а схема считывания при вводе подобна таковой при перекрестном слиянии ка лентах. Если оптимальная степень слияния значительно больше, чем число устройств, то перекрестный метод становится менее привлекательным. Раз¬ мещая на одном устройстве по нескольку областей, чтобы обеспечить слияния больших степеней, можно увеличить время поиска. При 15-поточном слиянии на восьми устройствах, например, доступ осуществляется к 15 областям при помощи семи штанг. Каждая штанга неэффективно перемещается туда-сюда между двумя потоками строк. При сортировке возможны ситуации, когда вследствие уменьшения времени поиска перекрестное слияние, степень кото¬ рого равна числу штанг, будет более производительно, нежели перекрестное слияние большей степени. При наличии нескольких штанг сбалансированное слияние также может извлекать пользу из уменьшения времени поиска, хотя большинство совре¬ менных известных конструкций, отличных от перекрестной, не получают боль¬ шого выигрыша от наличия более чем двух устройств. Очень резкое измене¬ ние производительности происходит, когда есть разделенные штанги для счи¬ тывания и записи. Это разделение позволяет не только избегать перемещения Штанги, но и осуществлять считывание и поиск параллельно. При сбаланси¬ рованном слиянии из одной области в другую, очевидно, выгоднее иметь области ввода и вывода на разных дисках. Использование нескольких дисков при сбалансированном слиянии (с чере¬ дованием или без него) включает расширение области, содержащей строки, при помощи конкатенации цилиндров, расположенных на разных устройствах. Получающийся при этом «.логический цилиндр» будет иметь п штанг, кото¬ рые обслуживают слияние строк в этой области, а поле памяти, доступное й области за одно перемещение штанги, будет в п раз больше. Принцип логического цилиндра можно также объединить с принципом *аписи на место. Поскольку при записи на место для сокращения перемеще¬ ния штанги нет необходимости разделять процессы записи и считывания, то преимущество нескольких штанг проистекает из совмещения и возможности Санирования считывания и записи при минимальном перемещении штанги»
250 ГЛ. 18. СОРТИРОВКИ С ПРОИЗВОЛЬНЫМ ДОСТУПОМ Ясно, что преимущество конструкции с несколькими штангами зависит от того, являются ли все штанги постоянно доступными. В некоторых вычисли- тельных системах, мультипрограммных или с удаленным доступом, штанги временно может перехватывать супервизор операционной системы. Если такой перехват возможен, то разработчик сортировки не может рассчитывать на достижение теоретических выгод обработки несколькими штангами. 18.3. Дополнительные соображения о слиянии с произвольным доступом В предыдущих разделах была изложена сущность слияния в среде с про* невольным доступом. Были рассмотрены определенные степени слияния, кон¬ струкция слияния, управление временем поиска и некоторые подходы в случаях нескольких устройств. Осталось несколько вопросов, которые группи¬ руются вокруг слияния с произвольным доступом, не относящихся к какому- то конкретному методу, но образующих широкий круг соображений и воз¬ можностей, которые все-таки связаны с сущностью слияния, программами и машиной. Они рассматриваются здесь для того, чтобы завершить рассмотре¬ ние слияний с произвольным доступом в этой главе. 18.3.1. Размер строк: каталоги. Размер строк может изменяться при слия¬ нии с произвольным доступом, если при распределении не используется чере¬ дование. Когда оно используется, то размер строк может изменяться, если чередование выполняется после распределения [1]. Каталог строк и их длин позволяет «на ходу» строить шаги чередования. В общем случае, когда раз¬ мер строк разрешается изменять, каталог будет необходим, если слияние не¬ скольких строк выполняется (как при сбалансированном слиянии) в одной области (а не в разных областях). Для того чтобы система могла выполнять слияние, ей должно быть сообщено расположение начала строк. При любом методе, основанном на приближении оптимального дерева, размер всех строк должен быть известен. Недавно Фрэйзер и Уонг предло¬ жили увеличивать размер строк, используя дисковую память и расширение выбора с замещением. Смысл такого увеличения строк состоит в том, что про¬ грамма может преднамеренно строить наборы строк разной длины. Возмож¬ ность управлять изменением размера строк может, следовательно, обеспечить оптимизацию времени слияния за счет более эффективного построения опти¬ мального дерева. Если строятся строки определенного размера, то их можно распределять оптимальным путем, а именно, так, чтобы короткие строки были доступны прежде всего. 18.3.2. Буферизация. В среде с произвольным доступом совмещение счи* тывания-записи-вычислений наступает при буферизации, а решения, относя¬ щиеся к буферизации, являются здесь столь же важными, как и в случае Лент. В этой среде буферизация основана на степени слияния (т). Двойная бу* феризация (2т + 2) примерно тождественна предварительному выбору пла¬ вающих буферов, при котором используется (т + 2 + Я) буферов, где X число плавающих буферов, которое может изменяться от 1 до (т — 1). Зна*
18.3. СЛИЯНИЕ с ПРОИЗВОЛЬНЫМ ДОСТУПОМ 251 чс-ние X определяет, насколько полно предварительный выбор будет тожде¬ ствен двойной буферизации [43]. Надлежащий уровень буферизации будет сняться вместе со скоростью центрального процессора, отношением скоро¬ стей центрального процессора и подсистемы ввода-вывода, а также с разме¬ рами внешней памяти. Вообще для разработчика крайне нежелательно, чтобы число буферов превышало Х = 2> если большие значения будут стоить слиянию мощности. Как и в случае лент, надо провести исследование относительной производительности слияний больших и малых степеней с точки зрения вре¬ мени совмещения. Размер блока и оптимальное слияние надо согласовывать и изменять в свете размещения буферов. 18.3.3. Разбиение на блоки. Возможностью, которую ни в коем случае нельзя игнорировать, является использование динамического разбиения на блоки: изменение размеров блоков от просмотра к просмотру в процессе слияния на основе заранее известной степени слияния на следующем про¬ смотре. Короткие блоки могут быть записаны на этапе распределения. В про¬ цессе слияния эти блоки объединяются и считываются в связанные группы, образуя большие блоки, подходящие для данной степени слияния. 18.3.4. Поиск с просмотром вперед: планирование перемещений штанги. Поиск с просмотром вперед и планирование перемещения штанги — это только два из многих способов ввода-вывода в среде сортировки-слияния. В большинстве систем с предварительным выбором можно начинать поиск следующего блока для считывания до того, как он потребуется, совмещая тем самым поиск и обработку. Поиск можно начинать прежде, чем станет доступным буфер. Планирование перемещения штанги включает накопление запросов на считывание и запись и их удовлетворение в порядке удаленности. Очередь запросов упорядочивается так, чтобы перемещение штанги было плавным, а поиск между операциями ввода-вывода минимальным. Если этот прием применяется к случаю нескольких штанг, то в нужную позицию посы¬ лается та штанга, которая расположена ближе всех к требуемой записи. Однако устройства с несколькими штангами, которые имеют доступ к одной и той же записи, в настоящее время являются редостыо. 18.3.5. Сортировка записей или признаков. В литературе много внима¬ ния было уделено вопросу о сортировке признаков в противовес сортировке записей в случае дисков. Сортировка признаков включает построение вспо¬ могательного файла признаков. Вместо слияния записей эта процедура сли¬ пает лишь файл признаков. По окончании слияния записи последовательно набираются из памяти и помещаются на окончательное устройство вывода. Сортировка признаков может дать конкретные преимущества. Она может Уменьшить перемещение данных, число блоков (и, следовательно, количество поисков) при любой степени слияния или увеличить степень слияния вслед- Ствие уменьшения блоков, необходимых для представления файла. Недостаток Этой сортировки заключается в числе поисков, необходимых для доступа к записям при создании упорядоченного файла [39]. 18.3.6. Увеличение строк и переопределение. Вероятность, что сортируемые данные не являются «случайными», очень велика. Под воздействием механиз¬ ма сбора данных, а также, возможно, вследствие предыдущих операций сор- бровки, в файлах данных будет зачастую появляться масса пригодной для
252 ГЛ. 18. СОРТИРОВКИ С ПРОИЗВОЛЬНЫМ ДОСТУПОМ использования «упорядоченности» [19]. Использование выбора с заменой в качестве метода распределяющего просмотра позволит воспользоваться упо« рядоченностью данных. В разделе 12.7.1 рассматривались способы расширения строк и ограничения на них при использовании лент. Диски обеспечивают значительно более сложное применение расширения и переопределения строк, Читатель найдет материал, принципиально связанный с этим разделом, в гла¬ ве 9, где обсуждается использование таблиц описания строк. Идея, лежащая в основе расширения строк в случае дисков взята из ра- боты Фрейзера «Natural Selection». При сортировке методом выбора с заме- ной тех строк, которые ранее были сформированы этим методом, можно управлять их числом и размером так, чтобы последовательные этапы слияния были оптимальны. Важная реализация идеи переопределения в ходе сортировки есть в си¬ стеме сортировки 5740-SMI, поставляемой фирмой IBM под именем PEER. Эта система сортировки содержит несколько методов. Метод PEER обладает значительными преимуществами перед другими (классическими) методами, когда исходный файл является частично упорядоченным. Метод PEER исполь¬ зуется лишь там, где есть память с произвольным доступом. Важной целью этого метода (которая описана здесь в общей форме) яв¬ ляется уменьшение числа строк за счет распознавания того, где строки мож¬ но дополнить, а где их можно расчленить. На этапе распределения для каж¬ дой строки строится ряд индексов. Каждый индекс представляет некоторый сегмент строки. Сегмент строки в методе PEER, например, определяется как такая часть строки, которая помещается на одной дорожке устройства. На рис. 18.16 показан индекс сегмента строки. Одна строка, согласно этому ри¬ сунку, описывается индексным числом, младшим и старшим ключами этого сегмента, количеством записей в сегменте и адресом сегмента на диске. Эле¬ менты таблицы описывают строку из 30 элементов, расставленных по величи¬ не ключа от 2 до 49. Когда этап распределения закончен, начинается этап переопределения строк, на котором сортируются индексы сегментов строк по возрастанию зна¬ чений младших ключей. На рис. 18.17 отсортированный список индексов со¬ держит 16 сегментов строк. Этот список используется для определения двух новых строк: одна содержит 12 сегментов, другая четыре сегмента. Этот про¬ цесс можно описать следующим образом: 1. Поместить индекс с наименьшим ключом в новый список строки. 2. Определить, можно ли расширить новый список следующим индексом, т. е. является ли младший ключ следующего индекса равным либо большим старшего ключа индекса в новом списке? Добавить следующий индекс, если он удовлетворяет этому условию; если нет, то поместить его в следующий новый список, который определяет другую строку. 3. Проверить каждый индекс исходного списка на предмет возможности его занесения в один из новых списков строк. При необходимости начать но¬ вые списки. Сокращенная совокупность таким образом определенных строк раздел*1' ется потом на части по рабочим областям. Количество строк в каждой части определяется степенью слияния. В методе PEER первой части выделяется
18.3. СЛИЯНИЕ с ПРОИЗВОЛЬНЫМ ДОСТУПОМ 253 Номер сегмента Меньший ключ Больший ключ #Записи Адрес 1 2 27 10 ADDRESS 2 23 36 10 ADDRESS 3 37 49 10 ADDRESS Рис. 18.16. Индекс сегмента в методе PEER. Индексы * L Н 3 2 4 5 3 7 4 8 11 6 9 16 7 11 17 1 23 29 2 29 34 8 34 39 9 38 43 10 41 45 13 46 49 15 49 57 И 53 60 12 61 68 14 70 74 16 78 93 Новые строки # L Н 3 2 4 4 8 И 7 11 17 1 23 29 2 29 34 8 34 39 10. 41 45 13 46 49 15 49 57 12 61 69 14 70 ’ 74 16 78 93 # L Н 5 3 7 6 9 10 9 38 43 11 53 60 Рис. 18.17. Перераспределение строк в методе PEER (L — младший ключ; Н — старший ключ).
254 ГЛ. 18. СОРТИРОВКИ С ПРОИЗВОЛЬНЫМ ДОСТУПОМ (т — 1) строк, а все остальные части содержат по т строк. Если т = ^ т в первой части будет три строки и по четыре строки во всех остальных ца. стих. Каждая часть теперь упорядочивается, используя индексы и выбор с заменой. Сокращение совокупности строк происходит в соответствии со спи. ском индексов и зависит от упорядоченности в данных. Когда этап определения строк свернет данную совокупность строк, на- чинается этап слияния, который сворачивает все части, кроме первой, до 0д. ней строки. Если число строк в первой части плюс все оставшиеся строки (По одной в каждой части) не больше степени слияния на последнем просмотре то выполняется последний просмотр слияния. Если нет, то выполняется еще один этап переопределения строк. Последовательность переопределения строк- слияния частей продолжается до тех пор, пока совокупность строк не станет меньше либо равной степени слияния последнего просмотра.
Часть III. СИСТЕМЫ СОРТИРОВКИ Глава 19. УНИВЕРСАЛЬНЫЕ СИСТЕМЫ сортировки 19.1. Универсальная сортировка Для большинства вычислительных систем универсальные системы сорти¬ ровки либо поставляются вместе с вычислительной системой, либо продаются изготовителями программного обеспечения. Универсальные системы предназна¬ чены для широкого спектра приложений, легки в использовании и достаточно эффективны. Системы сортировки с широкой областью применения можно использовать для сортировки файлов с разными характеристиками, например, из несколь¬ ких томов данных, с разными длинами ключей, записей и т. д. Такая система включает некоторый язык, на котором пользователь может описать сортируе¬ мые данные и ресурсы машины, необходимые ему для сортировки. Система интерпретирует описание, заданное пользователем, и формирует для его дан¬ ных рабочую сортировку. Некоторые системы обеспечивают полную програм¬ му сортировки, другие изготавливают по этому описанию некоторый прототип сортировки. Простота использования такой системы определяется качеством языка сортировки и рабочими характеристиками ее программ. Возможности перезапуска системы, установки контрольных точек и выдачи хороших сооб¬ щений по ходу работы повышают практическую ценность такой системы. Поскольку универсальная система должна приспосабливаться к разным Данным и машинам, есть некоторая потеря эффективности. В системах эту обычную цену универсальности компенсируют, предоставляя в рамках одного пакета совершенно разные методы сортировки и (более или менее) изощрен- НЬ1е алгоритмы для определения предпочтительной степени слияния, характе¬ ристик разбиения на блоки и буферизации для конкретной сортировки-слия¬ ния. , Помимо изменений в данных и конфигурации разработчик универсальной ^Щтемы сортировки должен учитывать характер других компонент пакета. Должен решить, какие компоненты пакета следует использовать при сор- ^ровке, какие характеристики сортировки надо описывать па языке управле- ‘я заданиями, можно ли данную сортировку использовать как подпрограмму Г1Р0ГТ0Р°Й программы, на каком языке программирования следует писать эту °бла^аММ^ " Т' Д’ Р>азРа^0ТЧПКИ сортировки, кроме того, что они должны ^ть специальными знаниями в области сортировки и ввода-вывода, ЫЬ1 хорошо разбираться в методах генерации программ, структурах
256 ГЛ. 19. УНИВЕРСАЛЬНЫЕ СИСТЕМЫ СОРТИРОВКИ языков, моделировании и массе других вещей из области программного обес- печения. Создание хорошей универсальной сортировки требует мастерства и глубокого знания арсенала средств системного программирования. 19.2. Основная структура Универсальная сортировка-слияние состоит из следующей последователь¬ ности этапов: 1. Назначение. 2. Сортировка. 3. Слияние. 4. Последний просмотр слияния. 19.2.1. Назначение. Этап назначения (также называемый этапом управле- пня) образует модуль подготовки сортировки. Его конкретные функции зави¬ сят от задаваемых параметров сортировки и интерфейсов с операционной си¬ стемой. Среди функций, которые могут выполняться на этапе назначения, встречаются следующие: 1. Чтение управляющих карт сортировки и построение таблицы парамет¬ ров сортировки. Эта таблица содержит информацию, которая используется подготовительными функциями данной сортировки, а также на этапах слия¬ ния. 2. Интерфейс с операционной системой для определения количества до¬ ступной памяти и занесения этого значения в таблицу параметров. 3. Интерфейс с операционной системой для того, чтобы определить, ка¬ кие назначения устройств ввода-вывода уже сделаны, или для того, чтобы дать запрос на назначения. 4. Создание надлежащих функций сравнения или определения ключей на основе описания данных. 5. Выбор способа внутренней сортировки. 6. Вычисление размера области сортировки и буферизации. 7. Вычисление размеров блоков и степени слияния. 8. Оптимизация алгоритма распределения для увеличения совмещения при операциях ввода-вывода. 9. Определение способа слияния. 10. Загрузка и связь с сегментами «собственного кода» пользователя. 11. Подсчет времени работы сортировки. Фактический объем работы на этапе назначения зависит от конструкции пакета и интерфейса сортировки с операционной системой. 19.2.2. Сортировка. Пакеты сортировки различаются по степени специи- лнзации как самого этапа сортировки, так и этапа назначения. Необходимая степень специализации зависит от «гибкости» пакета и степени оптимизации- Как минимум, необходимо создать программу сравнения, определить единив обмена для ввода-вывода и задать стандартным программам ввода-вывоД3 адреса устройств. Необходимо обеспечить пользователя средством программирования <<с0^ ственного кода». Таким средством может быть ассемблер, компилятор иЛ1] загрузчик. Подробнее эта процедура будет рассмотрена позже»
19.3. ПАРАМЕТРЫ И ИХ ИСПОЛЬЗОВАНИЕ 257 19.2.3. Слияние. Этап слияния, иногда называемый промежуточным эта¬ пом слияния, включает все просмотры слияния кроме последнего. Как и этап сорТИровки он может либо все уточнения для себя делать сам, либо получить от этапа назначения, либо делать это совместно с этапом назначения. Обязательно должно быть сделано следующее: выбраны адреса устройств, организовано средство для m-поточного сравнения (m-поточного слияния) и включены программы «собственного кода» пользователя. «Собственный код» пользователя, называемый EPOC (each pass own code — собственный код каж¬ дого просмотра), не всегда допустим на промежуточных этапах пакета сор¬ тировки. 19.2.4. Последний просмотр. Последний просмотр слияния отделен от остальных, так как он взаимодействует с пользователем, который определяет размер блока вывода и может изменить устройство ввода-вывода. Запись должна иметь тот формат, какой определил пользователь; как следствие этих изменений буферизация, единица объема и распределение памяти на послед¬ нем просмотре должны определяться отдельно. 19.3. Параметры и их использование Системы различаются по своим возможностям и гибкости. Обязательные параметры отражают различия в назначении и способах оптимизации. Есть три основных функции сортировки-слияния, которые определяются парамет¬ рами: 1. Сравнение. 2. Пересылка элементов данных. 3. Ввод-вывод. Всякая универсальная сортировка имеет особенности в каждой из этих областей [16]. 19.3.1. Сравнение. Функция сравнения — это программный модуль, кото¬ рый сравнивает значения ключей. В универсальном пакете для подготовки Функции сравнения к работе требуется три вида данных: 1. Позиция и длина каждого сравниваемого ключа. 2. Кодировка каждого ключа. 3. Упорядоченность сортировки (возрастающая или убывающая). Некоторые системы сортировки такие, как сортировка-слияние для опе¬ рационной системы EXEC 1 для UNIVАС 1107 [20], позволяют пользователю °пРеделять свою логическую последовательность для упорядочения элементов Данных. Кодировка ключей описывает их вид и формат. На машинах со сметан¬ ам представлением информации (десятичным, двоичным и т. д.) необходимо °писывать способ представления. В пакете сортировки для OS IBM/360—370, НазЫваемом SM —023 [7, 14], возможны следующие описания: СН — символьный; — зонный десятичный; PD — упакованный десятичный; —с фиксированной запятой; ® U Лорин
258 ГЛ. 19. УНИВЕРСАЛЬНЫЕ СИСТЕМЫ СОРТИРОВКИ BI —ДВОИЧНЫЙ; FD — с плавающей запятой. С описанием кодировки данных можно поступать по-разному. Выбор при этом частично зависит от архитектуры машины. Если машина может обраба¬ тывать несколько разных форматов и выполнять разные сравнения, то функ. ция сравнения для одного формата будет выглядеть совершенно иначе, не¬ жели для другого. Команды двоичного сравнения, логического сравнения, алфавитного сравнения, которые могут непосредственно определять относи¬ тельное значение, не требуя дополнительных преобразований, есть на многих IBM OS/360 Sort SORT FIELDS =(1, 3, ZD. A, 7, 4, 2, BI, A) UNIVAC III/SORT III COMPARE*KEYS 0, 9, 15. 2, 3 UNIVAC 1050 SORT 1, 2, D, В KEY 1, 3, 1 KEY 2, 4, 7 Рис. 19.1. Описание ключей для трех систем сортировки. машинах. Если таких команд нет, то надо применять процедуру преобразо¬ вания для того, чтобы ключи сравнивались в нужном формате. То, что можно сделать при помощи параметров форматов, частично за¬ висит от методов генерации, используемых системой сортировки. Большей специализации можно достичь в том случае, когда функция сравнения строит¬ ся в виде макрокоманды ассемблера, которая затем настраивается по пара¬ метрам в момент загрузки. Выбор одной из заранее фиксированных функций сравнения на основе описания данных позволяет сократить затраты на созда¬ ние высокоспециализированного кода во время исполнения. Позиция ключа должна включаться в кодировку как на машинах, ориен¬ тированных на обработку символов, так и на машинах, ориентированных на обработку слов. На машинах, ориентированных на обработку слов, ключи могут занимать несколько слов, могут быть упакованы по нескольку в одно слово и могут либо зависеть, либо нет от знака слова, в котором они появи¬ лись. Описание поля включает указание разрядов слова или слов, которые содержат ключ. Длина ключа и его начало влияют на процедуру сравнения. Некоторые системы в зависимости от длины ключа могут выбирать либо сравнения типа регистр-регистр, либо сравнения типа регистр-память. Машины, обрабаты¬ вающие слова, должны будут либо параметризовать, либо строить команДь1 выделения ключа на основе позиции ключа. На рис. 19.1 показано описание ключей для трех систем сортировки: ДлЯ IBM OS/360—370 [14], UNIVAC III/SORT III [18, 19] и UNIVAC 1050. Д"'1* системы IBM 360—370 соответствующий оператор указывается на управля10
19.3. ПАРАМЕТРЫ И ИХ ИСПОЛЬЗОВАНИЕ 259 щей карте сортировки, которая считывается во время исполнения сортировки. Для остальных двух систем описанием ключа служит системная макрокоман¬ да ассемблера. Оператор OS/360 описывает два ключевых поля. Старший ключ длиной в три байта начинается с байта 1 записи. Это поле имеет зон¬ ный формат и должно упорядочиваться по возрастанию. Второе поле длиной 34 разряда начинается с байта 7 записи и занимает 4 байта (32 разряда) и два дополнительных разряда. Это двоичное поле сортируется по возрастанию. Оператор UN I VAC III описывает два ключа для макрокоманды Compare. Один ключ занимает все 24-разрядное первое слово записи. Второй ключ на¬ чинается с разряда 9 слова 2 (третье слово) и продолжается до разряда 15 слова 3 (четвертое слово). Эта информация представлена цифрами 9, 15, 2, 3. Оператор UNIVAC 1050 для описания двух ключей, одного десятичного и одного двоичного, использует макрокоманду SORT 1. Макрооператоры KEY 1 и KEY 2 задают длины и позиции ключей. Есть системы, которые используют другие способы описания полей, пред¬ ставляющих ключи. Вне зависимости от формата надо стремиться сделать так, чтобы пользователю не надо было строить свою функцию сравнения для каждого файла. Если общность системы не охватывает всех возможных раз¬ мещений ключей и кодировок, то система должна представить механизм, ко¬ торый бы позволил пользователю встраивать в контекст пакета сортировки собственный алгоритм сравнения. 19.3.2. Пересылка элементов данных. Функция, известная как пересылка элемента данных, вводит в сортировку новые элементы и изымает их из сор¬ тировки. По существу, это интерфейсная функция ввода-вывода. Она должна обладать информацией о том, сколь велика запись и имеет ли она переменную длину (если записи переменной длины допускаются сортировкой). Если система допускает записи как постоянной, так и переменной длины, и/или если в течение сортировки-слияния можно менять длину записщ то нужна более подробная информация. Типичный пример представляет собой необязательный оператор RECORD сортировки-слияния в OS/360. Этот оператор позволяет классифицировать записи как F (фиксированной Длины) или V (переменной длины) и предварительно задавать описания длин. Для записей фиксированной длины могут быть заданы три значения: длина записи при вводе, при выводе и при сортировке. Один параметр указывает на то, что «собственный код» обработки, вставленный пользователем, может изменять длины записей в процессе сортировки-слияния. Оператор такого Типа, например RECORD TYPE = F, LENGTH --= (100, 50, 60), описывает записи по 100 байт фиксированной длины исходного файла, преобразуемые ПеРед сортировкой «собственным кодом» в 50-байтные и преобразуемые на Последнем просмотре в 60-байтные. Для записей переменной длины должны быть указаны нужные значения максимальной длины в разные моменты вре- Мени- Кроме того, может быть указана минимальная длина записи при вводе и наиболее вероятная длина записи. Работа процедуры пересылки элемента данных обеспечивает разбиение ^анных на блоки и разблокирование при сортировке-слиянии, а также интер- Ф^йс с. пакетами поддержки ввода-вывода. Поскольку разбиение на блоки и ^блокирование являются общесистемными функциями, то средства для 9*
260 ГЛ. 19. УНИВЕРСАЛЬНЫЕ СИСТЕМЫ СОРТИРОВКИ описания длины записей могут находиться и в других местах помимо языка управления сортировкой. При наличии хорошо развитой операционной систе¬ мы описание длины записей обеспечивает язык управления. Язык ассемблера и языки высокого уровня (в особенности кобол и PL/1) также позволяют описывать записи. Разработчик языка управления сортировкой должен ре¬ шить, надо ли обеспечивать такую же возможность в языке сортировки. Это решение зависит от взаимосвязей между системой сортировки, операционной системой и языками программирования. Решающим критерием является до¬ ступность информации, описывающей записи, для функции генерации сорти¬ ровки в момент генерации сортировки. В OS/360—370 оператор описания за¬ писей является необязательным для управления сортировкой и используется только тогда, когда длины записей изменяются. Система сортировки получает описания записей через средства описания данных в языке управления зада¬ ниями (JCL). 19.3.3. Ввод-вывод. Ввод-вывод — это область, в которой взаимосвязь между управлением сортировкой и общим управлением заданиями становится наиболее туманной. Полное описание ввода-вывода для функций сортировки- слияния должно включать следующие элементы: 1. Размещение исходного файла. 2. Устройства, на которых будут храниться промежуточные строки. 3. Устройства, на которые будет осуществляться вывод. 4. Размер блока при вводе. 5. Размер блока при выводе. 6. Подробности формата исходного файла и файла данных вывода. 7. Размер хранимого файла. 8. Объем доступной памяти на каждом запоминающем устройстве с про¬ извольным доступом, используемом при слиянии. Читатели, знакомые с современными операционными системами, заметят, что за исключением пункта 7 все требования ввода-вывода могут быть удо¬ влетворены языком управления заданиями. В системах, где нет языка управ¬ ления заданиями, средства описания среды ввода-вывода будут находиться в языке программирования. Таким образом, индивидуальный язык ввода-вы¬ вода необходимо определять и поддерживать лишь для сортировки, стоящей обособленно «черным ящиком». При проектировании ввода-вывода для систем сортировки особый интерес представляет то, что пользователь может определить, что он доло/сен опреде¬ лить и что возлагается на элементы управления сортировкой и операционную систему. Эти характеристики особенно важны для ряда рабочих устройств, объема и организации памяти на устройствах с произвольным доступом и распределении устройств по каналам. Пользователи должны получить подроб¬ ное руководство от поставщика для того, чтобы определить, что они могут и что они должны описывать. Обычно это руководство берется из руководств для пользователей, которые предоставляет поставщик и которые более или ме' нее подробно объясняют влияние различных решений на поведение сорт11' ровки. Для того чтобы овладеть всем потенциалом технологии в системе я случае развитых пакетов сортировки для пользователя весьма существенно иметь хотя бы основное представление о процессе сортировки-слияния. Это
19.4. ДОПОЛНИТЕЛЬНЫЕ ПАРАМЕТРЫ 261 справедливо как в случае, когда главным средством является язык сортиров- ки так и тогда, когда таковым является язык управления заданиями. При слиянии на лентах максимальную степень слияния определяет выде¬ ленное пользователем количество рабочих устройств. Параметр, задаваемый пользователем, определяет распределение лент по каналам и доступную сте- пеНь совмещения при чтении-записи. В большинстве современных систем сор¬ тировки выбор ленточного метода основан на доступном количестве устройств й каналов. Также решающим является пространство на диске, определенное пользо¬ вателем. У каждого слияния на лентах есть алгоритм назначения памяти, но количество используемых накопителей (штанг) и их распределение по кана¬ лам определяет пользователь. Кроме того, пользователя могут попросить (как в OS/360—370) определить рабочее пространство на устройствах. Задаваемое число рабочих областей и размеры каждой из них могут влиять на перемеще¬ ние штанг. В современных операционных системах описание ввода-вывода обычно является частью управления заданием на этапе исполнения. Естественно, же¬ лательна гибкость описания устройств; лучше всего она достигается путем задания параметров управления вводом-выводом до момента исполнения. 19.4. Дополнительные параметры Основными параметрами универсального пакета сортировки являются ха¬ рактеристики ключей, записей и среды ввода-вывода. Возможно множество других параметров, наиболее распространенные из которых будут описаны в этом разделе.* Когда какого-то параметра нет в системе, то возможно, нет соответствующей услуги или функции, или она обеспечивается на основе решений, принимаемых сугубо внутри системы. Например, некоторые сорти¬ ровки предлагают широкий выбор типов слияний, но не позволяют пользо¬ вателю указать, какое он хочет. Слияние выбирается на основе некоторого алгоритма пакета. Некоторые сортировки позволяют пользователю задавать необязательное описание типа слияния. Однако отсутствие этого параметра в языке пользователя не есть показатель гибкости пакета или наличия раз¬ ных типов сортировки. 19.4.1. Размер файла. Размер файла является почти универсальным па¬ раметром для любой сортировки. Пользователя могут обязать дать хотя бы какое-нибудь предположение о размере файла, либо этот параметр может быть не обязательным. Пакет сортировки может варьировать использование эт°й информации в зависимости от целей и гибкости имеющихся средств °птимизации. Размер файла как параметр можно использовать при выборе метода Слияния. Распределение строк по устройствам и областям памяти изменяется 0т слияния к слиянию, и некоторым методам присуща более высокая произ¬ водительность, чем другим. Этот параметр также можно использовать для °1Г'енки числа строк, которые будут построены, и выбрать слияние и/или сте- Нь слияния на основе этого ожидаемого числа строк.
262 ГЛ. 19. УНИВЕРСАЛЬНЫЕ СИСТЕМЫ СОРТИРОВКИ 19.4.2. Размер памяти. Общим параметром для сортировок, которые пред¬ назначены для работы в потенциально мультипрограммных средах, является описание объема основной памяти, которая будет доступна для сортировки. Это количество обычно представляет пространство, доступное всей функции сортировки в целом, и используется в вычислениях при определении рабочей области, размера блока, степени слияния, буферизации и т. д. Иная форма параметра размера памяти позволяет пользователю задавать размер рабочей области сортировки, которую он хочет использовать в течение просмотра распределения. 19.4.3. Контрольные точки. Установка в процессе сортировки-слияния то¬ чек, которые представляют места возврата, является важной характеристикой конструкции пакета. Общая процедура контрольной точки встраивается в сор¬ тировку и обязана устанавливать контрольные точки в конце просмотра рас¬ пределения и в конце каждого просмотра слияния или частичного просмотра. Разные слияния отличаются тем, когда берутся контрольные точки, но все схожи в том, что пытаются обеспечить контрольные точки возврата так, что¬ бы защитить пользователя в случае ошибки от потери более чем одного про¬ смотра данных. Процедуры программы, которые обеспечивают функцию контрольной точ¬ ки не «бесплатны». На определенных этапах слияния необходимо представить некоторое количество памяти для представления данных. Необходимо время для подготовки устройств и записи управляющей информации. В большинстве пакетов пользователь может либо удалить функцию контрольной точки, либо специально указать, чтобы она была включена. В OS/360—370 SM—23 ключе- оее слово СКРТ является параметром периода исполнения, вызывающим за¬ щиту контрольными точками. Это специальное действие пакета зависит от ис¬ пользуемого способа слияния. 19.4.4. Выбор слияния. Современные системы позволяют использовать раз¬ личные способы слияния. Выбор способа либо полностью возлагается на си¬ стему, либо у пользователя есть возможность заставить систему взять кон¬ кретный способ. Полезность принуждения при слиянии зависит от тщатель¬ ности выбора системой способа и знаний пользователя. Безусловно, выбором следует пользоваться осторожно, позволяя пользователю реализовать свои знания аппаратуры и данных. Прежде чем пользоваться выбором, пользова¬ телю следует очень тщательно разобраться, как этот выбор осуществляется системой. Он может обнаружить, что критерии используемые системой недо¬ статочно полны. Они могут быть слишком произвольными. Какая-нибудь де¬ таль пакета может «забивать» другие детали и делать предпочтительным другое слияние. Например, (1) пакет может накладывать некоторые произ¬ вольные ограничения на степень слияния, размер записи и/или размер блока, в результате чего обычно предпочтительный метод становится менее эффеК' тивным и пользователь может выбрать другой метод в принудительном по¬ рядке; (2) пользователь может быть уверен, что он создаст совершенное рас' пределение для конкретного способа. 19.4.5. «Собственный код». Возможность использовать «собственный код» в пакете сортировки преследует две цели. Она дает механизм для опй* сания функций, связанных с сортировкой, которые неудобно выражать в виДе
19.5. ПРЕДСТАВЛЕНИЕ СОРТИРОВКИ 263 параметров, а также позволяет пользователю расширять то, что может быть ыполнено в течение сортировки, создавая функции, не связанные с сорти- кой. Примером «собственного кода», связанного с сортировкой, является программа, устанавливающая условие равенства ключей. разнообразие функций, которые могут быть выполнены «собственным ко¬ дом»» определяется общей структурой сортирующего пакета. В системах сор¬ тировки, основанных на наборе макроопераций сортировки, пользователь в своем «собственном коде» задает «основу». Он должен вызвать макроопера¬ ции сортировки и ввода-вывода, обеспечить точки начала программы, конца и сопряжения. Пользователь отвечает за доставку элементов данных к сор¬ тировке, за получение элементов данных от сортировки, за ее окончание и т. д. Сортировка выглядит подобно функции внутри программы пользователя. Когда сортировка рассматривается как «черный ящик», то взаимосвязь между «собственным кодом» и сортировкой становится обратной. Обеспечи¬ вается конкретное число выходов или точек сопряжения (на которые пользо¬ ватель может подать свой код). Порожденная загрузчиком сортировка такая, как OS/360—370 SM—023, предусматривает структуру программы и конкрет¬ нее число выходов, но практически без ограничений допускает использование функций в каждой из этих точек. Независимо от направления связи между сортировкой и «собственным кодом», необходим набор соглашений о связи. Прежде всего эти соглашения включают использование набора меток, индекс-регистров и условий выхода и входа. Если основу обеспечивает «собственный код», то пользователь должен указать, какие метки следует использовать при адресации функций сортиров¬ ки, к которым он обращается. Когда основу образует пакет сортировки, то пользователь должен указать, как осуществить возврат. При использовании «собственного кода» кроме основной структуры необ¬ ходимо принять и другие решения. Важно решить, что будет допускать ин¬ терфейс между языками, отличными от языка ассемблера, и сортировкой. Нужен некоторый интерфейс между коболбм, PL/1 и т. д. и пакетом сорти¬ ровки. Обращение к средствам сортировки из программ на коболе предусма¬ тривается Американским национальным стандартом (ANS), а глагол SORT*) описан в руководствах по коболу. Есть также интерфейс между сортировкой и PL/1. Применительно к этим интерфейсам необходимо принять решение — будут ли функции «собственного кода», доступные на ассемблере, доступными На языке -более высокого уровня. 19.5. Представление сортировки Общие возможности сортировки в универсальной системе сортировки- зияния обычно описывают в виде набора подпрограмм в библиотеке сорти- Р°вки. В зависимости от операционной системы библиотека сортировки может 1Ть трансформирована в рабочую программу сортировки либо во время ком¬ пиляции или сборки, либо во время загрузки, либо в некоторые промежуточ- е периоды времени, по ходу исполнения сортировки. Библиотека сортировки ) SORT — сортировать. (Прим. перев.)
264 ГЛ. 19. УНИВЕРСАЛЬНЫЕ СИСТЕМЫ СОРТИРОВКИ включает те программы сортировки, которые будут являться частью рабочей программы сортировки (рабочие модули), а также те, которые будут настраи- вать рабочие модули в ходе работы (назначающие модули). «Скелетный» код образуют либо рабочие, либо назначающие модули. Они могут быть генери¬ рующими макрооперациями, могут быть фиксированными подпрограммами которые для разных сортировок различаются только расположением в памяти. В последующих разделах изложены два различных подхода к построению сор. тировки, которые могут послужить полезными примерами. 19.5.1. Построение сортировки на основе ассемблера. Библиотека сорти¬ ровки состоит из четырех основных секций. 1. Секция построения, содержащая макрогенератор для подпрограмм сравнения и всех назначающих модулей, необходимых для настройки сорти¬ ровки, включая a) подпрограмму, которая устанавливает параметры размера записей; b) подпрограмму, которая устанавливает параметры для устройства ино¬ да и разбиения на блоки при вводе; c) подпрограмму, которая устанавливает параметры для устройства вы¬ вода и разбиения на блоки при выводе; d) подпрограмму, которая устанавливает адреса устройств для слияния; e) подпрограмму, которая устанавливает для размещения рабочей обла¬ сти сортировки; f) подпрограмму входа в сортировку. 2. Код сортировки, состоящий из рабочих модулей сортировки. (Рабочие модули сортировки — это те модули, которые включаются в рабочую сорти¬ ровку.) 3. Стандартная подпрограмма управления внешними устройствами, кото¬ рая задействуется тогда, когда сортировка должна использоваться как «черный ящик», и которая содержит необходимые подпрограммы поддержки ввода- вывода. 4. Набор подпрограмм связи, которые используются, когда к сортировке обращаются из кобола. Все секции находятся в библиотеке системы в виде символьного кода на языке ассемблера. Все параметры для сортировки передаются посредством макрокоманд языка ассемблера. Построение сортировки выполняет макро¬ ассемблер. Если создаваемая сортировка должна работать как «черный яшик»> то код на ассемблере включает обращение в библиотеку за вспомогательной программой управления внешними устройствами. Пользователь может предо* ставить свою программу управления внешними устройствами на языке ассеМ* блера, а не обращаться за таковой к пакету. Конструктивно сортировка рабо¬ тает как подпрограмма боле.е длинной программы, и пользователь может предоставить программу управления внешними устройствами такой сложно* сти, какая ему необходима. На выходе ассемблера образуется программа сор* тировки, которая может работать без дальнейшей параметризации. Этап на' значения частично возлагается на ассемблер. Там, где сортировки, как правило, работают неоднократно над одн11М11 и теми же файлами данных, однократная настройка сортировки, включаю1113* ассемблирование, не представляет неудобств и может способствовать ускоре
19.5. ПРЕДСТАВЛЕНИЕ СОРТИРОВКИ 265 НцЮ сортировки. Параметризация и настройка сортировки, предшествующие периоду загрузки, могут представлять недостаток в очень динамичных средах крупных машин. 19.5.2. Построение сортировки на основе системного загрузчика. Возмож¬ ности сортировки представлены в системной библиотеке и библиотеке сорти¬ ровки. Этап назначения сортировки является частью библиотеки операционной системы. Модули этапа назначения находятся в перемещаемой форме загруз¬ ки и считываются из системной библиотеки при обращении к сортировке. Библиотека сортировки также перемещаема. Она строится во время ге¬ нерации системы из всего набора нескольких сотен модулей, представляющих разные функции программы сортировки. Это подмножество библиотеки сор¬ тировки содержит все модули, которые могут понадобиться на данной вычис¬ лительной системе при создании любой возможной сортировки. (Из библиоте¬ ки сортировки могут быть исключены такие модули, как, например, подпро¬ граммы работы с дисками, если в существующей конфигурации есть только ленты.) Из построенной библиотеки сортировки создаются сортировка, слия¬ ние и этапы последнего просмотра. Когда происходит обращение к сортировке, этап назначения вызывается из системной библиотеки системным загрузчиком. Модули этапа назначения строят по управляющим картам таблицу параметров сортировки. На этом эта¬ пе рассчитываются блоки, буферизация, слияния, и устанавливается связь с операционной системой для назначения устройств. Затем на этапе назначения формируется запрос к системному загрузчику на загрузку начальных модулей этапа сортировки. Начальные модули этапа сортировки готовят этот этап к работе. Все мо¬ дули кроме «собственного кода» пользователя, системного ввода-вывода и обработки прерываний, берутся из библиотеки сортировки. Начальный за¬ грузчик загружает последовательность назначающих модулей этапа сортиров¬ ки. Каждый загруженный модуль выполняет свою функцию, и на его место загружается следующий. Выполняемая настройка включает генерацию функ¬ ции сравнения, организацию памяти для буфера и областей сортировки, и, если необходимо, организацию структуры для сортировки по дереву. На осно¬ ве таблицы параметров происходит построение, выбор и загрузка модулей, а также передача информации подготовленной рабочей программе. Промежуточный этап слияния и последний этап строятся абсолютно оди¬ наково. Каждый этап состоит из набора модулей библиотеки сортировки, Некоторые из которых выбираются и загружаются. Некоторые проводят пред- Варительные вычисления, некоторые выполняют разметку памяти, а остальные генерируют код. На рис. 19.2 дан пример типов модулей в библиотеке — частичный список модулей сортировки SM—023 для IBM OS/360, представ¬ ляющий лишь малую часть более чем 200 модулей из этой сортировки. Каж- дая пара подпрограмм предполагает выбор: при сортировке будут использо- ®аться либо ROA, либо ROB или либо RDP, либо RDO или либо AOR, либо Этот подход годится для больших библиотек и уменьшает потреб¬ ить в генерации кода. Там, где диапазон возможных ситуаций нельзя по- кРЬ1ть за счет выбора модулей, генерация все-таки необходима. Примером ньляется случай с функцией сравнения.
266 ГЛ. 19. УНИВЕРСАЛЬНЫЕ СИСТЕМЫ СОРТИРОВКИ В интерфейсе с системой есть несколько точек, которые следует делать явными. Система сортировки, основанная на системном загрузчике, при опре¬ делении среды ввода-вывода опирается на средства управления системы. Си¬ стемный планировщик и распределитель внешних устройств всегда назначают устройства до загрузки первого модуля сортировки. Эти назначения отража¬ ются в таблицах системы, которые можно просмотреть на этапе назначения. Таким образом, работа сортировки зависит от наличия в операционной системе средств доступа к управляющей информации и распределения ресурсов. Далее, активизация сортировки выполняется после того, как операционная система даст запрос системному загрузчику на загрузку первого модуля сортировки. Другая зависимость сортировки от услуг системы связана с «собственным кодом» пользователя. Модулей, созданных пользователем в виде «собствен¬ ного кода», нет ни в системной библиотеке, ни в библиотеке сортировки. Они Имя Этап Функция ROA сортировка замещение с простым управляющим полем ROB сортировка замещение с составным управляющим полем RDP осциллирующая несблокированная запись < 256 байт сортировка RDO осциллирующая несблокированная запись ^256 байт сортировка AOR слияние алгоритм сбалансированного слияния на ленте AOS г. слияние алгоритм многоэтапного слияния на ленте Рис. 19.2. Типичные библиотечные модули (сортировка IBM OS/360). должны быть ассемблированы и скомпилированы в личную библиотеку поль¬ зователя, откуда их и следует брать. На то, что «собственный код» есть и что он должен быть применен при сортировке, указывает параметрическая карта. В этом случае сортировке необходима дополнительная системная функ¬ ция для подготовки модулей пользователя к загрузке. OS/360, например, должна использовать системный редактор связей при подготовке модулей «собственного кода» для сортировки. Отличительной чертой такой схемы построения сортировки является то, что она тесно связана с операционной системой и опирается на нее. Другой характеристикой является использование в библиотеке модулей, перемещае¬ мых на уровне языка машины, а не на уровне ассемблера или компилятора, а также использование дублирования и выбора, а не генерации, как основ¬ ного способа настройки сортировки. Рабочая сортировка никогда не «генери¬ руется». Программа сортировки «специализируется» при каждом обращении к сортировке и не является повторно используемой, как в случае ранее опи¬ санной системы. 19.6. Решения, принимаемые системой В дополнение к параметрам, которые указывает пользователь, или в |<а' честве альтернативы для них система сортировки сама принимает решения по следующим вопросам. 1. Какое слияние подходит для данного случая сортировки — на диске или ленте?
19.6. РЕШЕНИЯ, ПРИНИМАЕМЫЕ СИСТЕМОЙ 267 2. Какие уровни буферизации и способ буферизации необходимы? 3. Какой размер блока следует использовать, особенно на этапе слияния? Его следует оптимизировать для слияния. 4. Какова степень слияния? Кроме этого есть вопросы структуры программ, структуры загрузки мо¬ дулей программы, таблиц управления, распределения памяти и внешних свя¬ зей, которые должны генерироваться и вычисляться системой. Специфика вычислений изменяется от системы к системе так же, как и усилия нахождения оптимально сбалансированного метода, степени слияния, разбиения на блоки и буферизации. 19.6.1. Выбор способа. В современных пакетах выбор ограничен в основ¬ ном либо ленточным, либо дисковым способом слияния. Внутренние алгорит¬ мы фиксированы и выбираются, например, на основе решения о сортировке ключей или записей. Как мы уже видели ранее, критериями для выбора слияния являются следующие: 1. Возможности устройств. 2. Распределение каналов. 3. Размер основной памяти. 4. Число устройств. 5. Размеры файла, размеры записей. Возможности устройств как критерий, связаны с тенденцией некоторых распределений размещать на одном устройстве непропорциональный объем файла. Распределение каналов имеет значение, когда в среде со сбалансиро¬ ванными каналами есть тенденция к взаимным помехам процессов чтения и за¬ писи, как это бывает при (k—1)-поточном слиянии на ленте. Размер основ¬ ной памяти может служить ограничивающим фактором для перекрестного и осциллирующего слияния, для которых необходимо, чтобы в памяти одновре¬ менно находились и программа сортировки, и программа слияния, либо чтобы они исполнялись в режиме перезагрузки. Размер основной памяти также дол¬ жен быть учтен при увеличении числа строк, которые могут быть построены. Размер файла и размер записи также влияют на ожидаемое число строк; как мы уже видели, ожидаемое число строк влияет на выбор метода слияния. 19.6.2. Расчет использования основной памяти. Материал глав 12 и 13, где обсуждались степень слияния, буферизация, разбиение на блоки, есте¬ ственно переплетается с контекстом действий, выполняемых универсальной сортировкой-слиянием. Функция этапа назначения или подготовительного эта- “а слияния должна определить степень слияния, произвести разбиение на бло¬ ки и буферизацию для любой генерируемой сортировки. Эти расчеты, в их простейшей форме, включают ряд решений, которые Запоминают то, что было в главах 12 и 13. 1. Размер программы. Размер программы зависит от размеров генерируе- мых подпрограмм и подпрограмм, выбранных из библиотеки. Он может за- й1,сеть от количества устройств ввода-вывода, размера «собственного кода» п°льзователя, длины записей, формата и длины ключей, типа слияния и С1спени слияния. Размер программы вычитают из размера доступной основ- йой памяти, чтобы определить размер пространства, используемого вводом-
268 ГЛ. 19. УНИВЕРСАЛЬНЫЕ СИСТЕМЫ СОРТИРОВКИ выводом и областью сортировки. Расчеты для сортировки, слияния и послед, него просмотра обычно дают разные длины программ. 2. Размер блока и буферизация. Нужное пространство памяти зависит от степени слияния, способности аппаратуры совмещать операции чтения, записи и вычислений и сбалансированности машины. Стратегия буферизации зависит от соотношения скоростей центрального процессора и ввода-вывода машины, размера основной памяти и методов сортировки. В пакете она обычно фиксц. руется. Обычной стратегией является двойная буферизация, при которой ка ж- дое устройство слияния имеет два буфера. Читатель опять отсылается к об¬ суждению буферизации в главе 12. Если используется идеология фиксированных буферов, то размер блока вычисляется легко. Возможно, что по каким-то причинам размер блока при- дется менять по сравнению с размером, вычисленным вначале. Например, если этап распределения не способен строить достаточно большие блоки, то ис¬ пользуется самый большой блок, который может быть сформирован сортиров¬ кой. По причинам, диктуемым системой, возможно, придется увеличивать или сокращать размер блока или предпочесть какие-то конкретные размеры. Для дисковых систем подходящим размером блока является размер одной или не¬ скольких дорожек. Удобный размер блока такого типа, представляемый си¬ стемой, часто является хорошей отправной точкой для расчета. 3. Степень слияния. Степень слияния для ленточных систем определяется числом доступных лентопротяжных устройств. Некоторые системы пытаются предвидеть поведение слияния небольшой степени. В дисковых системах степень слияния определяется идеологией и случаем. Если в системе применяется идеология слияния максимальной поточности, то степень слияния всегда равна числу строк. Однако, такого не встретишь в современных системах, которые пытаются уравновесить степень слияния, раз¬ биение на блоки и буферизацию. Степень слияния может вытекать и из дру¬ гих расчетов. Например, если размер системной дорожки — 3600 байт и есть 90 ООО ячеек основной памяти, то хорошим первым приближением степени слияния будет 24. Если есть два буфера вывода, то степень слияния сокра¬ тится до 23. В зависимости от стратегии буферизации степень слияния можно сокращать до тех пор, пока не будет найдена подходящая. Например, при двух буферах ввода, 3600-байтных блоках и 90 ООО ячейках памяти m ста¬ новится равным 11. 19.7. Создание универсальной сортировки и аппаратура При изложении время от времени мы обсуждали влияние особенностей машины на сортировку. Архитектура канала и центрального процессора, а также то, как они соединены, естественно, будет влиять на поведение про¬ граммы, реализующей метод сортировки или сортировки-слияния. Характер собственно машины влияет на реализацию универсальной сортировки не мень¬ ше, чем в случае специализированной сортировки. Следующие разделы служат введением к обсуждению влияния аппаратуры на сортировку с точки зрения разработчика системы.
19.7. СОЗДАНИЕ УНИВЕРСАЛЬНОЙ СОРТИРОВКИ 269 19.7.1. Линия обработки. В настоящее время для некоторых изготовите¬ лей вычислительных систем стало обычным делом предлагать покупателю се¬ мейство устройств, которому на диаграмме «цена-производительность» соот¬ ветствует бесчисленное множество точек. Эти семейства характеризуются сле¬ дующими различиями. 1. Возможны несколько центральных процессоров с разными скоростями (миллион операций в секунду), но практически с одинаковой архитектурой. Цель изготовителя — перенос программ с одного центрального процессора на другой по мере того, как пользователю будет необходимо увеличивать мощ¬ ность центрального процессора. 2. Память разного размера может быть соединена с разными централь¬ ными процессорами в линию обработки. Диапазон размера памяти может быть от 16К символов до 4000К символов. Разные центральные процессоры в этой линии будут иметь размер основной памяти разного диапазона. На¬ пример, Модель 1 с самым медленным центральным процессором может иметь от 16К до 64К; Модель 2 — от 32К до 256К; Модель 3 от 64К до 512К; Модель 4 от 256К до 2000К и т. д. 3. Памяти с разной организацией и интерфейсами могут быть соединены с разными центральными процессорами. Один интерфейс может передавать по олному символу из памяти в центральный процессор, другой — по четыре, третий — по восемь и т. д. Для выравнивания скоростей центрального процес¬ сора и памяти могут использоваться разные методы чередования или рас¬ пределения адресов по банкам памяти. 4. К разным центральным процессорам могут подсоединяться каналы раз¬ ных типов и разной скорости. Два широко известных класса каналов — муль¬ типлексный канал с разделением времени для медленных устройств и быстрый селекторный канал для быстрых устройств — ведут себя совершенно по-раз¬ ному. Многие изготовители поставляют каналы, имеющие разные скорости. Более того, любой центральный процессор допускает одновременное подклю¬ чение и работу нескольких каналов различных типов. Возможности этих ма¬ шин часто зависят от фактического состава устройств, имеющих разные ско¬ рости, в конкретной конфигурации. 5. В линии обработки могут использоваться разные способы сопряжения каналов и центральных процессоров. Степень независимости каналов и объем логики, общей с центральным процессором, могут меняться от модели к мо¬ дели центрального процессора и могут быть различными для разных каналов. В зависимости от интерфейса канала в подсистеме ввода-вывода могут быть представлены разные возможности программирования. Сцепление команд и Данных, разные формы процессов собирающей записи и чтения вразброс Могут быть представлены на различных уровнях системы. 6. К разным центральным процессорам разные устройства ввода-вывода Могут быть подключены в разных количествах. Крупные центральные процес- соры могут иметь высокоскоростные барабаны большого объема. Для малых Антральных процессоров эти барабаны могут быть и недоступны из-за очень большой скорости этих устройств. 7. В линии обработки на разных уровнях многие центральные процессоры а подсистемы ввода-вывода могут иметь специальные средства. Примерами
270 ГЛ. 19. УНИВЕРСАЛЬНЫЕ СИСТЕМЫ СОРТИРОВКИ таких средств в центральном процессоре являются расширенные наборы команд, специальное высокоскоростное выполнение некоторых команд, разная глубина просмотра команд вперед, быстрые буферы для команд и/или дан¬ ных. Примерами таких средств в подсистемах ввода-вывода являются спе¬ циальные контроллеры ввода-вывода такие, как контроллер каналов для IBM 360/67 или ЮС для UNIVAC 1108, которые частично освобождают центральный процессор от управления вводом-выводом. Объем совмещения операций ввода-вывода и вычислений может быть существенно увеличен за счет дополнительных устройств такого типа. 8. Набор устройств системы может быть обогащен за счет приспосабли¬ вания старых устройств и совместимости. Может быть несколько лентопро¬ тяжных устройств с различной плотностью записи и скоростью. Кроме этого возможно считывание лент, которые были записаны на лентопротяжных устройствах предыдущих поколений данного изготовителя с другой плотно¬ стью и, возможно, другими видами кодировки. С точки зрения изготовителя, может быть, следует предложить совместимые накопители на лентах для обработки лент, которые были записаны или должны считываться на нако¬ пителях другого изготовителя. Прежде чем приступать к кодированию сортировки, следует хорошенько подумать. Стратегии операционной системы могут до некоторой степени упро¬ стить работу разработчика, определяя группу машин, которые поддержива¬ ются базовой операционной системой, а также те машины, которые под¬ держиваются промежуточной и высокоуровневой операционной системами. Это облегчает работу разработчика тем, что ограничивает диапазон конфигураций машины, на которых пакет должен работать с приемлемой эффективностью. 19.7.2. Методы для линии обработки. Поскольку семейство известных ме¬ тодов сортировки надо некоторым разумным образом применить к разным конфигурациям системы, то создание сортировки требует некоторого изуче¬ ния систем, которое заключается примерно в следующем: 1. Определение тенденции критичности к работе центрального процессора на нижних уровнях. 2. Определение минимальной возможной конфигурации, которая должна поддерживаться сортировкой. 3. Определение существенности изменений скорости центрального процес¬ сора, размера основной памяти, и числа каналов для производительности сортировки. 4. Выявление новых устройств или интерфейсов, которые предполагают возможность использования нового метода или серьезной модификации ста¬ рей либо пересмотра ранее отвергнутого. Разработчики сортировки помимо изучения влияния на производитель¬ ность проектируемой аппаратуры должны думать о совокупности тех кон¬ фигураций, которые могут встретиться. Если большой процент пользователей имеет небольшую основную память, и у них нет возможности совмещать чтение-запись-вычисления, то выбор с заменой не может рассматриваться как метод для этапа распределения. Сортировку можно поддерживать лишь на некоторых конкретных устройствах или на некотором минимальном числе устройств, если меньших конфигураций не ожидается.
19.8. СОРТИРОВКИ И ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ 271 Для того, чтобы подобрать репертуар методов, применимых к данной линии обработки, необходимо тщательно изучить и использовать целый ряд весьма изощренных средств. Для того, чтобы определить, надо ли для от¬ дельных конфигураций или групп конфигураций предоставлять специальные методы, а также критерии выбора метода, можно моделировать поведение различных методов сортировки на разных моделях и конфигурациях с раз¬ ными файлами. Результатом исследования является выбор точек оптимиза¬ ции: размеры основной памяти, конфигурации каналов, а также те централь¬ ные процессоры, на которых сортировки разных конструкций наиболее 'эффек¬ тивны. 19.7.3. Подробности ввода-вывода. Для того чтобы найти найлучший под¬ ход к вводу-выводу, особенно для слияния, необходимо, тщательно изучить подсистему ввода-вывода. Методы распределения для слияния на диске чув¬ ствительны как к оптимизации времени поиска и времени задержки при вра¬ щении, так и к оптимизации просмотра данных, и, следовательно, при опре¬ делении производительности слияния способы ввода-вывода столь же важны, как и технология слияния. Определяющее значение при создании сортировки имеют новое устройство, новый канал, новая логика ввода-вывода. На ха¬ рактеристики разбиения на блоки влияют размеры дорожки и полосы*), воз¬ можность сцепления команд и данных влияет на способы распределения; вре¬ менные характеристики включения и отключения между каналом, устройством управления и внешним устройством будут влиять на конструкцию слияния и будут разными для разных моделей системы. 19.8. Сортировки и программное обеспечение На пакет сортировки влияет программное окружение той линии обработ¬ ки, для которой эта сортировка планируется. Ранее в разных разделах дан¬ ной главы обсуждалось влияние операционной системы, ее средств, вспомога¬ тельных программ и языков на структуру системы сортировки. В последую¬ щих разделах мы еще раз коснемся характера этих взаимосвязей и в особен¬ ности взаимосвязей между сортировкой и поддержкой ввода-вывода. 19.8.1. Сортировка и операционная система. Взаимосвязь между сорти¬ ровкой и операционной системой важна, поскольку она влияет как на про¬ изводительность, так и на конструкцию. Пришлось бы быть многословным, чтобы объяснить, почему сортировка, созданная под операционную систему, не будет столь же быстрой, как такая же сортировка, реализованная на «го¬ лей» машине, но бесспорно, что использование вспомогательных функций Операционной системы и отказ от некоторых элементов управления аппара- тУрой не увеличивает скорость сортировки. Обособленную сортировку было ^ь: трудно оправдать в атмосфере, которая сегодня царит среди разработчи¬ ков систем. Однако для малых машин это все-таки возможно. Для больших Машин часто важно, чтобы сортировка могла работать в мультипрограммном Режиме. *) Полоса — группа дорожек на запоминающих устройствах таких, как ®аРабан или диск. (Прим. перев.)
272 ГЛ. 19. УНИВЕРСАЛЬНЫЕ СИСТЕМЫ СОРТИРОВКИ Между сортировкой и операционной системой есть два основных типа специальных интерфейсов. Первый — между сортировкой и теми процедурами операционной системы, которые подготавливают окружение машины к выпол¬ нению сортировки, равно как и к выполнению любой другой программы. Дру. гой тип интерфейсов включает те оперативные услуги, которые операционная система предоставляет в виде обслуживающего совместно используемого ре¬ зидентного модуля. Конкретный набор услуг, предоставляемых операционной системой как в предварительной ее роли планировщика-распределителя внеш¬ них устройств-загрузчика, так и в другой ее роли — диспетчера-контроллера ввода-вывода — зависит от конструкции операционной системы. Ниже приве¬ ден примерный перечень услуг, которые будут выполнены прежде, чем начнет работу любой элемент сортировки. 1. Операционная система воспринимает язык управления заданиями, вы¬ зывает для исполнения сортировку и строит внутреннее представление. 2. Используя любые механизмы, зависящие от приоритета услуг или ис¬ пользования ресурсов и связанные с планированием, операционная система выбирает конкретную сортировку. 3. Операционная система распределяет ленты/диски/барабаны для сорти¬ ровки, формирует системные таблицы управления. Часто пользователь сорти¬ ровки может в определенной степени управлять распределением, и это управ¬ ление важно для производительности. В языке управления заданиями с раз¬ ной степенью детализации могут быть указаны количество и типы устройств. Пользователь может запросить 10 лент; он может запросить 10 лент конкрет¬ ной модели; он может запросить 10 лент и указать, какие ленты располага¬ ются на каких каналах; или он может запросить 10 лент с конкретными адресами. Если те ленты, какие он запросил, недоступны, то начало сортиров¬ ки может быть задержано. В некоторых случаях в зависимости от стратегии планирования и распределения, используемых операционной системой, они могут быть заранее захвачены сортировкой. В любом случае пользователь, заинтересованный в наилучшей работе сортирован, старается указывать кон¬ кретные устройства, а не полагаться на механизм распределения операцион¬ ной системы. Поскольку такие механизмы универсальны, то при определении оптимального распределения для сортировки они зачастую совершенно беспо¬ мощны. Эти замечания особенно важны для мультипрограммных сред. Одна¬ ко, следует заметить, что оптимизация, достигнутая одним пользователем, мо¬ жет отрицательно влиять на производительность других задач, работающих р мультипрограммном режиме. 4. Операционная система выделяет для сортировки пространство в опе¬ ративной памяти. Этого пространства может быть достаточно для работы всей сортировки-слияния, либо оно может составлять только часть, необходи¬ мую для работы первых элементов этапа назначения. В последнем случае сортировка запрашивает дополнительную память по мере необходимости. 5. Операционная система обеспечивает интерфейс с оператором и ис¬ пользует его при запросе сортировки на установку диска или ленты. 6. Прежде чем сортировка начнет работать, операционная система неко¬ торыми вспомогательными средствами должна оказать помощь в построении сортировки. Модули сортировки и модули пользователей могут соединяться
19.8. СОРТИРОВКИ И ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ 273 либо библиотечной управляющей системой, либо сводиться воедино во время ис.п°лнения* ^ЛЯ загРУзки и редактирования связей модулей в форму за¬ грузки и исполнения может использоваться системный загрузчик. Во время исполнения сортировки ей могут предоставляться следующие услуги* 1. Открытие и закрытие файлов. Стандартная услуга операционной си¬ стемы, которая обеспечивает проверку меток и инитерфейс . с операто¬ ром. 2. Загрузка дополнительных модулей для этапа или загрузка нового этапа. 3. Получение и/или освобождение пространства в оперативной памяти, на диске, барабане по мере требования от этапа к этапу или в течение одного этапа. 4. Обработка команд ввода-вывода и прерываний системой управле¬ ния. 5. Управление буферизацией и другие услуги «уровня разбиения на бло¬ ки», не включенные в п. 4. Уровень блоков при вводе-выводе обеспечивается программами ввода-вывода, которые предоставляют пользователю блоки в от¬ вет на команды READ. 6. Управление перемещением записей (разбиение на блоки и разблокиро¬ вание) не включенное в п. 5. Перемещение записей, обеспечивается командами GET/PUT. 7. Создание контрольной точки и перезапуск модулей. 8. Выдача счетчиков записей или других данных о развитии процесса сортировки на терминале оператора. Эти услуги периода исполнения обеспечиваются системными макрокоман¬ дами, доступными программе сортировки (равно как и любой другой про¬ грамме). Все интерфейсы периода исполнения и предварительной активизации предоставляются разработчику сортировки как часть уже существующей опе¬ рационной системы, с которой эта сортировка должна работать; либо они могут динамически подключаться в процессе совместного развития ОС и сор¬ тировки. Очевидно, на конструкцию языка управления сортировкой будут влиять средства языка управления заданиями системы. Разработчику сортировки сле¬ дует иметь весьма обстоятельное представление о языке управления задания¬ ми. Его должно интересовать, насколько пользователь может управлять рас- иределением. Его должно интересовать поведение и возможности системного эагрузчика, поскольку потенциально это рабочий компонент его сортировки. Поскольку сортировка является одним из самых важных прикладных пакетов, пРедоставляемых (или предлагаемых) вместе с системой, и так как скорость сортировки — это важный фактор, определяющий предпочтительность аппа¬ ратной части системы для пользователя, то группа разработки сортировки Д°лжна иметь возможность влиять на многие элементы системы, которые ьнешне кажутся не связанными с сортировкой. Используя подход «то, что хо¬ рошо для сортировки, хорошо и для системы», разработчику сортировки еле- ДУет настаивать на одобрении того, на что он рассчитывает.
274 ГЛ. 19. УНИВЕРСАЛЬНЫЕ СИСТЕМЫ СОРТИРОВКИ 19.8.2. Сортировка и поддержка ввода-вывода. Операционная система как правило, предлагает услуги ввода-вывода на трех уровнях. Первый уровень GET/PUT, на котором прикладная программа взаимодействует с опе¬ рационной системой для получения или вывода элемента данных. Он соответ- ствует тем шести услугам периода исполнения, которые перечислены в преды¬ дущем разделе. Есть уровень поддержки чтения-записи, на котором приклад, ная программа взаимодействует с операционной системой, чтобы считать блок из конкретного буфера или записать в него. Этот уровень поддержки отли¬ чается от уровня GET/PUT тем, что за перемещение элемента данных и за формирование блока на выходе отвечает прикладная программа. Самым ниж¬ ним уровнем поддержки ввода-вывода является управление устройствами. Прикладная программа берет на себя ответственность за все аспекты опе ра¬ ции ввода-вывода, кроме непосредственной связи с устройством. Она защи¬ щена от особенностей устройства, его эксцентричности и от прерываний си¬ стемы, но в других отношениях она управляет вводом-выводом. В системе IBM OS/360—370 этот уровень примерно соответствует уровню ЕХСР. (Па очень ь1алых машинах программисту могут разрешить непосредственную связь с устройствами ввода-вывода, но такие машины обычно не имеют универсаль¬ ных систем сортировки.) Одним из очень важных конструкторских решений, которое необходимо rir-инять для пакета сортировки, является решение об уровне взаимодействия с поддержкой ввода-вывода системы. Обычное решение — взаимодействовать по возможности на самом низком уровне и сохранять, насколько это возмож¬ но, управление со стороны сортировки всеми операциями ввода-вывода, за исключением, возможно, считывания управляющих карт и выдачи системных сообщений. Недостатком является дополнительная работа по реализации и проверке программ ввода-вывода, усложняемая зависимостью от особенностей устройств и необходимостью модифицировать сортировку, чтобы обеспечить программы для устройств, которые появились позднее. Поскольку отказ ог услуг, любезно предоставляемых программам пользователей, в принципе не дает преимуществ, то отказываться от них следует лишь при необходимости. На ранних этапах многих проектов сортировки встречаются причудливые на¬ мерения использовать системный ввод-вывод с условием выхода того или иного типа, как, например, «до тех пор, пока потери производительности не превысят х процентов». Фундаментальные трудности при использовании высокоуровневой под¬ держки ввода-вывода состоят в том, что программы такой поддержки всегда медленнее собственного ввода-вывода, и при этом могут быть исключены по¬ лезные возможности. Медлительность и исключение суть следствия характера универсальной поддержки. Функции, которые поддерживает пакет ввода-вы¬ вода, редко представляют все возможности современного канала. Попытка полностью предоставить возможности аппаратуры обычно включает значи¬ тельные затраты. Разработчик сортировки, используя пакет ввода-вывода целиком, может снизить производительность сортировки тем, что он не сможет выполнять некоторые функции, какие ему следует выполнять в интересах эффективности*
19.8. СОРТИРОВКИ И ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ 275 ^апример, независимые просмотры вперед могут не поддерживаться IOCS *), они могут быть решающими для производительности сортировки. Есть ряд совершенно очевидных соображений, определяющих, следует ли использовать поддержку высокого уровня. Если поддержка ввода-вывода для системы создается во время создания сортировки, то некоторые из этих со¬ ображений могут обсуждаться, но никакое обсуждение не разрешит все спорные вопросы, и сортировка будет нести определенные потери. Эти сооб¬ ражения можно свести к следующим вопросам и комментариям. 1. Есть ли у устройства какая-нибудь функция, необходимая сортировке, и которая совсем не поддерживается IOCS? 2. Есть ли потери оперативной памяти из-за дополнительных уровней буферизации, которые могут понизить производительность, оставляя меньше памяти для больших т или больших блоков? 3. Есть ли какие-нибудь потери из-за кодировки подпрограмм поддержки ввода-вывода? Например, поддержка ввода-вывода может выполнять боль¬ шое число команд для того, чтобы определить, что полученная команда сфор¬ мирована правильно. Сортировка могла бы выполнять функцию ввода-вывода без таких проверок, так как раз она оттестирована я отлажена, то ее формы чтения-записи известны. Аналогично, может быть необходимо выявить неко¬ торые подфункции в универсальном пакете поддержки на идентификацию ко¬ торых подпрограмме ввода-вывода сортировки не надо тратить время, потому что они не могут встретиться. 19.8.3. Сортировка и мультипрограммирование. Возможно, что очень на¬ блюдательный пользователь с глубоким знанием аппаратуры, сортировки и операционной системы сможет организовать работу сортировки в мульти¬ программной среде так, что она будет занимать столько же времени, как если бы она работала одна. Требования для выполнения этого небольшого чуда состоят в том, чтобы оперативная память, устройства, пространство на устройствах, используемые другими программами, могли выгодно исполь¬ зоваться сортировкой, а также в том, чтобы не было задержек в работе сортировки из-за наличия других программ. Такие задержки возникают: из-за перемещения штанги по запросу других программ, что приводит к дополни¬ тельному времени поиска; из-за недоступности каналов, устройств управления или устройств, используемых в данное время другими программами; из-за пре¬ рываний сортировки операционной системой при обслуживании ввода-вывода "о запросам, ранее выданным другими программами. Эти задержки могут воз¬ никать даже тогда, когда сортировка имеет максимально возможный приори- Тет по отношению к другим программам. Их острота зависит как от уровня к°нфли1Ктности из-за расурсов, так и от громоздкости механизмов операцион¬ ной системы, которые обеспечивают возможность мультипрограммирования. Уязвимым местом для последующих задержек является как раз та сте- Пень, в которой сортировка должна разделять каналы и штанги с другими ^^граммами. Если сортировка работает с более низким или таким же при- °Ритетом, как и другие программы, которые работают вместе с ней, то эти *) IOCS (Input-Output Control System)—система управления вводом-вы- °Аом- (Прим. перев.)
276 ГЛ. 19. УНИВЕРСАЛЬНЫЕ СИСТЕМЫ СОРТИРОВКИ задержки станут более существенными. В течение работы любой про--рMbl возможны периоды, когда центральный процессор ожидает завершения Н1>0 да-вывода и не может продолжать вычислений, а также периоды, когда ввод вывод приостанавливается до тех пор, пока центральный процессор не сч1;0р. мирует задание па чтение или запись. Высокоприоритетная программа буд0т терять контроль над центральным процессором или подсистемой ввода-вь:во1а лишь на те периоды времени, когда она не может использовать их. Програ^. ма с более низким приоритетом будет испытывать задержки при обращении к центральному процессору из-за того, что программа с более высоким при. оритетом не будет освобождать его. Таким образом, задержки при мулы и. программном режиме распадаются на две категории. 1. Задержки вследствие потери ресурсов или разделения ресурсов, которые увеличивают время обработки и время ожидания выполнения ввода-вывода. 2. Задержки из-за приостановки, когда центральный процессор обслужи, вает высокоприоритетную программу. Если программа должна оставаться критичной по записи, то чувствитель¬ ность производительности к обоим типам задержек очевидна. Пользователь может до некоторой степени контролировать задержки, возникающие вслед¬ ствие конфликтов, выбирая программы из резидентной части на основе мини¬ мальности конфликтов и управляя назначением оперативной памяти и устройств так, чтобы свести к минимуму влияние на сортировку. Возможно, что окончание сортировки не является решающим. В этом случае она может работать как «фоновое» задание вместе с другими, опера¬ тивными задачами. Результатом будет усиление использования устройства по мере того, как сортировка будет «насыщаться» циклами канала. Мультипро¬ граммная среда идеальна для тех сортировок, для которых время окончания не существенно. Между этими двумя крайностями — крайней необходимостью избежать всяких задержек и полным безразличием ко времени окончания — распола¬ гается множество допусков для задержек и большое число случаев, в кото¬ рых мультипрограммные задержки приемлемы. Разработчики сортировки и операционной системы обязаны предоставить пользователю разумный выбор возможностей и механизмы для их реализации. 19.8.4. Сортировка и языки программирования. Языки программирования, доступные в операционной системе, связаны с сортировкой рядом обстоя¬ тельств. 1. Этот язык может быть тем, на чем написана сама сортировка. 2. Этот язык может быть тем языком, на котором в системе поддержи¬ вается библиотека сортировки. 3. Этот язык может обеспечивать механизмы для вызова и/или для пере* дачи параметров сортировке. 4. Этот язык может обеспечивать функции «собственного кода» в РаМ* ках структуры пакета сортировки. 5. Язык может иметь средства сортировки, которые будут поддерживать* сч пакетом сортировки. Языки системы могут включать язык ассемблера и ряд языков высокого уровня таких как PL/1, кобол, фортран, алгол, APL, лисп и т. д. Из эти*
19.8. СОРТИРОВКИ И ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ 277 ов У кобола и PL/1 связи с системой сортировки определены на уровне зыка, и таким образом, эти языки представляют для нас особый интерес. 19.8.4.1. Язык сортировки. Необходимо определить, какой язык бу- использоваться для написания сортировки. Разумным выбором был бы язык ассемблера, потому что он дает программисту максимальный контроль над качеством кода. Использование языка ассемблера также помогает при не¬ обходимости генерировать некоторые элементы пакета. На языках высокого уровня работа с частями слова или битами часто либо невозможна либо крайне неуклюжа как при описании, так и при генерации кода. По мнению автора, качество кода и выразительные возможности делают язык ассемблера привлекательным средством при создании сортировки. В последние годы много обсуждаются и даже были созданы некоторые системы программирования на языках высокого уровня, которые имеют необ¬ ходимую выразительную мощь и генерируют адекватный код. Если там, где создается сортировка, такой язык есть, то его безусловно следует опробовать, но при проверке тяжелым бременем будет сам язык. Поскольку сортировка является универсальным приложением, очень сильно ориентированным на про¬ изводительность, то при одобрении надо быть крайне осторожным, даже если многие другие приложения были уже успешно перенесены в языки, ко¬ торые являются менее машинно-ориентированными. 19.8.4.2. Язык библиотеки сортировки. Если в системе есть семейство языковых процессоров, то библиотека сортировки может поддержи¬ ваться на любом языке этого семейства. Формирование библиотеки и даже функции генерации могут выполняться, например, процессорами библиотеки кобола или средствами генерации периода компиляции языка PL/1. На практике, как правило, библиотека сортировки представлена на уровне языка ассемблера или на некотором субъязыковом уровне системы. Субъязы- ковый уровень — это некоторое представление процедуры, которое не может быть описано или обычно не описывается программистом. В настоящее время программист не пишет процедуры в виде мащинных, загружаемых, перемеща¬ емых модулей, а такое представление было бы субъязыковой формой. На самом деле, одной сортировке может быть сопоставлено несколько библиотек сортировки. Когда же есть процедура генерации системы, при помощи которой пользователь определяет систему и сортировку как подмно¬ жество всех возможностей операционной системы, то возможна одна общая библиотека сортировки на языке ассемблера. Генерация системы — «генери¬ рование генератора» — собирает все модули, которые должны быть включены р‘ систему и компонует их на субъязыковом уровне, который является пред¬ ъявлением генератора сортировки пользователя. Генераторы систем есть в °Чень больших и универсальных системах, таких как OS/360. Построение ге- НеРатора должно быть редко используемой функцией. Представление рабочей библиотеки сортировки обязательно накладывает 0граничение на процесс генерации сортировки. Если библиотека представлена На языке ассемблера, то код пользователя может быть добавлен на этом язы- » а вся сортировка, включающая элементы библиотеки сортировки и «соб- ^пенный код», может порождаться единым процессом сборки. Если библио- Ка хранится на субъязыковом уровне, то код пользователя должен.
278 ГЛ. 19. УНИВЕРСАЛЬНЫЕ СИСТЕМЫ СОРТИРОВКИ отдельно либо ассемблироваться, либо компилироваться, и для того, чгобц породить всю сортировку, нужен редактор связей либо загрузчик. 19.8.4.3. Язык «собственного кода». Любой язык является по, тенциальным источником модулей «собственного кода». Эта возможность це зависит от какого-либо интерфейса между пакетом сортировки и компилято, ром. Интерфейс между коболом и языком пакета сортировки или между р\ц и языком сортировки есть средство, никак не связанное с возможностью на¬ писания кода на этом языке, компиляцией этого кода и последующей перс- дачей скомпилированного кода как «собственного кода». Чтобы осуществить такую возможность, операционная система должна позволять организовывать программы, написанные на разных языках, в одну большую рабочую ппо- грамму. Эта организация достигается при помощи единых соглашений о свя¬ зях и соглашений об именовании, библиотек и функций редактирующего загрузчика. Возможность, позволяющая приспосабливать «собственный код» на произвольном языке к выходам сортировки, не совпадает со следующей темой обсуждения — возможности вызова пакета сортировки из программы на коболе или PL/1. 19.8.4.4. Кобол и сортировка. Кобол имеет средства для обраще¬ ния к сортировке [17]. Хотя полное изложение этого средства языка лучше всего посмотреть в описании языка кобол, этот раздел может служить вве¬ дением в интерфейс и некоторые вопросы, связанные с ним. Разумно потре¬ бовать, чтобы пакет сортировки поддерживал глагол кобола SORT так, что¬ бы сортировка кобола не обязательно создавалась отдельно. Интерфейс ко¬ бол/сортировка, определяемый языком, делает функцию сортировки внутрен¬ ней подпрограммой программы на коболе. Нет никаких ограничений на то, что может делать программа на коболе до передачи записей сортировке и после получения записей от сортировки. Для последовательной передачи за¬ писей в файл сортировки язык предоставляет процедуру ввода, которая вводит запись в сортировку. Процедура ввода является процедурой кобола, указанной в глаголе SORT. В описании языка нет ограничений на то, что может делать процедура ввода до получения записи. Однако, конкретная реализация сортировки может ограничивать то, что она может делать. Пакет сортировки не накладывает каких-либо ограничений на процедуру ввода, но так как он организуется по фиксированным функциональным выходам, то такие ограничения могут потребоваться В коболе процедура ввода часто ис¬ пользуется как заданный выход этапа сортировки. Функции, которые не могут выполняться этим выходом, не могут выполняться и процедур011 ввода. Процедура ввода взаимодействует с этапом сортировки. Глагол RE¬ LEASE *) устанавливает указатель на запись, после чего сортировка прини¬ мает запись и возвращается к процедуре ввода кобола. Когда управление передается от процедуры ввода, сортировка берет его на себя и работает Д° пгследнего просмотра. На последнем просмотре записи передаются процеДУРе вывода, написанной на коболе, которая связана с выходом последнего пр0' смотра. *) RELEASE — передать. (Прим. перев.)
19.8. СОРТИРОВКИ И ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ 279 Характер конкретного алгоритма сортировки, естественно, будет влиять на интерфейс кобол/сортировка. Выбор с заменой является идеальным мето¬ дом Для получения за один раз одной записи и выбора победителя. Каж¬ дый Раз передается одна запись, запускается турнир, выбирается победитель, а новая запись используется, как замена. Фактически с таким интерфейсом дюбая сортировка выбором или вставкой будет работать хорошо. Сортировка Hcj основе обмена (например, быстрая сортировка), которой для обработки нужен набор записей, будет работать хуже, так как рабочую область для предаваемых записей надо выбирать прежде, чем начнет работать алгоритм сортировки. Некоторые параметры задаются в разделе данных, который описывает сортируемые записи, и в описании задания, связанном с данной программой на коболе. Фактически глагол кобола SORT задает имена процедур ввода и вывода и определяет управляющие поля. Он определяет, какая последовательность должна быть сопоставлена управляющему полю — возрастающая или убы¬ вающая. Компилятор с кобола знает файлы, относящиеся к сортировке, и будет строить таблицы параметров согласно требованиям интерфейса сортировки и модуля подготовки сортировки. Глагол SORT может устанавливать связь с интерфейсным модулем кобола из библиотеки сортировки или системы, кото¬ рый затем будет использоваться для размещения процедур ввода и вывода в надлежащих позициях выхода. При ином подходе необходим интерфейс с операционной системой. Глагол RELEASE будет передавать записи интер¬ фейсному модулю сортировки, который лишь строит файл сортировки на не¬ котором устройстве. Сортировка не начнется до тех пор, пока процедура ввода не выдаст сообщение об окончании последовательной передачи записей. Затем операционная система запрашивается для запуска сортировки. Файл сортировки сортируется так, как будто он был вызван обычным, поддержи¬ ваемым операционной системой способом, как подзадача. На первый взгляд это непривлекательный подход, поскольку он требует дополнительного про¬ смотра данных. Однако возможно, что сортировке будет выделено значи¬ тельно больше памяти, будут сэкономлены просмотры слияния, и, следо- аательно, сортировка-слияние будет работать быстрее без процедуры ввода. 19.8.4.5. PL/1 и сортировка. PL/1 может вызывать функцию сорти- Р°вки, но когда писалась эта книга, эта возможность не была общей и оди- иаковой для всех версий PL/1. Она существенно зависит от системы, исполь- 3>я специальные имена модулей сортировки и имена выходов, сопоставлен¬ ие конкретному пакету сортировки. Компилятор строит таблицу параметров и* параметров, записанных в виде строк символов и соединенных со стан¬ дартным обращением к именованному модулю пакета сортировки. В интер¬ фейсе OS/360—PL/1 обращение может включать, а может и не включать Днрование на PL/1 выхода сортировки, назначенного OS/360 в зависимости того, существуют ли уже сортируемые записи в наборе данных или же они жны быть построены или изменены программой на PL/1, которая обрати¬ сь к сортировке.
280 ГЛ. 19. УНИВЕРСАЛЬНЫЕ СИСТЕМЫ СОРТИРОВКИ 19.9. Время сортировки Как разработчику, так и пользователю крайне необходима возможность оценки времени работы отдельной сортировки. Разработчику необходимо знать, насколько удачной будет его новая система сортировки. Пользователю эта информация необходима для планирования использования машины. Также он часто хочет знать, как сравнить производительность конкурирующих сор. тировок. К каждому серийно поставляемому пакету сортировки прилагается руко¬ водство с таблицами времен для разных применений данного пакета, либо набор формул для вычисления этих времен, либо и то, и другое вместе [5, 15 22]. Таблицы времен, публикуемые разработчиком сортировки, можно постро¬ ить при помощи программы, которая использует некоторый набор формул, а не отслеживает работу сортировки во время ее прогонов. Все временные ха¬ рактеристики сортировки, естественно, являются приблизительными. Качество оценки зависит от изощренности формул временных характеристик и объема учитываемых подробностей. Даже самая лучшая формула статической оценки временных характеристик является источником серьезной ошибки. Вследствие изменений в упорядоченности данных будут возникать и значительные изме¬ нения производительности. Кроме этого предельные изменения в производи¬ тельности аппаратуры в рамках, допускаемых аппаратурой, могут накапли¬ ваться, искажать поведение сортировки на отдельном канале или отдельных лентах в определенное время. Предельные патологии, такие, как необычно высокая скорость записи на ленту с распознаванием ошибок (которая по бу¬ дет вызывать перехода к контрольной точке, но которая будет увеличивать время записи) также будет искажать поведение сортировки. Общее выражение для времени сортировки задается в виде: время сортировки = время подготовки + время распределения + + время слияния + время последнего просмотра. Для того, чтобы количественно оценить это отношение, надо описать эле¬ менты, образующие каждый этап, и установить соответствие между временем и конкретной функцией. В общем случае у программы есть три временные компоненты: время ввода, время вывода и время обработки. В зависимости от характеристик совмещения работы аппаратуры системы, на которой рабо¬ тает сортировка, общее время одного этапа будет равно: 1) SUM (время обработки, время ввода, время вывода), когда нет со¬ вмещения; 2) МАХ (время обработки, время ввода, время вывода), когда есть пол¬ ное совмещение чтения/записи/вычислений; 3) МАХ (время ввода + время вывода, время обработки), когда есть воз¬ можность совмещать чтение с записью или вычислениями; 4) МАХ (время ввода + время обработки, время вывода + время обра‘ ботки), когда есть возможность совмещения чтение/вычисления или запись/ вычисления. Создание хорошей временной формулы требует больших усилий. Оп° включает вычисление ряда констант, представляющих времена для отдельны*
19.9. ВРЕМЯ СОРТИРОВКИ 281 киий и использование различных взаимосвязей между функциями компо йент сортировки. Остальная работа состоит в том, чтобы найти наилучший п*одХОд к построению формулы и выражению взаимосвязей. Материал этого й последующих разделов предназначен для того, чтобы проиллюстрировать построение временных формул сортировки и ввести необходимые рассуждения для их построения. Читателю ни в коем случае не следует делать вывод О том, что взаимосвязи, построенные здесь, являются наилучшими из воз¬ можных. 19.9.1. Время этапа распределения. Время этапа распределения зависит от следующих факторов. 1. Длина записи; 2. Размер блока при вводе; 3. Размер блока при выводе; 4. Характеристики устройства ввода; 5. Характеристики устройства (устройств) вывода; 6. Размер памяти; 7. Размер управляющего поля; 8. Способ буферизации; 9. Число устройств вывода; 10. Пространство памяти для «собственного кода»; И. Время выполнения «собственного кода»; 12. Метод сортировки; 13. Скорость памяти и центрального процессора; 14. Число записей; 15. Исходная упорядоченность записей в файле. Процедура определения времени сортировки может быть в той или иной степени параметризована. Программа, реализующая эту процедуру, может требовать параметры, представляющие все факторы, перечисленные выше, или только их часть. Константы или выражения, описывающие характеристики ап¬ паратуры, могут передаваться программе определения времени или задаваться внутри нее, передавая в виде параметров лишь имена устройств. Разработ¬ чику следует основывать свое решение о количестве информации, передавае¬ мой программе определения времени сортировки, на предполагаемом исполь¬ зовании этой программы. Если она должна использоваться для определения времени известной сортировки в устойчивом окружении устройств, то парамет¬ ризация может быть сведена к минимуму. Если понадобится оценить время сортировки с новым устройством или для того, чтобы ввести новые методы сравнения, то параметризацию, естественно, придется расширить. Разумный вход программы оценки времени сортировки для развитого и Распространяемого пакета сортировки включает следующие элементы: 1) Длина записи; 2) Размер блока при вводе; 3) Имена устройств; 4) Размер памяти; 3) Размер управляющего поля; 6) Число устройств вывода; 7) Число записей.
282 ГЛ. 19. УНИВЕРСАЛЬНЫЕ СИСТЕМЫ СОРТИРОВКИ Этот список дает приемлемое приближение того, что может быть пред0. ставлено в качестве параметров сортировки. Программа оценки времени сортировки сама содержит детали поведения устройств и используемого ме¬ тода, при этом она вычисляет размер блока вывода, размер области сорти¬ ровки- и т. д. так же, как сортировка. 19.9.2. Время этапа слияния. Процесс хронометрирования слияния анало¬ гичен процессу определения времени этапа распределения. Вычисляется время затраченное каждым этапом слияния, это время умножается на число этапов слияния, полученное произведение и есть время слияния. Оценки ввода и вывода строятся точно так же, как оценки этапа рас¬ пределения. Время работы процессора вычисляется аналогично, с той лишь разницей, что используются модули слияния, а не модули сортировки. Необ¬ ходимо учитывать время перемотки и изменения направления движения, а также «стоимость» «собственного кода» и вычисляемых контрольных точек. Сегодняшний пользователь больше расположен видеть таблицы, чем фор¬ мулы, однако, ему следует иметь представление о том, как определить время работы сортировки. Возможность хронометрирования, безусловно, является существенной для разработчика сортировки. 19.10. Моделирование сортировки Программные системы для моделирования сортировок стали стандартным инструментом в лабораториях для проверки новой аппаратуры, равно как и для проверки новых идей сортировки. Полезность инструмента частично опре¬ деляется простотой или сложностью описания нового устройства или новых методов сортировки. Преимущество моделирования перед статическим хро¬ нометрированием заключается в том, что не нужны никакие допущения, пред¬ положения и усреднения. Каждое событие может быть хронометрировано, можно узнать время его начала и окончания, а время каждого события вво¬ да-вывода можно измерить непосредственно. Временные оценки, полученные путем моделирования, могут быть очень близки к фактическому времени вы¬ полнения. Моделирование обладает еще одним важным свойством — возмож¬ ностью введения псевдофайлов с различным упорядочением для того, чтобы проследить влияние разных упорядочений на алгоритм сортировки. Разумным подходом к моделированию является прогон внутренней сорти¬ ровки с хронометрированием и моделирование событий ввода-вывода. Моде¬ лирование события ввода-вывода включает определение времени активизации процесса и вычисление времени ввода-вывода по заданному адресу, размеру блока, характеристикам устройств и т. д. Можно четко увидеть результаты буферизации и динамического взаимодействия ввода-вывода и центрального процессора. Можно выявить задержки и оценить стратегию буферизации. Параметры моделирующей программы по существу те же, что у про¬ граммы статического хронометрирования. Поскольку моделирующая програм¬ ма как правило используется разработчиками, а не пользователями, то можно предположить большую осведомленность ее пользователей. По этой причине и в силу гибкости — одного из основных требований — параметризация может
20.1. ПЕРЕМЕЩЕНИЕ ПРОГРАММ И ВИРТУАЛЬНАЯ ПАМЯТЬ 283 достаточно обширной. Способ слияния, степень слияния, разбиение на \) ф О / . О б10Ки, буферизация, метод внутренней сортировки, тип(ы) устройств, модель цеНТрального процессора и операционная система, — все это обычные пара¬ метр ьь Важно, чтобы характеристики аппаратуры системы были бы представле- НЬ1 так, что описание новых устройств не требовало значительных усилий. Вели моделирующая система не имеет регулярного и удобного механизма для расширения своих возможностей, то она не позволит в случае необходимости увидеть влияние нового файла на диске, нового алгоритма слияния или ко- Бого канала. Глава 20. СПЕЦИАЛЬНЫЕ СИСТЕМНЫЕ ФАКТОРЫ 20.1. Перемещение программ и виртуальная память Идея перемещения программ основана на различии между именами, ис¬ пользуемыми в программе при обращении к объектам, и машинными адреса¬ ми этих объектов. Ассемблеры и компиляторы создают «перемещаемый» код, который не может быть выполнен до тех пор, пока он не будет обработан загрузчиком, который построит фактические машинные адреса. Будучи загру¬ женной, перемещаемая программа работает подобно любой другой программе. При другом подходе фактические адреса могут строиться динамически при помощи аппаратуры отображения. Поскольку современная технология ди¬ намического перемещения имеет непосредственное и существенное влияние на сортировку, то любая книга, посвященная сортировке, должна включать определенное обсуждение перемещения программ. Прежде всего мы должны представить некоторые элементарные принципы перемещения. 20.1.1. Листание. На рис. 20.1 показана программа из 13 000 слов, рас¬ пределенная в памяти так, что первая тысяча -слов программы располагается в ячейках памяти 1000—1999, следующая тысяча — в ячейках 8000—8999. Оставшаяся часть программы распределена в памяти по 1000 слов. Выбор места в памяти для каждой порции из 1000 слов произволен и определяется лишь имеющимся пространством. Порции из 1000 слов обычно называются листами, а устройство, размещающееся между программой и памятью, назы¬ вается листающим устройством или устройством перемещения программ. Оперативная память представляется в виде набора листов фи'ксирован- Ного размера, а распределение памяти происходит листами. В современных системах поиск свободного листа в памяти и загрузка листов программы в Физические листы памяти в основном возлагается на программное обеспече- Ние- Когда лист найден и сделаны назначения, аппаратура обеспечивает тРансляцию адресов. В системах с листовой организацией памяти адресная часть командного CJ1°Ba состоит из поля листа и поля смещения в листе. Если размер листа Р?*вен 1024, то максимальное смещение или относительный адрес в листе ра- Ь1 1023. Поскольку представление величины 1023 занимает 10 разрядов, то аДресе под поле смещения в листе требуется 10 разрядов. Остальные
284 ГЛ. 20. СПЕЦИАЛЬНЫЕ СИСТЕМНЫЕ ФАКТОРЫ разряды адреса образуют ссылку на лист. Система с 16-разрядным адрсс0м может иметь 64 листа по 1024 слов в каждом. Часть адреса, ссылающаяся на лист, передается на вход устройства ли* стания. Выход этого механизма — место в памяти нулевого слова данного листа. Аппаратная ассоциативная память предоставляет быстрый способ пре, образования номера листа в физический адрес памяти [6]. Функцию листания Программа 0 1 2 3 4 5 6 7 8 9 10 ГГ 12 13 Листающее устройство Листы Программные слова -7—► 12.000 - 12.999 о ^ 0.000 - 0.999 — 3 ► 5Л00 - 5.999 - 4 —э*- 5.000 - 5,999 - 5 —► 7.000 - 7.999 - 6 —*- 9,000 — 9.Ш 7 8 - 9 ► 1.000 - 1.999 10 11 12 13 15 15 16 17 ■18 2,005 2,999 19 20 *- 8.000— 8.999 21 22 -23 ^ 10,000—10,999 25 -25 ^ 11.000-11.999 26 27 28 29 -30—** 6,000 - 6,999 31 -32 Н 3,000 - 3,999 Фактические адреса О памяти ОООО - 1000 - 2000 - 3000. - 9000 ~ 5000 - 6000 - 7000 - * 8000 - 9000 - 10000 - 11000 - 12000 - 13000 - 10000 - 15000 - 16000 - * 17000 - 18000 - * 19000 - 20000 - 21000 - * 22000 - 23000 - * 20000 — 25000 - 26000 - 27000 — 28000 - * 29000 - 30000 - * 31000 - 0999 1999 2999 3999 9999 5999 6999 7999 8999 9999 10999 11999 12999 13999 15999 15999 16999 17999 18999 19999 20999 21999 22999 23999 29999 25999 26999 27999 28999 29959 30999 31999 примечание *Показывает Ьрисутствие листов программы в памяти Рис. 20.1. Распределение памяти листами. можно проследить на примере десятичного адреса 11643, используя его каК вход для ассоциативной памяти, показанной на рис. 20.2. Ссылка на лист —' 11 — является поисковым признаком, который используется при поиске иа совпадение среди полей признаков ассоциативной памяти. Содержимое сов¬ павшего входа указывает на физический лист памяти 24. Первое слово ли ста 11 программы находится в ячейке памяти 24 ООО. Этот выход используете* как дополнение к относительному адресу листа 643. Истинный исполнитель ный адрес равен 24643. Модификация адреса при помощи индексного РеГЙ
20.1. ПЕРЕМЕЩЕНИЕ ПРОГРАММ И ВИРТУАЛЬНАЯ ПАМЯТЬ 285 оа если таковая имеет место, выполняется проще. Принципиальное преиму¬ щество механизма листания заключается в скорости, с которой выполняется отображение. Он также сигнализирует об отсутствии разыскиваемого листа. Основное внимание разработчиков системы занимают условия возникновения «ошибок», необходимые действия при этом и влияние на производительность. Ассоциативная память дорогая; существенная экономия может быть до¬ стигнута такими механизмами листания, которые сократят размер ассоциа¬ тивной памяти или расширят входы в память. Эти подходы осуществлены в Признак Вывод 00 01 01 06 02 17 • 03 31 04 02 05 03 06 27 07 40 08 14 09 05 10 22 s 11 V о л 12 00 11 643 исходный адрес т— 24000 Начало листа > +643 объем листа 24643 конечный адрес Рис. 20.2. Листание ассоциативной памяти. нескольких машинах. Две очень простых, но элегантных схемы представлены в ATLAS фирмы Ferranti и в IBM 360/67. Ассоциативная память машины atlas содержит только номера листов. Физическое место в памяти опреде¬ ляется входом, на котором достигнуто совпадение. Система 360/67 содержит только восемь входов. Листы и физические адреса текущих восьми листов, которые использовались самыми последними, записываются в ассоциативную Память. Когда происходит обращение к листу, которого нет в ассоциативной Памяти, то для трансляции используется таблица из оперативной памяти. Эта таблица «листания*), расположенная в оперативной памяти, содержит адре- Са листов в физической памяти. Поле листа адреса программы используется в качестве индекса этой таблицы. Например, 01 использует содержимое вто- Рог° элемента таблицы листов в качестве физического базового адреса памя- Ти> И использует двенадцатый и т. д. Когда происходит обращение к листу, к°торого нет в ассоциативной памяти, то для него формируется вход в ассо- ат»вной памяти, и последующие обращения используют этот вход. Ассо- тивная память проверяется при каждом обращении к листу. Если надле¬ *) Также называемая «таблицей приписки». (Прим. перев.)
2в6 ГЛ. 20. СПЕЦИАЛЬНЫЕ СИСТЕМНЫЕ ФАКТОРЫ жащий вход в ней отсутствует, используется алгоритм с применением таб лицы листов. 20.1.2. Запрос листа. Механизм листания повышает эффективность ис пользования основной памяти, предохраняя ее от разделения на фрагменты бесполезной величины. В любой конкретный момент времени в основной па- мяти может находиться лишь подмножество листов программы. Остальные листы располагаются на внешнем запоминающем устройстве — диске или ба¬ рабане. При ссылке на лист, отсутствующий в основной памяти, вырабаты¬ вается сигнал отсутствия листа и предпринимаются действия для его ввода Эта процедура, называемая запросом листа, предназначена для поддержки программ, превышающих имеющийся объем основной памяти. Особенно она полезна в системах мультипрограммирования и разделения времени. Запрос листа — это способ динамического распределения памяти, позволяющий вво¬ дить листы в основную память лишь по мере обращения к ним. В каждый конкретный момент времени программист (или пользователь за терминалом) не имеет ни малейшего представления о том, какая часть их программы фак¬ тически находится в памяти или где она находится. С идеей запроса листа естественно связан целый ряд вопросов произво¬ дительности. Программа объемом в 64К на машине с 32К может работать намного медленнее, чем на машине с 64К. Здесь возможны задержки, если не¬ резидентные листы вводятся только тогда, когда к ним обращаются. Степень задержки зависит от скорости операции листания и от числа таких операций. Число запросов листа в программе зависит от нескольких отдельных фак¬ торов, каждый из которых влияет на качество динамического отображения требуемых листов и имеющихся листов. Ниже перечислены факторы, влияю¬ щие на загрузку листа при запросе листа системой. 1. Локальность программы. Запрос листа как рабочий метод зависит от понятия локальности. Ссылки программы в течение коротких промежутков времени обычно группируются: команды выбираются из последовательных ячеек; программа может ссылаться на данные, расположенные в одной и тон же области массива или в отдельной записи с соприкасающимися полями. Разные программы будут проявлять разные формы локальности. Некоторые программы будут медленно переходить от «окрестности» к «окрестности»; другие будут быстро переключаться с одного места на другое; вместе с тем есть программы, которые имеют столь малую локальность, что их формы ссы¬ лок непредсказуемы. В программе с малой локальностью обращения к любому адресу почти равновероятны. В таких программах невозможно выделить пред¬ почтительный набор резидентных листов—листов «в окрестности». Программа, как правило, делает ссылки в пределах одной окрестности, и в любой момент времени требуется присутствие в памяти немногих листов. У каждой програм* мы свое «подсобное хозяйство» — количество листов, необходимых в памяти для того, чтобы избежать неприемлемых задержек из-за перезагрузки листов. Сравним формы адресации при сортировках линейным выбором и двоич- ной вставкой. Линейный выбор перемещает элементы в список один за ДрУ* гим, последовательно изменяя локальность обращений. Древовидная стрУ11' тура двоичной вставки образует разбросанную форму адресации с переход0*1 от средней точки к точке квартили и к конечной точке по ходу проверки.
20.1. ПЕРЕМЕЩЕНИЕ ПРОГРАММ И ВИРТУАЛЬНАЯ ПАМЯТЬ 287 2. Размер листа. Размер системного листа влияет на количество запросов обмен листа, увеличивая или уменьшая вероятность того, что очередная ссылка не будет в том же листе, что и последняя предыдущая ссылка. При небольших листах часть программы, представляемая отдельным листом, будет небольшой, и программа может переходить от листа к листу очень быстро. Если объем физической памяти ограничен, то переход от одного листа к дру¬ гому будет увеличивать необходимость запроса листа, поскольку новые за¬ прашиваемые листы будут отсутствовать в памяти. С другой стороны, очень большие листы могут быть неэффективны из-за «мертвого», пространства листа. Если используется только половина листа в 4К, то оставшиеся 2К эффективно используется тогда, когда этот лист находится в памяти. Цель оптимального использования памяти подрывается тем обстоятельством, что значительная часть памяти «скрыта» в листе. 3. Алгоритмы замещения листа. Если затребованный лист не найден, его необходимо ввести в основную память. Если в основной памяти для него есть место, то никаких вопросов не возникает. Если места нет, то надо ре¬ шить, какой резидентный лист заменить. Различные стратегии выбора назы¬ ваются алгоритмами замещения листа. Цель такого алгоритма — минимизиро¬ вать листание, заменяя те листы, которые не принадлежат текущим окрестно¬ стям всех активных программ и которые, следовательно, имеют наименьшую вероятность быть вызванными в ближайшем будущем. Если количество ли¬ стов, которые должны скоро быть вызваны, слишком велико, чтобы поме¬ ститься всем вместе, то задача листания становится трудноразрешимой. Когда одни и те же листы вводятся повторно, возникает состояние известное как «толкотня в памяти». Самой простой и наиболее «прозрачной» стратегией является FIFO*). Если необходимо ввести некоторый лист, то заменяется тот лист, который дольше всех находился в памяти. Тем самым предполагается, что более ста¬ рые листы с большой вероятностью не принадлежат окрестности. Более дина¬ мичный подход включает попытку заметить, какие листы все еще находятся в окрестности. Некоторая запись фиксирует использование листов и те листы, которые дольше всего не использовались (LRU**), становятся наиболее ве¬ роятными кандидатами для замещения. Есть разные алгоритмы LRU. Есть разные мнения о том, сколь сложной Должна быть стратегия замещения, чтобы быть действенной. Концепция, комбинирующая основную идею LRU и идею «подсобного хозяйства», называется рабочим множеством. По окончании периода обслу¬ живания метятся все листы, к которым обращались в течение этого периода иДи некоторого определенного последнего интервала этого периода. Подсчи- тываются те листы, которые использовались самыми последними, и размер °крестности равен необходимому для них пространству памяти. Управление Не будет передано программе до тех пор, пока ей не будет гарантирован та- *) FIFO — «First In First Out» — «первым вошел, первым вышел». (Прим. ПеРев.) **) LRU — «Least Recently Used» — не используемый дольше всех. (Прим. п*рев.)
288 ГЛ. 20. СПЕЦИАЛЬНЫЕ СИСТЕМНЫЕ ФАКТОРЫ кой объем памяти. Эта схема великолепно подходит для мультипрограммно^ среды, в которой она позволяет динамически увеличивать или уменьщать запросы программ на память и предотвращать «толкотню в памяти», учитьь вая как разумные потребности в памяти, так и разумный выбор листа хоро. шей схемы замещения. Существует неисчислимое множество улучшений, которые можно прнме. нить к алгоритмам замещения. В этой стратегии предпочтение часто отдается тем листам, которые не должны изменяться. Когда загружается неизменяе¬ мый лист, операция записи не нужна, и операция листания сокращается д0 операции чтения вместо чтения-записи. В мультипрограммном окружении можно использовать относительный приоритет для того, чтобы позволить вы¬ сокоприоритетным программам «пожирать» другие программы вместо того, чтобы перезагружать свои листы. 20.1.3. Виртуальная память. С листанием связано понятие виртуальной памяти. Поскольку программа отображается на физическую память лишь по требованию, программист при создании программы может считать, что у него есть значительно расширенное пространство памяти. IBM 370/168 с OS/VS 2.2 дает пользователю 16 миллионов ячеек виртуальной памяти. Программист мо¬ жет строить свою программу так, как если бы при исполнении ей были до¬ ступны миллионы ячеек памяти. Концепция виртуальной памяти освобождает программиста (и компилятор) от необходимости планировать сложные струк¬ туры перезагрузки. Механизм листания заменяет по мере необходимости одни листы задачи на другие. Наличие большого объема виртуальной па¬ мяти влияет также на ввод-вывод. Файлы данных, которым обычно управ¬ ляют команды ввода-вывода, могут быть представлены в виртуальной памяти как резидентные, и механизм листания становится по существу механизмом ввода-вывода. Программист, желающий переместить свои файлы в виртуаль¬ ной памяти, не использует явных команд ввода-вывода. Таким образом, концепция виртуальной памяти наводит на мысль о воз¬ можности упорядочивать большие совокупности файлов, используя непосред¬ ственно внутренние методы сортировки. По мере развития концепция разде¬ ления физических и логических ресурсов так можно будет проводить все сор¬ тировки. Однако, поскольку поведение перезагрузки виртульной памяти измен¬ чиво, специалист по технике сортировки должен выяснить, какие внутренние сортировки подходят для упорядочения файлов в виртуальной памяти [2]. 20.1.4. Стиль программирования. Вместе с упрощением тонкостей про¬ граммирования благодаря аппаратному управлению перезагрузкой модулей и (возможно) вводом-выводом, виртуальная память вводит новый набор дис¬ циплин программирования и стилей. Структура и стиль программирования влияют на поведение программ в среде с механизмом листания. Методы про¬ граммирования, хорошие в прошлом, могут стать плохими при использовании листания. Например, переходы к подпрограммам могут увеличивать листание, если эти подпрограммы располагаются вне тех листов, из которых были обра¬ щения к подпрограммам. Таким образом, там, где используется листание, предпочтительнее копирование кода «в строку». Возможно, программист захо¬ чет учесть листание в своей организации структур данных, для чего сплани¬ рует модули и связи. Сколь много необходимо знать, чтобы спланировать
£0.1. ПЕРЕМЕЩЕНИЕ ПРОГРАММ И ВИРТУАЛЬНАЯ ПАМЯТЬ 289 хорошую программу в той среде, где есть листание, вопрос все еще спорный. СлеДУет ли знать РазмеР листа для того, чтобы разместить элементы про¬ граммы в одном и том же листе? Следует ли знать алгоритм замещения? Насколько нужно быть осторожным в выборе адресации? В общем случае, программа, спланированная под окружение с виртуальной памятью, будет работать лучше той, в которой не учитывается этот аспект машины. Если программист хочет, чтобы его сортировка работала эффективно, то он дол¬ жен обращать внимание как на поведение алгоритмов сортировки при нали¬ чии листания, так и на структуру своей программы [4]. 20.1.5. Сортировка и листание. Проблема сортировки в случае листания двойственна. С одной стороны, необходимо определить, как будут себя вести известные алгоритмы сортировки, когда у них меньше памяти, чем им необхо¬ димо для кода и данных. С другой стороны, надо использовать возможность замены внешних методов упорядочения сортировками для виртуальной памяти. До сих пор критериями для оценки внутреннего метода служили число сравнений и перемещений данных. К ним теперь надо добавить меру объема листания, какую потребует метод сортировки при разном количестве опера¬ тивной памяти. Этот объем будет зависеть от тонкостей кодировки, количе¬ ства и размера сортируемых элементов и алгоритма замещения. У каждого алгоритма сортировки свои характеристики локальности и свое подсобное хо¬ зяйство, частично определяемое его формой адресации и состоянием данных. На отдельных системах для некоторых сортировок проводились исследования, однако было бы преждевременно попытаться дать какое-либо общее утвер¬ ждение о сортировке на машине е механизмом листания. Влияние различных алгоритмов замещения на конкретные сортирозки, вообще говоря, неизвестно, а сортировки на виртуальной памяти широко не сравнивались с внешними слияниями разной конструкции и степени. Новые способы сортировки, нацеленные именно на виртуальную память, до сих пор йе появились. Можно занять и такую позицию, что любая сортировка будет работать лишь тогда, когда она имеет всю необходимую память, когда все ее листы остаются в памяти. Такая позиция необходима для оптимальных сор¬ тировок. Возможно, что не существует метода сортировки с хорошими свой¬ ствами листания, т. е. медленно деградирующего при уменьшении физической памяти, способного конкурировать по производительности с сортировкой с великолепными свойствами сравнения, но плохими свойствами листания. Од¬ нако есть определенные основания надеяться на то, что это не так, и что техника листания может дать позитивный вклад в сортировку. В следующем Разделе рассматриваются некоторые факторы, которые надо учитывать как сУЩественные. 20.1.6. Локальность, замещение, физическое пространство и время. Для сРеды с листанием, подходящим является такой алгоритм сортировки, кото¬ рый проявляет максимальную локальность и, как правило, образует линей- Н>К) последовательность ссылок на сортируемый список. Поскольку многие Из наиболее эффективных сортировок используют древовидные структуры с большим разбросом адресов по списку данных, то им должны быть присущи Кснфликты между минимизацией сравнений и минимизацией листания. На Рис. 20.3 показан пример простой сортировки обменом 16 элементов. Каждый Ю Г. Лорин
290 ГЛ. 20. СПЕЦИАЛЬНЫЕ СИСТЕМНЫЕ ФАКТОРЫ адрес сравнивается со своим непосредственным соседом. При первом про, смотре ссылки за пределы листа происходят лишь при пересечении границы листа, т. е. когда в линейной последовательности сравнений листва готов «Вь,. пасть» из окрестности. На рис. 20.3 показана линейная последовательность сравнений, листы, на которые были ссылки, и резидентные листы для первого просмотра, размещающего ключ 1, изначально находившийся в ячейке 13 Ячейка Начало Лист Конец просмотра 1 Лист Сравнения (ячейки) 16 : 15 15 : 14 14 : 13 13 : 12 12 : 11 11 : 10 10 : 9 9 : 8 8:7 7:6 6:5 5 : 4 4 : 3 3 : 2 2 : 1 Обмены 16 - 15 - 15 14 13 12 12 11 И ч-> 10 10 ч-*- 9 9 ч-> 8 8 ч-> 7 6 5 4 3 2 1 7 ч-*- 6 ч-> 5 ч-> 4 ч-> Зч-> 2 «-► 1. 13 А 1 А 2. 6 13 3. 4 6 4. 9 4 5. 11 В 9 В 6. 8 11 7. 7 8 8. 16 7 9. 14 16 10. 3 С 14 С 11. 5 3 12. 15 5 13. 1 D 15 D 14. 10 2 15. 12 10 16. 2 12 Ссылки на листы D D D D, С С С С В, С В В В В, А А А А Листы в памяти С, D В, С В, С В, С В, С А, В А. В А, В Л, В Замененные листы Листание (R-чтение. W-запись) 1R 1R 1W, IR 1W, IR Рис. 20.3. Локальность на первом просмотре сортировки обменом. В памяти отведено пространство для двух листов данных, и используется схема замещения листов FIFO. В каждый момент времени резидентными яв¬ ляются два листа по четыре элемента в каждом, т. е. 50 процентов упоряД0' чиваемого списка. Поскольку изначально есть память для загрузки листов & и С, то ничего перезаписывать не надо. На всем просмотре требуется четырс раза ввести лист и два раза вывести. Если бы имеющейся памяти хватало
20.1. ПЕРЕМЕЩЕНИЕ ПРОГРАММ И ВИРТУАЛЬНАЯ ПАМЯТЬ 291 ла весь список, то для формирования списка в памяти все равно понадоби¬ лось бы четыре раза вводить листы. Потери при работе в уменьшенной па¬ мяти вызваны перезаписью листа. Выгодность высокой локальности этого ме¬ тода очевидна. На рис. 20.4 указаны количества сравнений и листаний для остальных просмотров сортировки обменом. При пристальном изучении поведения этой сортировки можно обнаружить, что этот метод проявляет как хорошие, так и плохие характеристики для листания. Плохая характеристика заключается п том, что локальность программы резко смещается в конце каждого просмо¬ тра. Физическая память в конце просмотра 1 содержит листы Ли В, первым листом, к которому происходит обращение на просмотре 2, является лист D, за которым следует обращение к листу С. На каждом просмотре, где есть смотр Сравнения Листание 2 14 4R, 4W 3 13 4R, 4W 4 12 4R, 4W 5 11 4R, 4W 6 10 3R, 3W 7 9 3R, 3W 8 8 3R, 3W Ю 6 3R, 3W 11 5 2R, 2W 12 4 - 13 3 - 14 4 - 15 1 _ 16 0 - W6 30R, 30W 1 15 4R, 2W 121 Всего 34R, 32W Рис. 20.4. Сортировка обменом, остальные просмотры. обращения ко всем листам, листы А и В должны быть выведены и затем вновь считаны, а листы С и D должны быть считаны, а потом выведены. Хорошей характеристикой метода является то, что его локальность растет со Временем. К концу пятого просмотра больше незачем обращаться к листу А, к концу девятого просмотра незачем обращаться ни к Л, ни к В, и с размеще¬ нием листов С и D в физической памяти на десятом просмотре все листания прекращаются. Эта характеристика растущей локальности есть, вообще го¬ воря, то, что ищут, когда сортируют в среде с виртуальной памятью. Изменение локальности в конце каждого просмотра наводит на мысль 0 возможной модификации данного метода. Если, перемещая элементы, про¬ смотры с четными номерами «опускают» их, а просмотры с нечетными номе¬ рами «поднимают», то каждый просмотр будет обнаруживать в памяти те листы, к которым он обращался изначально. Устранение разрывов локально¬ сти от просмотра к просмотру сделало бы любой резидентный лист полезным. Как и в случае однонаправленной сортировки все листания прекратились бы После размещения десятого элемента. В целом листание можно было бы со¬ кратить до 22 вводов и 20 выводов листа. Ю*
292 ГЛ. 20. СПЕЦИАЛЬНЫЕ СИСТЕМНЫЕ ФАКТОРЫ На объем листания влияет также упорядоченность [10]. Если в данных есть удачная упорядоченность и алгоритм замещения распознает изменяемые и неизменяемые листы, то можно значительно сократить количество операций вывода листа. При просмотре, как правило, отыскивают упорядоченные листы и оставляют их без изменения. Когда их необходимо сменить в оперативной памяти, то их не надо переписывать, поскольку во внешней памяти уже есть правильная копия. Между локальностью или тенденцией к линейности в программе и алго¬ ритмом замещения листов есть еще одна взаимосвязь. Чем больше линей¬ ность, тем выше относительная эффективность алгоритма FIFO. Поскольку список просматривается последовательно, то листы, считанные первыми (во¬ шли первыми), на самом деле будут наименее используемыми в последнее время, таким образом алгоритм LRU не повышает производительности, так как не изменяет выбора листа. Это замечание применимо лишь к листам данных. Влияние FIFO и LRU на версии разной направленности одной и той же сортировки нетривиально. Пусть в начале второго просмотра в оперативной памяти есть Л и В, и первым вошел В. Как только этот просмотр пытается опустить большой ключ, он пересекает границу между В и С. Следующее нужное содержимое памяти составляют В и С. Операция листания при FIFO даст, однако, Л и С, потому что Л поступил после В. Если должен произойти обмен, то есть если последний элемент в В действительно больше элементов в С, то В необходимо будет вернуть. Явное уменьшение листания за счет изменения направленности достигается лишь при LRU. При переходе по LRU отЛи5к5иС листом, к которому было самое последнее обращение, яв¬ ляется В, и, следовательно, С сразу будет заменять Л. Если допускается три резидентных листа, а не два, листание сокращается, потому что упорядочиваемый список после размещения пятого элемента сжи¬ мается до таких размеров, что может поместиться в оперативной памяти. В данном примере предоставление дополнительного пространства менее эф¬ фективно, чем изменения направленности. Важно заметить, что сокращение памяти ощущается немедленно. Задержки листания изменяются от 0 до 23 при потере одного листа физической памяти и от 23 до 34 при потере двух. Работать лишь при небольшом сокращении требуемой оперативной памяти столь же плохо, как и при более существенном ее уменьшении. И наоборот, польза от добавления дополнительных листов невелика. Каждый метод про¬ являет разную чувствительность, но на самом деле сортировка может работать на 95% требуемой памяти, не гарантируя хорошей производительности. Если сортировка работает в мультипрограммном окружении, то она может терять управление центральным процессором. За то время, пока у сортировки нет центрального процессора, ее листы в оперативной памяти могут быть уте¬ ряны. Уместным в этой связи фактором является интервал времени, в течение которого сортировка владеет управлением центральным процессором и объем обмена при ее локальности в это время. Иначе это можно выразить числом команд, которые может выполнить сортировка прежде, чем она потеряет управление центральным процессором. Потеряет ли сортировка управление прежде, чем она сможет окончить просмотр? К концу просмотра? В некото¬ рой точке п~го просмотра? Существенным здесь становится характер управ¬
20.1. ПЕРЕМЕЩЕНИЕ ПРОГРАММ И ВИРТУАЛЬНАЯ ПАМЯТЬ 293 ления памятью в операционной системе и стратегии диспетчирования: он оПределяет, в какой степени можно ожидать, что сортировка, когда к ней вер¬ нется управление, найдет некоторые или все листы, какие она оставила в оперативной памяти. Факторы, связанные с задержками вследствие мульти¬ программирования и вследствие листания, переплетаются. Если при обмене сортировка теряет в конце просмотра и управление, и листы, то нет никакого смысла менять направленность, так как листание будет возникать всякий раз, когда сортировка получит управление на новом просмотре. Если сортировка теряет управление в течение просмотров, то может быть невыгодно выделять дополнительную память. Например, наличие в памяти Л, В и С, а не только и В не имеет значения, если сортировка теряет управление прежде, чем закончит работать с Л. Концепция локальности связана со временем, так как окрестность изменяется во времени. В динамическом окружении листание будет возникать отчасти из-за логики системы, а отчасти из-за самого алго¬ ритма. Самое большое, на что может надеяться программист — это свести листание до минимума, определяемого системой, ее алгоритмами управления памятью при мультипрограммировании. 20Л.7. Турнирная сортировка и листание. На' рис. 20.5 показан первый просмотр сортировки по дереву — минимальной по памяти турнирной сорти¬ ровки, описанной в главе 5. Эта сортировка представляет собой интересное средство для расширения представлений о локальности и воздействии упо¬ рядоченности. Если мы рассмотрим только этот первый просмотр, то список сравнений покажет, что адресация в этом методе отнюдь не случайная, она имеет локальность, но непрерывность локальности зависит от упорядоченно¬ сти. Этот метод существенно быстрее обрабатывает список, сравнивая MAX(LOC, LOC—1) с (LOC—1)/2. На рис. 20.5 размещение листов спла¬ нировано так, что для упорядочения тройки в оперативной памяти сортировке нужны два листа. В одном хранятся родственные потомки, а в другом — их предшественник. Замещение листа происходит при пересечении границы листа. Дополнительное листание может возникать, если просмотр оставляет кон¬ цевые узлы, так как каждый малый элемент должен как можно быстрее спу¬ скаться по дереву, возможно, обратно к концевому узлу. Требование того, чтобы все вершины были больше своих потомков, служит резкому изменению формы адресации. Поскольку в основной памяти есть только два листа — один для родственных потомков, другой для их предшественников, то внезап¬ ная необходимость обратиться к потомкам потомков вниз по дереву вызывает замену либо листа потомков, либо листа их предшественников. После загруз¬ ки D — первого листа потомков — и В — первого листа предшественников — операция ввода листа выполняется 11 раз. Первый ввод листа С (заменив¬ шего В) происходит из-за пересечения границы листа D. Лист В должен не¬ медленно быть возвращен (заменяя D) для сравнения 12 : 6. Лист D распола¬ гается теперь вне окрестности. Заметим, однако, что первое сравнение вразброс Ьновь вызывает D, потому что исходное содержимое ячейки 4 должно быть проверено: надо ли его опускать ниже. Второе сравнение вразброс должно вкинуть из памяти оба текущих листа для того, чтобы вновь вызвать С и D. Этот метод чувствительнее к размеру листа по сравнению с линейным Методом и требует больше резидентных листов для сокращения листания при
294 ГЛ. 20. СПЕЦИАЛЬНЫЕ СИСТЕМНЫЕ ФАКТОРЫ Начало Конец А 7 13 13 2 6 16 3 4 15' 4 9 14 В 5 11 11 6 8 8 7 7 12 8 16 9 С 9 14 6 10 3 11 6 6 12 16 4 13 1 1 14 10 10 16 12 7 16 2. 2 Сравнение Обмен Ссылки на листы Листы в памяти Изымаемый лист Листание FIFO первый последний 16 : 8 £>, В D В 2R 15 : 14 D D В Щ:7 15 7 D, В D В 13 :12 £>, С D С В 1W. IR 12 : 6 12 А-+ 6 С, В С В D 1W, 1R И : 10 С С В 11 : 5 С С В 9:8 С. В С В 8:4 8 ч-> 4 В, А В А С 1W, IR • 16 : 8 D, В В D А 1W. IR 7: 6 В В D 6 : 3 6 ч-> 3 В, А В А D 1W, IR * 13 : 12 С, D С D В, А 2W. 2R *12:6 12 —>6 В, С D В С 1W, IR 5 : 4 В. А В А D 1W, IR 4 : 2 4 —> 2 А В А 8 : 9 В, С В С А 1W. IR 9 : 4 9 —> 4 С, А С А В 1W, IR * Толкотня в памяти 11W, I3R Рис. 20.5. Сортировка по дереву с листами (дерево показано в конце про¬ смотра).
20.1. ПЕРЕМЕЩЕНИЕ ПРОГРАММ И ВИРТУАЛЬНАЯ ПАМЯТЬ 295 любом наборе выполняемых команд. По сравнению с линейным методом з/(ссь окрестность будет сдвигаться туда и обратно на меньшее число команд. Просмотр 2 сделает три сравнения и три листания; просмотр 3 сделает пять сравнении и шесть листаний. На этих просмотрах определенно будет возни¬ кать «толкотня в памяти», так как листы выводятся и немедленно возвра¬ щаются, а скорость листания превосходит скорость сравнения. Листание в этом методе со временем уменьшается, потому что листы становятся упорядоченными и выпадают из окрестности. По мере того, как окрестность сжимается, она начнет помещаться в имеющейся физической па¬ мяти. Однако, до тех пор, пока это не произойдет, просмотры этого метода сортировки будут неистово листать память, и проявлять локальность, не мень¬ шую, чем весь список данных. Упорядочение по возрастанию будет ухудшать ситуацию, увеличивая среднее расстояние, на которое элементы должны пере¬ мещаться вниз по дереву. Все методы сортировки, использующие древовидные структуры, рыская по ним, будут вести себя таким же образом, и поэтому должны быть либо модифицированы, либо тщательно подогнаны под механизм листания. 20.1.8. Влияние и значение листания. Если предыдущие разделы сформи¬ ровали представление о том, что при наличии механизма листания линейные сортировки как таковые предпочтительнее древовидных методов, то это пред¬ ставление необходимо исправить. Среди чисто внутренних сортировок или сортировок, которые выглядят таковыми из-за виртуальной памяти, есть дре¬ вовидные методы, которые не проявляют нежелательной адресации и которые можно использовать с небольшими потерями. Подходящими для любой ситуа¬ ции методами являются быстрая сортировка и слияние, их можно использо¬ вать с небольшими потерями применительно к виртуальной памяти или меха¬ низму листания. В случае других методов надо позаботиться о том, чтобы сократить листание до приемлемого уровня, если программист имеет представ¬ ление о том, сколь много памяти ему хорошо было бы иметь. Самое лучшее, на что может рассчитывать программист в системе с за¬ просом на лист — это то, что число операций листания будет равно числу используемых листов. Это равносильно работе при наличии всей необходимой Памяти, так как время однократной загрузки листов равно времени загрузки. В худшем случае программист может ожидать, что каждое сравнение или Пересылка (то или иное может возникать более часто в конкретном методе) 'будет вызывать исключение листа (или двух, если алгоритм замещения имеет тенденцию к перезагрузке требуемых листов). Такой предельный случай ли¬ стания может возникать тогда, когда в листе есть место для одного элемента, а в памяти есть место для одного листа. Затраты при этом зависели бы от Нисла элементов. Каждому методу присуща своя вероятность ссылки за пре¬ делы листа, а при любом отображении метода на оперативную память есть вероятность, что ссылка за пределы листа выйдет за пределы оперативной Памяти. Первая задача — это найти метод с хорошей адресацией. Следую¬ щая— это организовать метод так, чтобы гарантировать хорошую производи¬ тельность в некотором минимальном пространстве. Третья задача — закодиро¬ вать метод так, чтобы дополнительное листание не затрагивало листы про- ЩЩуры.
296 ГЛ. 20. СПЕЦИАЛЬНЫЕ СИСТЕМНЫЕ ФАКТОРЫ 20.1.9. Быстрая сортировка и слияние. Быстрая сортировка и слияние-^ внутренние сортировки с почти линейными формами адресации и небольщИм количеством сравнений, а следовательно, они великолепно подходят для ис¬ пользования в среде с механизмом листания. Быстрая сортировка последовательно просматривает список в поисках величины, большей выбранной основы. Когда таковая найдена, происходит обмен с меньшей величиной. Поиск меньшей и поиск большей величин идут навстречу друг другу, и при встрече просмотр заканчивается. Если есть один лист для поиска снизу-вверх и один для поиска сверху-вниз, листание будет возникать'лишь при пересечении границ листа. Листание между просмотрами зависит от размеров физической памяти, потому что локальность резко сме¬ щается после просмотра. По мере работы метода порции данных умень¬ шаются, и в некоторый момент времени будут помещаться в имеющейся па¬ мяти. Чем больще пространство памяти, тем скорее порции будут целиком помещаться в физической памяти и тем меньше будут расходы, связанные с листанием. В процессе слияния форма адресации становится менее локальной, по остается линейной. Критическим фактором конструкции является сохранение такого равновесия между степенью слияния и числом листов, при котором все подстроки всегда находятся в оперативной памяти. Для двухпоточного Слияния, как минимум, необходимо три листа: по листу для каждой строки и лист для слитой строки по мере ее образования. Добавление памяти не улучшает производительность слияния. На рис. 20.6 показано поведение первого просмотра быстрой сортировки в случаях, описанных ранее. Листание происходит лишь при пересечении гра¬ ницы (между Л и В, а затем между В и С). В конце просмотра образуется две порции. Эта конфигурация представляет особый случай — одна порция полностью располагается в оперативной памяти и прекрасно помещается в листе — преимущества которого можно было бы использовать По мере того, как порции сокращаются до размера листа или становятся еще меньше, для упорядочения становится пригоден любой способ, так как листаний нет. 20.1.10. Выбор с заменой и листание. Чрезмерная загрузка памяти на внутреннем этапе может усугубить проблемы семейства методов выбора с заменой. Если сортировка организована так, что дерево турнира об¬ ращается к самим записям (неотделенная таблица), то при наличии случай¬ ных данных вероятность ссылки в один лист записей в пространстве записей столь же велика как и при ссылке в другой. При каждом сравнении будет происходить обращение за ключом в область записей. Место данной записи в пространстве записей совершенно непредсказуемо, и даже при небольших изменениях в физической памяти может происходить интенсивное листа пне. Например, если для списка записей размером в четыре листа доступно три листа, то вероятность ссылки на лист записей, которого нет в оперативно11 памяти, равна 0.25. Если есть список из 16 элементов, то для выбора побе¬ дителя потребуется log2 16 = 4 сравнения. Выбор победителей для всего спя- ска потребует 64 сравнения (без учета подготовительного этапа). Если ве¬ роятность ссылки на нерезидентный лист пространства записей равна 0.2>» тс возможно 16 «промахов» при обращении к лиисту. Если хватает места
20.1. ПЕРЕМЕЩЕНИЕ ПРОГРАММ И ВИРТУАЛЬНАЯ ПАМЯТЬ 297 1. 2. 3. 4. 9. 10. 11. 12. 13. 14. 15. 16. Начало Просмотра 11 8 7 13 14 3 15 1 10 12 2 Конец Просмотра 2 6 4 9 11 8 Часть 1 7 12 10 3 5 5 13 15 14 Часть 2 16 Сравнения по позициям Пересылки по позициям Ссылки В памяти Листание 16 : TEMP й : TEMP 3->: TEMP 4 : TEMP 5 : TEMP 6 : TEMP 7 : TEMP 8 : TEMP 15 : TEMP 9 : TEMP 14 : TEMP TEMP TEMP TEMP TEMP 10 : H : 12 ; 13 : 1 - 16 ■ TEMP 1 8 ■ 15 9 - 14 ■ 12- 13 - TEMP - 15 9 14 12 13 A, D A A A ' В В В B, D B, D C, D С, D С С С, D A, D A, D A, D A, D D, В D, В D, В D, В D, В С, D С, D С, D С, D С, D 2R 1W, 1R 1W, 1R Рис. 20.6. Быстрая сортировка с основой PIVOT = 13.
298 ГЛ. 20. СПЕЦИАЛЬНЫЕ СИСТЕМНЫЕ ФАКТОРЫ лишь для двух листов, то в оперативной памяти не будет 2/4 листов, и Bcs роятность обращения в нерезидентный лист записей равна 0.5. «Вероятно» исключение листа произойдет 32 раза. Число операций с листами равно ве¬ роятности обращения к листам, отсутствующим в оперативной памяти, умно¬ женной на число сравнений. В турнире размером в 10 листов, при наличии места в оперативной памяти для восьми листов с листами по 50 элементов подготовка строк из 10 000 входных элементов приведет к 2/10 X 140 000 иск¬ лючений листов; а именно, 140 000 — это 10 000, умноженное на f" log2 10 000~] f а 2/10 — вероятность обращения к нерезидентному элементу. При 20-процент¬ ном сокращении оперативной памяти будет 28 000 исключений листов пли более 2.8 исключений на один сортируемый элемент. Степень деградации алгоритма сортировки даже при одном нерезидентном листе равна 10/10 X 140 000 или 14 000 операций листания. Что же фактически означают 14 000 операций листания? Для 14 000 срав¬ нений последовательность загрузка-сравнение-ветвление выполняется 14 000 раз. С сопутствующим управлением, подготовкой ключей и другими вспомогательными командами, операция сравнения непосредственно включает около 15 команд. Значение 14 000 операций листания совершенно иное. Пока происходит пересылка листов, происходит сотни обращений за командами, выполняющими листание, и тратится время центрального процессора. Листа¬ ние будет включать по крайней мере одно чтение, которое сопровождается поиском среднего размера, задержку вращения и время передачи данных. Листание — это операция миллисекундного уровня, а не микросекундного, как при сравнениях даже на малых машинах. Есть несколько стратегий, позволяющих сделать выбор с замещением устойчивым. Более того, они представляют самостоятельный интерес, потому что включают приемы, которые можно применять вообще в средах с меха¬ низмом листания. Одна стратегия состоит в том, чтобы сократить число записей в турнире до размера, помещающегося в оперативной памяти. При этом для слияния будет порождаться больше строк, и в результате может возрасти число про¬ смотров слияния. Если число просмотров слияния возросло, то дополнитель¬ ные просмотры слияния, возможно, не увеличат время, затраченное на сорти¬ ровку-слияние, больше, чем сэкономлено на листании. Основное время зави¬ сит от соотношения скоростей механизма листания и механизмов слияния, Степени слияния и т. д. Другая стратегия состоит в организации дерева в виде отделенной таб¬ лицы. Все сравнения выполняются на таблице (сортировка дерева признаков), и обращения к записям нет до тех пор, пока не будет упорядочена таблица признаков. Размер этого дерева можно ограничить так, чтобы гарантировать его постоянное присутствие в оперативной памяти. Когда таблица признаков выдает победителя, нужные записи разыскиваются и передаются на выход. Число исключений листов равно вероятности ссылки на нерезидентный лист» умноженной на N. Эта величина значительно ниже уровней неотделепиэп турнирной сортировки. Если обращение в область записей происходит только при перемещении победителя, то построение строки из 16 победителей вызовет лишь 16 операций листания.
20.1. ПЕРЕМЕЩЕНИЕ ПРОГРАММ И ВИРТУАЛЬНАЯ ПАМЯТЬ 299 20.1.11. Сортировка ключей или сортировка записей. Если размер ключа меньше размера записи, а таблицы признаков могут быть полностью разме¬ щены в оперативной памяти, то в случае отделенной таблицы, сортируя отделенные признаки, можно сократить число исключений листов до уровня выбора с заменой. Сортировка неотделенной таблицы почти не имеет значения для листания; поскольку обращение к записи необходимо для каж¬ дого ключа, то листание записей почти не изменяется. Пространство, затре¬ буем ое для таблицы, может даже увеличить листание. 20.1.12. Внешнее слияние. Значительную проблему для внешнего слияния представляет связь между схемами буферизации и блокировки с .одной сто¬ роны и схемами листания с другой. При больших размерах блока и глубокой схеме буферизации возможны случаи, когда не для всякой сливаемой строки есть элемент в физической памяти. Между оптимизацией слияния и минимиза¬ цией листания необходимо достичь равновесия. В условиях ограниченной памяти блоки-дублеры будут, как правило, изы¬ маться из памяти при листании, а объектом листания могут быть «концы» очень больших основных блоков. Механизмы листания могут не дать схеме буферизации реализовать свое назначение. Если среднее время досту¬ па к блоку на устройстве слияния (диске) существенно больше, чем на устройстве листания (например, барабане), то все равно, возможно, стоит «спользовать удвоенную буферизацию и разрешить листание. Повторный вы¬ зов блока с устройства листания может занимать меньше времени, чем ожи¬ дание считывания этого блока с медленного устройства. По отношению к блокам память с листанием действует как некоторое устройство, сбрасываю¬ щее ненужные элементы конструкции. Когда устройство листания и устрой¬ ство слияния одинаковы, то использование буферизации с дублированием ста¬ новится несколько подозрительным. Такая буферизация требует дополнитель¬ ного пространства памяти и не гарантирует присутствия записи в памяти, когда она нужна центральному процессору. Однако, если буферизация с Дублированием становится сомнительной, вся концепция равновесия между нейтральным процессором и вводом-выводом должна быть подвергнута кро¬ потливому повторному анализу. Эта проблема сохранения совмещения ввода- вывода с работой центрального процессора встает особенно остро в системах о «одноуровневой» памятью, где весь ввод-вывод «загнан» в пространство виртуальной памяти и распределение данных «очевидно» для сортировки. Размер блока также будет влиять на поведение листания. Блоки, большие листа, естественно, более уязвимы для листания, чем блоки, равные или мень¬ ше листа. Идеальная ситуация достигается при малых блоках, которые сум¬ марно помещаются в листах. Пусть дан блок размером 2К, лист размером 4К 11 слияние степени 8; в этом случае четыре листа могут обеспечить буфериза¬ цию с дублированием, причем листания не будет, если для ввода можно га¬ рантировать четыре листа. Если предпочтителен блок в 4К, то можно ис¬ пользовать какой-нибудь прием плавающего буфера. Однако, плавающие бу- ^еРы представляют потенциальную опасность, потому что они вносят случай¬ ность в форму ссылок на буферы. В общем случае степень слияния не должна превышать пространства, не¬ обходимого для того, чтобы гарантировать размещения блока из каждой
300 ГЛ. 20. СПЕЦИАЛЬНЫЕ СИСТЕМНЫЕ ФАКТОРЫ строки. Основное соглашение при слиянии в среде с механизмом листана* состоит в установлении равновесия между обычным вводом-выводом и вво¬ дом-выводом при листании. Хороший механизм требует, чтобы пользователь или программист знал, какое пространство памяти он хотел бы иметь, ц0, скольку вычисление степени слияния, размер блока и схема буферизации все это зависит от возможности вычислять скорость листания в сравнении с ухудшением ввода-вывода при разных размерах пространства памяти. 20.1.13. Скрытая буферная память*). Скрытая буферная память — это средство, аналогичное механизму листания (и часть конструкции многих ма. шин). Это память, время доступа которой значительно меньше времени до. ступа к основной памяти. В силу автоматической системы управления содер¬ жимым существование скрытой буферной помяти не очевидно для програм¬ миста. IBM 360/85 была первой серийной машиной**), оснащенной скрьпой буферной памятью, и многие машины семейства IBM 370 имеют это средство. Скорость памяти, как правило, является ограничивающим фактором, т. о. быстрый центральный процессор будет работать тем быстрее, чем быстрее будет реагировать память. Среднее время выполнения команды зависит от того, процента команд, данные для которых находятся в скрытой буферном памяти. Данные помещаются в скрытую буферную память блоками, блок остается в ней до тех пор, пока его не вытеснит другой блок. Перемещение данных в скрытую буферную память и из нее обычно поддерживается аппаратной реализацией алгоритма LRU. Интерфейс между оперативной памятью и скры¬ той буферной памятью и проблемы размещения совершенно аналогичны ин¬ терфейсу оперативная память-дополнительная память, который поддерживает¬ ся механизмом листания. Скрытая буферная память, подобно механизму листания, основана на концепции локальности в программе. Размер скрытой буферной памяти со¬ ставляет несколько процентов от размера всей оперативной памяти — поряд¬ ка 1—5 процентов. Для того, чтобы это средство было эффективным, есте¬ ственно, необходимо, чтобы более 5 процентов ссылок в память находило в нем свои данные. Для большинства программ минимальным требованием следует считать более 75 или 80 процентов всех обращений к памяти. Определенное внимание следует обратить на формы адресации, поскольку они связаны с эффективностью скрытой буферной памяти и на самом деле будут изменять производительность. Программист, пишущий внутренную сор¬ тировку на уровне пользователя, мало рискует если эта сортировка подобна быстрой сортировке, чьи средства адресации используют скрытую буферную память. Использование таблицы отделенных ключей, которая может быть втиснута в скрытую буферную память, представляет хороший подход. Сами записи в конечном итоге будут выбираться со скоростью памяти, а все обме¬ ны и сравнения будут выполняться со скоростью скрытой буферной памяти. *) В других источниках как синоним этого понятия читатель может встретить термин «кэш» (cache). (Прим. перев.) ** Следует отметить, что БЭСМ-6 — отечественная машина, появившаяся до IBM 360/85, имела прототип скрытой буферной памяти. (Прим. перев.)
20.2. МНОГОПРОЦЕССОРНЫЕ СИСТЕМЫ 301 20.2. Многопроцессорные системы Существует несколько машинных систем с различной формой и степенью параллелизма. Наличие машин, которые могут выполнять в одно и то же время несколько команд, или выполнять одну и ту же команду в нескольких местах одновременно, представляет вызов для разработчика алгоритмов сор¬ тировки. 20.2.1. Универсальные многопроцессорные системы. Многопроцессорная система—это вычислительная система, способная выполнять несколько пото¬ ков команд. На рис. 20.7 показана система из четырех банков памяти, со¬ единенных с тремя процессорами через центральное устройство управления памятью (MCU). Каждый адрес памяти одинаково доступен всем процессо¬ рам через MCU, которое также разрешает конфликты между процессорами при обращении в память. Каждый процессор взаимодействует с двумя про¬ цессорами ввода-вывода, которые обеспечивают доступ к набору устройств управления и устройствам ввода-вывода. В таких системах ни одно подмно¬ жество устройств не является «собственностью» процессора, скорее все про¬ цессоры имеют доступ к общему набору. Для этой многопроцессорной системы характерен макропараллелизм, т. е. отдельные или связанные программы' могут работать одновременно, не ис¬ пользуя какой-либо прием разделения процессора (мультипрограммирования). Эффективность таких систем частично зависит от количества программ, кото¬ рые могут работать независимо в любой момент времени и размера конфлик¬ тов из-за ресурсов системы вследствие работы нескольких центральных про¬ цессоров. Для того, чтобы использовать многопроцессорную систему, необхо¬ димо, чтобы было сформировано несколько заданий, имелось достаточно па¬ мяти и обеспечен ввод-вывод для поддержки центральных процессоров, вы¬ полняющих эти задания, без неприемлемых задержек из-за конфликтов между памятью, каналами и пространством на устройствах. Многие проблемы, связанные с многопроцессорными системами, аналогич¬ ны проблемам мультипрограммирования. Есть несколько проблем, связанных с работой (Р -f X) процессов на Р процессорах. Они включают дисциплину очередей, защиту совместно используемой системной информации, идеологию планирования, стратегии распределения и т. д. В общем случае, пределом мечтаний для многопроцессорной системы с /V процессорами является решение задачи в N раз быстрее, однако эта цель труднодостижима по целому ряду причин. 1. Конфликты между процессорами из-за ресурсов будут понижать про¬ изводительность каждого процессора. 2. Временные издержки на запуск и синхронизацию параллельных про¬ фессоров будут добавлять немалые накладные расходы. 3. Задачи часто не разделяются на одинаковые части. 20.2.2. Быстрая сортировка на многопроцессорной системе. Быстрая сор¬ тировка или некоторая ее модификация, по-видимому, является наиболее под¬ ходящей как чисто внутренняя сортировка для многопроцессорной системы с эффективным механизмом запуска процессоров. Описание использования бы¬ строй сортировки на разных многопроцессорных системах проиллюстрирует
302 ГЛ. 20. СПЕЦИАЛЬНЫЕ СИСТЕМНЫЕ ФАКТОРЫ D D Рис. 20.7. Универсальная многопроцессорная система.
20.2. МНОГОПРОЦЕССОРНЫЕ СИСТЕМЫ 303 ряд факторов и проблем, связанных с эффективным использованием много¬ процессорных систем в качестве средства сортировки. На рис. 20.8 показано дерево полной быстрой сортировки. При использо¬ вании этого алгоритма образуются части данных равной длины. Исходная часть имеет 64 элемента, а далее последовательно строится две части по 32, четыре части по 16, восемь частей по 8 и т. д. элементов. Эта идеа¬ лизированная операция быстрой сортировки происходит всегда (см. главу 7), когда основа является медианой списка. В программе быстрой сортировки, которая использует k сравнений на каждую часть, где k — длина части, будет около NXogiN сравнений (в данном примере 384). В дальнешем изло¬ жении уменьшение числа сравнений будет использоваться включительно как мера эффективности многопроцессорной системы. Чтобы упростить изложение, мы сделаем ряд серьезных допущений. 1. Запрос процессора почти ничего не стоит. 2. При запросе процессоров они доступны сразу, и, следовательно на ожидание освобождения процессора время не теряется. Если все процессоры, используемые в ходе сортировки, были распределены заранее, то это условие гарантируется. Такое предварительное распределение не типично для исполь¬ зования многопроцессорных систем (реальных и гипотетических). Однако, отрицательный эффект предварительного распределения вскоре станет очеви¬ ден. 3. Наиболее серьезное допущение из всех состоит в том, что процессор будет обрабатывать часть с постоянной скоростью, вне зависимости от того, работают ли другие процессоры, простаивают или решают другие задачи. Упорядочиваемый список может быть так распределен по банкам *) памяти, что при каждом обращении к данным процессоры будут мешать друг другу. Помехи при обращении за командами будут значительными тогда, когда не¬ сколько процессоров обращаются за командами в один и тот же банк памяти. Наличие в системе индивидуальной скрытой буферной памяти будет сокра¬ щать задержки из-за конфликтов в памяти. Иначе, данные можно переме¬ стить в банки памяти и тем самым локализовать обращения к данным каж¬ дого процессора в отдельных банках. Дублирование кода, индивидуальные копии для каждого процессора и оправданное распределение копий сократят конфликты при обращениях. Использование дополнительных копий кода, без¬ условно, будет ограничивать длину сортируемых списков вследствие исполь¬ зования дополнительного пространства под процедуры. Все эти соображения должны приниматься в расчет, если алгоритм со¬ ставляется для мультипроцессорной системы. Мы же пока оставим в стороне эти соображения и займемся производительностью быстрой сортировки как алгоритма для идеализированной многопроцессорной системы. На рис. 20.8 в части (Ь) собрана некоторая статистика по производитель¬ ности 32-процессорной системы, примененной к оптимальному дереву быстрой сортировки. На уровне L0 этого дерева один процессор, выполняя этот алго¬ ритм, строит две части. На уровне L{ добавляется еще один процессор. *) В отечественной литературе, как синоним термину «банк памяти», ис¬ пользуется термин «куб памяти». (Прим. перев.)
304 ГЛ. 20. СПЕЦИАЛЬНЫЕ СИСТЕМНЫЕ ФАКТОРЫ + + + + + + + Ои (X _ * a L L L О. Он Он Он Он Он <и CD СО CD СО СО СО U Q s CL О* с Ъ) Сравнения с) сравнения по процессорам Замечание. Р—идентификация процессора. Числа в узлах —размеры частей.
20.2. МНОГОПРОЦЕССОРНЫЕ СИСТЕМЫ 305 Для обработки части из 32 элементоз необходимо 32 сравнения. Каждый процессор обрабатывает одну часть и завершает свой просмотр за 32 единицы времени, каждая из которых равна времени одного сравнения. На каждом уровне выполняется 64 сравнения, но используется не один процессор, и, сле¬ довательно, число сравнений фактически равно числу сравнений для обра¬ ботки одной части. Суммарное количество сравнений, выполняемых раздель¬ но при упорядочении всего 64-элементного списка, равно 126. Затраченное время (время последовательных сравнений) сократилось с 384 до 126. Заме¬ тим, что в данном примере ради простоты обработанный элемент на каждом просмотре рассматривался как часть части. Более точный пример показал бы, что после просмотра 1 образуются части из 32 и 31 элемента. Сокращение затраченного времени на 2/3 должно обескураживать, по¬ скольку теоретически цель применения 32 процессоров к некоторой пробле¬ ме— сократить затраченное время до 1/32 однопроцессорного времени. Эта идеальная цель достижима, лишь если каждый процессор выполняет 1/32 всей работы и используется на 100 процентов в течение всего процесса. Для вы¬ полнения 384 сравнений идеальным разделением работы для каждого про¬ цессора были бы 32 части по 12 элементов каждая. Однако, быстрая сорти¬ ровка сама не образует такого набора частей. В части (с) на рис. 20.8 по¬ казано, почему пропорция сокращения времени сравнения столь скромна. Из 384 сравнений процессор 1 выполняет 126 сравнений, процессор 2 — 62, про¬ цессор 31—2. Загрузка процессоров, измеряемая числом сравнений, выпол¬ няемых за время, необходимое для выполнения 126 сравнений, подтверждает, что большинство процессоров вносят в сортировку лишь незначительный вклад. Это присуще данному методу из-за способа построения частей. В динамической системе, где процессоры выделяются по мере необходи¬ мости, низкая загруженность процессоров не является серьезной проблемой Для пропускной способности. Можно считать, что, когда процессоры не уча¬ ствуют в сортировке, они выполняют другую полезную работу. Динамиче¬ ское выделение процессоров, безусловно, подразумевает задержки — интерва¬ лы времени, в течение которых порции не обрабатываются, поскольку про¬ цессоры заняты другими заданиями. Создание быстрой сортировки по принципу «один процессор для каждой порции» неприемлемо как с точки зрения интересов сортировки, так и с точки зрения пропускной способности системы. Допустим, что две 32-процессорныс системы могут выполнить 4032 сравнений за то же время, за какое один про¬ цессор выполнит 126 сравнений. Время сортировки, требующей 4000 сравнений (по 125 на один процессор), может быть меньше, чем у быстрой сортировки, требующей в целом 384 сравнения. Есть два весьма разумных подхода к решению той проблемы, которую **ы только что отметили. Первый — исследовать поведение алгоритма для сокращения количества процессоров, а другой — модифицировать или заме¬ нить алгоритм. На рис. 20.9 показана обработка того же самого 64-элементного списка На четырех процессорах (дерево несколько искажено и не полно). У каждого Узла указан конкретный процессор, а в кружочке — сравнения. На уровне L2 Дерево обрезано. В конце этого уровня в стеке порций есть восемь частей
306 ГЛ. 20. СПЕЦИАЛЬНЫЕ СИСТЕМНЫЕ ФАКТОРЫ а) Дерево Lo Ч ч ГЧл lL3B [ l4A I L4B I l4C { 4d Число Несовме- процес- Сра.зне- щенные соров ния сравнения 1 2 64 64 Р! 160 100% 64 32 Р2 96 60% 64 16 Р3 64 40% 32 > 8 Р4 64 40% 32 ) 8 384 i“i с) Сравнения по процессорам l5A 4 8' 2 l5B 4 8 2 L5C 4 8 2 4d 4 8 2 l6E 4 8 i 2 L5F 4 8 2 L5Q 4 8 2 1ЧН 4 k 8 2 384 160 Ь) Сравнения Рис. 20.9. Быстрая сортировка (64 элемента) на четырехпроцессорной системе.
20.2. МНОГОПРОЦЕССОРНЫЕ СИСТЕМЫ 307 длины 8. В дереве показана обработка только четырех из них. (Уровень 33 яе показан). Узлы правых ветвей L44 дерева изображены так, что располо¬ жены ниже левых ветвей. Это умышленное искажение дерева показывает, что обработка левых ветвей будет происходить позже. Окончания Л, Б, С в обо¬ значении уровней используются для того, чтобы показать повторные исполь¬ зования одних и тех же процессоров на частях одинаковой длины. Напри¬ мер, на уровне L^a мы встречаем первый случай обработки частей длины 4, а на уровне Б4В — второй. Хотя это и не показано, на уровнях L4c и L4D имеет место то же самое. Один процессор обрабатывает части длины 32 и дли¬ ны 16 только один раз, а вот части длины 8 дважды, длины 4 — четырежды, Уровень Число просмотров Число сравнений Время 0 1 64 64 1 2 64 32 2 4 64 16 3 8 64 8 4А 8 32 4 4В 8 32 4 5А 8 16 2 5В 8 16 2 5С 8 16 2 5D 8 16 Всего 384 2 Всего 136 Рис. 20.10. Время, затраченное на сравнения, при восьми процессорах. и длины 2 — восемь раз. Таким образом, на четыре процессора опять-таки распределяется 32 части. Увеличение числа сравнений — это непосредственный результат нехватки процессоров. На четырех-процессорной системе максимальная эффективная ширина параллелизма — четыре. Для выполнения 64 сравнений, которые нуж¬ ны для обработки 16 частей длины 4, требуется 4 итерации четырех процес¬ соров, которые фактически выполняют на каждой итерации четыре сравнения. Для обработки частей L4 надо добавить время шестнадцати последовательных сравнений, тогда как при 32 процессорах потребовалось бы время лишь четы¬ рех последовательных сравнений. Сортировка затягивается, но незначительно; сокращение числа процессоров до 1/8 (4/32) приводит к потере производи¬ тельности менее чем на 30 процентов. Конфликтов становится меньше, когда система работает с четырьмя про¬ цессорами, а не с 32, следовательно, в некоторых специальных случаях сор¬ тировки четыре процессора могут быть производительнее 32. Безусловно, оп¬ тимальное число процессоров для такой сортировки будет где-то между 4 и 32. Восемь процессоров потребовали бы времени 136 сравнений (рис. 20.10), и не было бы особой причины запрашивать дополнительные процессоры. Применение минимальной многопроцессорности — двухпроцессорной кон¬ фигурации — требует времени для 224 сравнений. Второй процессор выпол¬ няет 160 сравнений и используется в течение 71 процента времени от вре- Мени, затраченного на 224 сравнения. На рис. 20.11 дана намного более правдоподобная картина поведе- нИя быстрой сортировки. Данный случай не особо плох, так как требует
308 ГЛ. 20. СПЕЦИАЛЬНЫЕ СИСТЕМНЫЕ ФАКТОРЫ Ожидаемые срав¬ нения = 14X64X6 = 537 Фактические срав-
20.2. МНОГОПРОЦЕССОРНЫЕ СИСТЕМЫ 309 428 сравнений, что меньше 537 ожидаемых сравнений. Построение дерева осно¬ вано на предположении, что те части, (которые образуются из одной части, имеют размер в пропорции 3 : 1 для одних, 2 : 1 для других, а 1 : 1 лишь для исходных частей размера 4. Это дерево произвольно, поскольку произвольны порции фактической сортировки. В итоге будет обработано 60 частей. Программист, совершенно не зная, сколько частей будет сформировано, должен решить, сколько следует использовать процессоров. Незадачливый программист, решивший использовать 32 процессора для 32 частей, ожидае¬ мых от полного дерева, будет очень удивлен. Число частей нельзя определить точнее числа сравнений. Оно полностью зависит о г данных. Дерево на рис. 20.11 показывает, что на любом уровне этого дерева эф¬ фективно работает не более 12 процессоров, поскольку каждый уровень имеет Сравнения Сравнения Pi 256 Pi 170 р2 174 Р2 116 430 Рз 68 Несовмещенные: 262 Р4 72 Р5 6 432 Несовмещенные : 224 а) Ь) Рис. 20.12. Производительность (а) двухпроцессорной системы и (Ь) системы без ожидания на «случайном» дереве. не более 12 узлов. Однако, когда принимается решение о количестве исполь¬ зуемых процессоров, эти данные, как и другие, неизвестны. Если процессоры можно получать динамически, то это решение, конечно, можно обойти. Дру¬ гое существенное «открытие» рис. 20.11 состоит в том, что некоторые процес¬ соры обрабатывают части размера 8, тогда как другие нескольких разных размеров, а также в том, что в течение всей сортировки высвобождение про¬ цессора для выбора других частей становится непредсказуемым и хаотич¬ ным. Нельзя предсказать, когда и какой процессор будет обрабатывать какую часть. Если можно было бы знать заранее форму дерева, то можно было бы оптимально распределить части разного размера между процессорами, но так как дерево строится динамически, то такую стратегию применить Нельзя. На рис. 20.12 показана работа двух-процессорной системы и системы, Которая гарантирует, что части в стеке скапливаться не будут. Как только Часть сформирована, для нее есть процессор. Механизмы соответствия часть-процессор имеют определенное влияние на производительность. Для системы на рис. 20.12 используется следующий Механизм: процессор строит две части, меньшую всегда оставляет себе, а большую помещает в стек. Как только процессор начинает работать, ему передается последовательность частей. Например, начальный процессор Р\ обработает части размером 64, 16, 4 и 2 (самую левую ветвь дерева), пре¬ жде чем он станет «свободным». Аналогично, когда процессор 2 становится активным, он обрабатывает части размером 48, 12, 4 и 2. Обработка части Размера 2 завершает последовательность частей, и процессор обращается К общей очереди (стеку) за следующим заданием. Если такового нет, то
310 ГЛ. 20. СПЕЦИАЛЬНЫЕ СИСТЕМНЫЕ ФАКТОРЫ процессор либо будет отдан, либо будет ждать. Если используется предвари, тельное распределение процессоров, то процессор будет ждать до тех пор пока в стеке не появится работа. Если используется динамическое распреде¬ ление процессоров, то процессор обратится к какой-то другой очереди работ Две системы рис. 20.12 имеют простое отличие. В случае (а) два процес¬ сора распределяются заранее, построенные порции помещаются в стек до тех пор, пока какой-нибудь процессор не освободится. В гарантированной системе процессор выделяется при необходимости, и, следовательно, порции никогда не образуют очереди в стеке. Таким образом, рис. 20.12 представляет собой оптимальное распределение многопроцессорной системы для конкретного де¬ рева рис. 20.11. Интересным свойством дерева на рис. 20.11 является непредсказуемость. В разные моменты процессор может выбрать ту или иную часть. Если Р1 освободился и обратился в стек за частью в то же самое время, когда Р2 готов поместить туда свою часть, то нельзя заранее сказать, кто из них за¬ хватит стек первым. Победу в этих «состязаниях» решают микросекунды. Если система распознает запрос Рi за микросекунду до стековой операции Р2, то Pi выберет то, что находилось в вершине стека, пока Р4 и Р2 были заняты только что обработанными частями. Если первым захватывает стек Р2, то он поместит свою часть в вершину стека. Когда Pi получит часть, то это будет та самая часть, которую только что поместил Р2. Когда процессор помещает в стек или берет из него, другие процессоры должны быть «забло¬ кированы», предотвращая доступ к общему ресурсу — стеку. Современные мультипроцессорные системы зависят от выполнения команды блокирования для предотвращения одновременного обращения двух процессоров к общим ресурсам. Модификация быстрой сортировки для многопроцессорной среды предпо¬ лагает использование на каждом просмотре двух основ, таким образом, вто¬ рой процессор может участвовать в исходном разделении списка на части. Список элементов, меньших одной границы, группируется у вершины; список элементов, больших другой границы, — внизу. Опубликованные результаты не позволяют сделать заключения о том, что этот подход быстрее быстрой сор¬ тировки. 20.2.3. Парный обмен на многопроцессорной системе. Выбор метода для параллельной обработки включает определение степени параллелелизма, допу¬ скаемой данным методом, и отображение его на предполагаемое количество машин. Решающим критерием является затраченное время. Тот метод, в ко¬ тором степень использования каждого процессора, выделенного сортировке, очень высока, обеспечивает максимальный параллелизм, и ему должно отда¬ ваться предпочтение. Рассмотрим систему, в которой можно определить до¬ ступное количество процессоров. В этом случае сортировка может строить Столько порций, сколько доступно процессоров, и выполнять Р-поточное слия¬ ние на одном процессоре, освобождая все остальные. Можно выполнять серии слияний малых степеней, используя все доступные процессоры. Методом сор¬ тировки для каждой части может служить быстрая сортировка, но ни один процессор не может сортировать те части, которые ему не были выделены с самого начала.
20.2. МНОГОПРОЦЕССОРНЫЕ СИСТЕМЫ 311 В гл. 2 был описан метод сортировки, названный парным обменом. Он характеризуется тем, что все сравнения не пересекаются, т. е. сравниваются позиции К и К + 1, затем К+ 2 и /( + 3. Поскольку последовательные срав¬ нения не имеют общих элементов, то они могут выполняться одновременно. Пусть дано N элементов, каждый просмотр этого метода требует N/2 сравне¬ ний. Имея N/2 процессоров, можно каждое сравнение выполнять на отдель¬ ном процессоре. Процессор 1 может выполнять сравнение позиции 1 с пози¬ цией 2; процессор 2 — сравнение 3:4; ... процессор 32 — сравнение 63 : 64. На каждом просмотре время требуется лишь для одного сравнения и одного обмена, которые выполняет каждый процессор, если он обнаружит инверсию. Этот метод требует максимально N + 1 просмотров. Список из 64 элементов при использований 32 процессоров потребует столько времени, сколько необ¬ ходимо максимум для 65 последовательных сравнений. Всего при этом будет более 2000 сравнений. В данном случае общее число сравнений в четыре раза больше, чем в быстрой сортировке, но время, фактически затраченное на сравнение, равно половине того, что требует быстрая сортировка в лучшем случае. Вследствие разделения работы плохой однопроцессорный метод может эффективно использовать многопроцессорную систему, давая увеличение про¬ изводительности примерно пропорционально числу добавляемых процессоров. При 16 процессорах каждый процессор может выполнять по два сравнения за просмотр. Общее фактически затраченное время одного просмотра равно времени двух сравнений. Время сортировки удваивается. Есть много методов программирования, которые могут быть полезными для параллельного процессора. С неопределенностью связано понятие избы¬ точности. Можно разрешить процессорам выполнять одинаковые действия и все же получить хорошие временные характеристики, если тот метод, в кото¬ ром возникает такое дублирование, имеет максимальный параллелизм. В мно¬ гопроцессорной среде эффективной может быть распределяющая сортировка. Увеличение скорости может быть почти пропорционально числу процессоров. Процессоры быстро распределяются по бункерам, сокращая на каждом про¬ смотре время распределения в некоторое число раз, близкое к Р. 20.2.4. Параллельное слияние. Один метод сортировки для многопро¬ цессорной системы получается из модификации сортировки Шелла, которая гарантирует, что на любом просмотре нет сравнений, которые используют один и тот же аргумент. Этот метод описан здесь благодаря Бэтчеру [1] и тесно связан с той работой, которая проводится в области сортирующих сетей. Сортирующая сеть — это аппаратное устройство, состоящее из нескольких Устройств сравнения, многие из которых могут работать параллельно. Сеть Конструируется для сортировки с конкретным числом входов, и критерием Для сети является количество сравнений, необходимое для сортировки задан¬ ного числа элементов. В теории много внимания уделялось минимизации чис¬ ла сравнений, необходимых для сортировки конкретного N (всегда весьма не¬ большого). Первая статья в литературе по вычислительной технике была °публикована Боузом и Нельсоном в Journal of ACM, v. 9, с. 282 (1962) [3]. Эта статья называлась «Проблема сортировки» и в ней обсуждался «р-опе- Раторный» метод для построения подходящей последовательности сравнений.
312 ГЛ. 20. СПЕЦИАЛЬНЫЕ СИСТЕМНЫЕ ФАКТОРЫ Хиббард в 1963 г. в этом же журнале опубликовал алгоритм на алголе, ко¬ торый строил такие последовательности для различных N [12]. Впоследствии поиском оптимальных сортирующих сетей занимались Флойд и Кнут [8, 9] Ван Воорис [24] и другие. Форма сравнений в сортирующих сетях может быть использована в уци. версальной многопроцессорной системе. «Сердцем» такой сортировки является построение последовательностей непересекающихся сравнений, таким образом некоторое число процессоров может работать, как независимые устройства сравнения. В этом методе дополнительные затраты образуются из-за по¬ строения нужных последовательностей сравнения. «Параллельное слияние» Бэтчера состоит из ряда многоэтапных просмот¬ ров. Предварительные просмотры размещают элементы так, чтобы на послед- нем этапе последнего просмотра ни один элемент не был бы удален более чем на одну позицию от его итогового места. Каждый элемент в течение по¬ следнего этапа последнего просмотра может быть упорядочен надлежащим образом путем сравнения (и, возможно, обмена) с его соседом. На последнем этапе все сравнения непересекающиеся и могут выполняться параллельно, В духе сортировки Шелла этапы работают с разными расстояниями меж¬ ду сравниваемыми элементами. Задача всех этапов сформировать до начала последнего этапа упорядоченный список из нечетных элементов и упорядочен¬ ный список из четных элементов. На последнем этапе элементы четного и не¬ четного списков являются соседями и «сливаются» при сравнениях послед¬ него этапа. В данном случае структура управления значительно сложнее, чем в сор¬ тировке Шелла. Основное различие заключается в количестве этапов и рас¬ стоянии между элементами, управление которыми осуществляется -при по¬ мощи отдельных переменных. Третья переменная нужна для определения по¬ следовательностей сравнения на этапе. Четвертая переменная используется для управления переходом от этапа к этапу и от просмотра к про¬ смотру. Исходное значение Р (счетчик просмотров) равно 2*-1, где t= flogzAH • Читатель, наверное, помнит, что это равно первому значению D в версии Хиббарда сортировки Шелла. Для списка из 16 элементов на рис. 20.13 на¬ чальным значением Р будет 8. В данном случае t = 4 и 2*-1 = 23, или 8. Начальное значение D (расстояние) давно также 8, переменная построения последовательностей (S) сначала равна 0, а начальное значение переменной управления этапами (С) равно 8. Алгоритм установки исходных значений та¬ ков: Р = D = Р, S = 0 и S = 2t~i. В никогда не будет перезагру¬ жаться, а будет уменьшаться последовательными целочисленными делениями на два. В начале каждого просмотра переменным D, 5 и С будут присваи¬ ваться их исходные значения. В течение просмотра в конце каждого этапа они будут иметь разные значения. Построение правильного сравнения зависит от указателя (t), который из¬ меняется в течение этапа от 0 до N — (D+ 1). Для каждого значения i та¬ кого, что результат логической операции «И» над двоичными представлениями i и Р равно S, есть надлежащее сравнение для данного этапа. Для того, что¬ бы выполнять сравнения параллельно, их необходимо сформировать до на¬
20.2. МНОГОПРОЦЕССОРНЫЕ СИСТЕМЫ 313 чала каждого этапа. Читателя не должна смущать неочевидность отдельных действий над D, С и 5. На рис. 20.13 за преобразованным списком (а) показаны последователь¬ ность сравнений и обменов для i от 0 до 7 (Ь). Управление просмотром для Список Исходный после список этапа Позиция / + 1 : / + 1 + D Обмены 1. 13 13 i = 0 1:9 2. 11 3 1 2 : 10 2 <— 10 3. 7 7 2 3:11 4. 6 6 3 4 : 12 5. 4 4 4 5 : 13 6. 5 5 4 6 : 14 7. 9 2 6 7 : 15 7-и. 15 8. 8 1 7 8 : 16 9 16 9. 14 14 10. 3 11 Ь) Последовательность сравнений. И. 12 12 12. 16 16 13. 15 15 14. 10 10 15. 2 9 16. 1 8 а) Список до этапа 1 и после него Р =8 (23) i i Д P (в двоичной системе) D=8 0 оооо д 1000=0=s 5 =0 1 0001 Л 1000 = 0 = s С =8 2 ooio a iooo=o=s lim i = N — (D + 1) = 7 3 ooii a iooo=o=s новый просмотр (Р = С) 4 oi oo a iooo=o=s Р=Р/ 2 5 oioi aiooo=o=s D=P 6 oi Ю a iooc= i=s S = 0 7 oiii a iolo=o=s С = 8 с) управление этапом Рис. 20.13. Этап 1 просмотра 1. данного этапа происходит в соответствии с тем, что было сказано выше о значениях Р, D, S и С. Указатель i ограничен 7, потому что N — (7) + 1) = 16 — 9. На данном этапе ни одно значение i не имеет единицы в разряде 23, таким образом, все сравнения i: Р дают в результате 0, т. е. равны значению S. Всегда, когда результат «И» над i и Р не равен S, сравнение, соответствую¬ щее этому значению i, не выполняется. Сравниваемыми позициями являются Позиции (i + 1) и (i + 1 + &)• Цель ограничения i величиной (N — (D + 1)) — Исключить совпадения (пересекающиеся сравнения). Заметим, что следующее сравнение было бы 9:17 при i = 8. Это сравнение не должно было бы вы¬ полняться, даже если бы в списке был семнадцатый член, потому что пози¬ ция 9 уже включалась в сравнение на данном этапе. Операция «И» над i и Р служит той же самой цели. Операция «И» над двумя величинами всегда Дает 0 в двоичном разряде, если у этих величин в этом разряде нет 1.
314 ГЛ. 20. СПЕЦИАЛЬНЫЕ СИСТЕМНЫЕ ФАКТОРЫ Если доступно восемь процессоров, то этап может закончиться за время одного сравнения-обмена плюс время построения адреса. Есть много возмож¬ ных способов реализации этого метода. Все сравнения может построить одиц процессор и потом вызвать восемь процессоров для сравнения-обмена. По-ви¬ димому, эффективнее разрешить начальному процессору взять значение i = o и затем обратиться за процессором для обработки значения i = 1. Процессор Список Список в начале после этапа 1 просмотра просмотра 2 Позиция t + 1 : 1+1 +D Обмены 1. 13 4 t=0 1:5 1 ч-v 5 2. 3 3 1 2:6 3. 7 2 2 3:7 3 ч-* 7 4. 6 1 3 4:8 4 ч-v 8 5. 4 13 4 — 6. 5 5 5 — 7. 2 7 6 — 8. 1 6 7 — 9. 14 14 8 9: 13 10. И 10 9 10 : 14 10 ч-v 14 11. 12 9 10 11:15 11 ч-> 15 12. 16 8 11 12:16 12 ч-v 16 13. 15 15 b) Последовательность сравнений 14. 10 11 15. 9 12 16. 8 16 а) Список Исключается 1 if\P S Р=4 4 0100 Д 0100 0 D=4 5 0101 А 0100 0 5=0 6 оподоюо^о С=8 7 ОШДОЮО^О lim i = N — (D + 1) = 11 Новый этап (Р Ф С) D — C — Р=4 С = С/2=4 S=P = 4 с) Управление этапом Рис. 20.14. Этап 1 просмотра 2. i = 0 вычисляет свою последовательность сравнений и выполняет сравнение- обмен. Процессор i = 1 обращается за процессором i = 2 и т. д. В за¬ висимости от числа доступных процессоров запросы процессоров могут не¬ которое время ждать в очереди. Если для данного этапа есть восемь процес¬ соров, то каждый процессор (кроме восьмого) будет обращаться к другому процессору, вычислять адреса для одного сравнения, выполнять его и освобо¬ ждаться. Процессор, который освобождается последним, обслуживает про¬ цедуры окончания этапа. Если процессоров меньше восьми, то некоторые про¬ цессоры могут неоднократно обращаться в «очередь ожидающих i». Заметим, что порядок выполнения сравнений не существен. Когда этап завершен, т. е. когда i = N- (D+ 1),
20.2. МНОГОПРОЦЕССОРНЫЕ СИСТЕМЫ 315 оГ,ределяется, нужен ли дополнительный этап или же следует начать новый просмотр. Если Я равно С, то начинается новый просмотр. Если Р не рав¬ но С, то начинается дополнительный эгап того же самого просмотра. Новый просмотр характеризуется новым значением Р, равным LCJ • В конце этапа на рис. 20.13 Я и С равны, и начинается новый просмотр. Начальные значения для этого просмотра таковы: Р = 4, D = 4, 5 = 0, Список в начале и конце просмотра Позиция / + 1 : i + 1 + D Обмены а) Список 1. 4 *‘ = 0 — 2. 3 1 — 3. 2 2 — 4. 1 3 — 5. 13 4 5: 9 6. 5 5 6 : 10 Нет 7. 7 6 7 :11 8. 6 7 8 : 12 9. 14 8 — 10. 10 9 — И. 9 10 — 12. 8 11 — 13. 15 14. 11 в) Последовательность сравнений 15. 12 16. 16 Исключается i iAp S Р = 4 0 0000 Л 0100 Ф 4 £> = 4 3 ООП Д0100=4 5=4 8 1000 А 0100=4 С = 4 11 1011 Д0100=4 lim i — N — (D 1)= 11 Новый просмотр (Р = С) Р = 4 D = 4 5 = 0 С=8 с) Управление этапом Рис. 20.15. Этап 2 просмотра 2, С = 8. Первый этап изображен на рис. 20.14. На нем 8 сравнений, 4 сравне¬ ния исключены по правилу i и Я. При Я = 4 и i = 4, 5, 6, 7 получается Результат, не равный 5 = 0. В результате этого исключения не выполняются сравнения 5:9, 6:10, 7:11 и 8:12. Их необходимо было исключить потому, Нто 9, 10, 11 и 12 уже использовались при сравнениях на данном этапе. Про¬ цессоры, которые строят исключаемые сравнения, могут либо освобождаться, либо обращаться в очередь за новым значением i. В конце этого этапа наступает условие нового этапа Я ф С. Соответ¬ ствующими значениями для D, Я, 5, С являются: D = С — Я = 8 — 4 = 4, 5 = Я = 4, С = С/2 = 4. Переменные управления этапом для второго этапа просмотра 2 равны 4, 4, 4, как показано на рис. 20.15. При 5 = 4 в этом методе выполняются Лишь те сравнения, для которых «И» от i и Я равно 4. При Я = 4 и i = 4,
Список Конец Конец Конец в начале просмотра первого этапа второго этапа третьего этапа 316 ГЛ. 20. СПЕЦИАЛЬНЫЕ СИСТЕМНЫЕ ФАКТОРЫ <N-H^eOC'.iOO>tO<NOOCOO'-tf* — ЮСО <N <—i-^COb~inoOcOOOO^*OCJ.-« Ю СО <N + 11 а О | Q- . Е а.=з if о I со.|| Q- -Е о,- £ * о • со ч*1 О Ю to | 1 ?.Г. 1 17.7 I 1 II со ^ t"- 00 — <м а, 1?.7. со Tf о I г Он а о S а. с Я Он оо п ^*С0СЧ~С01Г1^С0ч**О0>00Ю-«<МСО о;1 оГ-* fa о 1 *Л a х о и X а и е сз н 0) 1-1 сч оо* ^ «о to’ t>T оо’ а> о ~ сч со’ ю to* # # | j t^OO j | ^ - -н <N ю'сО СТ> О into ^ 17.7. * со Oli о^счсотгюсо^ооа>о-^<мсо
20.2. МНОГОПРОЦЕССОРНЫЕ СИСТЕМЫ 317 ^ 6 7 таковые имеются. Ими будут те сравнения, которые были исключены на первом этапе (см- рис‘ 20-14^ Когда этот этап закончен, выполняется условие для нового просмотра (Р = С). Р делится пополам, D полагается равным Р, S и С получают исход- яые значения 0 и 8. На рис. 20.16 показан третий просмотр при Р = 2. На 1. Список в начале просмотра 2 Конец первого этапа 1 Конец второго этапа 1 Конец третьего этапа 1 Конец четвертого этапа 1 2. 1 2 2 2 2 3. 4 3 3 3 3 4. 3 4 4 4 4 5. 7 5 5 5 5 6. 5 7 7 7 6 7. 9 6 6 6 7 8. 6 9 9 9 9 9. 12 8 8 8 9 10. 8 12 12 11 11 11. 13 10 10 10 И 12. 10 13 13 13 12 13. 14 11 И 12 13 14. 11 14 14 14 14 15. 15 15 15 15 15 16. 16 16 16 16 16 а) Список Этап 1 Этап 2 Этап 3 Этап 4 Р, D, S, С=1, 1, 0, 8 Р, D, S, С = 1, 7, 1, 4 Р, D, 5, С= 1. 3, 1, 2 Р, D, S, C=l, I, 1 1 Иш i = ТУ — (D -j- 1) = 14 ]im i = /V — (D + l) = 8 Hm i = N — (D+l) = 12 lim i = N — (D + l’)= 14 i=0 1:2* 1 — 2 3:4* 3 — 4 5:6* 5 — 6 7:8* 7 — 8 9 : 10 * 9 _ 10 11 : 12 * 11 _ 12 13 : 14 * 13 _ 14 15 : 16 15 — * Звездочки указывают обмены b) Сравнение и управление просмотром Рис. 20.17. Последний просмотр. 3том просмотре 3 этапа. На первом этапе могут кооперироваться восемь про- ^ессоров, на втором этапе — 4 процессора, на третьем этапе — 6 процессоров. с* что число процессоров изменяется от этапа к этапу, является недостат¬ ком этого метода. Поскольку сравнения одного этапа могут, вообще говоря, ^впадать со сравнениями другого (например, 7 i 13 на этапе два, 7 : 9 на ^апе три), то в общем случае нельзя в одно и то же время выполнять 2 : 9 2 : 5 2 : 3 4 : 1 4 : 7 4 : 7 6 : 13 6 : 9 6:7* 8 : 15 8 : 11 8:9* - 10 : 13* 10 : 11 * - 12 : 15 12 : 13* - - 14 : 15 I
318 ГЛ. 20. СПЕЦИАЛЬНЫЕ СИСТЕМНЫЕ ФАКТОРЫ несколько этапов. Однако, возможны случаи, как на рис. 20.16, когда их мо>к но проводить параллельно. Если N известно, то можно заранее составить пол ный план работы, так как последовательность сравнений не зависит от Ип ходной упорядоченности в списке. На рис. 20.17 изображен заключительны!! этап. Обратите внимание, что с самого начала последнего этапа ни одни эле- мент не удален более чем на одну позицию от той позиции, которая соот. вс-тствует его значению. Следует реализовывать этот метод , на универсальной многопроцессорной системе или нет, частично зависит от относительной эффективности выделения и освобождения процессора. Для этой функции первый механизм является Сравнения Сравнения Сравнения Сравнении (общее число) (наилучшее число) (2 процессора) (4 процессора) Просмотр 1. этап 1 8 1 4 2 Просмотр 2, этап 1 8 1 4 2 Просмотр 2, этап 2 4 1 2 1 Просмотр 3, этап 1 8 1 4 2 Просмотр 3, этап 2 4 1 2 1 Просмотр 3, этап 3 6 1 3 2 Просмотр 4, этап 1 8 1 4 2 Просмотр 4, этап 2 4 1 2 1 Просмотр 4, этап 3 6 1 3 2 Просмотр 4, этап 4 _7 1 4 2 63 10 32 19 Рис. 20.18. Итог просмотров «в лучшем случае» — процессор доступен в лю¬ бой момент. привлекательным и эффективным средством. На рис. 20.18 сопоставлены все сравнения и затраченное время. 20.2.5. Внешнее слияние на многопроцессорной системе. Внешнюю сор¬ тировку-слияние для многопроцессорной системы можно сконструировать так, чтобы как при создании строк, так и при слиянии или только при слиянии использовалось несколько процессоров. Любой файл можно разделить на V частей так, чтобы фактически его сортировали и сливали раздельно N про¬ цессоров с проверкой всего заключительного файла. Каждый процессор может самостоятельно строить строки и самостоятельно выполнять слияние. ТруД* ность этого подхода заключается в том, что требование памяти для того, что¬ бы одновременно резидентными были сортировка, слияние и отдельные обла¬ сти сортировки, может влиять на размер строки. Равновесие надо искать меж¬ ду увеличением числа строк и временем записи строк. Основное препму^е' ство независимого построения строк состоит в том, что можно совмещать процесс их записи. Независимые сортировки блоков на независимых процессорах, по-впд*[М°‘ му, представляют разумный подход к использованию возможностей мисп°* процессорной системы. Короткие строки, порождаемые этими сортировка^» могут эффективно сливаться одним или несколькими процессорами по пУт11 на промежуточные устройства. Выбор конструкции слияния будет зависеть от тех характеристик доступа к данным и передачи данных, которые рассматривались в предыдущих глаВ^ Если процессоры делят общий ввод-вывод, необходимо учитывать конфДик
20.3. ДРУГИЕ АППАРАТНЫЕ СРЕДСТВА 319 меЖДУ процессорами из-за каналов и штанг. Кому в принципе отдать пред- „очтение— десятипоточному слиянию на однопроцессорной системе или пяти- „сточному слиянию на двухпроцессорной системе и т. д. — можно определить при помощи тех видов анализа, которые уже обсуждались в связи со слия¬ нием. 20.3. Другие аппаратные средства Листание и параллельная обработка представляют лишь два аппаратных средства, для которых может быть приспособлена сортировка. Другие пробле¬ мы, связанные с созданием сортировки, включают следующее. 1. Создание способа одновременной записи по нескольким каналам без сокращения размера строк. Известны способы сортировки на основе турнира и идей расширения строк, которые могут писать параллельно несколько строк. Пусть есть N направлений вывода, последний элемент каждой строки запо¬ минается, и новый элемент сравнивается со всеми последними элементами. Новый элемент присоединяется к первой же подходящей строке. Например, при четырех направлениях вывода одновременно будут строиться четыре строки. Сначала упорядочиваются четыре элемента. Каждый последующий элемент сравнивается с элементами этого списка. Когда обнаружен больший, этот элемент списка изымается и помещается в свою строку. Трудность этого метода состоит в том, что хотя он очень быстро за небольшое число сравне¬ ний выполняет просмотр распределения и позволяет использовать аппаратное совмещение при записи, он приводит к увеличению просмотров слияния, так как существенно уменьшает размер строки. 2. Архивы и иерархическая память. В больших вычислительных системах есть несколько уровней запоминающих устройств разной емкости и с разной скоростью обмена, поэтому необходимо определить, какое из них следует ис¬ пользовать для сортировки. Следует ли файл на медленной ленте сортировать на этом устройстве или же перед сортировкой его следует «отфильтровать» на быстрые устройства? Проблема разнородных устройств в очень больших системах подымает системные вопросы и вопросы программного обеспечения. Специалисты по организации данных и вводу-выводу склоняются к концеп¬ ции четкого отделения устройства. В будущем прикладная программа будет работать, ничего не зная о том устройстве, с которого она получает свои дан¬ ные. В стандартных системах интерфейсы данных «скрывают» от прикладных программ все устройства и вопросы, связанные с форматами. Такой подход, очевидно, создает очень трудную проблему для сортиров¬ ки, которая должна знать как можно больше о характеристиках устройств, Их количестве и расположении до того, как она примет принципиальные ре¬ шения о степени слияния, буферизации и разбиении на блоки. В системах с одним уровнем памяти, где программы не имеют непосредственного доступа к Устройствам, такие решения выносятся из сортировки. При условии развития концепций виртуальной памяти и стратегии орга¬ низации данных, сортировка может быть совмещена с отделением устройств. ^Днако, если только сортировка требует внешних операций, то в среде, где пР°граммы и устройства разделены, система сортировки не может осуществ¬ ить эффективную оптимизацию.
320 ГЛ. 20. СПЕЦИАЛЬНЫЕ СИСТЕМНЫЕ ФАКТОРЫ 3. Микропрограммирование. Сортировку можно включить в машину Иа микропрограммном уровне, можно создать архитектуру, оптимальную для сор. тировки, в виде микропрограмм и считывать их в микропрограммную память превращая тем самым центральный процессор в сортировщик. Влияние такого подхода на существующие алгоритмы требует исследования. 4. Ассоциативные памяти. Алгоритмы сортировки и поиска на микропро- граммном уровне или уровне схем могут быть заменены программными сор. тировками. Поскольку при сортировке положение объекта фиксируется удоб. ным образом, то на возможности этой сортировки в системе естественно влияют устройства, к которым можно обращаться по имени. Дополнительно небольшая ассоциативная память может использоваться для поддержки про¬ граммных сортировок. 5. Сортирующие машины. За последнее время был сделан ряд попыток к созданию сортирующих машин. Система File-Computer фирмы UNIVAC предлагает автономное устройство для работы с лентой, на панели которого программируются параметры данных [23]. IBM 703 было задумано как сор¬ тирующее устройство, но никогда не было коммерчески доступно. Трудность создания автономных, «чисто аппаратных сортирующих машин» заключается в том, что для того, чтобы достичь гибкости в управлении данными и на¬ стройки способа сортировки к характеристикам данных, они требуют пример¬ но такого же объема логики и таких же возможностей, как и универсальный процессор. От реализации алгоритмов сортировки в виде аппаратных средств или в какой-нибудь другой форме, отличной от центрального процессора, ни в коем случае нельзя отказываться. Нельзя отказываться и от поисков новых средств центрального процессора, которые сделают сортировку более эффек¬ тивной. Вполне вероятно, что в один прекрасный день логика М-поточпого сравнения, которая нам часто «приходила на ум», действительно появится в машине. На машине с восемью арифметическими регистрами вполне можно реализовать команду восьмипоточного сравнения. Общая тенденция к распределению функций в системе посредством пре¬ вращения устройств управления и каналов в специализированные процессоры может быть распространена и на сортировку. Устройство управления лентой или диском можно превратить в участника сортировки. Цель при этом со¬ стоит, возможно, не столько в том, чтобы сортировать быстрее, сколько в том, чтобы сортировать дешевле, позволяя небольшой подсистеме сортиро¬ вать, в то время как центральный процессор занят другой работой. Когда же устройство управления не сортирует, оно может функционировать как обычное устройство. Для системы IBM 360 создано сортирующее устройство, которое работает в режиме управления центральным процессором. Его можно купить вместе с OS-сортировкой. Электронный сортировщик фирмы Astrodata Corporation создан для выполнения этапа распределения при слиянии в OS-сортировке. На этом этапе освобождаются циклы памяти и центрального процессора за счет подключения этого устройства, которое строит строки подобно специали¬ зированному процессору сортировки. Этап слияния OS-сортировки выполняет- ся обычным образом.
ЛИТЕРАТУРА Часть 1. ВНУТРЕННЯЯ СОРТИРОВКА ИСТОЧНИКИ И ДОПОЛНИТЕЛЬНАЯ ЛИТЕРАТУРА К ПРЕДИСЛОВИЮ И ГЛАВАМ 1-11 Здесь указаны все источники для части 1 кроме алгоритмов из ACM, ко- тс«рые приведены в Приложении А. 1. Applebaum F. Н. Variable Word Sorting in RCA 501 System. — Asso¬ ciation for Computing Machinery 14th National Meeting (1959). 2. Bayes A. A Generalized Partial-Pass Block Sort. — Comm. ACM 11, 7, 491—493. 3. В e 1 1 D. A. The Principles of Sorting. — Computer J. 1 (1959), 71—77. See also Computer J. 10 (1968), 123; 1 (1959), 171. 4. Burge W. H. Sorting, Trees, and Measures of Order. — Inform. Contr. 1 (1958), 181—197. 5. Feerst S. and F. Sherwood. The Effect of Simultaneity on Sorting Operations. — Paper 42, Association for Computing Machinery 14th National Meeting (1959). 6. Flores I. Computer Time for Address Calculation Sorting. — Journal ACM 7, 389—409. 7. Flores I. Analysis of Internal Computer Sorting. — Journal ACM 8 (1961), 41—80. 8. Frazer W. D. and С. K. Wong. Sorting by Natural Selection. — Comm. ACM 15, 10, 910—912. 9. F г a z e г W. D. and А. С. M с К e 11 a r. Samplesort — A Sampling Approach to Minimal Storage in All Sorting. — Journal ACM 17, 3, 496—507. 10. Frank R. M. and R. B. Lazarus. A High-Speed Sorting Procedure.— Comm. ACM 3, 1, 20—23. И Gotlieb С. C. Sorting on Computers. — Comm. ACM 6, 5, 194—201. 12. H a 11 М. M. A Method of Comparing the Time Requirements of Sorting Methods. — Comm. ACM 6, 5, 259—263 13. Hibbard T. Some Combinatorial Properties of Certain Trees with Applica¬ tion to Searching and Sorting. — Journal ACM (1962), 13—28. 14. Hibbard T. N. An Empirical Study of Minimal-Storage Sorting. — Comm. ACM 6, 5, 206—213. !&• Hi lde brant P. and H. I s b i t z. Radix Exchange — An Internal Sorting Method for Digital Computers. — Journal ACM 6, 156—163. 13. Hoare C. A. R. Quicksort. — Computer J. 5 (1962), 10—15. ['• Hosken J. C. Evaluation of Sorting Methods. — Proceedings EJCC, 1955. 13. IBM Corporation, Sorting Techniques. — C20—1639 (1965). lQ- Isaac Ё. J. and R. C. Singleton. Sorting by Address Calculation.— 9 Journal ACM 3 (1956), 169—174. Jones B. A Variation on Sorting by Address Calculation.—Comm. ACM 13, 2, 105—107. i- Knuth D. E. The Art of Computer Programming; Volume 3, Sorting and Searching. — Reading, Mass.: Addison*Wesley, 1973. И Г. Лорин
322 ЛИТЕРАТУРА 22. Kronmal R. and M. Tarter. Cumulative Polygon Address-Calculation Sorting. — ACM 20th National Conference (1965), 376—385. 23. Lorin H. A Guided Bibliography to Sorting. — IBM Systems Journal Ю 3, 244—254. 24. Maclaren M. D. Radix Exchange Plus Sifting. — Journal ACM 13, 404- 411. 25. Martin W. A. Sorting. — ACM Computing Surveys, 3, 4, 147—174. 26. Nagle r H. Amphisbaenic Sorting. — Journal ACM 6, 4, 459—468. 27. Shell D. L. A High-Speed Sorting Procedure. — Comm. ACM 2, 7, 30—33 28. Van Emden М. H. Increasing the Efficiency of Quicksort. — Comm. ACM 13, 9, 563—567. 29. Wind ley P. F. Trees, Forests and Rearranging. — Computer J. (1960) 84—88. 30. Woo drum L. J. Internal Sorting with Minimal Comparing. — IBM Sy¬ stems Journal 8, 3, 189—203. Часть 2. ВНЕШНЯЯ СОРТИРОВКА ИСТОЧНИКИ И ДОПОЛНИТЕЛЬНАЯ ЛИТЕРАТУРА К ГЛАВАМ 12—18 1. Bennett В. Т. and W. D. Frazer, Approximating Optimal Direct-Access Merge Performance. — Proceedings of the IFIP Congress 1971, Vol. 1, 450— 453. 2. Betz D. K. and W. C. Carter. New Merge Sorting Techniques. — Pro¬ ceedings ACM, 14th National Conference (1959). 3. Black N. A. Optimum Merging from Mass Storage. — Comm. ACM 13, 12, 745—749. 4. Buhagiar J. and A. J 0 n s A Scan Sort Using Magnetic Tape Units.— Computer Bulletin 12, 1, 11—13. 5 Burge W. H. Analysis of Compromise Merge Sort Techniques. — Proceed¬ ings of the IFIP Congress 1971, Vol. 1, 454—459. 6. Cooke W. S. A Tape File Merge Pattern Generator. — Comm. ACM 6, 5, 227—230. 7. Dinsmore R. J. Longer Strings from Sorting. — Comm. ACM 8, 1, 48. 8. Edwards L. G. Flexible Replacement Presorting, ACM Sort Symposium, November 1962. 9. F a 1 k i n J. and S. S a v a s t a n 0, Jr. Sorting with Large-Volume, Random- Access, Drum Storage. — Comm. ACM 6, 5, 240—244. 10. F e r g u s 0 n D. E. More on Merging (letter to editor). — Comm. ACM 7, 4, 297. 11. Ferguson D. E. Buffer Allocation in Merge Sorting. — Comm. ACM H 7, 476—478. 12 Frazer W. D. and В. T. Bennett. Bounds on Optimal Merge Perform¬ ance and a Strategy for Optimality. — Journal ACM 19, 4, 641—648. 13 French N. C. Computer Planned Collates. — Comm. ACM 6, 5, 225—220. 14. Friend E. H., Sorting on Electronic Computer Systems. — Journal ACM 3 (1956), 134—168. 15 Oassner B. J. Sorting by Replacement Selecting. — Comm. ACM Ю, 2, 89—93. 16. Gilstad R. L. Polyphase Merge Sorting — An Advanced Technique.-' Proceedings EJCC, Vol. 18, December 1960, 143—148. r 17. Gilstad R. L. Read-Backward Polyphase Sorting. — Comm. ACM 6, 220—223. 18. G licks man S. Concerning the Merging of Equal-Length Tape Fil-'s- Journal ACM 12, 254—258. 19. Goetz M. A. Organization and Structure of Data on Disc-File Systems for Efficient Sorting and Other Data Processing Programs. — ^1 Sort Symposium, November 1962.
ЛИТЕРАТУРА 323 on Goetz М. A. Internal and Таре Sorting using the Replacement-Selection Technique. — Comm. ACM 6, 5, 201—206. 21. Goetz M. A. and G. S. Toth. A Comparison Between the Polyphase and Oscillating Sort Techniques. — Comm. ACM 6, 5, 223—225. 22. Goetz M. A. Design and Characteiistics of a Variable-Length Record Sort using New Fixed-Length Record Sort Techniques. — Comm. ACM 6, 5, 264— 267. 23 Goetz M. A. Three Letters on Merging (II) (letter to editor). — Comm. ACM 6, 10, 586. 24 Goetz M. A. More on Sorting Techniques (letter to editor). — Comm. ACM ’ 7, 6, 379—380. 25 Goetz M. A. Some Improvements in the Technology of String Merging and Internal Sorting. — AFIPS SJCC 25 (1964), 599—607. 26. Hooker W. W. On the Expected Lengths of Sequences Generated in Sort¬ ing by Replacement Selection — Comm. ACM 12, 7, 411—413. 27. H u b b a r d G. V. Some Characteristics of Sorting in Computing Systems using Random-Access Storage Devices. — Comm. ACM 6, 5, 248—255. 28. J о h n s e n T. L. Efficiency of the Polyphase Merge and a Related Me¬ thod.—BIT 6 (1966), 129—143. 29. Knuth D. E. Length of Strings for a Merge Sort. — Comm. ACM 6, 11, 685—688. 30. К n u t h D. E. Three Letters on Merging (I, III) (letter to editor).— Comm. ACM 6, 10, 585. 31. L о r i n H., A. Silver stein and M. Smith. — A. Report on Sorting. Sperry Rand Corporation, 1963. 32. Malcolm W. D. Jr. String Distribution for the Polyphase Sort.— Comm. ACM 6, 5, 217—220. 33. Manker H. H. Multiphase Sorting. — Comm. ACM 6, 5, 214—217. 34. McAllester R. L. Polyphase Sorting with Overlapped Rewind.— Comm. ACM 7, 3, 158—159. 35 M e n d о z a A. G. A Dispersion Pass Algorithm for the Polyphase Merge.— Comm. ACM 5, 10, 502—504. 36. Radke С. E. Merge Sort Analysis by Matrix Techniques. — IBM Systems Journal 5, 4, 226—247. 37. Reynolds S. W. A Generalized Polyphase Merge Algorithm. — Comm. ACM 4, 8, 347—349; Addendum, 495 38. Sackman B. S. and T. Singer. A Vector Model for Merge Sort Ana¬ lysis.— ACM Sort Symposium, November 1962. 39. Schick T. Disk-File Sorting. — Comm. ACM 6, 6, 330—331. 40. Shell D. L. Optimizing the Polyphase Sort. — Comm. ACM 14, 11, 713— 719. 41. S о b e 1 S. Oscillating Sort — A New Sort Merging Technique. — Journal ACM 9, 372—374. 42 Wind ley P. F. The Influence of Storage Access Time on Merging Pro¬ cesses in a Computer. — Computer J. 2, 2, 49—53. 43. W о о d r u m L. J. Model of Floating Buffering. — IBM Systems Journal 9, 2, 118. Часть 3. СОРТИРУЮЩИЕ СИСТЕМЫ ИСТОЧНИКИ И ДОПОЛНИТЕЛЬНАЯ ЛИТЕРАТУРА К ГЛАВАМ 19-20 Batcher К. Е. Sorting Networks and Their Applications. — AFIPS SJCC Vol. 32 (1968), 307—314. ^95US ^ ^ ^S6 *n^orma^on in Porting. — Journal ACM 17, 482— 11*
324 ЛИТЕРАТУРА 3. Bose R. С. and R. J. Nelson. A Sorting Problem. — JACM 9, 2 28o 296. ’ ~ 4. В raw m B. D., F. G. Gustavson and E. S. Mankin. Sorting in , Paging Environment. — Comm. ACM 13, 8, 483—494. 4 5. Control Data Corp.— 3400 Computer System, Sort/Merge Reference Manual 6. De Fiore C. R. Fast Sorting. — Datamation 16, 8, 47—51. 7. Fa lk man H. H. Sort/Merge — Its Facilities and Method of Operation.^ Presentation to Guide Utilities Committee, Session P15 and P26, 27 1971. y 8« Floyd R. W. and D. E. Knuth. Improved Constructions for the Bcse-^ Nelson Sorting Problem. — Notices American Mathematics Society 14 (1967) 283. 9. F1 о у d R. W. and D. E. Knuth. The Bose — Nelson Sorting Problem Stanford Computer Science Memo, STAN — CS — 70— 177, November 197o! 10. Foster С. C. Sorting Almost Ordered Arrays. — Computer J. 11, 134—!37’ 11. Glore J. B. Sorting Nonredundant Files — Techniques Used in the FACT Compiler. — Comm. ACM 6, 5, 231—249. 12. Hibbard T. N. A Simple Sorting Algorithm. — JACM 10, 2, 142—150. 13 Johnson L. R. and R. D. Pratt. An Introduction [0 the Complete UNIVAC II Sort — Merge System SESAME. — UNIVAC Rev ew, Fall iЭ58 14 IBM. IBM System/360 OS Sort/Merge. — GC28—6543. 15 IBM. IBM System/360 OS Sort/Merge Tirmng Estimates. — GC33—4008. 16. IBM. Sorting Methods for IBM Data Processing Systems. — F28—800i (1958). 17. Paterson J. B. The COBOL Sort Verb. — Comm. ACM 6, 5 255—258 18. Pratt R. D. The Sort Program for the UNIVAC III Data Processing System. — ACM Sort Symposium, 1962. 19. Sperry Rand Corp. Sort III. — UNIVAC III General Reference Manual, U3518. 20 Sperry Rand Corp. Sort/Merge I. — UNIVAC 1107 General Reference Ma¬ nual, UP-3959. 21 Sperry Rand Corp. Sort/Merge Program Programiner’s Reference.— UNIVAC 1107 Technical Bulletin, UT 2576. 22. Sperry Rand Corp. Sort/Merge. — UNIVAC 490 Real-Time System Technical Bulletin, UP—3809. 23. Sperry Rand Corp. UNIVAC File Computer Sort —Collate System.— U1489B8. 24. V a n V о 0 r h i s D. C. Efficient Sorting Networks, (author’s thesis). — Stan* ford University: University Microfilms, 72—16282, 1972,
Приложение А ПРОЦЕДУРЫ СОРТИРОВКИ ИЗ АЛГОРИТМОВ САСМ Нижеследующие алгоритмы и связанные с ними обсуждения и замечания перепечатаны с разрешения Communications of the ACM, Copyright 1960—1971, Association for Computing Machinery, Inc. *) АЛГОРИТМЫ, ИХ АПРОБАЦИЯ И ТЕСТЫ Алгоритм 23 MATHSORT У. Фойрциг (Wallace Feurzeig) **) procedure MATHSORT (INVEC, OUTVEC, TOTEVEC, n, k, SETFUNC); value n, k; array INVEC, OUTVEC; integer array TOTEVEC; integer procedure SETFUNC; integer n, k; fjeign comment MATHSORT — это быстрый сортирующий алгоритм, который неожиданным, хотя и хорошо знакомым способом производит монотонную перестановку набора произвольно расположенных п чисел (представлен¬ ных вектором invec). Отсортированное множество представлено вектором outvec. Поле ключа, т. е. упорядоченный набор битов (или байтов), кото¬ рый подлежит сортировке, получают при помощи некоторой функции вы¬ деления setounc. Поле ключа допускает к возможных значений 0, 1, ... ..., к — 1. Прежде всего эта процедура определяет распределение частоты встре¬ чаемости ключей в заданном множестве, т. е. число элементов в invec со значением ключа равным j для всех j от 0 до к — 1. Для 0 ^ j ^ к — 1 вычисляется значение эмпирической функции распределения totvec [i] =, j = 2 (число элементов в invec со значением ключа =j). Это индуци- i = 0 рует непосредственное соответствие (функцию отображения памяти) каж¬ дого элемента invec единственной координате outvec. Таким образом, этот алгоритм требует только 2п операций «просмотреть и выполнить» плюс к—1 сложение (чтобы получить распределение частоты встречаемости). Этот алгоритм может быть легко и эффективно распространен на случай сортировки символов или составных ключей. Для того чтобы сор¬ тировать по другому ключу, надо этот же алгоритм применить к новому полю ключа с новым invec, полученным при последнем индуцированном упорядочении (т. е. текущем outvec). Этот алгоритм интенсивно исполь¬ *) Следуя автору, мы не стали вводить единообразия в написании алго¬ ритмов, а оставили их в том виде, в каком они были даны в САСМ. {Прим, пере в.) **) Comm. ACM, Nov. 1960.
326 ПРИЛОЖЕНИЕ А зуется в LAS *) на разных машинах как для внутренних сортировок, так- и для больших сортировок на лентах; for i := 1 step 1 until n do TOTEVEC [SETFUNC (INVEC [i] )] := TOTEVEC [SETFUNC(INVEC [i] )] + 1; for i := 1 step 1 until k — 1 do TOTEVEC [i] := TOTEVEC [i] + TOTEVEC [i - 1]; for i := 1 step 1 until n do begin OUTVEC [TOTEVEC [SETFUNC (INVEC [i])]] := IN VEC [ i]; TOTEVEC [SETFUNC (INVEC [i] )] : = TOTEVEC [SETFUNC (INVEC [i] )] - 1; end end MATHSORT. Апробация алгоритма 23 MATHSORT P. Рэншоу (Russell W. Ranshaw). Процедура mathsort в том виде, как она была опубликована, была зако¬ дирована на фортране на IBM/7070. Было выявлено два недостатка: 1. Массив totvec не очищается в процедуре. Это приводит к ошибкам при повторном использовании процедуры. 2. Входные вектора, уже отсортированные по одному полю, при сорти¬ ровке по несортированным полям оказывались неотсортированными. Напри¬ мер, для последовательности 31, 21, 32, 22, 33 mathsort — построила бы при сортировке цифр десятков 22, 21, 33, 32, 31, что, очевидно, является неотсортированной последовательностью. В следующей модификации этой процедуры указанные недостатки устра- нены. Обратите внимание на превращение символов, procedure MATHSORT (I,0,T,n,k, S); value n,k; array 1,0; integer array T; integer procedure S; integer n,k; begin for i := 0 step 1 until k — 1 do T [i] := 0; for i := 1 step 1 until n do T [S (I [i] )] := T [S (I [i] )] + 1; for i := k — 2 step —1 until 0 do T [i] := T [i] + T [i + П; for i := 1 step 1 until n do begin О [n + 1 — T [S (I [i] )]] := I [i]* T [S (I [i] )] := T [S (I [i])] - 1; end end MATHSORT. При десятикратном применении процедуры mathsort, использующей пр°' цедуру S, выделяющую цифры по порядку, 1000 случайных чисел из 10 цифр каждое были отсортированы за 31 с. Метод обнаружения наименьшего эле¬ мента, обмена с первым элементом и так до тех пор, пока не просмотрен весь список, для полной сортировки тех же самых 1000 случайных чисел занял 227 с. Использование команды Table-Lookup-Lowest на IBM/7070 даеТ 56 с для того же самого набора случайных чисел. *) LAS — Laboritories for Applied Science.— {Прим. перев.)
ПРИЛОЖЕНИЕ А 327 Алгоритм 63 PARTITION Ч. Хоар (С. A. R. Ноаге) *) procedure partition (A,M,N,I,J); value M,N; array A; integer M,N,I,J; comment I и J — выходные переменные, A — массив (с границами индекса M:N), с которым работает эта процедура. Процедура partition берет значение X случайного элемента массива А и переставляет элементы этого массива так, чтобы существовали целые I и J такие, что М ^ J < I ^ N при условии М < N' A[R]<X для M<R<J A [R] = X для J < R < I A[R]>X для I<R<N. Эта процедура использует целочисленную процедуру random (М, N), которая с одинаковой вероятностью выбирает произвольное целое F ме¬ жду М и N, а также процедуру exchange, которая меняет значения двух ее параметров; begin real X; integer F; F := random (M,N); X := A [F]; I :=M; J:=N; up: for I : = I step 1 until N do if X < A [I] then go to down; I : = N; down: for J := J step —1 until M do if A [J] < X then go to change; J := M; change: if I < J then begin exchange (A [I], A [J] ); I :=I + 1; J : = J — 1; go to up end •else if I < F then begin exchange (A [I], A [F] ); I :== I + 1 end «lse if F < J then begin exchange (A [F], A [J] ); J : = J — 1 end; «id partition Алгоритм 64 QUICKSORT («быстрая сортировка») Ч. Хоар (С. A. R. Ноаге) *) procedure quicksort (A,A'1,N): value M,N; array A; integer M,N; comment quicksort — очень быстрый и удобный метод сортировки массивов в памяти с произвольным доступом. Сортировать можно содержимое всей памяти целиком, так как дополнительного пространства не надо. Сред¬ нее число сравнений равно 2(N — M)ln(N — М), а среднее число обменов равно 1/6 числа сравнений. При реализации этого метода на конкретной машине его желательно модифицировать надлежащим образом; ®egin integer I,J: if M<N then begin partition (A,M,N,I,J); quicksort (A,M,J); quicksort (A,I,N) end *nd quicksort *) Comm. ACM, July 1961.
328 ПРИЛОЖЕНИЕ А Алгоритм 65 FIND Ч. Хоар (С. A. R. Ноаге) *) procedure find (A,M,N,K); value M,N,K; array A; integer M,N,K; comment Процедура find присваивает элементу A[K1 значение, которое он имел бы, если бы массив A[M:N1 уже был отсортирован. Массив А бу¬ дет сортироваться частично, и последующие обращения к процедуре бу¬ дут происходить “быстрее чем первое; begin integer I,J; if M < N then begin partition (A,M,N,I,J); if К ^ I then find (A,M,I,K) else if J^K then find (A,J,N,K) end end find Апробация алгоритмов 63, 64, 65 Дж. Гиллмор (J. S. Hillmore) Тело процедуры find было исправлено следующим образом: begin integer /,/; if М < N then begin partition (A,M,N,/,/); if К ^ / then find (AyMtJ,K) else if / ^ К then find (A,I,N,K) end end find Затем это трио процедур было успешно испробовано с использованием транслятора с алгола для National — Elliott 803. Оценка автора—1/3 {N — M)ln(N— М) — число обменов, необходимых для сортировки случайного набора, подтвердилась. Однако число сравнений, вообще говоря, меньше, чем 2(N — M)\n(N — М) даже без указанных ниже изменений. Эффективность процедуры quicksort была повышена путем следующих изменений тела процедуры: begin integer /,/: if M<N — 1 then begin partition (A,M,N,/,/); quicksort (AyMyJ)\ quicksort (A,I, N) end else if N — M = 1 then begin if A [A] < A [M] then exchange (A [Af], A [A] ) end end quicksort Это изменение сократило число сравнений, включаемых в сортировку па- бора случайных чисел на 4—5% и число обращений к процедуре partition па 25-30%. Апробация алгоритмов 63, 64, 65 PARTITION, QUICKSORT, FIND Б. Рэнделл и Л. Расселл (В. Randell, L. J. Russell). Алгоритмы 63, 64 и 65 были проверены с помощью компилятора с алго¬ ла-60'Pegasus, который был создан в De Havilland Aircraft Comp. Ltd., Hat¬ field, England. *) Comm. ACM, July 1961.
ПРИЛОЖЕНИЕ А 329 Алгоритмы 63 и 64 (partition и quicksort) работали удовлетворительно и никаких изменений не потребовали. Однако замечание о том, что quicksort будет сортировать массив, не требуя дополнительной памяти, неверно, так как память нужна для организации последовательности рекурсивных обра¬ щений к процедуре, или если не использовать рекурсивных процедур, то для хранения информации о развитии процесса разделения на части и сортировки. Опечатка (‘if’ вместо ‘if’ в строке ‘else if J ^ К then...’) в алгоритме 65 была исправлена, однако было обнаружено, что в некоторых случаях после¬ довательность рекурсивных обращений к find не оканчивается успешно. По¬ скольку partition создает на выходе такие две целые величины / и /, что эле¬ менты массива A[M:N], лежащие между A[J] и А [У], занимают те позиции, которые они будут занимать по окончании сортировки этого массива, то сле¬ дует прекратить рекурсивные обращения к find, если выполнено условие J < К <. I. Таким образом, условный оператор в теле find принимает такой вид- if /С</ then find (A,M,J,K) else if /</С then find (A,I ,N ,K) С такими изменениями эта процедура работает удовлетворительно. Алгоритм 113 TREESORT («Сортировка по дереву») Роберт Флойд (Robert W. Floyd) procedure TREESORT (UNSORTED, n, SORTED, k)\ value n, k; integer n, k; array UNSORTED, SORTED; comment Treesort сортирует наименьшие k элементов я-компонентного массива unsorted в 6-компонентный массив sorted (эти два массива могут совпа¬ дать). Число операций примерно равно 2 X п + 6 log2(rc). Требуемое чис¬ ло вспомогательных ячеек памяти равно примерно 2 X п. Предполагается, что есть процедуры для нахождения минимума из двух величин, упа¬ ковки одного вещественного числа и одного целого в одно слово, и по¬ лучения левой и правой половины упакованного слова. Считается, что значение infinity больше любого элемента из unsorted; begin integer i, /; array m [1 :2X« - 1]; for i := 1 step 1 until n do m [n + i — 1] := pack (UNSORTED [/], n + i — 1); for i := n — \ step — 1 until 1 do m [/] := minimum (m [2 X 0» m [2X/ + l]); for / := 1 step 1 until k do begin SORTED [/] := left half (m [1]); i := right half (m [1]); m [i] := infinity; for i := / -т-2 while i > 0 do m [/] := minimum (m [2 X *’]> л*’[2 X / + 1] ) end <nd TREESORT Алгоритм 143 TREESORT 1 А. Кауп младший (Arthur F. Каире, Jr.) procedure TREESORT 1 (UNSORTED, n, SORTED, k): value n, k; integer n, k\ array UNSORTED, SORTED; •comment Treesort 1—это модификация treesort (алгоритм 113), которая не требует ни «упакованного» массива т, ни машинных процедур pack, left half, right half и minimum. Идентификатор infinity используется как
330 ПРИЛОЖЕНИЕ А нелокальная переменная типа real, значения которой больше любого эле¬ мента из unsorted; begin integer i, /; array ml [1 : 2 X n — 1]; integer array m2 [1 :2X л - 1]; procedure minimum; if ml [2 X i] ^ tn\ [2 X i + 1] then begin ml [г] := ml [2 X i]\ m2 [/] •= m2 [2 X i] end else begin ml [/] := ml [2 X * + 1]; m2 [/] := m2 [2 X i + 1] end minimum; for i := n step 1 until 2X^—1 do begin ml [г] := UNSORTED [i — n + 1]; m2 [/] := i end for i:=n— 1 step —1 until 1 do minimum; for / := 1 step 1 until k do begin SORTED [/']:= ml [1]; /:=m2[l]; ml [/] := infinity; for i := i -г- 2 while />0 do minimum end end TREESORT 1 Алгоритм 114 TREESORT 2 А. Кауп младший (Arthur F. Каире, Jr.) procedure TREESORT 2 (U NSORTED, n, SORTED; /г, ordered)', value /г, /г; integer n, k\ array UNSORTED, SORTED; Boolean procedure ordered; comment TREESORT 2 — это универсальная версия TREESORT 1. Boolean’ procedure ordered должна иметь два аргумента типа real. Массив sorted будет обладать свойством: ordered (SORTED [t], SORTED [у]) равно true при / > i, если ordered есть отношение линейной упорядоченности: begin integer i, у; array ml [1 : 2 X n— 1]; integer array m2 [ 1 : 2 X n — П* procedure minimum; if ordered (ml [2 X *’]> ml [2 X г + 1]) then begin ml [/] := ml [2 X **]; m2 [/] := m2 [2 X i] end else begin ml [/] := ml [2X^+1]; m2 [/| := m2 [2X^+1] enc* minimum', for i:=n step 1 until 2X^-1 do b^gin ml [/] := UN SORTED [i — n + 1]; m2 [/] := i end for i:=n— 1 step —1 until 1 do minimum’, for / := 1 step 1 until k do begin SORTED [/] := ml [1]; i := m2 [1]; ml [i] := infinity) for i:= i -r- 2 while / > 0 do minimum end end TREESORT 2 Алгоритм 175 SHUTTLE SORT («Челночная сортировка») Ч. Шоу, Т. Трапмбл (С. J. Shaw, Т. N. Trimble) *) procedure shuttle sort (m, Temporary, N); value m; integer m; array N [I : m]; comment Эта процедура упорядочивает список чисел с N[ 1] по N[m] по воз¬ растанию, попарно переставляя числа, стоящие «не по порядку». Про¬ цедура проста, в качестве дополнительной памяти требует только пере¬ менную Temporary, и достаточно быстра для коротких списков (например» из 25 чисел), а также вполне пригодна для немного больших списков- (например, из 100 чисел). Для еще больших списков более быстрыми ока- *) Comm. ACM, June 1963.
ПРИЛОЖЕНИЕ А 331 зываются все же другие методы. Фактические параметры, соответствую¬ щие Temporary и N, должны быть одного типа; rfcegin integer i, /; for i := 1 step 1 until m — 1 do begin for / := i step —1 until 1 do begin if N{j]^N[j+\] then go to Test; Exchange: Temporary := N [/]; N [j] := N [j + \]\ N Ц + 1] •'= Temporary; end of / loop; Jest: end of i loop end shuttle sort Апробация алгоритма 175 SHUTTLE SORT Дж. Шуберт (George G. Schubert) Алгоритм 175 был оттранслирован на Balgol и успешно пропущен на Burroughs 220. Получены следующие фактические продолжительности сорти¬ ровки: Число элементов Среднее время, с 25 1.6 50 6.2 100 25.8 250 181 500 684 Этот алгоритм можно расширить так, что сортировка будет выполняться ■на одном массиве, сохраняя в то же время соответствие один к одному с дру¬ гим массивом. Для этого непосредственно перед end цикла / следует вставить: Temporary : = У [/]; У [у] : = У [/+ 1]; У[/ + 1] := Temporary; где Y[k] —элемент, соответствующий N[k], Очевидно, возможны другие мо¬ дификации. Замечание к алгоритму 175 SHUTTLE SORT О. Джулич (О. С. Juelich). Авторы этого алгоритма поступают совершенно верно, напоминая чита¬ телю, что shuttle sort неэффективная процедура, за исключением списков на¬ столько коротких, что они не оправдывают накладные расходы, присущие использованию обычных подпрограмм сортировки. В опубликованном виде алгоритм не свободен от ошибок. Оператор for у := i step —1 until 1 do ■следует заменить либо на for у := т — 1 step — 1 until i do либо на for j :=1 step 1 until m — i do В первом случае можно проследить, как этот процесс помещает на место *-й наименьший элемент на i-м просмотре; в последнем случае на i-м про¬ смотре на место помещается i-й наибольший элемент. Метка Test должна предшествовать ограничителю «end цикла по у», а не «end цикла по i». Алгоритм можно слегка ускорить, если переписать тело процедуры так: begin integer i, /, / max; i: = m — 1; loop: j max := 1; for / := 1 step 1 until i do
332 ПРИЛОЖЕНИЕ А begin compare: if N [j] > N [j + 1] then begin Exchange: Temporary := N [/']; N[j]:=Nlj+ 1]; N [j + 1] := Temporary; / max := / end Exchange; end of / loop; / := / majr, if / > 1 then go to loop; end shuttle sort При измененном теле процедуры не будет избыточных итераций, которые мо¬ гут возникнуть, если данные уже упорядочены. В такой форме алгоритм был изучен Р. Бойеллом (R. L. Boyell) и авто¬ ром этих строк на Ordvac в Лабораториях баллистики (Абердин) в 1955 г. Для случайно упорядоченных данных можно ожидать, что цикл по i будет выполнен т — л/т раз. Замечания к алгоритму 175 SHUTTLE SORT О. Джулич (Otto С. Juelich). Апробация, сделанная Шубертом, заставила меня вновь изучить этот ал¬ горитм. То, что я предложил в отношении изменения порядка выполнения сравнений, оказалось неверным. Это изменение влияет на эффективность алго¬ ритма незначительно, так как число выполнений оператора с меткой Exchange остается тем же самым. Алгоритм 201 SHELLSORT («Сортировка Шелла») Дж. Бутройд (J. Boothroyd) *) procedure Shellsort (а, /г); value п; real array a; integer п comment Элементы с а [и по а[п] массива а[\ : п] упорядочиваются в пп- рядке возрастания. Этот метод предложен Д. Шеллом (A high-speed sorting procedure, Comm. АСДА 2 (1959), 30—32), причем подпоследова¬ тельности выбираются так, как предложил Т. Хиббард (An empirical study of minimal storage sorting, SDC Report SP—982). Подпоследовательности зависят от mi — первого рабочего значения т. В данном случае mt = = 2k— 1 для 2k ^ п ^ 2k+l. Для реализации выбора т4 по Шеллу — т\ = [я/21— надо заменить первый оператор на т: = п\ begin integer /, /, k, m; real w; for / := 1 step i until n do m := 2 X i — 1; for m := m -f* 2 while m Ф 0 do begin k := n — m: for j := 1 step 1 until k do begin for i'=i step — m until 1 do begin if a [I + m] ^ a [/] then go to 1; w := a [/]; a [i] := a [i + m]; a [i + m] := до; end /; 1:end j end m end Shellsort; *) Comm. ACM 6 (Aug. 1963), p. 445.
ПРИЛОЖЕНИЕ А 333 Апробация алгоритма 201 SHELLSORT М. Бэтти (М. A. Batty) Этот алгоритм был успешно проверен с помощью компилятора с алгола Рейсе. Когда первый оператор алгоритма был заменен на оператор т:=п для реализации выбора по Шеллу mi := /г/2, наблюдалось небольшое увели¬ чение продолжительности сортировки в большинстве проверяемых случаев. Замечание к алгоритму 201 SHELLSORT Дж. Чендлер и У. Харрисон (J. P. Chandler, W С. Harrison) Хиббард *) закодировал свой метод так, что скорость существенно увели¬ чилась. В shellsort каждый этап каждого просеивания состоит из последова¬ тельных обменов. В модификации каждые п пар обменов заменены на одно «запоминание», п — 1 перемещение и одну вставку. В табл. А1 приведены продолжительности работы версий shellsort на ал¬ голе, фортране и compass (язык ассемблера) и модифицированной версии (названной shellsort 2) для CDC 6400. Экономия времени, достигнутая моди¬ фикацией, составила 32%, 17% и 21% соответственно. Экономия получается больше, если сортируются векторы, состоящие более чем из одного слова. Довольно интересно сравнить продолжительности исполнения алгольной и фортранной версий для оценки этих компиляторов. Таблица А1 Время сортировки (в секундах) 10 000 случайно упорядоченных чисел на CDC 6400 Алгоритм Язык алгол фортран compass SHELLSORT 53.40 7.18 2.38 SHELLSORT 2 36.56 5.98 1.87 Литература: 1. Hibbard Т. N. An empirical study of minimal storage sorting, Comm, ACM 6 (May 1963), 206. Алгоритм 207 STRINGSORT (Сортировка строк) Дж. Бутройд (J. Boothroyd) **) procedure stringsort (a, n)\ comment элементы a[ 1 ], ..., a[ri\ из a[\\2n\ сортируются в возрастающую последовательность, используя af/z+l]... ... ci[2ri\ как вспомогательную память. Для слияния входных строк с обоих концов исходной зоны в строки вывода, которые поочередно на¬ правляются на оба конца принимающей зоны, используется обобщенная логика строк фон Неймана. Эта процедура использует естественно возни¬ кающее возрастающее или убывающее упорядочение в исходных данных; value п\ integer п; array а\ begin integer d, i, j, m, u, v, z\ integer array c[ — 1 : 1]; switch p := jz 1, str i\ switch q := merge, jz2\ oddpass: / := 1; / := n; с [ — 1] := n + 1; с [1] := 2 X n\ allpass: d := 1; go to firststring; merge: i? a [i] ^ a [z] *) Hibbard T. N. An empirical study of minimal storage sorting.— Comm. ACM 6 (Mav 1963), 206. **) Comm. ACM 6 (Oct. 1963), p. 615.
334 ПРИЛОЖЕНИЕ А then begin go to p [u]; /г1: if a [j] ^ a [z] then ij: begin if a [/] ^ a [/] then str j: begin a [m] := a [/]; j := j — 1 end else str i: begin a [m] := a [/]; i := i + 1 end end else begin v:=2; go to str i end end else begin и := 2: jz2: if a [/] ^ a [z] then go to str j else begin d := — d; c[cf]:=m; firststring: m:=c[— d\\ v := и := 1; go to ij end end; z := m\ m\— m + d; if j ^ i then go to q [«J; if m > n + 1 then begin comment evenpass; i n-f 1; / := 2 X n\ с [ — 1J := 1; c[\]\=n\ goto allpass end else if m < n + 1 then go to oddpass end stringsort; Апробация алгоритма 207 STRINGSORT Чарльз Блэйр (Charles R. Blair) Stringsort была оттранслирована и успешно пропущена на CDC 1604А с помощью транслятора Aldap. При этом были получены следующие продол¬ жительности сортировки. Число элементов Время в секундах 10 0.03 20 0.05 50 0.20 100 0.38 200 1.03 500 3.22 1 000 6.43 2 000 12.85 5 000 38.72 10 000 90.72 Алгоритм 232 HEAPSORT («Сортировка кучи») Дж. Уильямс (J. W. J. Williams) comment Нижеследующие процедуры связаны с treesort (см. алгоритмы 113> 143, 144), но не используют указателей и гем самым экономят память. Все процедуры работают с однословными элементами, сортируя элементы с 1 по п массива А. Элементы обычно расставляются так, что A\i]^A[j] для 2 ^ ^ пу i = j-т-2. Такую расстановку назовем кучей. А[1]—все¬ гда самый последний элемент кучи.
ПРИЛОЖЕНИЕ А 33^ Процедура setheap расставляет п элементов в виде кучи, inheap до¬ бавляет новый элемент в существующую кучу, outheap удаляет из кучи последний элемент, a swopheap есть фактически результат outheap, сле¬ дующий за inheap. В любом случае массив А содержит элементы, рас¬ ставленные в виде кучи. Swopheap по существу является тем же, что и турнирная сортировка, описанная Айверсоном*), которая является методом «сверху вниз», но использует улучшенное распределение памяти и настройку. Inheap схожа с treesort тем, что также использует метод «снизу вверх». Таким образом, heapsort можно рассматривать как объединение этих двух методов. Процедуры можно использовать для сортировки выбором с заменой, для сортировки элементов массива или для выбора минимума в наборе элементов, в который время от времени добавляются новые элементы. Эти процедуры очень полезны, потому что сохраняют активные элементы массива плотно упакованными в виде элементов с А[1] по А [п]; procedure SWOPHEAP (А,п,in,out); value in,/г; integer п; real in,out; real array A; comment Для swopheap задается массив А, элементы которого cA[l] по A [n\ образуют кучу, и п ^ 0. Swopheap добавляет элемент in в кучу, изымает из нее и присваивает переменной out значение наименьшего чле¬ на результирующего множества, причем остальные элементы образуют кучу исходного размера. В этом процессе элементы массива А с 1 по п + 1 могут быть перемешаны. Максимальное число повторений цикла с меткой scan равно log2 п; begin integer i,j; real temp, temp 1; it in ^ A [I] then out := in else begin i := 1; A [n + 1 ] := in; comment Этот последний оператор необходим только в случае j = п или п = 0; out := А [1]; scan: j := i + i; if j n then begin temp := A [/]; temp 1 := A [j + 1]; if temp 1 < temp then begin temp := temp 1; /:=/+! end; if temp < in then begin A [/] := temp; • / := /; go to scan end end; A [/] := in end end SWOPHEAP; *) I verson К. E. A Programming Language, 1962, p. 223—226.
336 ПРИЛОЖЕНИЕ А procedure INHEAP value in\ integer n: real in\ real array Л; comment Для inheap задается массив Л, элементы которого с Л [11 По А[п] образуют кучу, и п ^ 0. Inheap добавляет элемент in в кучу и со¬ ответственно корректирует п. Цикл, помеченный scan, может быть повто¬ рен log2 п раз, но в среднем повторяется лишь дважды; begin integer /,/; i ;= п := п + 1; scan: if i > 1 then begin /:=/-=- 2; if in < A [/] then begin A [/] := A [/]; go to scan end end; A [/] := in end INHEAP; procedure OUTHEAP (Atn,out); integer n\ real out; real array Л; comment Для outheap задан массив Л, элементы с 1 по п которого обра-; зуют кучу, п ^ 1, outheap присваивает out значение Л[1] наименьшего члена кучи, и переставляет остальные члены, как элементы Л от 1 до п— 1. При этом п соответственно корректируется; begin SWOPHEAP (Л,п- 1, A[n]9out)\ п:= п — 1 end OUTHEAP; procedure SET НЕ АР (А,п)\ value n\ integer n\ real array Л: comment Setheap расставляет элементы с Л [ 1] по Л \п\ в форме кучи; begin integer /; /:= l; L: INHEAP (A,/, Л [/ + 1]); if j < n then go to L end SETHEAP Алгоритм 245 TREESORT 3 P. Флойд (Robert W. Floyd) *) procedure TREESORT 3 (M,n); value n: array Mm integer n: comment Treesort 3 — это treesort, значительно пересмотренная на основе идей heapsort, от которой она отличается наличием сортировки по месту. Она короче и, вероятно, быстрее, использует меньше сравнений и только одно деление. Она сортирует массив М\\:п\у требуя не более чем 2 X (2 fp — 2) X (Р — 1) или, приблизительно, 2 X п X (log2 (п) — 1) сравне¬ ний и вдвое меньше обменов в худшем случае для сортировки п = 2\р—1 элементов. Этот алгоритм легко проследить, если предста- *) Comm. ACM 7 (Dec. 1964), p. 701.
ПРИЛОЖЕНИЕ А 337 вить себе М как дерево, в котором M[/-h 2] есть отец для M[j] при 1 < i <п\ begin procedure exchange (xty)\ real xty\ begin real t\ t := x: x := y\ y:=t end exchange', procedure siftup (i,n)\ value i, n\ integer it n: comment M[i] перемещается вверх в поддереве М[1 :n]t в котором он яв¬ ляется корнем; begin real copy: integer /; copy := M [/]; loop : / := 2 X i\ if / ^ n then begin if j < n then begin if M [j + 1] > M [j] then / := / + 1 end; if M [/'] > copy then begin M [/] := M i := j; go to loop end end; M [i] := copy end siftup; integer i\ for i:=n-r-2 step —1 until 2 do siftup (itn); for i := n step —1 until 2 do begin siftup (1,0; comment M [/ 2] ^ M [/] для 1 < j i; exchange (M [1], M [/]); comment M [i: n] полностью отсортирован; end end TREESORT 3 Апробация алгоритма 245 TREESORT 3 Ф. Абрамс (Philip S. Abrams) Процедура treesort 3 была оттранслирована на расширенный алгол для В5000 и проверена на Burroughs 5500. Тесты прогонялись па массивах Длиной от 50 до 1000 с шагом 50. Для каждого размера массива строилось 50 случайных массивов, которые сортировались, хронометрировались и прове¬ рялись на упорядоченность. Никаких изменений ие потребовалось, и процеду¬ ра дала корректный результат на всех тестах. Exchange не обязательна как отдельная процедура, так как она исполь¬ зуется только в одном месте treesort 3. Было обнаружено, что сортировки протекают быстрее, когда тело exchange вставлено в надлежащее место, чем Когда они выполняются по этому алгоритму в опубликованном виде. Апробация алгоритма 245 TREESORT 3 Доказательство алгоритмов — новый вид апробации. Р. Лондон (Ralph L. London). Аннотация: апробация алгоритмов может принимать форму доказа¬ тельства корректности алгоритмов. В качестве иллюстративного, но практиче¬ ского примера доказывается корректность алгоритма 245 treesort 3 сортировки Массивов.
338 ПРИЛОЖЕНИЕ А Апробация алгоритмов при помощи доказательства. Поскольку в настоя, щее время есть подходящие способы доказательства корректности многих агь горитмов, то можно и нужно апробировать алгоритмы путем доказательства их корректности. Такая проверка в большинстве случаев заменяла бы обыч¬ ную апробацию или служила бы дополнением к ней. Апробация тестирова¬ нием все же полезна потому, что она дает, например, временные характера, стики. Тем не менее существование доказательства было бы желательной д0. полнительной апробацией алгоритма. Доказательство показывает, что алго¬ ритм проверен, логически демонстрируя отсутствие ошибок. Неважно, что не все пользователи захотят или будут способны проверить, иногда слишком длинное доказательство. Принимать доказательство алгоритма перед его использованием следует не в большей степени, чем несколько раз прогонять алгоритм на проверочных данных. В общих случаях результат может зависеть, по крайней мере частич¬ но, от автора и рецензента. В качестве примера апробации доказательством демонстрируется, что алгоритм treesort 3 правильно решает поставленную перед ним задачу сорти¬ ровки массива М[\ : п] в возрастающем порядке. Ранее этот алгоритм был апробирован в [1], но в этой проверке, например, не был оттестирован ни один массив нечетной длины. Поскольку treesort 3 является быстрым практи¬ ческим алгоритмом для сортировки по месту и достаточно сложным, так что его корректность сразу не очевидна, то его использование в качестве примера есть нечто большее, чем абстрактное упражнение. Этот пример имеет опре¬ деленную практическую важность. Краткое описание treesort 3 и метода доказательства. Этот алгоритм легче всего проследить, если рассматривать массив М как двоичное дерево. M[k-r- 2]—предок M[k], 2 ^ k ^ п. Другими словами, потомками M[j] являются M[2j] и М[2/4- 1]. Первая часть алгоритма переставляет массив М так, что в любом сегмен¬ те массива предок больше обоих своих потомков (или одного, если второго нс-т). Каждое обращение к вспомогательной процедуре siftup расширяет сег¬ мент, вводя еще одного предка, доминирующего над своими потомками. Вто¬ рая часть алгоритма использует siftup для того, чтобы сделать предков наи¬ большими в массиве, меняя М[1] с последним элементом и повторяя этот процесс над массивом, укороченным на один элемент. Все вышесказанное — это общие соображения, но не часть формального доказательства. Корректность treesort 3 доказывается в три этапа. Сначала покажем, что процедура siftup работает так, как формально было определено выше. Затем покажем, что в теле treesort 3, где siftup используется двумя способами, мас¬ сив сортируется в возрастающем порядке. (Доказательство процедуры ex¬ change опущено.) Доказательства проводятся методом, описанным в [3, 4, 7]: утверждения, касающиеся процесса вычислений, сделаны между строчками кода, и доказательство состоит в демонстрации того, что каждое утверждение истинно всякий раз, когда ему передается управление, при условии, что рапсе встретившиеся утверждения истинны. В заключение отдельно показано завер¬ шение алгоритма. Строчки исходного алгоритма пронумерованы, и утверждения, сделанные в форме комментариев в программе пронумерованы соответствующим обра¬ зом. Номера используются только для ссылки на код и на утверждения 11 другого смысла не имеют. Дополнительная пара being-end была вставлена в тело treesort 3 для того, чтобы контрольные точки двух утверждений (3.1 4.1) можно было бы разделить. В siftup утверждения 10.1 и 10.2 формул11' р)ют корректный результат в теле treesort 3; утверждения 9.3 и 9.4 делаю? то же самое. Описание siftup и обозначения. Сейчас мы формально опишем процедур? siftup(i, я), где п — формальный параметр, а не длина массива М. Пусть Msj обозначает множество неравенств М[k ч- 2] ^ М[6]: 2s ^ k ^ п. (ЕсЛ s > п -т- 2, то A(s) не определено.) Если A[i + 1] не пусто до обращения 1 siftup (i, п) и если 1 ^ i ^ я ^ размер массива, то после siftup (i, я);
ПРИЛОЖЕНИЕ А 339 1) A(i) не пусто; 2) в сегменте массива с M[i] по М[п\ сделаны перестановки; 3) сегмент вне M[i] — M[ri\ не изменяется. Для того чтобы доказать эти свойства siftup нужны некоторые обозначе¬ ния. Формальный параметр i изменяется в siftup. Поскольку i вызывается по значению, то это изменение не будет чувствоваться вне siftup. Тем не менее при доказательстве необходимо использовать как начальное значение i, так и его текущее значение. Пусть i0 обозначает значение i до входа в siftup. Аналогично, пусть М0 обозначает массив М до входа в siftup. Обозначе¬ ние «М = р(М0) при М := сору» означает «если M[i\ := сору выполнено, то М — перестановка М0 согласно (2) и (3) в описании siftup». «М = р(М0)» означает то же самое без M[i] := сору. Код и утверждения для siftup. О procedure siftup (i,n)-} value i,n\ integer /,я; \ begin real copy\ integer /; comment 1.1: 1 ^ /о = / ^ n ^ размер массива i -2: A (i'o + 1) 1.3: M = p(M0); 2 copy := M [/]; 3 loop : /:=2Xi; comment 3.1: /<л 3.2: 2i = j 3.3: i = io or / ^ 2iQ 3.4: M = p (Mo) при M [/] := copy 3.5: A (i0) или (/ = i0 и A (i0 + 1)) 3.6: M [/ -г- 2] > copy или / = /0 3.7: M [/ — 2] ^ М [/] или / = /0; 4 if / ^ п then 5 begin if / < п then begin if M [/' + 1] > M [/] then *6b j :== / + 1 end; comment 6.1: i = j-r2 6.2: 2i ^ ^ n 6.3: i = io или i ^ 2io 6.4: M = p (M0) при M [/] := copy 6.5: A (i0) or (/ = io и A (i0 + 1)) 6.6: M [/ 4- 2] > copy или i = i0 6.7: M [/ -r- 2] ^ M [/] или i — iQ 6.8: (2/ < n and M [/] = max (M [2/], M [2i + 1])) или (2i = n и M[j] = M [n] ) 6.9: M [/] ^ M [/] или i = i0) 7 if M [j] > copy then begin M [/] := M [/]; comment 8.1: i = i0 или i^2i0
3-1 о ПРИЛОЖЕНИЕ А 8.3: МЦ + 2] = АЩ] = МЦ\> сору 8.4: М [;-т-2]>М [/] /0 8.5: М = р (М0) при М [/] := сору 8.5: А (/0); 8Ь / : = у; comment 8.7: />2/0 8.8: i = j ^ п 8.9: Л1 [/ 2] > сору 8.10: М [/ 2( >ЛГ [/] 8.11: М = р (М) при М [/] := сору 8.12: Л (/0); 8с go to loop end 9 end; comment 9.1: M [/] Оорг/ если достигается из 7 или 2i = j > п если достигается из 4; Ю М [/] := сору: comment 10.1: М = р(М0) 10.2: А (/о); 11 end sift up; Проверка утверждений в siftup. Ниже приведены причины истинности каждого утверждения. 1.1 —1.2: Предположения об использовании siftup. 1.3: р — суть перестановка. 3.1—3.7: Если достигается из 2, то 3.1: 1.1. 3.2: 3. 3.3,3.5—3.7: / = /0 согласно 1.1, 3.5 также требует 1.2. 3.4: 1.3 и 2. Если достигается из 8, то соответственно 8.8, 3, 8.7, 8.11, 8.12, 8.9 и 8 10. 6.1: В 3.2 / = 2/ и согласно 6b, j может быть 2/ + 1. / = /-^2 в любом случае. 6.2: После 4, / ^ п, / изменяется между 3.1 и 6.2 только в 6Ь. До 6b j < п согласно 5. Следовательно, в 6.2 / ^ п, 2/ ^ / согласно 6.1. 6.3—6.7: 3.3—3.7 соответственно. 6.8: Если 4 — true, а 5 — false, то / = 2/ = п (используя 3.2), так что имеет место второе предложение 6.8. Если 4 — true и 5 — true то в 6а, 2/=/</г ( используя 3.2), так что А/[/ -f- 1 ] = Af[2Z+l] определено. Теперь в 6.8 / = 2/ или / = 2/ + 1- В любом случае согласно 6а и 6Ь первое предло¬ жение 6.8 имеет силу. 6.9: Согласно 6.5 / ф /0 дает Л(/0). 2/0 ^ 2/ ^ ^ п согласно 6.3 и 6.2. Сле¬ довательно, А (/о) и 6.1 дают М[/']= 44[/~-2]> M[j]. 8.1: 6.3. 8.2: 6.2. 8.3: i = j -г- 2 согласно 6.1, M[i] = M[j] согласно 8а и M\j] > сору согласно 7 8.4: 6.7 и 6.9. 8.5: 6.4 требует, чтобы М[7] заменялось на сору. Поскольку в силу За M[i]= M[j], то M[j] также можно заменить на сору. 8.1 и 8.2 дают /о ^ i ^ п, так что изменения М в 8а происходят в сегменте Л1 [/<,] — М[п\.
ПРИЛОЖЕНИЕ А g6: Согласно 8а, и если 6.8 (первое предложение) имеет силу, то M\t\^ ^ M[2i] и M\i~] ^ M\2i -f- 1]. Если же имеет силу 6.8 (второе предло¬ жение), то M[i] = М[/] = M\ri\ = M[2i], а M[2i ф 1] не существует при данном обращении к siftup. В 6.5 АНоФ П не пусто, так как A(io) подразумевает A(io+\). Если i = i0, то ,4(/0-f 1) и указанные выше соотношения для M[i] дают A {to). Если i ф iо, то 8а, 8.4, Л (to) в 6.5 и указанные выше соотношения на M[i] дают A (io) в 8.6. g 7: 8Ь, 8.1 и 8.2. 8,8: 8Ь и 8.2. 8 9: 8Ь и 8.3. 8.10: В 8.6 2/о ^ ^ п в силу 8.1 и 8.2. Следовательно, согласно 8.6 M[j ~ 2] ^ М[у]. Для M[j -4- 2] ^ M[j] используем 8Ь. 8.11: 8Ь и 8.5. 8.12: 8.6. 9.1: 9.1 достигается, лишь когда 7 — false или 4 — false. В силу 3.2 2i = /. 10.1 —10.2: Если достигаются из 7, то 10.1: 6.4 и 10. (6.2 и 6.3 дают io ^ i ^ п, гарантируя, что измерения М в 10 будут в сегменте Л4|70]—М[п].) 10.2: В силу 10, 9.1, 6.2 и 6.8, M\i] = copy ^ M[j] ^ M[2i], и если M[2i‘+1] существует то M[j] ^ Al[2i -f- 1]. Если i = io, то 10.2 полу¬ чается, как 8.6. Если i ф i0l то 6.6 и 10 дают M[i -4- 2] > сору = М[/]. A(i0) в 6.5 теперь дает A(i0) в 10.2. Если достигаются из 4, то 10.1: 3.4 и 10. (3.1 и 3.3 дают г'о ^ i ^ п.) 10.2: 2i > п означает, что в A(i0) отношения вида M[i]^... не вы¬ полнены. Если i — i0, то 3.5 дает 10.2. Если i ф /0, то 3.6 и 10 дают М [i -4- 2] > сору = М [7]. /4 (t0) в 3.5 теперь дают 10.2. Код и утверждения для treesort 3. 0 integer /; comment 0.1: Л (я-f- 2+1); 1 for / := я-4- 2 step —1 until 2 do 2 begin comment 2.1: A(i+ 1) 2.2: предположения для siftup выполнены; 3 sijtup (/,«); comment 3.1: A{i)\ 4 end; comment 4.1: M [p] ^ M [p + 1 ] для n + 1 p ^ n — 1 4.2: A (2), т. e. М[/г -г 2]>M [k] для 4 < k < n\ 5 for i := n step —1 until 2 do 3 begin comment 6.1: M [p] ^ M [p + 1] для i + 1 ^ p n — 1 6.2: M[k + 2]^M[k] для 4 <£</ 6.3: M [i + 1 ] ^ M [г] для 1 ^ r ^ i 6.4: предположения для siftup выполнены; 7 siftup (1,/);
<N CO ^ 342 ПРИЛОЖЕНИЕ A comment 7.1: M [p] ^ M [p + 1] Для i + 1 ^ p n 1 7.2: M [k -s- 2] > M [&] для 2 < £ < i 7.3: M [1]>M [г] для 2 < r </ 7.4: M[i+ 1]>M[1]; 8 exchange (M[l], M [/]); comment 8.1: M [/] ^ M [г] для 1 ^ r ^ i — 1 8.2: M [p] <; M [p + 1] для i ^ p ^ n — 1 8.3: M\k 4- 2] > M [k] для 4 < k < i - 1; 9 end; comment 9.1: M [p] ^ M [p + 1] для 2 ^ p ^ n — 1 9.2: Af[2]>M[l] 9.3: Af [p] < M Ip + 1] для 1 ^ p ^ n — 1, т. e. M полностью упорядочено 9.4: M перестановка Af0; Причины истинности каждого утверждения таковы: 0.1: Пустое утверждение, так как 2 (п -г- 2 + 1) > я. 2.1: Если достигается из 0.1, то согласно 1 замена i = п -г- 2. Если дости-. гается из 3.1, то согласно 1 замена t = i + l в 3.1 для того, чтобы объяснить изменения i с 3.1 до 2.1. .2: 2.1, ограничение на i, налагаемое 1, и размер массива равны п. .1: 2.1 и описание siftup (i,n). .1: Пустое утверждение. .2: Если п ^ 4, то выполняется 3; следовательно, 3.1 с i = 2, Если я ^ 3, то утверждение бессмысленно. 6.1 —6.3: Если достигается из 4.1, то 6.1 —6.2: в силу 5 замена i = п в 4.1 и 4.2. 6.3: Пустой оператор при i — п. Если достигается из 8.1, то согласно 5 замена i = t’+ 1 в 8.2, 8.3 и 8.1 соответственно. 6.4: 5 и 6.2, т. е. Л (2) для части массива М[ 1 : i]. 7.1: 6.1 и (3) в siftup. 7.2: 6.2 и (1) в siftup. 7.3: 7.2 означает, что М[1] = М[к -^-2], если k = 2, и использует транзитив¬ ность отношения «^». 7.4: Бессмысленно при i = п. В противном случае 6.3 при надлежащем г, так как согласно (2) из siftup, М[1] в 7.3 есть одно из М[г], 1 ^ г ^ из 6.3. 8.1: 7.3 с изменениями, вызванными 8 (только М[11 и M[i\ изменяются опе¬ ратором 8). 8.2: Согласно 8 замена Л1 [ 1 "| на M[i] в 7.4; в этом случае 7.1 также имеет место при р = i. 8.3: 7.2 исключает только одно или два отношения М[ 1]^... и одно отно¬ шение ... ^M\i\. 9.1—9.3: Если п ^ 2, то выполняется 8; 9.1: 8.2 при i = 2. 9.2: 8.1 при I = 2. 9.3: 9.1 и 9.2. Если п ^ 1, то 9.1—9.3 — бессмысленные утверждения. ’9.4: Единственными операциями, выполняемыми над М, являются siftup и exchange, каждая из которых представляет М в виде перестановки Мо-
ПРИЛОЖЕНИЕ А 34& Доказательство завершения treesort 3. Если завершаются siftup и ex¬ change, ясно, что будет завершаться и treesort 3. Заметим, что каждый пара¬ метр siftup вызывается по значению, так что значение i не изменяется в теле циклов. Процедура exchange, безусловно, завершается. В siftup единственным воз¬ можным незавершающимся циклом является цикл от 3 к 8Ь и возврат к 3. Заметим, что все изменения i (только в 8Ь) и / (только в 3 и в 6Ь) про¬ исходят в этом цикле, и что на каждой итерации этого цикла изменяется и i, и /. Согласно проверке в. 4, достаточно показать, что значения / строго возрастают, i ^ 1 означает 2i > i. В 8b j — i <2i до тех пор, пока в 3 j = 2i, т. е. j (в 3) = 2i > i = j (в 8Ь). Следовательно, при^ каждом изме¬ нении значения j в 3 оно строго увеличивается. Другое изменение значения / (в 6Ь), если оно происходит, аналогично увеличивает его значение. ЛИТЕРАТУРА: 1. Abrams P. S. Certification of Algorithm 245. Comm. ACM 8 (July 1965), 445. 2. Floyd R. W. Algorithm 245, TREESORT 3. Comm. ACM 7 (Dec. 1964), 701. 3. Floyd R. W. Assigning meanings to programs. Proc. of a Symposium in Applied Mathematics, Vol 19 — Mathematical Aspects of Computer Science, J. T. Schwartz (Ed.), American Math. Society, Providence, R. I., 1967, pp. 19—32. 4*).Knuth D. E. The Art of Computer Programming, Vol. 1 — Fundamental Algorithms. Addison-Wesley, Reading, Mass., 1968, Sec. 1.2.1. 5. M с С a r t h у J. A basis for a mathematical theory of computation. In: Com¬ puter Programming and Formal Systems, P. Braffort and D. Hirschberg (Eds.), North Holland, Amsterdam, 1963, pp. 33—70. 6. McCarthy J., Painter J. A. Correctness of a compiler for arithmetic expressions. Proc. of a Symposium in Applied Mathematics, Vol. 19 — Ma¬ thematical Aspects of Computer Science, J. T. Schwartz (Ed.), American Math. Society, Providence, R. I., 1967, pp. 33—41. 7. N a u r P. Proof of algorithms by general snapshots. BIT 6 (1966), 310—316. Алгоритм 271 QUICKERSORT («Ускоренная сортировка») P. Скоуэн (R. S. Scowen) **) Эта работа была начата, когда автор работал в Englich Electric Co. Ltd , а завершена как часть исследовательской программы Национальной физиче¬ ской лаборатории и опубликована с разрешения дирекции этой лаборатории. procedure quicker sort (a,j)\ value /; integer /; array a; begin integer i, k, q, m, p\ real t, x; integer array ut, // [1 \ln (abs (/) + 2)lln (2) + 0.01]; comment Эта процедура сортирует элементы массива а[\ : j] в возрастающем порядке. В ней использован метод, аналогичный методу, использованному в процедуре quicksort Ч. Хоара [1], т. е. постоянно разделяющий массив на такие части, что все элементы одной части меньше всех элементов другой части, с третьей частью в середине, содержащей один элемент. Я благодарен за указание на то, что quickersort также имеет сходство с алгоритмом сортировки Т. Хиббарда [2, 3]. В частности, устранение яв¬ ной рекурсии выбором самой короткой подпоследовательности для вто¬ ричной сортировки было предложено Хиббардом в [2]. *) Есть русский перевод. — Д. Е. Кнут. Искусство программирования Для ЭВМ, т. 1. Основные алгоритмы. — М.: Мир, 1976. **) Comm. ACM 8 (Nov. 1965), p. 669.
344 ПРИЛОЖЕНИЕ А Элемент со значением t выбирается произвольно (в quickersort вы. бирается средний элемент, в quicksort — случайные), i и / задают ци>к', нюю и верхнюю границы расщепляемого сегмента. После того как рас.' щепление будет закончено, будет найдено такое значение q, что а [<7] = / и а[1] ^ t ^ а[/] для всех /, J таких, что i ^ / < q < J ^ /. Затем программа обрабатывает два сегмента a[i:q — 1] и a[q + I : j] следую, щим образом. Меньший сегмент расщепляется, а позиции большего сег- мента запоминаются в массивах It и ut (It и ut — обозначения для ниж¬ него временного и верхнего временного). Когда расщепляемый сегмент имеет два элемента или меньше, он сортируется, а из массивов It и at получают другой сегмент. Когда сегментов не остается, массив полностью отсортирован; /: = т : = 1; N : if j — i > 1 then begin comment Этот сегмент имеет более двух элементов, так что его следует расщепить; Р ■= (/ + 0"*“ 2; comment p-позиция произвольного элемента в сегменте а[/:/]. Наилучшим значением р было бы такое, которое расщепляет сегмент на две половины равной длины, таким образом, если массив (сегмент) частично отсорти¬ рован, то выбор среднего элемента был бы очень хорош. Если массив совершенно случаен, то средний элемент столь же хорош, как и другие. Если, однако, в массиве а[ 1 :/] обе части — а[ 1 : /-г* 2] и а[/д- 2-f- + 1 : /] — отсортированы, то средний элемент может быть очень плох. Соответственно, в некоторых обстоятельствах р:= (/ + /)Ч-2 следовало бы заменить на р : = (i + 3 X /) -5- 4 или р := RANDOM(t, /), как в quicksort; f :=а[р]; а[р]:=а[/]; I or k : = i + 1 step 1 until q do begin comment Поиск элемента a[k] > t начинается с начала сегмента; if a [k] > t then begin comment Такой a[k] найден; for q := q step —1 until k do begin comment Теперь поиск a[q]<. t начинается с конца сегмента; И a[q]<t then begin comment a[q] найдено, так что переставляем a[q] и a[k]\ х := a [k]\ a[k]:=a[q]-, а [<?] := х- q-=q— Г comment Поиск другой пары для перестановки; go to L end end for q\ q:=k—U comment q не определено в соответствии с 4.6.5 Пересмотренного со¬ общения об алголе-60;
ПРИЛОЖЕНИЕ А 345 go to М end; I: end for k\ comment Мы достигаем метки M тогда, когда поиск снизу-вверх встречается с поиском сверху-вниз; М: <*[/]:= a[q]\ a\q]:=t; comment Сегмент расщеплен на три части (третья часть имеет только' один элемент), теперь запомним позиции большего сегмента в массивах It и ut и изменим значения i и у, задав позиции следующего большего сегмента; if 2 X q > i + у then begin It [m] : = /; ut [m] := q — 1; / := q + 1 end else begin // [m] := q + 1; м/ [tn] := /; j:=q- 1 end; comment Возьмем новое значение m и расщепим этот новый меньший сегмент; m := m + 1; go to N end else if / ^ / then begin comment Этот сегмент имеет меньше двух элементов; go to Р end else begin comment Тот самый случай, когда сегмент имеет ровно два элемента, таким образом сортируем a[i] и а [у], где у = / + 1; if а [/] > а [у] then begin x\=a[i\, a[i] := a [/]; a[j] := a; end; comment Если в // и ut есть еще сегменты для сортировки, то повторяем этот процесс, расщепляя наименьший из сегментов. Если сегментов больше нет, то массив отсортирован полностью; Р: m : = m — 1; if т > 0 then begin i It [m]\
346 ПРИЛОЖЕНИЕ А / := ut [т]\ go to N end; end end quickersort ЛИТЕРАТУРА: 1. Ноаге С. A. R. Algorithms 63 and 64 Comm. ACA4 4 (July 1961), 321. 2. Hibbard, Thomas N. Some combinatorial properties of certain trees with applications to searching and sorting. J. ACM 9 (Jan. 1962), 13. 3. Hibbard, Thomas N. An empirical study of minimal storage sorting Comm. ACM 6 (May 1963), 206—213. Апробация алгоритма 271 QUICKERSORT Ч. Блэйр (Charles R. Blair) T а бл и ц a A2 Среднее время сортировки в секундах Число элементов Алгоритм 201 shellsort Алгоритм 207 stringsort Алгооитм 245 treesort 3 Алгоритм 271 quickersort целые веще¬ ствен¬ ные целые веще¬ ствен¬ ные целые веще¬ ствен¬ ные целые веще¬ ствен¬ ные ■ 10 0.01 0.01 0.03 0.03 0.02 0.02 0.01 0.01 20 0.02 0.02 0.05 0.05 0.04 0.04 0.02 0.02 50 0.08 0.08 0.20 0.20 0.11 0.11 0.06 0.06 100 0.19 0.22 0.39 0.40 0.26 0.27 0.13 0.13 200 0.48 0.53 1.0 1.1 0.59 0.62 0.28 0.30 500 1.5 1.7 2.8 2.9 1.7 1.8 0.80 0.85 1 000 3.7 4.2 6.6 6.9 3.7 4.0 1.8 1.9 2 000 9.1 10. 13. 14. 8.2 8.7 3.9 4.1 5 000 27. 30. 40. 41, 23. 24. 11. 12. 10 000 65. 72. 93. 97. 49. 52. 23. 25. Quickersort была пропущена без изменений через транслятор Aid ар для CDC 1604А. Сравнение средних времен сортировки, приведенных в табли¬ це А2, с другими недавно опубликованными алгоритмами показывает боль¬ шую производительность quickersort. Алгоритм 347 — эффективный алгоритм для сортировки с минимальной памятью Р Синглтон (Richard С. Singleton) *) procedure SORT (A, i, j); value i, /; integer i, /; array A; comment Эта процедура сортирует элементы массива А в возрастающем по¬ рядке так, что А [/г] ^ A [к + 1], k = r, i + 1, ..., j — 1. Сам метод ана¬ логичен quickersort Р. Скоуэна, в свою очередь аналогичному алгоритмам Хиббарда [2, 3] и Хоаровской quicksort [4]. Quickersort используется в качестве стандарта, так как недавно было показано, что он быстрее четырех проверенных алгоритмов ACM [1]. На Burroughs 5500 данный алгоритм быстрее quickersort на равномерно распределенных случайных числах примерно на 25% (см. табл. А*3), на числах натурального ряда *) Comm. ACM 12 (Маг. 1969), р. 185.
ПРИЛОЖЕНИЕ А 347 (1, 2, п), упорядоченных в обратном порядке (п, п— 1, ..., 1) и отсортированных по половинам (2, 4, ..., п, 1, 3, ..., п — 1) он быстрее примерно на 40%. Quickersort медленно сортирует данные с многочислен¬ ными «связанными» характеристиками. Эту проблему можно решить из¬ менением кода для перестановки элементов a[q]^ t из меньшего сег¬ мента с элементами a[g]^ t из большего сегмента. Это изменение дает лучшее расщепление исходного сегмента, что с лихвой компенсирует до¬ полнительные обмены. В более ранних алгоритмах из массива выбирался элемент со значением t. Затем массив расщеплялся на нижний сегмент, значения которого были'мень¬ ше или равны /, и верхний сегмент, значения которого больше или равны t. Таблица А Продолжительность сортировки в секундах для sort и quickersort на компьютере Burroughs 5500 — усредненные данные за пять испытаний Исходный порядок и число элементов Алгоритм sort quickersort Случайные равномернораспределенные: 500 0.48 0.63 1000 1.02 1.40 Упорядоченные естественным образом: 500 0.29 0.48 1000 0.62 1.00 Обратный порядок: 500 0.30 0.51 1000 0.63 1.08 Отсортированные по половинам: 500 0.73 1.15 1000 1.72 2.89 Постоянные по величине: 500 0.43 10.60 1000 0.97 41.65 Эти сегменты разделены третьим сегментом длины единица и содержащим значение /. Этот метод применялся рекурсивно к нижнему и верхнему сег¬ ментам, до тех пор пока все сегменты не становились единичной длины, и данные не отсортировывались. Рассматриваемый метод несколько отличается: средний сегмент обычно отсутствует, так как при расщеплении сравниваемый элемент со значением t не удаляется из массива. Более существенное отличие состоит в том, что в качестве t используется среднее значение из А [7], Л [ (t -f- у) 2] и А [/], давая лучшую оценку медианы сегмента, чем един¬ ственный элемент, использовавшийся в более ранних алгоритмах. Затем, пока ищется пара элементов для обмена, ранее отсортированные данные (первона¬ чально A[i]^/^A[/]) используются как границы поиска, а индексные величины сравниваются лишь тогда, когда необходимо выполнять обмен. Это ведет к небольшому числу «промахов» при поиске, что увеличивает ту часть расходов на расщепление сегмента, которая заключена в самой программе, но уменьшает ту их часть, которая зависит от исходных данных. Самый длин¬ ный сегмент после расщепления сегмента длины п имеет длину, меньшую пли равную п — 2, в отличие от п — 1 в quickersort. Для большей эффективности верхний и нижний сегменты после расщеп¬ ления должны быть примерно равной длины. Таким образом, t должно быть близко к медиане данных расщепляемого* сегмента. Ради хороших
48 ПРИЛОЖЕНИЕ А статистических свойств, оценка медианы должна быть основана на нечет;, > числе наблюдений. Три лучше одного, а для длинных сегментов, особенно aj ранних этапах сортировки, вполне могут быть оправданы и дополнительный усилия, связанные с использованием пяти или более наблюдений. Для сортировки коротких последовательностей Хиббард [3] предлагает использовать другой метод, подобный методу Шелла [6]. Экспериментальные исследования этой идеи с использованием показанного здесь расщепляющего алгоритма показали отсутствие улучшений алгоритма Шелла, т. е. знакомым нам методом сортировки «погружением» путем обмена смежных пар. Мини, мальное время было получено при сортировке по этому методу последова¬ тельностей из 11 или меньшего числа элементов. Число сравнений уменьши* лось благодаря использованию самих данных в качестве границ нисходящего поиска. Для этого необходимо, чтобы A[i — 1 ] ^ A [k], i ^ k ^ /. Таким образом, исходный сегмент нельзя сортировать описанным способом. Исходный сегмент рассмативается как специальный случай и сортируется расщепляющим алгоритмом. Из-за этого свойства данный алгоритм не обла¬ дает чисто рекурсивной структурой, присущей более ранним алгоритмам. Для п сортируемых элементов, где 2к ^ п ^ 2к+\ в массивах IL и IU должно быть максимум по k элементов. На В5500 одномерные массивы имеют максимальную длину 1023. Таким образом, достаточен массив с границами [0:8]. Этот алгоритм был написан как подпрограмма на фортране, а затем от¬ транслирован на алгол. Ниже приведена исходная версия на фортране: SUBROUTINE SORT (А, II, JJ) С СОРТИРУЕТ МАССИВ А В ВОЗРАСТАЮЩЕМ ПОРЯДКЕ ОТ А(П) ДО С A(JJ). С УПОРЯДОЧЕНИЕ ПРОИСХОДИТ СОГЛАСНО ЦЕЛОЧИСЛЕННОМУ С ВЫЧИТАНИЮ, С ТАК ЧТО ЧИСЛА С ПЛАВАЮЩЕЙ ЗАПЯТОЙ ДОЛЖНЫ БЫТЬ В С НОРМАЛИЗОВАННОЙ ФОРМЕ. С МАССИВЫ Ш(К) И IL (К) ПОЗВОЛЯЮТ СОРТИРОВАТЬ ДО 2** (К +1) — 1 ЭЛЕМЕНТОВ DIMENSION A (I), IU (16), IL (16) INTEGER А.Т.ТТ М = 1 1 = 11 J = JJ 5 IF (I.GE.J) GO ТО 70 10 к = I IJ = (J + № Т = A (IJ) IF (A (I).LE.T) GO ТО 20 A (IJ) = А (!) А (I) = Т Т = A (IJ) 20 L = J IF (A (J).GE.T) GO ТО 40 A (IJ) = A (J) A (J) = Т Т = A (I J) IF(A(I),LE.T) GO ТО 40
ПРИЛОЖЕНИЕ А 349 A (IJ) = А (I) А (I) = Т Т = A (IJ) GO ТО 40 30 A (L) = А (К) А (К) = ТТ 40 L = L - 1 IF (A (L).GT.T) GO ТО 40 ТТ = A (L) 50 К = К + 1 IF (A (K).LT.T) С J ТО 50 IF (K.LE.L) GO ТО 30 IF (L — I.LE.J — К) GO TO 60 IL (M) = I IU (M) = L I = К M = M+ 1 GO TO 80 60 IL (M) = К IU (M) = J J = L M = M + 1 GO TO 80 70 M = M - 1 IF (M.EQ.0) RETURN I = IL (M) J = TU (M) 80 IF (J — I.GE.ll) GO TO 10 IF (I. EQ.II) GO TO 5 1 = 1-1 90 I = I + 1 IF (1 .EQ. J) GO TO 70 T = A (I + 1) IF (A (I).LE.T) GO TO 90 K = I 100 A (K + 1) = A (K) К = К — 1 IF (T.LT.A (K)) GO TO 100 A (K + 1) = T GO TO 90 END Приведенная выше подпрограмма на фортране была оттестирована на CDC 6400. Для равномерно распределенных случайных чисел отношение вре¬ мени сортировки к п log2 п было примерно постоянно и равно 20.2 XI 0~3 при 100 ^ ^ 10 000. Для 1000 элементов потребовалось время 0.202 с. Подпрограмма также была оптимизирована вручную для этой же машины. Для этой версии коэффициент пропорциональности был равен 5.2• 10—6 при
350 ПРИЛОЖЕНИЕ А времени в 0.052 с для 1000 элементов. В обоих случаях для упорядочения чисел с плавающей запятой в нормализованной форме использовалось цело¬ численное сравнение. ЛИТЕРАТУРА: 1. Blair Charles R. Certification of algorithm 271. Comm. ACM 9 (May 1966), 354. * } 2. Hibbard Thomas N. Some combinatorial properties of certain trees with applications to searching and sorting. J. ACM 9 (Jan. 1962), 13—28. 3. H i b b a r d Thomas N. An empirical study of minimal storage sorting Comm. ACM 6 (May 1963), 206—213. to' 4. Hoare C. A. R. Algorithms 63, Partition, and 64, Quicksort. Comm. ACM 4 (July 1931), 321. 5. S со wen R. S. Algorithm 271, Quickersort. Comm. ACM 8 (Nov. 1965), 669. 6. S h e 1 1 D. L. A high speed sorting procedure. Comm. ACM 2 (July) 19591 30—32; begin real /, //; integer ii, ij, k, L, m; integer array /L, /£/[0:8]; m := 0; ii := /; go to L4; LI: //:=(/ /)"=" 2; / := A [//]; k := /; L : = /; if A [/] > t then begin A [//]: = A [/]; A [/] := /; t:=A[ij] end; if A [/] < t then begin A [//] := A [/]; A [/] := /; t := A [//]; if A [/] > t then begin A [ij]:= A [/]; A[i]:=t; t:=A[i]]end end; L2: L := L — 1; if A IL]> t then go to L2; // := A [L]; L3: k:=k+ 1; if A [k] < t then go to L3; if 6<L then begin A [L] := A [k}\ А [/г] := tt\ go to L2 end; if L — i > j — k then begin IL[m]:= i\ lU[m]\=L\ i := k end else begin IL [m\ := k\ IU [m] := j; j := L end; rn := m + 1; LA: if i — i > 10 then go to LI; ' if i = ii then begin if i < j then go to LI end; for i := i + 1 step 1 until / do begin t := A [/]; k := / — 1; if A[k]>t then
ПРИЛОЖЕНИЕ А 351 begin 1Ь: A[k+ 1 ]:=A[k]: k : = k - 1; if A [k] > t then go to L5; A[k + \]:-= t end end; m := m — 1; if rti ^ 0 then b^gin /:=/L[m]; /:=/t/[m]; go to L4 end end SORT Замечание к алгоритму 347 — эффективному алгоритму для сортировки с минимальной памятью Р. Гриффин и К. Редиш (Robin Griffin, К. A. Redish) Алгоритм был проверен на CDC 6400 с помощью компилятора с алгола (версия 1.1 в операционной системе Scope, версия 3.1.4). Для отладки был использован массив псевдослучайных чисел из 5000 элементов; результат был правильный. Время центрального процессора, равное примерно 6.9 с, соответствует значению К (определенного ниже) около 110 мкс. В духе алгола было бы лучше следовать quickersort [1] и сделать гра¬ ницы массивов IL и IU динамическими. Это потребовало бы изменить строч- t ку 4 на странице 187 *) с integer arrayHL, IU [0:8] на integer array IL, IU [0 : In (/ — i -+- l)/ln (2) — 0.9]; Подпрограмма на фортране, приведенная в комментарии к алгоритму, была проверена с помощью компилятора с CDC фортран (компилятор RUN, версия 2.3, операционная система Scope, версия 3.1.4). Проверки выполня¬ лись для каждого из пяти упорядочений, описанных в алгоритме, с массивами разной длины от 500 до 40 000. Для целочисленных массивов результат был правильный; но когда в качестве фактического значения формального пара¬ метра А был вещественный массив, содержащий большие положительные и отрицательные числа, возникали ошибки. Это не означает, что данная под¬ программа непригодна, следует лишь изменить комментарий следующим об¬ разом: С СОРТИРУЕТ ЦЕЛОЧИСЛЕННЫЙ МАССИВ А В ВОЗРАСТАЮЩЕМ С ПОРЯДКЕ С А(Н) ДО A(IJ) С МАССИВЫ IL И IU ПОЗВОЛЯЮТ СОРТИРОВАТЬ ДО 2**(К+1) — 1 С ЭЛЕМЕНТОВ С ПОЛЬЗОВАТЕЛЬ ДОЛЖЕН УЧИТЫВАТЬ ВОЗМОЖНОСТЬ ЦЕЛО- С ЧИСЛЕННОГО ПЕРЕПОЛНЕНИЯ С ЕДИНСТВЕННАЯ АРИФМЕТИЧЕСКАЯ ОПЕРАЦИЯ ВЫПОЛНЯЕМАЯ С НАД ЭЛЕМЕНТАМИ МАССИВА — ВЫЧИТАНИЕ Этой информации достаточно, но вся ответственность за неправильное ис¬ пользование ANSI фортрана перекладывается на пользователя. Эта подпрограмма была также проверена на IBM/7074 с помощью ком¬ пилятора с фортрана (компилятор IBFTC в операционной системе IBSYS, вер¬ сия 9, уровень 10). Результат был правильный. Оператор INTEGER А, Т, ТТ был удален, и исправленная процедура проверялась с использованием таких же, но вещественных массивов. И в этом случае результат был правильным; на CDC 6400 время исполнения увеличилось на 5% и осталось тем же па IBM/7040. *) Имеется в виду САСМ 12 (Маг. 1969).— (Прим. перее.)
352 ПРИЛОЖЕНИЕ А В табл. А4 и А5 приведены времена исполнения, выраженные через К, где время = Кп log2 п. Для того чтобы использовать эту процедуру как библиотечную подпро¬ грамму, ее рекомендуется слегка изменить: следует проверять JJ — II На входе и, если эта разность отрицательна, выдавать надлежащее сообщение. Таблица А4 Время сортировки Т = Кп Iog2 п, где К в микросекундах Тест Метод Исходное упорядочение и число элементов В 5500 алгол *) С DC 6400 фортран (REAL) CDC 6400 фортран (целочисленный массив) IBM 7040 фортран Случайное равномерное распре¬ деление 500 107 21.2 20.5 1 ООО 102 21.7 20.5 5 000 21.1 20.2 269 10 000 21.1 20.1 263 40 000 21.2 20.1 Естественное упорядочение 500 65 12.9 12.5 1 000 62 13.1 12.4 146 5 000 12.6 11.9 148 10 000 12.7 12.0 40 000 12.9 12.1 Обратное упорядочение 500 67 14.3 13.4 j 1 1 000 63 13.9 13.4 | ! 5 000 13.4 12.7 158 10 000 13.4 12.7 158 40 000 13.5 12.8 Отсортированное по половинам 500 163 34.8 32.6 1 000 173 37.1 35.1 5 000 39.5 37.2 465 10 000 41.8 39.3 491 40 000 46.6 44.1 Постоянные по величине 500 96 19.2 18.5 1 000 . 97 19.4 18.7 5 000 19.4 18.7 237 10 000 19.9 19.0 241 40 000 20.2 19.5 *) Вычислено по результатам Синглтона. Таблица А5 Значения п log2 п 500 1000 5000 10000 | 40000 10 6 п log? п 0.00448 0.00993 0.061 1 0.1329 0.6115
ПРИЛОЖЕНИЕ А 353 ЛИТЕРАТУРА: 1. S со we 11 R. S. Algorithm 271, Quickersort. Comm. ACM 8 (Nov. 1965), 669—670. Замечания к алгоритму 347 — эффективному алгоритму для сортировки с минимальной памятью Р. Пето (Richard Peto) Если значения ij, вместо обычного (i + j) -f- 2, располагаются на различ¬ ных позициях между i и /, то появление такой исходной структуры, которая препятствовала бы быстрому выполнению алгоритма, маловероятно. Позицию ij можно изменять, заменив операторы т := 0; И := /; goto L4; LI: //:=(/ + j) -f- 2 на. real г, г := 0.375; т := 0, И := /; goto L4; L1: г := if г > 0.58984375 then г — 0.21875 else г + 0.0390625; Ч '■= ‘ + (/ — 0 X п comment Эти четыре десятичные константы, равные соответственно 48/128, 75.5/128, 28/128 и 5/128, дозольно произвольны. В большинстве компи¬ ляторов их двоичное представление будет точным, а их использование заставит г в операторе L1 циклически пробегать 33 значения 48/128... ...80/128. Таким образом, ij занимает переменную позицию где-то в средней четверти сортируемого сегмента. Более широкий диапазон изме¬ нения ij был бы нежелателен в некоторых случаях предварительно отсор¬ тированных массивов; При сортировке массива из /V элементов, который изначально был слу* чаен, на это будет тратиться (на ICL Atlas) менее А7/105 с, но если массив был, например, составлен из двух одинаковых предварительно отсортирован¬ ных половин, то использование исходной версии удвоило бы время сортиров¬ ки по сравнению с модифицированной при N > 104. Как указывает автор, опубликованная версия не будет работать на мас¬ сивах, состоящих более чем из 1024 элементов, потому, что верхние границы Ш и IL не отвечают требованиям таких массивов. Для стандартной процеду¬ ры описание 1L, /(7[0:8] следует заменить на ILyIU[0:20]. Это позволит сортировать массивы до 4 миллионов элементов, что при современных разме¬ рах памяти вполне достаточно. Оператор tt := a[L]y который предшествует L3: будет выполняться реже, если его поместить в следующий условный оператор, который после этого будет иметь следующий вид: If А L then begin tt:=a[L]; a[L\:= a[k]\ a[k\:—tt\ goto L2 end Алгоритм 402 Повышение эффективности QUICKSORT М. X. ван Эмден (М. Н. van Emden) *) procedure qsort (a, /1, ы1); value /1, «1; integer /1, и 1; array a; comment Эта процедура сортирует элементы a[l 1], af/l + 1], ..., q\u\] в неубывающем порядке. Она основана на идее, описанной в [1]. Ниже эта процедура сравнивается с другой процедурой, называемой sortvec, по¬ лученной путем комбинирования хоаровской quicksort [2] и скоуэновскон quickersort [3] так, чтобы она была оптимальной для системы алгол-60, используемой на машине Electrologica Х-8 в Математическом центре *) Comm. ACM 13 (Nov. 1970), p. 693—694. 12 г. Лорин
354 ПРИЛОЖЕНИЕ А (Амстердам, Голландия). Здесь «повторения» обозначают количество по¬ вторных сортировок последовательности указанной «длины»; «среднее вре¬ мя»— среднее время в секундах для данного числа повторений; «вы¬ игрыш»— разница во времени по сравнению с процедурой sortvec. Процедура Длина Повторения Среднее время Выигрьп sortvec 30 23 .09 qsort 30 23 .06 + .37 sortvec 300 16 1.25 qsort 300 16 1.03 + .17 sortvec 3 000 9 17.43 qsort 3 000 9 15.25 + .13 sortvec 30 000 2 232.46 qsort 30 000 2 197.96 + .15 ЛИТЕРАТУРА: 1. van Е m d е n, М. Н. Increasing the efficiency of quicksort. Comm. ACM 13 (Sept. 1970), 563—567. 2. H о a r e, C. A. R. Algorithm 64, quicksort. Comm. ACM 4 (July 1961), 321 — 322. 3. Scowen, R. S. Algorithm 271, quickersort. Comm. ACM 8 (Nov. 1965), 669; begin integer p, q, ix, iz; real x, xx, tj, zz, z; procedure sort; begin integer /, u; I := /1; и := ul; part: p:=/; q := u; x:=a[p]; z:=a[q]; if x > z then begin у := x; a [p] := x := z; a [q] := z := у end; if и — / > 1 then begin xx := x; ix := p; zz := z; iz := q\ left: for p := p + 1 while p < q do begin x:=a[p\, if x xx then go to right end; p := q — 1: go to out; right for q := q — 1 while q > p do begin Z := a [<7]; if 2^2:2 then go to dist end; q:=p; p~p — \;z:=x; x\=a[p\\ dist if x > 2 then
ПРИЛОЖЕНИЕ А 355 begin у := ху а [р] := х := г; а 1<?1 '•= г:= у end; if х > хх then begin хх := x\ ix := p end; if z < 22 then begin гг := г; iz := q end; go to lejt\ out: if p ф ix Д x Ф xx then begin a[p]\—xx\ a[ix]\=x end; if q Ф i2 A 2 Ф 22 then begin a[q}\=22' а[/г]:=г end; if и — q > p — / then begin /1 := /; w 1 := p — 1; / := q + 1 end else « begin и 1 := и; l\ := q + 1; и := p — 1 end; if u\ > /1 then sort; if и > / then go to part end end of sort', if u\ > /1 then sort end of qsort Замечания к алгоритму 402 P. Уилер (Robert E. Wheeler). При выполнении этого алгоритма может случиться так, что будут встре¬ чаться уже неубывающие последовательности, которые не надо сортировать. Ниже указаны изменения алгоритма, учитывающие это. Для версии алгоритма на фортране, которая работала на UNIVAC 1108, эти изменения сократили время выполнения на 1.25% при сортировке случайных массивов длины 500 и на 2.7% при сортировке случайных массивов длины 50. Строчка Заменяется на: 2 integer р, q, ix, i2, /, /': 9 р := 1 * q := и\ x\=a[p]\ г ~a[q]\ 36 begin xx := x; /:=/ + 1; ix := p end; 38 begin гг := г; /:==/+ 1; iz := q ertd; 48.5 if i ф j begin 50.5 end; Алгоритм 72 PARTIAL SORTING («Частичная сортировка») Дж. Чэмберс (J. М. Chambers) Описание. Понятие частичной сортировки мы вводим следующим образом. Дан не¬ который массив А т N элементов. В результате сортировки этого массива элементы А должны быть расставлены так, чтобы А(1)< А(2)< ...<A(tf), или, иначе, для J = 1, 2, ..., N значение A(J) таково, что для 1 ^ ^ ^ < К < N A{I)^A{1)^A(K). (1) 12*
356 ПРИЛОЖЕНИЕ А Это свойство также эквивалентно утверждению о том, что Л (/) — это /-я порядковая статистика А |Ч] для всех У. Частичная сортировка — это такая процедура, которая перестраивает А так, что (1) выполняется для некоторых выбранных значений У, но не обяза¬ тельно для всех. Преимущество частичной сортировки состоит в том, что в этом случае, если число требуемых порядковых статистик меньше /V, то за¬ траты существенно меньше, чем для сортировки. Такой случай встречается часто, например, в статистических приложениях, когда из выборки используются лишь некоторые порядковые статистики. При больших N необходима только часть проб, даже для построения эмпирической функции распределения. Конкретно, в алгоритме psort, который приведен ниже, пользователь ука¬ зывает массив А размера N и набор индексов IND размера Д7. На выходе А будет перестроено так, что отношение (1) будет выполняться, т. г*. A(J) бу¬ дет иметь такое значение, как если бы А было отсортировано пои J — IND( 1) Ш)(2), ..., IND(NI). Например, предложим, что А — вектор (10.,8.,3.,5.,7.,2.), a IND — вектор (2, 5). Тогда после частичной сортировки А с данным IND будет Л(2)=3 и А (5) =8. Используемый метод основан на версии Синглтона [3] метода Хоара [1, 2]. Метод Хоара включает в себя выбор элемента А (т) и расщепление массива на три порции, которые меньше, равны и больше этого элемента соответственно. Затем этот метод применяется рекурсивно к первой и третьей порциям до тех пор, пока данные не будут полностью отсортированы. После¬ дующие версии, ведущие к [2], изменяют метод в четырех важных пунк¬ тах (а) вместо произвольного выбора А(т) выбирается среднее из первого, последнего и срединного элементов; (Ъ) рекурсия скорее кажущаяся, чем подлинная; (с) короткие последовательности (в [3] менее 10) сортируются методом «погружения»; (d) вводятся различные толкования «связанных» ха¬ рактеристик. Метод Хоара очень хорошо подходит для решения задачи частичной сор¬ тировки. Этот алгоритм модифицируется, просто пропуская те части А, ин¬ дексы которых отсутствуют в IND. Раз мы установили сегмент А, который не содержит нужные порядковые статистики, то в дальнейшем его не надо сортировать. Особый случай N1 — 1 рассматривается в процедуре FIND [1]. При фиксированном числе индексов накладные расходы по применению psort почти пропорциональны N в отличие от полной сортировки, где они имеют порядок AMog2 N. В силу простоты модифицированного алгоритма на¬ кладные расходы psort почти всегда меньше накладных расходов полной сортировки благодаря тому, что N1 существенно меньше N. Заметим однако, что будет выполняться полная сортировка, если некоторые смежные элементы IND отличаются более чем на 10. Необходимо отметить следующие ограничения: предполагается, что IND предварительно отсортирован по возрастанию; А имеет тип real; если N — размерность массива А, то массивы INDU.t INDLt 1U, IL должны иметь раз¬ мерность К, где N <2* +1 (см. [3]). П р н мер ы. В табл. А6 указаны некоторые примеры работы psort на массивах разной длины с разными исходными упорядочениями. Эти примеры были построены следующим образом. Моделировалась выборка объема N, имеющая стандартное нормальное маргинальное распределение и коэффициент корреляции р с упорядоченной нормальной выборкой. (А именно, мы строили ah bi для i= 1, N, в виде независимых стандартных нормально распре¬ деленных случайных величин, затем строили (1—р2)1/26< н сорти¬ ровали уи сохраняя соответствие по щ. Результирующие щ и составили же¬ лаемый вход для psort.) Вычисления выполнялись двумя способами. Заменой сравнений элемен¬ тов из А специальными функциями было подсчитано число сравнений и по¬ казано в столбце С табл. А6. Это представляет собой результат, не завися¬ щий от машины, но при этом не учитываются накладные расходы на пере*
ПРИЛОЖЕНИЕ А 357 становку, логику и т. д. Поэтому в столбце Т табл. А6 мы также указали времена для исходного алгоритма на машине GE 635. Единица времени — одна миллисекунда. Таблица А6 Примеры PSORT С — число сравнений, Т — время в 10 3 с N 100 100 500 503 500 500 1000 .V/ 2 3 2 3 3 3 33 25 33 25 125 250 IND 07 50 67 50 250 Обраще¬ 500 75 75 375 ние к SORT 750 -1.0 С T 303 11.0 323 11.8 1122 36.0 1182 37.9 1628 49.3 151.3 3258 96.9 -0.5 T 38-i i 1.2 468 17.5 1356 43.7 1414 46.3 2213 70.1 151.2 4870 145.1 0.0 с 392 429 1169 1307 2184 4438 T 14.2 15.9 36.7 41.5 71.3 150.2 137.27 +0.5 с T 386 13.6 470 16.7 1362 41.3 1406 43.1 2205 67.2 150.4 4725 140.4 + 1.0 с 291 329 1121 1181 1748 3503 I 9.0 10.2 27.8 29.9 43.9 150.9 85.6 Результаты табл. А6 показывают, что, как и следовало ожидать, наиболее «дорогой» случай при заданном значении наступает тогда, когда нужные по¬ рядковые статистики распределены равномерно, т. е. 1) для / = , = 1, ..., NJ. В этом плохом случае накладные расходы растут пропорцио¬ нально N (согласно таблице несколько медленнее). Для сравнения с полной сортировкой по алгоритму Синглтона использовалась выборка объема 500. ЛИТЕРАТУРА: 1. II о are С. A. R. Algorithms 63, Partition; 64, Quicksort; and 65, Find. Comm ACM 4 (July 1961), 321—322. 2. Hoare C. A. R. Quicksort. Comput. J. 5 (1962), 10—15. 3. Singleton R. S. Algorithm 347 Sort. Comm. ACM 12 (1969), 185—186. 4. Wilks S. S. Mathematical Statistics. Wiley, New York, 1962, p. 234. Алгоритм SUBROUTINE PSORT (A,N,IND,NI) С ПАРАМЕТРЫ PSORT ИМЕЮТ СЛЕДУЮЩИЙ СМЫСЛ С А СОРТИРУЕМЫЙ МАССИВ С N ЧИСЛО ЭЛЕМЕНТОВ В А С IND МАССИВ ИНДЕКСОВ В ВОЗРАСТАЮЩЕМ ПОРЯДКЕ С N1 ЧИСЛО ЭЛЕМЕНТОВ В IND DIMENSION A (N), IND (N1) DIMENSION INDV (16), INDL (16) DIMENSION IU (16), IL (16) INTEGER P
358 ПРИЛОЖЕНИЕ А JL = 1 JU = NT INDL (1) = 1 1NDU (1) = N1 С МАССИВЫ INDL, INDU ОТНОСЯТСЯ К ЧАСТИ IND, СВЯЗАННОЙ С С ТЕКУЩИМ СЕГМЕНТОМ УПОРЯДОЧИВАЕМЫХ ДАННЫХ 1 = 1 J = N М = 1 IF (I.GE.J) GO ТО 70 С СНАЧАЛА УПОРЯДОЧИМ A(I), A(J), A((I+J)/2) И ИСПОЛЬЗУЕМ С СРЕДНЕЕ ДЛЯ РАСЩЕПЛЕНИЯ К = I IJ = (I + J)/2 Т = A (IJ) IF (A (I).LE.T) GO ТО 20 A (IJ) = А (I) А (I) = Т Т = A (IJ) 20 L = J IF (A (J).GE.T) GO ТО 40 A (IJ) = A (J) A (J) = Т Т = A (IJ) IF (A (I).LE.T) GO ТО 40 A (IJ) = А (I) А (I) = Т Т = A (IJ) IF (A (I).LE.T) GO ТО 40 A (IJ) = А (I) А (I) = Т Т = A (IJ) GO ТО 40 30 A (L) = А (К) А(К)= ТТ 40 L = L — 1 IF (A (L).GT.T) GO ТО 40 ТТ = A (L) С РАСЩЕПИМ ДАННЫЕ НА A (I TOL).LT.T И А (К ТО J).GT.T 50 К = К + 1 IF (A (K).LT.T) GO ТО 50 IF (K.LE.L) GO TO 30 INDL (M) = JL INDU (M) = JU P =M M = M + 1
ПРИЛОЖЕНИЕ А 359 С РАСЩЕПИМ БОЛЬШОЙ СЕГМЕНТ IF (L-I.LE.J-K) GO ТО 60 IL (Р) = I IU (Р) = L I = К С ПРОПУСТИМ СЕГМЕНТЫ БЕЗ ИНДЕКСОВ В IND 55 IF (JL.GT.JU) GO ТО 70 IF (IND (JL).GEЛ) GO TO 58 JL = JL + 1 GO TO 55 58 INDU (P) = JL — 1 GO TO 80 60 IL (P) = К IU (P) = J J = L 65 IF (JL.GT.JU) GO TO 70 IF (IND (JU).LE.J) GO TO 68 JU = JU — 1 GO TO 65 68 INDL (P) = JU + 1 GO TO 80 70 M = M — 1 IF (M.EQ.0) RETURN I = IL (M) I = IU (M) IF (JL.GT.JU) GO TO 70 80 IF (J — I.GI.10) GO TO 10 IF (I.EQ.l) GO TO 5 1 = 1-1 90 1 = 1 + 1 IF (A (I).LE.T) GO TO 90 К = I 100 A (K + 1) = A (K) К = К — 1 IF (T.LT.A (K)) GO TO 100 A (K+ 1) = T GO TO 90 END Алгоритм 426. Алгоритм сортировки слиянием Ч. Брон (С. Вгоп) Описание. Существует мнение, что сортировка двухпоточным слиянием требует крайне сложной и громоздкой программы. Данная процедура на ал¬ голе-60 показывает, что с использованием рекурсии можно построить элегант¬ ный и эффективных алгоритм, корректность которого легко доказать [2]. При сортировке объектов максимальная глубина рекурсии достигает [log2(rt—1)+2]. Эта процедура особенно подходит для сортировки, когда нежелательно физически перемещать объекты в памяти, а критерий сорти¬ ровки не прост. В этом случае разумно взять в качестве меры скорости алго-
360 ПРИЛОЖЕНИЕ А ритма число операций сравнения. Если п есть целая степень 2, то это число будет располагаться между (п X logs п)/2 и (п X log2 п — п -f- 1). Если п — не целая степень 2, то эти формулы являются приближенными. Предполагается, что каждому объекту можно каким-то способом одно¬ значно сопоставить одно из целых чисел от 1 до п. Это соответствие необ¬ ходимо учесть при вызове путем замены hi и io двумя целочисленными пере¬ менными, а параметра Дженсена loafterlu логическим выражением, которое имеет значение true, если объект, идентифицируемый to, следует за объектом, идентифицируемым hi, в упорядочиваемой последовательности. В противном случае это выражение имеет значение false. Пусть eL — целое число, иденти¬ фицирующие i-й объект упорядочиваемой последовательности. При возврате из процедуры sort выдается значение Ci и массив указателей put, заполненный так, что put[e{] = et+i, К е,- ^ /I, и put[en]=0. Таким образом, границы фактического массива для put. должны включать диапазон [1 : п]. Сортируе¬ мые последовательности, которые возникают в процессе сортировки, будут иметь аналогичную цепочечную структуру. Сущность алгоритма заложена в процедуре head. Ее задача — сформиро¬ вать упорядоченную цепочку нужной длины (deslen) из объектов, идентифи¬ цируемых с count + 1 до count -f- deslen. Это достигается введением цепочки длины /, состоящей из count + 1 объектов, после чего длина этой цепочки постоянно удваивается путем слияния с цепочкой такой же длины, которая строится при рекурсивном вызове head. Если deslen не равно целой степени 2, то цепочка длины deslen не может быть построена путем удваивания. В этом случае перед последней операцией слияния строится цепочка длины (нужная длина — текущая длина), а слияние с текущей цепочкой дает нужный ре¬ зультат. В качестве примера обращения к процедуре сортировки мы взяли ' sort(10 000, chain, t, /, A[i] >> A [/]). Хотя следует подчеркнуть, что данная версия этого алгоритма неэффективна, когда критерий сортировки столь не прост, как сравнение двух элементов массива. В этом случае можно выиграть не только от замены формального параметра loafterhi на Л [1о] > Л [hi] и описания 1о и hi как локальных переменных процедуры sort; но также можно изменить технику сортировки по аналогии с [1] так, что вспомогательный массив put не понадобится. Сравнение данного алгоритма с quickersort [1], проведенное при эквивалентных условиях на системе Algol для EL Х-8, не выявило существенных различий в скорости, когда сортируемые массивы со* держали случайные числа. ЛИТЕРАТУРА: 1. S с о w е n, R. S. Quickersort, Comm. ACM 8 (Oct. 1965), 669—670. 2. В г о n, С., Proof of a merge sort algorithm, May 1971 (unpublished). Algorithm Integer procedure sort (n, put, lo, hi, loafterhi); value n\ integer /г, lo, hi; integer array put; Boolean loafterhi; begin integer count, link: comment link — рабочая ячейка слияния; integer procedure head (deslen); value deslen; integer deslen; comment Значением head будет целое число, идентифицирующее объект, в начале сортируемой цепочки; begin integer beg, len, nextlen; ВВОДИМ НОВУЮ ЦЕПОЧКУ ДЛИНЫ L;
ПРИЛОЖЕНИЕ А 361 СТАВИМ ПРИЗНАК КОНЦА: УСТАНАВЛИВАЕМ beg НА ЕЕ НАЧАЛО: beg := count := count + 1; put [beg] := 0; len := 1; TEST: ДОСТИГНУТА ЛИ НУЖНАЯ ДЛИНА: if len < deslen then begin nextlen := if len < deslen — len then len else deslen — len; ВВОДИМ НОВУЮ ЦЕПОЧКУ: hi := head (nextlen); И НАЧИНАЕМ СЛИЯНИЕ: НАХОДИМ НАЧАЛЬНЫЙ ОБЪЕКТ СЛИВАЕМОЙ ЦЕПОЧКИ: lo := beg; if loafterhi then begin beg := hi; hi := lo; lo := beg end; ПОДГОТОВКА ЦЕПОЧКИ К ОБРАБОТКЕ: link := lo; ПРОДОЛЖЕНИЕ ОБРАБОТКИ: lo := put [link]; ПРОВЕРКА НА ОКОНЧАНИЕ ЦЕПОЧКИ lo: if lo Ф 0 then begin ДОБАВЛЕНИЕ LINK К ЦЕПОЧКЕ: if loafterhi then begin ПЕРЕКЛЮЧЕНИЕ LINK НА ЦЕПОЧКУ hi: put [link] := link := hi; hi := lo end else ШАГ ВНИЗ ПО ЦЕПОЧКЕ lo: link := lo: ПРОДОЛЖЕНИЕ ОБРАБОТКИ; go to end ДОБАВЛЕНИЕ ОСТАВШЕГОСЯ ХВОСТА: put [link] := hi; len := len + nextlen; go to TEST end; head := beg end head; count := 0; sort := head (n) end sort;
Приложение В ПРОЦЕДУРЫ СОРТИРОВКИ НА PL/1 Представленные здесь алгоритмы призваны лишь проиллюстрировать тех¬ нику сортировки. ЛИНЕЙНЫЙ ВЫБОР LINSEL: PROCEDURE(TOSORT,SORTED , NUMBER); DECLARE TOSORT(*) FIXED BINARY(15,□), SORTED(*) FIXED BINARY(15,0), NUMBER FIXED BINARY(15,0), SOURCE FIXED BINARY(15,0), I FIXED BINARY(15,0), J FIXED BINARY(15,0), LOW FIXED BINARY(15,0); GROW: DO J=1 TO NUMBER BY 1; LOW=TOSORT(l); SOURCE=l; SELECT: DO I=E TO NUMBER BY 1; IF LOW>TOSORT(I) THEN DO LOW=TOSORT(I); SOURCE=I; END; ELSE; END SELECT; PLACE: SORTED(J)=L0W; TOSORT(SOURCE)=45; END GROW; END LINSEL; ОСНОВНОЙ ОБМЕН BASICEXC:PROCEDURE(TOSORT,NUMBER); DECLARE TOSORT(*) FIXED BINARY(15,0), NUMBER FIXED BINARY(15,0), EXCOUNT FIXED BINARY(15,0), ADJUST FIXED BINARY(15,0), ELIMIT FIXED BINARY(15,0), OLIMIT FIXED BINARY(15,0), ODDEVE FIXED BINARY(15,0), LIMIT FIXED BINARY(15,0), TEMP FIXED BINARY(15,0), PASSW FIXED BINARY(1,0), I FIXED BINARY(15,0), ADJUST=S*TRUNC(NUMBER/E);
ПРИЛОЖЕНИЕ В IF ADJUST<NUMBER THEN DO; ELIMIT=ADJUST; OLIMIT=ADJUST—1; END; ELSE DO; ELIMIT=NUMBER— OLIMIT=NUMBER-l; END; ODD: PASSW=1; LIMIT=OLIMIT; ODDEVE=l; PASS: EXCOUNT=0; DO I=ODDEVE TO LIMIT BY 5; IF TOSORT(I)^TOSORT(1+1) THEN DO; TEMP=TOSORT(I); TOSORT(I)=TOSORT(1+1); TOSORT(I+1)=TEMP; EXCOUNT=l; END; END; IF EXCOUNT=0 THEN GO TO EXIT: IF PASSW=1 THEN DO; PASSW=0; ODDEVE=2; LIMIT=ELIMIT; GO TO PASS; END; ELSE GO TO ODD; EXIT: END BASICEXC: СТАНДАРТНЫЙ ОБМЕН STEXCH:PROCEDURE(TOSORT/NUMBER)! DECLARE TOSORT(*) FIXED BINARY(15,0), NUMBER FIXED BINARY(1S,D), EXCOUNT FIXED BINARY(15,0), TEMP FIXED BINARY(IS,0), I FIXED BINARY(15,0), PASS: EXCOUNT=0; PASSLOOP: DO 1=1 TO NUMBER-1 BY l|j IF TOSORT(I) TOSORT(I+l) THEN DO; TEMP=TOSORT(I); TOSORT(I)=TOSORT(I+1);
364 приложение в TOSORT(I+1)=TEMP; EXC0UNT=1; END; END PASSLOOP; IF EXCOUNT=0 THEN GO TO EXIT;. GO TO PASS; EXIT: END STEXCHJ ПРОСТАЯ ВСТАВКА SIMSERT: PROCEDURE (TOSORT,NEW); DECLARE TOSORT(+) FIXED BINARY(IS,0), NEW FIXED BINARY(15,0), I FIXED BINARY(15,0), J FIXED BINARY(15,0), DO 1=1 TO LENGTH BY 1; IF NEW<=TOSORT(I) THEN DO; DO J=LENGTH TO I BY -1; TOSORT(J+1)=TOSORT(J); END; GO TO SETIN; END; END: SETIN: TOSORT(I)=NEW-. END SIMSERT; END FEED? ПРОСТОЕ ПРОСЕИВАНИЕ SHUTTLESORT: PROCEDURE (TOSORT,NUMBER), /* PUBLISHED IN ALGOL AS ALGORITHM 175, COMMUNICATIONS OF ACM, VOL b, NO b, P aia */ DECLARE TOSORT(*) FIXED BINARY(15,0), NUMBER FIXED BINARY(15,0), TEMP FIXED BINARY(15,0), I FIXED BINARY(15,0), j FIXED BINARY(15,0); PASS: DO 1=1 TO NUMBER-1 by 1; EXCH: DO J=I TO 1 BY -1; IF TOSORT(J)* =TOSORT(J+l) THEN GO TO EXIT; TEMP=TOSORT(J);
ПРИЛОЖЕНИЕ В TOSORT(J)=TOSORT(J+1) TOSORT(J+1)=TEMP; END EXCH; EXIT: END PASS; END SHUTTLESORT; СОРТИРОВКА ШЕЛЛА BSHELLSORT:PROCEDURE(TOSORT,NUMBER); /* ALGORITHM 501, SHELLSORT, PUBLISHED IN ALGOL PUBLICATION LANGUAGE, COMMUNICATIONS OF ACM, VOL t>, NO. fl, AUGUST 14L3 DECLARE TOSORT(*) FIXED BINARY (31,0), DISTANCE FIXED BINARY (31,0), LIMIT FIXED BINARY (31,0), TEMP FIXED BINARY (31,0), I FIXED BINARY (31,0), J FIXED BINARY (31,0), LOGNMBR FIXED BINARY (31,0), NUMBER FIXED BINARY (31,0), LOGNMBR=LOGS(NUMBER); DISTANCE=2**LOGNMBR—1; DIST: DO WHILE (DISTANCED);' LIMIT=NUMBER—DISTANCE; SETS: DO J=1 TO LIMIT BY 1; ELTS: DO I=J TO 1 by -DISTANCE; IF TOSORT(I+DISTANCE) =TOSORT(I) THEN GO TO OUT; TEMP=TOSORT(I); TOSORT(I)^TOSORT(I+DISTANCE); TOSORT(I+DISTANCE)=TEMP; END ELTS; OUT: END SETS; DISTANCE=DISTANCE/3; END DIST; END BSHELLSORT
366 ПРИЛОЖЕНИЕ В СОРТИРОВКУ по ДЕРЕВУ TREESORT I PROCEDURE(TOSORT,NUMBER); /* ALGORITHM 245, PUBLISHED IN COMMUNICATIONS ACM, VOL 7, NO 12, P 701 */ DECLARE TOSORT(*) FIXED BINARY (31,0), ANCESTOR FIXED BINARY (31,0), TEMP FIXED BINARY (31,0), I FIXED BINARY (31,0.), LIMNODE FIXED BINARY (31,0), FATHER FIXED BINARY (31,0), NUMBER FIXED BINARY (31,0), DO I=TRUNC(NUMBER/2) TO 2 BY -1; CALL UPTREE; END; 1=1; DO LIMNODE=NUMBER TO 2 BY -1; CALL UPTREE: TEMP=TOSORT(1); TOSORT(l)=TOSORT(LIMNODE); TOSORT(LIMNODE)=TEMP; END: UPTREE: PROCEDURE; ANCESTORS; TEMP=TOSORT (ANCESTOR); INLOOP: FATHER=2*ANCESTOR; IF FATHER>LIMNODE THEN GO TO SETIN; IF FATHER=LIMNODE THEN GO TO TEMPTEST; IF TOSORT (FATHER+1) "'TOSORT (FATHER) THEN FATHER=FATHER+1; TEMPTEST: IF TOSORT(FATHER)^TEMP THEN DO; TOSORT(ANCESTOR)=TOSORT(FATHER); ANCESTOR=FATHER; GO TO INLOOP; END; SETIN: TOSORT(ANCESTOR)=TEMP; END UPTREE; END TREESORT3
ПРИЛОЖЕНИЕ В 367 УСКОРЕННАЯ СОРТИРОВКА QUICKERSORT: PROCEDURE(TOSORT,NUMBER); /* ALGORITHM 871, COMMUNICATIONS ACM, VOL fl, NO 11, p ЬЬЯ */ DECLARE TOSORT(*) FIXED BINARY (31), NUMBER FIXED BINARY (31,0), ORIGIN FIXED BINARY (31,0), LOWLIM FIXED BINARY (31,0), HIGHLIM FIXED BINARY (31,0), PARTIND FIXED BINARY (31,0), PIVOT FIXED BINARY (31,0), TEMP FIXED BINARY (31,0), EXCH FIXED BINARY (31,0); LIMIT=S0; SORT: BEGIN; DECLARE PARTTABLON(LIMIT) FIXED BINARY (31,0), PARTTABHIGH(LIMIT) FIXED BINARY (31,0); ORIGIN=l; PARTIND=1; TESTSIZE:.IF NUMBER-ORIGIN 1 THEN DO; PIVOT=TRUNC ((NUMBER+ORIGIN)/3); TEMP=TOSORT(PIVOT); TOSORT(PIVOT)=TOSORT(ORIGIN); HIGHLIM=NUMBER; FINDHIGH: DO LOWLIM=ORIGIN+l TO HIGHLIM BY 1; IF TOSORT(LOWLIM)>TEMP THEN DO'; FINDLOW: DO HIGHLIM=HIGHLIM TO LOWLIM BY -1; IF TOSORT(HIGHLIM)<TEMP THEN DO; EXCH=TOSORT(LOWLIM); TOSORT(LOWLIM)=TOSORT(HIGHLIM); TOSORT(HIGHLIM)=EXCH; HIGHLIM=HIGHLIM—1; GO TO ENDHIGH: END; END FINDLOW; HIGHLIM=LOWLIM-l; GO TO LIMSMET; END; ENDHIGH: END FINDHIGH; LIMSMET: TOSORT(ORIGIN)=TOSORT(HIGHLIM); TOSORT(HIGHLIM)=TEMP;
368 ПРИЛОЖЕНИЕ В IF 2*HIGHLIM>0RIGIN+NUMBER THEN DO;, PARTTABLOW(PARTIND)=ORIGIN; PARTTABHIGH(PARTIND)=HIGHLIM-1; ORIGIN=HIGHLIM+l; END; ELSE DO; PARTTABLOW(PARTIND)=HIGHLIM+1; PARTTABHIGH(PARTIND)=NUMBER; NUMBER=HIGHLIM-1; END; PARTIND=PARTIND+1; GO TO TESTSIZE; END: IF ORIGIN=NUMBER THEN GO TO SETPART; IF TOSORT(ORIGIN)>TOSORT(NUMBER) THEN DO; EXCHfTOSORT(ORIGIN) TOSORT(ORIGIN)=TOSORT(NUMBER); TOSORT(NUMBER)=EXCH; END; SETPART: PARTIND=PARTIND—1; IF PARTIND>D THEN DO; GRIGIN=PARTTABLOW(PARTIND); NUMBER=PARTTABHIGH(PARTIND); GO TO TESTSIZE; END; END SORT; END QUICKERSORT; SIMGSORT SINGSORT: PROCEDURE(TOSORT,NUMBER), /* ALGORITHM 347, COMMUNICATIONS OF ACM, VOL 12, NO 3, DECLARE TOSORT(*) FIXED BINARY (31,0), PIVOT FIXED BINARY (31,0), TEMP2 FIXED BINARY (31,0), LIMDEX FIXED BINARY (31,0), INITIAL FIXED BINARY (31,0), MEDIAN FIXED BINARY (31,0), BOTIND FIXED BINARY (31,0)-, TOPIND FIXED BINARY (31,0), P 165 */
ПРИЛОЖЕНИЕ В LIMITS FIXED BINARY (31,0), I FIXED BINARY (31,0), NUMBER FIXED BINARY (31,0), PARTOP FIXED BINARY (31,0) INITIAL (1),; LIMITS=20; SORT: BEGIN; DECLARE TOPS(LIMITS) FIXED BINARY (31,0), BOTTOMS(LIMITS) FIXED BINARY (31,0), LIMDEX=1; INITIAL=PARTOP; GO TO SINKTEST; SPLIT: MEDIAN=TRUNC(PART0P+NUMBER)/2) PIVOT=TOSORT(MEDIAN); TOPIND=PARTOP; BOTIND=NUMBER; IF TOSORT(PARTOP)>PIVOT THEN DO; TOSORT(MEDIAN)=TOSORT(PARTOP); TOSORT(PARTOP)=PIVOT; PIVOT=TOSORT(MEDIAN); END; IF TOSORT(NUMBER)<PIVOT THEN DO; TOSORT(MEDIAN)=TOSORT(NUMBER), TOSORT(NUMBER)=PIVOT; PIVOT=TOSORT(MEDIAN); IF TOSORT(PARTOP)>PIVOT THEN DO; TOSORT(MEDIAN)=TOSORT(PARTOP); TOSORT(PARTOP)=PIVOT; PIVOT=TOSORT(MEDIAN); END: END; FINDSMALL: BOTIND=BOTIND—1; IF TOSORT(BOTIND)>PIVOT THEN GO TO FINDSMALL; TEMP2=TOS0RT(BOTIND); FINDLARGE: T0PIND=TOPIND+1; IF TOSORT(TOPIND)<PIVOT THEN GO TO FINDLARGE; IF TOPIND<=BOTIND THEN DO; TOSORT(BOTIND)=TOSORT(TOPIND), TOSORT(TOPIND)=TEMP2;
ПРИЛОЖЕНИЕ В GO ТО FINDSMALL; END; IF BOTIND—PARTOP<NUMBER—TOPIND THEN DO; TOPS(LIMDEX)=PARTOP; BOTTOMS(LIMDEX)=BOTIND; PARTOP^TOPIND; END; ELSE DO; TOPS(LIMDEX)=TOPIND; BOTTOMS (LIMDEX )=NUMBER; NUMBER=BOTIND; END; LIMDEX=LIMDEX+1; SINKTEST: IF NUMBER-PARTOP>10 THEN GO TO SPLIT IF INITIAL=PARTOP THEN DO; IF PARTOP<NUMBER THEN GO TO SPLIT; END; DO I=PARTOP+l TO NUMBER BY 1; PIVOT=TOSORT(I); TOPIND=I—1; IF TOSORT (TOPIND)>PIVOT THEN DO; SINK: TOSORT(TOPIND+1)=TOSORT(TOPIND); TOPIND=TOPIND—1; IF TOSORT(TOPIND)^PIVOT THEN GO TO SINK; TOSORT(TOPIND+1)=PIVOT; END; END; LIMDEX=LIMDEX-l; IF LIMDEX>=1 THEN DO; PARTOP=TOPS(LIMDEX); NUMBER=BOTTOMS(LIMDEX); GO TO SINKTEST; END; E»D SORT; END SINGSORT; END FEED;
ПРИЛОЖЕНИЕ В 371 СОРТИРОВКА СТРОК STRINGSORT: PROCEDURE(TOSORT,NUMBER); /* ALGORITHM 2D7, COMMUNICATIONS ACM, VOL 5, NO 10, P 215 */ DECLARE TOSORT(*) FIXED BINARY (31,0), NUMBER FIXED BINARY (31,0), SORT: BEGIN; DECLARE WORK(2*NUMBER) FIXED BINARY (31,0),^ TOPST FIXED BINARY (31,0), BOTST FIXED BINARY (31,0), LIMITS (2) FIXED BINARY (31,0), ADVANCE FIXED BINARY (31,0), NEXT FIXED BINARY (31,0), LAST FIXED BINARY (31,0), К FIXED BINARY (31,0), PASSW FIXED BINARY (1,0), EXTEND LABEL; INITIAL: DO 1=1 TO NUMBER BY 1; WORK(I)=TOSORT(I); END INITIAL; ODDPASS: TOPST=l; BOTST=NUMBER; LIMITS (1)=NUMBER'+1; LIMITS(2)=2*NUMBER; K=l; ADVANCE=1; PASSW=1; FIRSTST: EXTEND=NONDOWN; NEXT=LIMITS(K); IF WORK(TOPST)>=WCRK(BOTST) THEN GO TO BOTTOM; ELSE GO TO TOP; TOP: WORK(NEXT)=WORK(TOPST); TOPST=TOPST+l; GO TO NEWNEXT; BOTTOM: WORK(NEXT)=WORK(BOTST); BOTST=BOTST—1; NEWNEXT: LAST=NEXT; NEXT=NEXT+ADVANCE; IF BOTST>=TOPST THEN GO TO EXTEND; IF PASSW=Q THEN IF NEXT=NUMBER+1 THEN GO TO EXIT;
ПРИЛОЖЕНИЕ В ELSE GO ТО ODDPASS; ELSE IF NEXT=2*NUMBER+1 THEN GO TO EXIT; ELSE GO TO EVENPASS-; JDOWN: IF WORK(TOPST)"-=WORK(LAST) THEN GO TO TOP; ELSE GO TO BOTHDOWN; IDOWN: IF WORK(BOTST) -=WORK(LAST) THEN GO TO BOTTOM ELSE GO TO BOTHDOWN; NONDOWN: IF WORK(TOPST) >=WORK(LAST) THEN IF WORK(BOTST)>=WORK(LAST) THEN IF WORK(BOTST)>=WORK(TOPST) THEN GO TO TOP; ELSE GO TO BOTTOM; ELSE DO; EXTEND=JDOWN; GO TO TOP; END; ELSE DO; EXTEND=IDOWN; GO TO IDOWN; END; BOTHDOWN: LIMITS(K)=NEXT; IF K=1 THEN K=2; ELSE K=l; ADVANCE^ -ADVANCE; GO TO FIRSTST; EVENPASS: top.st=number+1: BOTST=2*NUMBER; LIMITS(1)=1; LIMITS(2)=NUMBER; ADVANCED; K=l; PASSW=0; GO TO FIRSTST; EXIT: DO 1=1 TO NUMBER BY 1; TOSORT(I)=WORK(LIMITS (1) -1+1)1 END; END SORT; END STRINGSORT;
ПРИЛОЖЕНИЕ В 373 СОРТИРОВКА ПОДСЧЕТОМ DIGIT COUNTING (MATHSORT) RMATHSORT: PROCEDURE(TOSORT,SORTED,NUMBER,RANGE); /* ALGORITHM 23 PUBLISHED IN CACM, VOL 3, NO 11, NOV, 1ЧЬО. THIS VERSION DERIVED FROM MODIFICATION OF RANSHAW. CACM VOL A NO 5, MAY 1ЧЫ. CODING HERE ASSUMES KEY DEVELOPMENT FUNCTION TO BE NULL. THAT IS, KEYS PRESENTED IN TOSORT CAN BE ySED DIRECTLY AS THEY FALL WITHIN RANGE. */ DECLARE TOSORT(*) FIXED BINARY (15,0), SORTED(*) FIXED BINARY (15,0). NUMBER FIXED BINARY (15,0), RANGE FIXED BINARY (15,0), I FIXED BINARY (15,0), J FIXED BINARY (15,0), К FIXED BINARY (15,0), SORT: BEGIN; DECLARE JOTALS (RANGE) FIXED BINARY INITIAL (RANGE)0); COUNT: DO 1=1 to NUMBER BY 1; TOTALS(TOSORT(I) )=TOTALS(TOSORT(I) )+l;, END COUNT; /* COUNT DEVELOPS IN TOSORT THE NUMBER OF OCCURRENCES OF ALL KEYS IN TOSORT */ CUMULATE: DO J=RANGE—1 TO 1 BY -1; TOTALS(J)=TOTALS(J)+TOTALS(J+l); END CUMULATE; /* CUMULATE DEVELOPS THE DESCENDING CUMULATIVE COUNT OF KEYS IN TOSORT GREATER THAN J */ PLACE: DO K=1 TO NUMBER BY 1; SORTED(NUMBER+1—TOTALS(TOSORT(К)))=TOSORT(K). TOTALS(TOSORT(К))=TOTALS(TOSORT(К))—1. END PLACE; END SORT; END RMATHSORT;
Приложение С ПОДПРОГРАММА ДЛЯ ПОСТРОЕНИЯ ТАБЛИЦ поточного слияния Распределения строк для компромиссных слияний изучены не достаточно хорошо. Этот алгоритм, написанный для удобства читателя на PL/1 образует до п уровней распределения максимально на п лентах для многоэтапного, каскадного и промежуточных между ними слияний. Строчки, помеченные звездочками, устанавливают уровень и ограничения на ленте, а также длины выводных полей. GENERATE STRING DISTRIBUTIONS DISFEED: PROCEDURE OPTIONS (MAIN); DECLARE *LVL FIXED BINARY (15,0) INITIAL (10), PHS FIXED BINARY (15,0), MRG FIXED BINARY (15,0), **DO MRG=2 TO 10 BY 1; DO PHS=0 TO MRG—1 BY 1; CALL DISPERSE (LVL,PHS,MRG); END; END; DISPERSE: PROCEDURE(LEVELS,PHASES,MERGE), /* ЭТА ПРОЦЕДУРА СТРОИТ СОВЕРШЕННЫЕ УРОВНИ ДЛЯ К—X ПО¬ ТОЧНЫХ СЛИЯНИИ, КОТОРЫЕ ИСЧЕРПЫВАЮТ ВЕСЬ ВВОД, ДО НА¬ ЧАЛА СЛИЯНИИ; ЕСЛИ PHASES = 0, ТО РАСПРЕДЕЛЕНИЕ БУДЕТ ДЛЯ МНОГОЭТАПНОГО СЛИЯНИЯ; ЕСЛИ PHASES = MERGE — 1 ИЛИ MERGE —2, ТО —ДЛЯ КАСКАДНОГО СЛИЯНИЯ. ПРИ ДРУГИХ ЗНАЧЕ¬ НИЯХ PHASES БУДУТ ПОСТРОЕНЫ СОВЕРШЕННЫЕ УРОВНИ ДЛЯ РАЗЛИЧНЫХ «компромиссных» слиянии. */ DECLARE LEVELS FIXED BINARY (15,0), PHASES FIXED BINARY (15,0), MERGE FIXED BINARY (15,0), SUM FIXED BINARY (31,0), PLACE FIXED BINARY (15,0), К FIXED BINARY (15,0), I FIXED BINARY (15,0), WIDTH FIXED BINARY (15,0), CURLEV FIXED BINARY (15,0); WIDTH=MERGE+1; STRINGS; BEGIN;
ПРИЛОЖЕНИЕ С 375 DECLARE HEADER (WIDTH) FIXF.D BINARY (15,0), TAPES(WIDTH,LEVELS) FIXED BINARY (31,0); HEADER(1)=1; DO K=c to MERGE+1; HEADER (K)=HEADER (K-l)+l; END; Ю K=1 to WIDTH; ***P0T EDIT (HEADER(K)) (X(b), F(2)); END; POT LIST (MERGE,PHASES); POT SKIP; CURLEV=1; TAPES=0; DO K=1 TO MERGE; TAPES (K,C0RLEV).=1; END; /* INITIAL STRINGS */ CYCLE: TAPES(MERGE,CORLEV+1)=TAPES(1,CORLEV); SOM=TAPES (1,CORLEV); PLACE=MERGE-1; CASCADE: DO K=2 TO PHASES+1; SOM=SOM+TAPES(К,CORLEV); TAPES(PLACE,CORLEV+1)=SOM; PLACE=PLACE—1; END CASCADE; 1=0; POLYPHASE: DO K=PLACE TO 1 BY -1; TAPES(К,CORLEV+1)=SOM+TAPES(MERGE-I,CORLEV); 1=1+1; END POLYPHASE; CORLEV=CORLEV+l; IF CORLEV<LEVELS THEN GO TO CYCLE; DO J=1 TO LEVELS; DO K=1 T0_ LEVELS; DO K=1 TO WIDTH; ****POT EDIT TAPES(K,J)) (X(2), F(b)), END: POT SKIP; END: END STRINGS; END DISPERSE; END DISFEED:
Приложение D ТЕСТИРУЮЩАЯ ПОДПРОГРАММА Сравнение сортировки, описанное в главе 12, основано на прогоне разных сортировок на различных наборах данных. Данный алгоритм, для которого формируются данные и который «руководит» всеми сортировками, показан с одной из тестируемых сортировок. FEED: PROCEDURE OPTIONS(MAIN); DECLARE INT CHARACTER(4), INTA CHARACTER(Я), INTB CHARACTER(Я), INTC CHARACTER(4), INPUT(SOOO) FIXED BINARY (31), SEED FIXED BINARY (31,0) INITIAL (1357Я), FHUM DECIMAL FLOAT (lb), HUM FIXED BINARY (31,0), TOPNUM DECIMAL FLOAT (lb), RANGE DECIMAL FLOAT (lb), LIMIT FIXED BINARY (31/0) INITIAL (0100), К FIXED BINARY (15,0) INITIAL (100), H FIXED BINARY (31,0) INITIAL (100), WORK (SSOO) FIXED BINARY (31,0), EXPON DECIMAL FLOAT (lb), CYCLES FIXED BINARY (15,0) INITIAL (0), Y DECIMAL FLOAT (lb); EXP0N=10**b; CYCLEIN: CALL GENERATE; DO 1=1 TO K; PUT EDIT (INPUT (I))(X(l),F(b)); END; int=time; CALL SHUTTLESORT(INPUT,N); INTA=TIME; PUT LIST (INT,INTA,INTB,INTC); DO 1=1 TO K; PUT LIST (INPUT(I)); END; INT=TIME; CALL SHUTTLESORT (INPUT,N); INTA=TIME; PUT LIST. (INT,INTA,INTB,INTC); DO 1=1 TO K/2; WORK (I)=INPUT(I); E&D; DO 1=1 TO K/2; INPUT(I)=INPUT(K/2+I); END; DO 1=1 TO K/3; INPUT(I+K/3)=WORK(I); END; DO 1=1 TO K; PUT EDIT (INPUT(I))(X(l),F(b)); END; INT=TIME;
ПРИЛОЖЕНИЕ D 377 CALL SHUTTLESORT(INPUT,N); INTA=TIME; PUT LIST (INT,INTA,INTB,INTC); DO 1=1 TO K; PUT LIST(INPUT(I)); END; J=l; DO I=K TO 2 BY -2; WORK(J)=INPUT(I); J=J+1; END; J=l; DO 1=2 К BY 2; INPUT(I)=WORK(J); J-J+l; END; DO 1=1 TO K; PUT EDIT (INPUT(I))(X(l),F(L)); END; INT=TIME; CALL SHUTTLESORT (INPUT,N); INTA=TIME; PUT LIST (INT,INTA,INTB,INTC); DO 1=1 TO K; PUT LIST (INPUT(I));END; EXPON=N/2; CALL GENERATE; DO 1=1 TO K; PUT LIST (INPUT(I)); END; INT=TIME; CALL SHUTTLESORT (INPUT,N); INTA=TIME; PUT LIST (INT,INTA,INTB,INTC); DO 1=1 TO K; PUT LIST (INPUT (I)); END; EXPON=10**L; CYCLES=CYCLES+1; IF CYCLES=1 THEN DO; LIMIT,K,N=1000; GO TO CYCLEIN; END; IF CYCLES=2 THEN DO-; LIMIT,K,N=5000; GO TO CYCLEIN; END; IF CYCLES=2 THEN DO; LIMIT,K,N=5000; GO TO CYCLEIN: END; (NOFIXEDOVERFLOW): GNERATE;PROCEDURE: RANGS=EXPON; DO 1=1 TO 5000; INPUT(I)=0; END; DO 1=1 TO LIMIT; NUM=SEED * L5534; SEED=NUM; FNUM=NUM; TOPNUM=FNUM * (2^-31); Y=TOPNUM * RANGE; INPUT(I)=Y; END;
378 ПРИЛОЖЕНИЕ D END GENERATE; SHUTTLESORT: PROCEDURE (TOSORT,NUMBER); A PUBLISHED IN ALGOL AS ALGORITHM 175, CACM JUNE 15L3 */ DECLARE TOSORT(*) FIXED BINARY (31,0), NUMBER FIXED BINARY (31,0), TEMP FIXED BINARY (31,0), I FIXED BINARY (15,0), J FIXED BINARY (15,0); INTB=TIME; PASS: DO 1=1 to NUMBER-1 by 1; EXCH: DO J=I TO 1 BY -1; IF TOSORT(J)=TOSORT(J=L) THEN GO TO EXIT; TEMP=TOSORT(J); TOSORT(J)=TOSORT(J+l); TOSORT(J+l)=TEMP; END EXCH; EXIT: END PASS; INTC=TIME; END SHUTTLESORT; END FEED;
ПРЕДМЕТНЫЙ УКАЗАТЕЛЬ Алгол 276 Архив 319 Ассемблер 256, 283 Ассоциативная память 284, 320 APL 276 Банк памяти 303 Библиотека сортировки 277 Блок 160 — ввода 156 — вывода 156 Бункер 130 Буфер 156, 159 — плавающий 184 Буферизация 152, 156, 159, 268 — динамическая 182 — удвоенная 181 Виртуальная память 152, 283, 28(8 Время доступа 231 — задержки при вращении 231 — подвода 231 — поиска 231 Вставка 33, 36, 364 — двоичная 33, 83, 146 , пересылки 88 ,сравнения 88 — линейная 11, 33 , перемещения данных 35, 36 с обменом 30 , сравнения 35, 36 — центрированная 33, 80, 146 , пересылки 81 , сравнения 81 , центрирование 81 Выбор квадратичный 98, 146 , вариант с признаками 105 пересылки 104 , разбиение на части 99, 103 сравнения 104 — линейный 11, 12, 36, 362 , пересылки 14, 36 с обменом 11, 36 , сравнения 14, 36 , обмены 17, 36 , просмотры 17 с подсчетом 11, 36 , пересылки 19, 36 — , просмотры 19 *— , сравнения 19, 36 •— n-Pi степени 98, 106 — предварительный 182 •— с заменой 165, 296 Двоичная группировка 135 Декремен1? 24 Дерево 42 — двоичное 42 , количество узлов 44 • , объем 44, 45 , уровни 44 — динамическое 86 — слияния 120 — статическое 84 Дуга 43 Зависание при чтении 182 Загрузчик 256, 265 Замещение (61 Запись 8 — на место 248 Запрос листа 286 Иерархическая память 319 Карман 130 Квантиль 83 Квартиль 84 Ключ 9 — буквенный 144 — двоичный 258 — десятичный зонный 257 упакованный 257 — младший 9 — необособленный 22 — обособленный 22 — символьный 257 ■<- составной 9 — с плавающей запятой 258 — старшин 9 — с фиксированной запятой 257 — управляющий 21 Кобол 260, 263, 264, 276—279 Код собственный 199, 256 — условия 22 Компилятор 256, 283 Контроллер 270 Контрольные точки 186, 262 Критичный параметр 88 Куб памяти 303 Кэш 300 Лисп 276 Листание 283 Листающее устройство 283 Локальность 286 Макрогенератор 264 Макрокоманда ассемблера 259 Маскирование 21 Медиана 81
380 ПРЕДМЕТНЫЙ УКАЗАТЕЛЬ Метод распределительный II — сравнительный 11 Микропрограммирование 320 Многопроцессорная система 301 Многоштанговое устройство 232 Модуль подготовки сортировки 256 Мультипрограммирование 275 Набор данных 9 Накопительная запись 162 Нечетно-четная перестановка 24 Обмен 15 — двоичный поразрядный 126, 146 , перемещения данных 129 , проверки 129 — основной 11, 362 — парный 24, 36, 310 , обмены 27 , просмотры 25 , сравнения 25, 36 -т- стандартный 11, 24, 27, 36, 363 , обмены 28, 36 , просмотры 28 , сравнения 28 Октиль 84 Операционная система 271 Основа 88, 93 Отсортированность по половинам 148 Параллелизм 301 Перемешивание 143 Перемещение программ 283 Перестановка 21 Повторяемость в данных 148 Поддерево 53 Подсписок 53 Поле записи 9 — ключевое 9 — неключевое 9 Полоса 271 Последовательность Фибоначчи 188, 189 обобщенная 191 Представление ключа 257 Прикладная программа 274 Провал 169 Прогнозирование 182 Просеивание 24, 30, 36, 37, 150, 364 —, обмены 32, 36 —, сравнения 31, 36 Просмотр 12 — частичный 119, 208 Проход 12 PL/1 260, 263, 276-279 Распределение 126, 132, 162 — вертикальное 163, 192 — горизонтальное 163, 192 — несбалансированное 163 — несовершенное 192 — парно-просмотровое 205 — сбалансированное 163 — смешанное 194 — строк 108 — частично-просмотровое 205 Расстановка 21 Расширение строки 164 Система ввода-вывода 164, 177, 233 — запоминающих устройств 233 — сортировок 256 — универсальная 256 Скрытая буферная память 300, 303 Слияние 106, 146, 150 — вертикальное 163 — внешнее 299, 318 — внутреннее 106 — горизонтальное 163 — двухпоточное 106, 146 — естественное 107, 146 — каскадное 200, 230, 374 — компромиссное 188, 211, 374 — методом фиктивных величин 194 — многопоточное 117 — многоэтапное 188, 230, 374 — несбалансированное 163 — несовершенное 172 — неустойчивое 174 — обратное 170, 196 — осциллирующее 216, 230 — параллельное 311, 312 — перекрестное 220 — прямое 107 — сбалансированное 163, 172, 230 — с обменом 37 Слой 206 Случайность в данных 148 Сортировка быстрая 88, 129, 146, 150, 296, 301 , вариант Синглтона 95, 149, 150, 151 , , обмены 98 , , сравнения 97 , — Хоара 88, 327 — внешняя 10, 152 — внутренняя 10, 146 — вычислением адреса 146 — «двуглавого змея» 136, 146 — интервальная 139 , просмотры 141 ,сравнения 141 — комбинированная И — кучи 335 — линейная 10 — методом пузырька 27 — минимальная по памяти 11 — нелинейная 10 — не минимальная по памяти 11 — по дереву 49, 150, 151, 294, 329, 366 — поразрядная 130 — простая 11 — распределительная 11, 125, 152 ,слияние 152 — сравнительная 11, 125 — строк 115, 147, 151, 333, 371 — турнирная 54, 56, 150, 293 минимальная по памяти 67 , обмены 74 , сравнения 72 ,организация памяти 75 — универсальная 255 — ускоренная 95, 147, 151, 343, 367 — Флойда 147, 148, 336 — частичная 355 — челночная 30, 146, 147, 151, 330 — Шелла 37, 146, 150, 365 , вариант Бутройда 147, 150, 151, 332 , вариант Хиббарда 40, 41, 147, 151 , — с отложенными обменами 41 , обмены 41 , сравнения 41 Сортирующая машина 320 — сеть 311 Список 10 Стек 128 Степень распределения 139
ПРЕДМЕТНЫЙ УКАЗАТЕЛЬ Степень слияния 117, 237 номинальная IG8 переменная 242 пробная 184 ■ эффективная 190 Строка 108 — возрастающая 112 — убывающая 112 Файл 9 Фортран 276 Функция вычисления адреса — расстановки 143 Хеширование 143 Таблица листания 285 — неотделенная 299 — описания строк ИЗ — отделенная 299 — приписки 285 Толкотня в памяти 287, 294, 295 Узел 43 — корневой .43 Указатель присоединенный 77 — слияния 222 Упорядочение алфавитное 9 — буквенно-цифровое 9 — числовое 9 Упорядоченность в данных 11, 148 Управляющий признак 22 Уровень базовый 221 — идеальный 163, 189 — псевдоидеальный 194 Устройство перемещения программ 283 Цилиндр 232 Частотность 126, 133 Чередование в данных 148 Чтение вразброс 162 Этап назначения 256 — слияния 152, 257 промежуточный 257 — сортировки 152—154, 256 — управления 256 Язык собственного кода 278 — сортировки 277
ОГЛАВЛЕНИЕ От редакционного бюро IBM . Предисловие Часть I. ВНУТРЕННЯЯ СОРТИРОВКА Глава 1. Основные понятия и методы сортировки . . . 1.1. Введение .... 1.2. Процедуры сортировки 1.3. Характеристики внутренних методов сортировки . . 1.4. Основные алгоритмы 1.5. Линейный выбор 1.6. Линейный выбор с обменом: использование обменов 1.7. Линейный выбор с подсчетом 1.8. Факторы, учитываемые при сортировке Глава 2. Сортировки обменом и линейная вставка . . 2.1. Сортировка обменом . . 2.2. Сортировка вставками 2.3. Краткий обзор основных сравнительных методов . . Глава 3. Метод сортировки Шелла 3.1. Введение ......... 3.2. Метод 3.3. Пример .... 3.4. Вычисление шага . .... 3.5. Вариант с отложенными обменами . . .... Глава 4. Структуры в сортировке 4.1. Представление о структуре 4.2. Двоичные деревья 4.3. Объем двоичного дерева ..... 4.4. Первый пример использования дерева . .... 4.5. Число сравнений и форма дерева 4.6. Разбиение 4.7. Другие деревья Глава 5. Турнирные сортировки 5.1. Общие замечания 5.2. Турнирная сортировка: использование рабочей памяти 5.3. Минимальная по памяти турнирная сортировка . . 5.4. Подробности организации турнирной сортировки . . Глава 6. Деревья при сортировке вставкой ... 6.1. Введение . . 6.2. Центрированная вставка .... 6.3. Двоичная вставка: дерево вставок 6.4. Сравнения и пересылки . . Глава 7. Быстрая сортировка 7.1. Введение . . 7.2. Метод 7.3. Подробности этапа , 3 5 7 7 9 10 И 12 15 17 19 24 24 33 36 37 37 37 37 40 41 42 42 42 44 Ф 49 5^ 53 54 54 56 67 75 79 79 80 83 88 88 88 89 90
ОГЛАВЛЕНИЕ 383 7.4. Межэтапные действия 92 7.5. Основа 93 7.6. Заключительный этап 95 7.7. Быстрая сортировка и комбинации 97 7.8. Обсуждение 97 Глава 8. Сортировка выбором: методы больших степеней .... .98 8.1. Введение 98 8.2. Квадратичный выбор 98 8.3. Выбор больших степеней 106 Глава 9. Внутреннее слияние . ... . . 106 9.1. Введение: основной процесс слияния 106 9.2. Многопросмотровое двухпоточное прямое слияние ...... 107 9.3. Естественное двухпоточное слияние 112 9.4. Дальнейшее обсуждение слияния 117 Глава 10. Распределительные сортировки 125 10.1. Распределительные сортировки 125 10.2. Двоичный поразрядный обмен: метод 126 10.3. Поразрядная сортировка: основной метод 130 10.4. Интервальная сортировка . . . 139 Глава 11. Сравнение внутренних сортировок . 146 11.1. Введение 146 11.2. Простые примеры 147 Часть И. ВНЕШНЯЯ СОРТИРОВКА Глава 12. Этап сортировки при внешней сортировке ...... 152 12.1. Внешняя сортировка 152 12.2. Сущность сортировки-слияния 152 12.3. Элементы этапа сортировки 154 12.4. Управление памятью: число и длина строк 154 12.5. Взаимосвязь сортировки и вывода 160 12.6. Взаимосвязь сортировки и ввода 161 12.7. Распределение 162 12.8. Характеристики сортировки 165 12.9. Заключительные замечания 167 Глава 13. Слияние на лентах . . 167 13.1. Сбалансированное слияние на лентах 167 13.2. Обратное сбалансированное слияние 170 13.3. Несовершенное сбалансированное слияние 172 13.4. Неустойчивое сбалансированное слияние 174 13.5. Рассуждения о проектировании слияния 175 13.6. Модель ввода-вывода при слиянии и характеристики системы 177 13.7. Влияние буферизации на слияние 179 13.8. Буферизация при вводе 181 13.9. Учебный пример слияния 183 13.10. Заключительные комментарии 186 Глава 14. Многоэтапное слияние на лентах 188 14.1. Введение 188 14.2. Многоэтапное слияние с прямым чтением на трех лентах . . . 188 14.3. Многоэтапное слияние с большим числом лент 190 14.4. Распределение при прямом многоэтапном слиянии 192 14.5. Фиктивные величины 194 14.6. Обратное многоэтапное слияние 196 14.7. Внутреннее влияние многоэтапного слияния 198 14.8. Подсистема ввода-вывода и многоэтапное слияние 199 14.9. Гибкость использования лент 199
384 ОГЛАВЛЕНИЕ Глава 15. Каскадное и компромиссное слияния на лентах . . . . 15.1. Введение 15.2. Каскадное слияние с прямым чтением: распределение и слияние 15.3. Уровни каскадного слияния . . . . . 15.4. Обратное каскадное слияние 15.5. Распределение строк при каскадном слиянии 15.6. Длина строки 15.7. Внутреннее влияние каскадного слияния 15.8. Подсистема ввода-вывода . 15.9. Дополнительные замечания 15.10. Компромиссные слияния Глава 16. Осциллирующее и перекрестное слияния .... 16.1. Введение 16.2. Осциллирующее слияние 16.3. Перекрестное слияние Глава 17. Обзор слияния на лентах . . . 17.1. Введение 17.2. Критерии слияния . 17.3. Факторы, влияющие на производительность слияния 17.4. Аппаратура и слияние 17.5. Сравнения слияний Глава 18. Сортировки с произвольным доступом 18.1. Характер устройств 18.2. Основные принципы слияния 18.3. Дополнительные соображения о слиянии с произвольным досту¬ пом ... Часть III. СИСТЕМЫ СОРТИРОВКИ Глава 19. Универсальные системы сортировки ...... 19.1. Универсальная сортировка 19.2. Основная структура 19.3. Параметры и их использование . 19.4. Дополнительные параметры 19.5. Представление сортировки 19.6. Решения, принимаемые системой 19.7. Создание универсальной сортировки и аппаратура 19.8. Сортировки и программное обеспечение 19.9. Время сортировки 19.10. Моделирование сортировки Глава 20. Специальные системные факторы 20.1. Перемещение программ и виртуальная память 20.2. Многопроцессорные системы 20.3. Другие аппаратные средства Литература Приложение А Приложение В Приложение С • Приложение D Предметный указатель 200 200 201 202 203 204 210 210 211 211 211 216 216 216 220 224 224 225 225 230 231 231 231 235- 250 255 255 256 257 261 263 266 268 271 280 282 283 283 301 319 321 325 362 374 376 379