Методические указания / METOD2 / EXMERGE
.DOC
Сортировка естественным слиянием.
Пример:
П
Естественное
слияние 44
55’ 12 42 94’ 18’ 06 67
44 55’18’
12
42 94’ 06 67’
12
42 44 55 94’ 06 18 67
12 42 44 55 94’
06
18 67’ 06
12 18 42 44 55 67 94
44 55 12 42 94 18 06 67 44 12 94 06
55 42 18 67
44 55’ 12 42’ 18 94’ 06 67’ 44 55’ 18 94
12 42’ 06 67
12 42 44 55’ 06 18 67 84’ 12 42 44 55’
06 18 67 84’
06 12 18 42 44 55 67 94
Метод сортировки, при котором каждый раз сливаются две самые длинные подпоследовательности , называется естественным слиянием .
Назовем серией самую длинную упорядоченную подпоследовательность.
Пусть исходная последовательность задана в виде файла с. Используются два вспомогательных файла а и b.
Каждый проход состоит из фазы распределения, которая распределяет серии поровну из с в а и b, и фазы слияния которая сливает серии из а и b в с. Сортировка заканчивается, когда число серий будет равно 1.
Рассмотрим алгоритм более подробно.
Пусть l - используется для подсчета числа серий, сливаемых в с.
Определим глобальные объекты:
Type
Item = record
key: integer;
end;
tape = file of item;
Var c: tape
Тогда алгоритм внешней сортировки можно реализовать на языке Стандартный Паскаль следующим образом:
{Сорт.
естеств. слиянием }
procedure
NaturalMerge;
var
l:integer;{Количество
серий}
a,b:tape;
begin
. repeat
rewrite(a);
rewrite(b);
reset(c);
Distribute;{распределение}
l:=0;
Merge {слияние} until
l=1
end;
Две
фазы выражаются двумя отдельными
операторами, которые раскроем в виде
процедур.
{
из
с
в
а
и
в }
procedure
Distribute;
begin
repeat
Copyrun(c,a);
if
not eof(c) then
Copyrun(c,b)
until
eof(c);
end
;
{ из а и в
в с .}
procedure
Merge; begin
repeat
MergeRun;
l:=l+1
until not eof(a);
if not
eof(a) then
begin
CopyRun(a,c);
l:=l+1
end
end;
Допущение. Предполагается, что при таком способе распределения в файлах а и b оказывается либо равное число серий, либо в файле а на одну серию больше , чем в b. Эту "лишнюю" серию следует просто переписать.
Эти процедуры используют подчиненные процедуры для обмена одной серии. Они требуют глобальной булевской переменной eor (end of the run), значение которой показывает, достигнут ли конец серии.
{Перепись
одной серии из x в y} {Слияние серий
из а и b в с}
procedure
CopyRun(var x,y:tape); procedure MergeRun; begin
begin
repeat
repeat Copy
(x,y) if
a^.key<b^.key then until
eor begin end;
Copy (a,c);
if
eor then
CopyRun
(b,c)
Как
только исчерпана одна из
end
двух
серий, процесс слияния за- else
канчивается.
после этого оста- begin
ток
другой серии, который еще
Copy(b,c);
не
исчерпан, пересылается в вы-
if eor then
ходную
серию путем простого ко-
CopyRun(a,c)
пирования:
процедура CopyRun. end
until
eor
end;
Обе эти процедуры определены с помощью подчиненной процедуры Сopy , которая пересылает элемент из файла x в файл y и определяет, достигнут ли конец серии. Для того, чтобы найти конец серии, нужно сохранять ключ последнего переписанного элемента для сравнения со следующим. Это "заглядывание вперед" достигается использованием буферной переменной файла x^.
{Пересылка
элемента из х в y}
procedure
Copy (var x,y:tape); var
buf:item;
begin
read(x,buf);
write(y,buf); if
eof(x) then
eor:=true
else
{Заглядывание вперед}
eor:=buf.key
> x^.key
end;
Задание на лабораторную работу 6
“Внешняя сортировка”
1. Программу NaturalMerge перевести в Турбо Паскаль, сделав ее работоспособной в Турбо среде
- избавиться от буферной переменной, реализуя “заглядывание вперед”;
- задать внешние имена для файлов;
2. Исправить некорректность программы, вызванную принятым Допущением.
3. Проверить исправленную программу на следующих тестах:
Пример 1 (неправильность допущения).
3 2 5 11'7 13 19 17 23 31 29 37 43 41 47 59 57 61 71 67
Пример 2 (некорректность программы).
17 19 13 57 23 29 11 59 31 37 7 61 41 43 5 67 47 71 2 3