ФЕДЕРАЛЬНОЕ АГЕНТСТВО УДК 681.3.06 ПО ОБРАЗОВАНИЮ ББК Р23 ВОЛОГОДСКИЙ ГОСУДАРСТВЕННЫЙ Рецензенты: ТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ Зейфман А.И., д.ф-м.н, декан факультета прикладной математики и С.Ю. Ржеуцкая, И.А. Андрианов, Д.А.Носов компьютерных технологий ВГПУ Полянский А.М., к.т.н., начальник управления технической эксплуатации комитета по ИТ Правительства Вологодской области Ржеуцкая С.Ю., Андрианов И.А., Носов Д.А. Структуры и алгоритмы обработки данных. Часть 2: Учеб. пособие. - Вологда: ВоГТУ, 2007. – 172 с. СТРУКТУРЫ ДАННЫХ И ISBN Учебное пособие предназначено для студентов АЛГОРИТМЫ ОБРАБОТКИ. специальности 230105 – программное обеспечение вычислительной техники и автоматизированных систем, но может быть полезно и студентам других специальностей. Часть 2 Вторая часть содержит методы внешней сортировки и поиска, алгоритмы исчерпывающего поиска, алгоритмы на графах, методы обработки текстов и введение в NP-полные задачи. Утверждено редакционно- издательским советом университета в качестве УДК 681.3.06 учебного пособия ББК Р23 ©Вологодский государственный технический университет, 2007 ISBN ©Ржеуцкая С.Ю. Андрианов И.А. Носов Д.А. Вологда 2007 2 данных, поэтому там, где это уместно, использовался объектно- Введение ориентированный подход. Вторая часть пособия является логическим продолжением первой Пособие предназначено для студентов специальности 230105— части и содержит пять глав. В первой из них дается довольно «Программное обеспечение вычислительной техники и подробное описание методов сортировки и поиска во внешней памяти, автоматизированных систем», но может использоваться студентами учитывая важность темы в связи с использованием этих методов в других специальностей, связанных с компьютерными технологиями, в базах данных. Вторая глава содержат описание алгоритмов качестве дополнительного материала для самостоятельного изучения. исчерпывающего поиска с примерами реализации и является Исследование структур данных и алгоритмов их обработки — это та введением в дискретные задачи оптимизации. Третья глава посвящена основа, на которой держатся все остальные компьютерные науки. алгоритмам на графах, четвертая содержит описание наиболее Грамотное решение задач в любой области программирования востребованных алгоритмов обработки текстов. Последняя глава невозможно без обширных и прочных знаний типовых структур содержит введение в NP-полные задачи и способы их приближенного данных и алгоритмов. решения. Несмотря на динамичное развитие различных направлений В качестве дополнения к пособию следует использовать методические информационных технологий, в этой области положение довольно указания по структурам и алгоритмам обработки данных, в которых стабильно. Конечно, новые задачи часто требуют нестандартных содержатся практические задания. решений, поэтому набор востребованных структур данных и алгоритмов постоянно пополняется. Тем не менее, основные способы организации данных хорошо проработаны, имеется несколько фундаментальных монографий по этому вопросу [3-5,8-10,14-16], набор типовых алгоритмов, которые могут найти применение при решении различных задач, также широко известен и освещен в многочисленной литературе. При изложении авторы в основном ориентируются на известные, много раз переиздававшиеся фундаментальные работы. Мы старались изложить лаконично и систематизированно материал, почерпнутый из большого количества монографий, дополнить его собственными примерами и сведениями о современном состоянии некоторых проблем. Иногда в различных учебниках встречается несогласованность терминологии. В этом случае употребляются наиболее распространенные термины, а остальные все-таки упоминаются со ссылкой на авторов. Все примеры в пособии написаны на языке С++, при этом авторы старались сделать тексты программ понятными и удобными для чтения, поэтому использовали такие конструкции языка, которые не затрудняют чтение исходных текстов. Мы стремились показать различные подходы к программированию алгоритмов обработки 3 4 Более подходящей абстрактной моделью является двухуровневая 1. Внешняя сортировка и поиск во модель памяти (основная память — внешняя память). В этом случае внешней памяти вычислительная сложность в общем случае зависит от двух факторов — количества операций обмена между основной и внешней памятью и временной сложности алгоритма обработки данных в 1.1. Общие сведения оперативной памяти. На современном этапе развития вычислительной техники операции обмена данными для любых внешних устройств выполняются пока значительно медленнее, чем обработка данных в Внешние методы используются для обработки файлов данных, оперативной памяти. Для задач сортировки и поиска, которые будут которые слишком велики, чтобы поместиться в основной памяти рассмотрены в данной главе, время обработки данных в оперативной целиком, и поэтому должны в течение процессов сортировки или памяти столь мало, что им можно пренебречь, при этом при оценке поиска считываться в память частями, располагаясь на устройствах производительности принимать во внимание только время, внешней памяти, обычно, магнитных дисках. Подавляющее необходимое для выполнения операций обмена между оперативной и большинство современных операционных систем поддерживает внешней памятью. концепцию виртуальной памяти, обеспечивая возможность автоматического обмена информацией между оперативной памятью и Разумеется, механизм обмена информацией определяется типом внешней (файлом подкачки). Однако стандартные средства поддержки внешнего устройства, поэтому алгоритмы внешних методов динамично виртуальной памяти, встроенные в операционную систему, не могут развиваются с развитием аппаратной основы. Наиболее учитывать особенности каждого конкретного алгоритма. Поэтому распространенным в настоящее время устройством внешней памяти методы внутренней сортировки и поиска, которые разбирались в является магнитный диск. Рассмотрим некоторые особенности обмена первой части пособия, на больших массивах информации, не данными с магнитным диском, которые потребуются при дальнейшем помещающихся целиком в оперативную память, в большинстве изложении. случаев будут работать неэффективно. Кроме того, их применение «в Операции чтения и записи на магнитных дисках требуют выполнения лоб» обычно приводит к недопустимым затратам системных ресурсов. довольно медленной механической операции подвода блока магнитных Между тем, внешняя сортировка и поиск — это наиболее головок к нужному месту на диске, после чего выполняются более востребованные задачи в системах управления базами данных (СУБД) быстрые операции чтения или записи информации. Время выполнения при выполнении различных запросов к большим таблицам. От операции подвода головок, в общем случае, зависит от их начального эффективности применяемых методов существенно зависит расположения, однако этот фактор очень сложно учесть при анализе производительность СУБД и ее конкурентоспособность. Учитывая алгоритмов, поэтому обычно используются усредненные данные. важность темы, посвятим отдельную главу разработке и анализу Для того, чтобы минимизировать количество медленных операций алгоритмов внешних методов. подвода головок, обмен данными между основной и внешней памятью Основной особенностью внешних методов является тот факт, что при выполняется блоками, которые читаются и пишутся последовательно. оценке временной сложности алгоритмов не может быть применена В современных операционных системах в качестве единицы обмена используемая ранее вычислительная модель, основанная на памяти с обычно используются блоки фиксированного размера, которые произвольным доступом. В такой модели при оценке временной называются страницами. Размер страницы зависит от операционной сложности (производительности) учитывается только процессорное системы, а некоторые СУБД, например, Oracle, могут устанавливать время, необходимое для выполнения алгоритма. свой собственный размер страницы, отличный от размера страницы операционной системы. В любом случае, страница может быть считана или записана только целиком. 5 6 Этих сведений вполне достаточно для анализа алгоритмов внешних фаз, на каждой из которых выполняется чтение и запись. Поэтому при методов. В данной главе не будем вдаваться в детали программной анализе алгоритмов внешней сортировки оценивают как число реализации, поскольку они существенно зависят от особенностей проходов, так и суммарное количество данных (обычно в страницах), аппаратуры внешнего устройства и поддерживающего базового прочитанных или записанных на каждом проходе. программного обеспечения. При записи аналитических зависимостей нам потребуется операция ⎡x⎤, обозначающая ближайшее целое, большее или равное x, например, 1.2. Внешняя сортировка ⎡2,1⎤ =3; ⎡2,9⎤ =3. Сначала познакомимся с внешней сортировкой слиянием. В ее основе Задача внешней сортировки ставится так же, как и задача внутренней, лежит простая идея — разбиение (распределение) исходного большого т. е. исходный файл состоит из элементов, являющихся записями. файла на части (последовательности), сортировка каждой Запись, в общем случае, содержит ключ сортировки (key) и связанную последовательности отдельно, а затем слияние полученных информацию (satellite data), однако для упрощения будем считать, что упорядоченных последовательностей. В [5,9] отсортированные каждая запись состоит ровно из одного поля, представляющего собой последовательности называются сериями. Под слиянием понимают ключ сортировки. объединение двух или более серий в одну, при этом различают В данной главе будут рассмотрены два альтернативных способа двухпутевое и многопутевое слияние. внешней сортировки — сортировка слиянием и поразрядная Начнем с двухпутевого слияния, поскольку многопутевое слияние (распределяющая) сортировка. Данные методы были разработаны является естественным развитием идей двухпутевого слияния. довольно давно и с успехом использовались для внешних устройств на магнитных лентах, но они хорошо работают и с магнитными дисками, 1.2.1. Прямое (простое) слияние поскольку требуют последовательных проходов по файлам данных. Несмотря на то, что диск является устройством прямого доступа, Предположим, что имеется последовательный файл A, состоящий из последовательное чтение и запись, единственно возможные при записей a , a , ..., a (для простоты предположим, что n представляет 1 2 n использовании магнитных лент, являются эффективным способом собой степень числа 2). Для сортировки используются два обмена информацией и для магнитных дисков, так как требуют вспомогательных файла B и C (размер каждого из них будет n/2). минимального количества операций подвода магнитных головок, Сортировка состоит из последовательности шагов, в каждом из особенно, если файл не фрагментирован. В случае, когда элементы которых выполняется разбиение (распределение) данных из файла A в файла имеют переменную длину (например, строки текста переменной файлы B и C, а затем слияние файлов B и C в файл A. длины), прямой доступ к ним вообще чрезвычайно затруднен. В силу этих причин способы сортировки последовательных внешних файлов На первом шаге последовательно читается файл A, и элементы a , 1 не теряют своей актуальности многие годы. Подробное исследование a ,...,a пишутся в файл B, а элементы a , a , ..., a — в файл C 3 n-1 2 4 n алгоритмов можно найти в [5, 9, 14]. (начальное разбиение). Файлы В и С пока не отсортированы, но их можно рассматривать как наборы упорядоченных последовательностей При оценке производительности алгоритмов внешней сортировки (серий) из одного элемента. Начальное слияние выполняется над принято использовать такую характеристику как число проходов парами (a , a ), (a , a ), ..., (a , a ), и результат записывается в файл A, (этапов). На каждом проходе выполняется чтение и/или запись всех 1 2 3 4 n-1 n который теперь будет состоять из упорядоченных пар элементов. сортируемых данных, причем идет одновременная работа с несколькими файлами, количество которых зависит от используемого На втором шаге снова последовательно читается файл A, и в файл B алгоритма. В некоторых алгоритмах проход может включать несколько записываются последовательные пары с нечетными номерами, а в файл 7 8 C — с четными. При слиянии образуются и пишутся в файл A В приведённом выше алгоритме предполагается, что число элементов упорядоченные четверки элементов, т. е. серии из четырех элементов. является степенью двойки. Однако не составляет труда изменить Далее процесс продолжается аналогично. алгоритм так, чтобы он работал для любых входных данных – просто разрешим, чтобы последняя серия в наборе могла быть неполной. Перед выполнением последнего шага файл A будет содержать две Такая серия называется хвостом. серии размером n/2 каждая. При разбиении первая из них попадет в файл B, а вторая — в файл C. После слияния файл A будет содержать Например: полностью упорядоченную последовательность элементов. Файл А: 55 44 12 42 94 18 6 67 11 55 78 Например, пусть исходный файл А содержит следующие данные: 1 проход. Разбиваем (по 1 элементу): Файл А: 55 44 12 42 94 18 6 67 Файл В: 55 | 12 | 94 | 6 | 11 | 78 1 проход. Фаза разбиения даст 2 набора серий из одного элемента: Файл С: 44 | 42 | 18| 67 | 55 | Файл В: 55 | 12 | 94 |6 Сливаем: Файл С: 44 | 42 | 18 |67 Файл А: 44 55 | 12 42 | 18 94 | 6 67 | 11 55 | 78 (хвост) Сливаем упорядоченные серии длины 1в файл А (фаза слияния): 2 проход. Разбиваем (по 2 элемента): Файл А: 44 55 | 12 42 | 18 94 | 6 67 Файл В: 44 55 | 18 94 | 11 55 2 проход. Снова разбиваем на 2 набора серий, уже из двух элементов. Файл С: 12 42 | 6 67 | 78 Эти серии упорядочены (это следует из предыдущего шага): Сливаем: Файл В: 44 55 | 18 94 Файл А: 12 42 44 55 | 6 18 67 94 | 11 55 78 Файл С: 12 42 | 6 67 3 проход. Разбиваем (по 4 элемента): Сливаем серии длины 2, получаем упорядоченные четверки в файле А: Файл В: 12 42 44 55 | 11 55 78 Файл А: 12 42 44 55 | 6 18 67 94 Файл С: 6 18 67 94 3 проход. Снова разбиваем на 2 набора серий, уже из четырёх элементов. Эти последовательности тоже упорядочены (что следует из Сливаем: предыдущего шага): Файл А: 6 12 18 42 44 55 67 94 | 11 55 78 Файл В: 12 42 44 55 4 проход. Разбиваем (по 8 элементов): Файл С: 6 18 67 94 Файл В: 6 12 18 42 44 55 67 94 Сливаем упорядоченные последовательности длины 4: Файл С: 11 55 78 Файл А: 6 12 18 42 44 55 67 94 – данные отсортированы. Сливаем: Восемь элементов отсортировано за три прохода. Файл А: 6 11 12 18 42 44 55 55 67 78 94 — данные упорядочены. 9 10 11 элементов отсортированы за четыре прохода. Сливаем Файл А: 5 17 31 34 59 | 11 13 23 29 41 43 47 67 | 2 3 7 19 57 71 | 37 61 Анализ алгоритма сортировки прямым Проход 2. Снова разбиваем на серии слиянием Файл В: 5 17 31 34 59 | 2 3 7 19 57 71 На каждом шаге длина серий удваивается, поэтому нетрудно показать, что весь процесс сортировки требует ⎡log n⎤ проходов, где n — Файл С: 11 13 23 29 41 43 47 67 | 37 61 2 количество элементов. Каждый проход, состоящий из двух фаз, Сливаем требует чтения и записи трех файлов (исходного файла А из n элементов и вспомогательных файлов B и C, содержащих в сумме Файл А: 5 11 13 17 23 29 31 34 41 43 47 59 67 | 2 3 7 19 37 57 61 71 также n элементов), т.е. на каждом проходе каждый из трех файлов Проход 3. обходится два раза (как минимум, 6 операций подвода головок), при этом общее количество записанных или прочитанных элементов Файл В: 5 11 13 17 23 29 31 34 41 43 47 59 67 составляет 4*n (каждый элемент два раза читается и два раза Файл C: 2 3 7 19 37 57 61 71 записывается — это очень много). Как известно, обмен с файлами выполняется страницами. Пусть в странице помещается ровно b Получилось по одной серии в каждом файле. Осталось только слить. элементов. Тогда общее число страниц, прочитанных и записанных во Файл А:2 3 5 7 11 13 17 19 23 29 31 34 37 41 43 47 57 59 61 67 71 время одного шага, составляет 4*n/b. Нам потребовалось только 3 прохода для 21 элемента, при сортировке Рассмотрим модификации данного алгоритма, которые позволят методом прямого слияния было бы сделано 5 проходов (⎡log 21⎤). уменьшить количество операций обмена. 2 Очевидно, что число проходов при использовании этого метода даже в 1.2.2. Естественное слияние самом худшем случае будет не больше, чем при применении метода прямого слияния, в среднем – лучше, а файлы, которые изначально При использовании метода простого слияния не принимается во почти упорядочены, можно отсортировать вообще за один-два внимание то, что исходный файл может быть частично прохода. С другой стороны, увеличивается число сравнений за счет отсортированным, т.е. содержать упорядоченные последовательности тех, которые требуются для распознавания концов серий, но этим (серии) элементов. Метод естественного слияния основывается на временем можно пренебречь. распознавании серий при каждом разбиении и их использовании при последующем слиянии. Поясним идею метода на примере. По- 1.2.3. Сбалансированное двухпутевое слияние прежнему используем исходный файл А и два вспомогательных файла В и С. Приведенные выше простые алгоритмы требуют минимальных затрат оперативной памяти — требуется лишь две буферные переменные для Файл А: 17 31 5 34 59 13 41 43 67 11 23 29 47 3 7 71 2 19 57 37 61 размещения очередных элементов из файлов B и C. При этом никаких Проход 1. Начальное разбиение по сериям, при котором распознаются сортировок в основной памяти не производится, что приводит к серии, уже имеющиеся в исходных данных: большому количеству операций обмена между внешней и оперативной памятью, поскольку практически все перемещения элементов, Файл В: 17 31 | 13 41 43 67 | 3 7 71 | 37 61 необходимые для их сортировки, выполняются между файлами. Файл С: 5 34 59 | 11 23 29 47 | 2 19 57 11 12 На практике в целях повышения производительности внешней Файл В1: 12 18 42 44 55 94 сортировки стараются задействовать как можно больший объем Файл B2: 6 11 55 67 78 оперативной памяти, а также увеличить количество вспомогательных файлов. Оба эти действия помогают уменьшить количество проходов 2 проход. Сливаем и сразу разбиваем на серии по 12 элементов: при сортировке. Для пояснения этой идеи рассмотрим сначала Файл C1: 6 11 12 18 42 44 55 55 67 78 94 — серия получилась неполной алгоритм сбалансированного двухпутевого слияния, который затем обобщим на случай многопутевого слияния. Файл С2 оказался пустым— сортировка 11 элементов завершена всего за два прохода слияния с разбиением плюс один проход, необходимый Пусть имеется объем оперативной памяти, достаточный для для начального разбиения. При использовании метода прямого размещения k элементов. Тогда можно выполнять разбиение входного слияния потребовалось бы четыре прохода. файла сразу на последовательности длины k и сортировать их, например, алгоритмом быстрой сортировки. Анализ алгоритма сортировки сбалансированным Внесем в алгоритм еще одно важное усовершенствование. Каждый двухпутевым слиянием проход сделаем однофазным, объединив фазы слияния и разбиения – результат слияния сразу разделяется на две последовательности, По сравнению с сортировкой прямым слиянием получается выигрыш которые на следующем проходе будут входными. Эта модификация как по количеству проходов, так и по количеству операций потребует еще одного дополнительного файла. Таким образом, данный чтения/записи во время каждого прохода. алгоритм будет использовать не три, а четыре файла. Поскольку Количество основных проходов слияния с разбиением вычисляем как алгоритмы разрабатывались первоначально для сортировки на ⎡log n/k⎤ . Здесь n/k — это начальное количество серий, которое магнитных лентах, они и назывались трехленточными или 2 уменьшается в два раза на каждом проходе. Прямое слияние можно четырехленточными [4]. рассматривать как частный случай при k=1. Еще один Снова поясним идею на примере. Разобьем имеющиеся четыре файла предварительный шаг потребуется сделать для начального разбиения, на две группы, обозначив именами B1, B2 и C1, C2. Каждая из групп т.е. всего получается ⎡log n/k⎤ +1 проходов. 2 будет сначала входной, потом выходной, затем снова входной и т.д. На каждом шаге будет выполняться чтение двух входных файлов и (предположим, что исходные данные находятся в одном из файлов, запись в два выходные, в сумме количество прочитанных и записанных например, В1). Пусть в оперативной памяти можно разместить k=3 элементов составит 2*n (или 2*n/b страниц) на каждом проходе, что в элементов, реально это значение, конечно, значительно больше. два раза меньше, чем при прямом слиянии. Исходное состояние: Файл B1: 55 44 12 42 94 18 6 67 11 55 78 Например, если у нас 1 000 000 элементов, то нам потребовалось бы 20 Файлы B2, C1, C2: пусты шагов при использовании метода прямого слияния, если начинать с серий по одному элементу. Предположим, что в оперативную память Начальное разбиение на два файла (серии по 3 элемента): помещается 10000 элементов. Тогда мы можем сразу сформировать Файл С1: 12 44 55 | 6 11 67 100 серий длиной 10000, поделённых поровну между двумя файлами. В результате потребуется всего 8 ( ⎡log 100⎤ +1) проходов, на каждом Файл С2: 18 42 94 | 55 78 2 проходе будет прочитано 1 000 000 элементов и столько же записано. После начального разбиения на каждом проходе выполняется слияние с последующим разбиением. 1 проход. Сливаем и сразу разбиваем на серии по 6 элементов: 13 14 1.2.4. Сбалансированное многопутевое слияние 21 элемент отсортирован за 4 прохода, из которых один начальный. Многопутевое слияние является естественным развитием идеи Анализ алгоритма сортировки сбалансированным обычного (двухпутевого) слияния. Алгоритм отличается только тем, что разбиение серий исходного файла выполняется не по двум, а по m многопутевым слиянием вспомогательным файлам B1, B2, ..., Bm и их слияние в m Уменьшение числа проходов при многопутевом слиянии подсчитать вспомогательных файлов C1, C2, ..., Cm. На следующем шаге нетрудно. Поскольку на каждом проходе длина серии увеличивается во производится слияние файлов C1, C2, ..., Cm в файлы B1, B2, ..., Bm и столько раз, сколько имеется путей слияния (в приведенном примере т.д., пока в B1 или C1 не образуется одна серия. Всего используется три, в общем случае — m), то в выражении для числа проходов 2*m файлов. логарифм берется не по основанию 2, а по основанию m, т. е. всего Например, рассмотрим трехпутевое слияние. Используем две группы получается ⎡log n/k⎤ +1 проходов. Для приведенного выше примера m файлов B1, B2, В3 и С1, С2, С3, которые используются поочередно то в ⎡log 21/2⎤ +1 = 4 прохода. Конечно, число сравнений в оперативной 3 качестве входных, то в качестве выходных. Пусть начальный размер памяти не будет меньше, чем при применении метода прямого серии k=2 (чтобы получилось побольше проходов). слияния. Файл B1: 17 31 5 34 59 13 41 43 67 11 23 29 47 3 7 71 2 19 57 37 61 Как бы ни был тривиален приведенный пример многопутевого слияния, он показывает, что по мере увеличения длины серий Все остальные файлы пусты. вспомогательные файлы с большими номерами перестают 1 проход. Начальное разбиение использоваться, поскольку им "не достается" ни одной серии. Этот недостаток устраняется в методе многофазной сортировки. Файл С1: 17 31 | 41 43 | 3 47 | 37 57 Файл C2: 5 34 | 11 67 | 7 71 | 61 1.2.5. Многофазная сортировка Файл С3: 13 59 | 23 29 | 2 19 Идея многофазной сортировки состоит в том, что из имеющихся m вспомогательных файлов (m-1) файл служит для ввода сливаемых 2 проход. Слияние с последующим разбиением последовательностей, и только один — для вывода образуемых серий. Файл B1: 5 13 17 31 34 59 | 37 57 61 Как только один из файлов ввода становится пустым, его начинают использовать для вывода серий, получаемых при слиянии серий нового Файл В2: 11 23 29 41 43 67 набора (m-1) файлов. Таким образом, имеется первый шаг, при Файл В3: 2 3 7 19 47 71 котором серии исходного файла распределяются по m-1 вспомогательному файлу, а затем выполняется многопутевое слияние 3 проход. Слияние с последующим разбиением серий из (m-1) файла, пока в одном из них не образуется одна серия. Файл С1: 2 3 5 7 11 13 17 19 23 29 31 34 41 43 47 59 67 71 Таким образом, в данном алгоритме понятие прохода становится нечетким в отличие от всех остальных алгоритмов, рассмотренных Файл С21: 37 57 71 ранее. Файл С1: пуст. Очевидно, что при произвольном начальном распределении серий по 4 проход. Осталось только слить файлы С1 и С2. вспомогательным файлам алгоритм может не сойтись, поскольку в единственном непустом файле будет существовать более, чем одна Файл В1 :2 3 5 7 11 13 17 19 23 29 31 34 37 41 43 47 57 59 61 67 71 серия. 15 16 Предположим, например, что используется три файла B1, B2 и B3, и распределение выглядело как (1,2,0) или (1,0,2). Опять для при начальном распределении в файл B1 помещены 10 серий, а в файл определенности остановимся на первом варианте. Чтобы его получить, B2 - 6. При слиянии B1 и B2 к моменту, когда мы дойдем до конца B2, на предыдущем этапе годились бы следующие распределения: (3,0,2) и в B1 останутся 4 серии, а в B3 попадут 6 серий. Продолжится слияние (0,3,1). Но второй вариант хуже, поскольку он приводится к слиянию B1 и B3, и при завершении просмотра B1 в B2 будут содержаться 4 только одной серии из файлов B2 и B3, в то время как при наличии серии, а в B3 останутся 2 серии. После слияния B2 и B3 в каждом из первого варианта распределения будут слиты две серии из файлов B1 и файлов B1 и B2 будет содержаться по 2 серии, которые будут слиты и B3. Пожеланием к предыдущему этапу было бы наличие образуют 2 серии в B3 при том, что B1 и B2 - пусты. распределения (0,3,5), еще раньше - (5,0,8), еще раньше - (13,8,0) и т.д. Тем самым, алгоритм не сошелся (таблица 1.1). Это рассмотрение показывает, что метод трехфазной внешней сортировки дает желаемый результат и работает максимально Таблица 1.1 эффективно (на каждом этапе сливается максимальное число серий), Пример начального распределения серий, при котором трехфазная если начальное распределение серий между вспомогательными внешняя сортировка не приводит к нужному результату файлами описывается соседними числами Фибоначчи. Напомним, что Число серий в Число серий в Число серий в последовательность чисел Фибоначчи начинается с 0, 1, а каждое файле B1 файле B2 файле B3 следующее число образуется как сумма двух предыдущих: (0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ....) 10 6 0 Аналогичные (хотя и более громоздкие) рассуждения показывают, что 4 0 6 в общем виде при использовании m вспомогательных файлов условием успешного завершения и эффективной работы метода многофазной 0 4 2 внешней сортировки является то, чтобы начальное распределение серий между m-1 файлами описывалось суммами соседних (m-1), (m- 2 2 0 2), ..., 1 чисел Фибоначчи порядка m-2. Последовательность чисел Фибоначчи порядка p начинается с p нулей, (p+1)-й элемент равен 1, а 0 0 2 каждый следующий равняется сумме предыдущих p+1 элементов. Ниже показано начало последовательности чисел Фибоначчи порядка 4: Попробуем понять, каким должно быть начальное распределение (0, 0, 0, 0, 1, 1, 2, 4, 8, 16, 31, 61, ...) серий, чтобы алгоритм трехфазной сортировки благополучно завершал работу и выполнялся максимально эффективно. Для этого рассмотрим При использовании шести вспомогательных файлов идеальными работу алгоритма в обратном порядке, начиная от желательного распределениями серий являются следующие: конечного состояния вспомогательных файлов. 1 0 0 0 0 Нас устраивает любая комбинация конечного числа серий в файлах B1, 1 1 1 1 1 B2 и B3 из (1,0,0), (0,1,0) и (0,0,1). Для определенности выберем 2 2 2 2 1 первую комбинацию. Для того, чтобы она сложилась, необходимо, 4 4 4 3 2 чтобы на непосредственно предыдущем этапе слияний существовало 8 8 7 6 4 распределение серий (0,1,1). Чтобы получить такое распределение, 16 15 14 12 8 необходимо, чтобы на непосредственно предыдущем этапе слияний 17 18 Понятно, что если распределение основано на числе Фибоначчи f, то 1 проход. Разделяем все ключи на две группы в соответствии с самым i минимальное число серий во вспомогательных файлах будет равно f, а младшим двоичным разрядом (в файле С1 оказываются все значения, у i максимальное - f . Поэтому после выполнения слияния мы получим которых в младшем разряде 0, а в файле С2 — значения, у которых i+1 максимальное число серий - f, а минимальное - f . На каждом этапе младший разряд равен 1). i i-1 будет выполняться максимально возможное число слияний, и процесс Файл С1: 4 2 0 6 сойдется к наличию всего одной серии. Файл С2: 3 1 7 5 Поскольку число серий в исходном файле может не обеспечивать возможность такого распределения серий, применяется метод 2 проход. Теперь сравнивается второй двоичный разряд (в нашем добавления пустых серий, которые в дальнейшем как можно более примере он средний) и данные каждого файла распределяются в равномерного распределяются между промежуточными файлами и соответствии с его значением. Теперь в файлах В1 и В2 будут по две опознаются при последующих слияниях. Понятно, что чем меньше группы, одна взята из файла С1, а другая из С2. таких пустых серий, т.е. чем ближе число начальных серий к Файл В1: 4 0 | 1 5 требованиям Фибоначчи, тем более эффективно работает алгоритм. Файл В2: 2 6 | 3 7 В [5] показано, что наиболее подходящим алгоритмом внутренней сортировки на этапе формирования начальных серий, является 3 проход. Сравниваем следующий двоичный разряд — в нашем пирамидальная сортировка. примере он самый старший. Теперь в файлах будет уже по 4 группы, а в каждой группе всего по одному значению. 1.2.6. Внешняя поразрядная сортировка Файл С1: 0 | 1 | 2 | 3 Альтернативным способу сортировки слиянием для внешних Файл С2: 4 | 5 | 6 | 7 последовательных файлов является поразрядная сортировка. Она имеет и другие названия — цифровая сортировка, распределяющая Больше разделять нечего, да данные уже и отсортированы. Осталось сортировка, сортировка методом разделения. В последнем названии только выполнить последнюю короткую фазу сборки, которая запишет явно подчеркивается, что этот способ является противоположным данные из файла С2 в конец файла С1. сортировке слиянием. Это действительно так, поскольку при Таким образом, весь процесс для трехразрядных ключей потребовал 3 поразрядной сортировке данные разделяются (распределяются по прохода и заключительный этап сборки. Легко обобщить этот случай файлам) в соответствии с отдельными двоичными разрядами ключей. на k-разрядные данные — k проходов и сборка. Идею поразрядной сортировки рассмотрим на примере одного из Если сравнить этот алгоритм с алгоритмом четырехленточной наиболее простых алгоритмов поразрядной сортировки — сортировки слиянием, то можно заметить, что они действительно четырехленточную сортировку, начинающуюся с младших разрядов. противоположны друг другу. При сортировке слиянием на каждом Для упрощения примера предположим, что ключи сортировки состоят проходе серии из двух файлов сливаются в более длинные серии, в всего из трех бит, т. е. возможно всего 8 значений ключей от 0 до 7. данном случае, наоборот, при проходах файлов происходит разделение Порядок их расположения значения не имеет, предположим, 3, 1, 4, 2, каждой группы на две более короткие. Более того, в [9] показано, что 7, 5, 0, 6. для каждого способа сортировки слиянием можно предложить Пусть мы имеем файлы В1,В2,С1 и С2. В начальный момент данные противоположную схему поразрядной сортировки разделением. находятся в файле В1, три остальных файла пусты. В целом внешняя поразрядная сортировка не имеет явных преимуществ перед сортировкой слиянием и даже проигрывает тем 19 20