Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ВНЕШНИЕ СОРТИРОВКИ.docx
Скачиваний:
19
Добавлен:
26.09.2019
Размер:
57.85 Кб
Скачать

Простое слияние (с/без внутренней сортировки)

Отличие между простым слиянием и естественным слиянием, которое рассмотрено в следующем разделе, заключается в определении серии. Впростом слиянии длина серии фиксирована. На первом шаге упорядоченные отрезки имеют длину, равную единице, то есть состоят из одного элемента. Потом они объединятся, и если слияние двухпутевое, то вновь сформированные отрезки будут состоять из двух элементов, если слияние многопутевое (количество вспомогательных файлов N), то — из N элементов. Длина серии в алгоритме простого слияния зависит от количества вспомогательных файлов, на которое идет распределение серий. Если k — это номер прохода, a N— количество вспомогательных файлов, то длина серии определяется формулой Nk. Обратим внимание на то, что на первых проходах длина серии растет медленно, например, в двухпутевой сортировке, чтобы получить серию, состоящую из 100 элементов, требуется семь проходов. Это не эффективно, и поэтому для улучшения алгоритма слияния можно использовать внутреннюю сортировку в качестве вспомогательной. В этом случае на первом проходе часть данных (фиксированное количество) переписывается в оперативную память, например, в массив, и там упорядочивается. Таким образом сразу формируется серия большой длины, и для дальнейшего слияния потребуется меньшее количество проходов. Этот способ упорядочения данных называется простым слиянием с использованием внутренней сортировки.

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

□ длина серии не меньше количества элементов в файле (определяется после фазы слияния);

□ количество серий — одна (определяется на фазе слияния);

□ второй по счету вспомогательный файл при однофазной сортировке после распределения серий остался пустым.

Без внутренней: (двухфазное)

F0: 5 9 8 6 13 3 4 19 6

F1: 5 8 13 4 6 len=1

F2: 9 6 3 19

F0: 5 9 6 8 3 13 4 19 6

F1: 5 9 3 13 6

F2: 6 8 4 19 len=2

F0: 5 6 8 9 3 4 13 19 6

F1: 5 6 8 9 6

F2: 3 4 13 19 len=4

F0: 3 4 5 6 8 9 13 19 8

F1: 3 4 5 6 8 9 13 19

F2: 6

F0: 3 4 5 6 6 8 9 13 19

Прекращаем когда len>= кол-ву элементов

Алгоритм:

-определить число элементов N>0

-len=1;

-repeat

Распределение (из f0 в f1,f2)

Слияние (из f1,f2 в f0)

Len=len*2;

Until len>=N

Распределение (f0,f1,f2,len)

-открыть файл(fo-чтение, f1,f2-запись)

-пока не конец f0

Пишем серию в f1

Если не конец f0

То пишем серию в f2

-закрыть файл

Слияние (f0,f1,f2,len)

-открыть файл (f1,f2-чтение, f0-запись)

-пока не конец f1 и не конец f2

Открыть серии

Пока не конец серии в f1 и в f2

Если элемент из f1<элемента из f2

То копируем из f1 в f0 и берем из f1

еще один элемент

иначе -\\- из f2

пока не конец серии в f1

копируем из него и берем следующий

пока не конец серии в f2

-\\ f2

Если не конец f1

Скопировать из f1 в f0

-закрыть файл

Type

TElem=integer;

TFile=file of TElem;

TSequence=class

Private

F:TFile;

FElem:TElem;

FEof:Boolean; //все ли записали

FCount:integer; //сколько осталось

FFileName:string;

Constructor Create(AFileName:string)

Begin

FFileName:=AFileName;

AssignFile(F,FFileName);

FEof:=true;

FCount:=0;

End;

Function SizeOf:integer;

Begin

Reset(f);

Result:=system.FileSize(F);

CloseFile(f);

End;

Procedure StartRead(len:integer);

Begin

Reset(f);

FEof:=system.Eof(f);

FCount:=len;

If not FEof then read (f,FElem);

End;

Procedure StartWrite

Rewrite (f);

Procedure CloseFile

System.CloseFile(f);

Procedure StartRun(len:integer);

FCount:=len;

Procedure Copy (y:TSequence);

Begin

Write(y.F,FElem);

FEof:=system.eof(f);

Dec(FCount)

If not FEof then read(f,FElem);

End;

Procedure CopyRun (y:TSequence);

Repeat Copy(y) until eor;

Function GetEor:Boolean;

Result:=Eof or (FCount=0)

Procedure Distribute

(f0,f1,f2:Tsequance;len:integer);

Begin

Fo.StertRead(len);

F1\f2.StartWrite;

While not f0 eof do begin

Fo.CopyRun(f1); f0.StartRun(len);

If not f0 eof then begin

Fo.copyRun(f2); fo.StartRun(len); end; end

F0\f1\f2 . CloseFile;

End;

Procedure Merge (f0,f1,f2:TSequence;len:int);

Begin

F0.StartWrite;

F1\f2. StartRead(len);

While (not f1.eof) and (not f2.eof) do begin

F1\f2. StartRun(len);

While (not f1.eof)and(not f2.eor) do

If f1.elem<f2.elem then f1.copy(f0)

Else f2.copy(f0)

If not f1.eor then f1.CopyRun(f0)

Else f2.copyRun(f0); end;

If not f1.eof then begin

F1.StartRun(len); f2.CopyRun(f0); end;

F1\f2\f0. CloseFile;

End;

Procedure Sort (FileName:string);

Var f0,f1,f2:TSequance; n,len:integer;

Begin

F0.TSequance.Create(filename)

N:=f0.SizeOf;

If N>1 then begin

F1:=TSequance.Create(‘a.tmp’);

F2:= -\\- (‘b.tmp’);

Len:=1;

Repeat

Distribute(f0,f1,f2,len);

Merge(f0,f1,f2,len);

Len:=len*2;

Until len>=N

F1.Erase; f1.Destroy;

--\\--- (f2); end;

F0.Destroy;

End;

Однофазное

Procedure MergeRun (f1,f2,f3:TSecuance;

Len:integer);

Begin

F1\f2. StartRun(len);

While (not f1.eor)and(not f2.eor) do

If f1.Elem<=f2.Elem then f1.copy(f3);

Else f2.copy (f3);

If not f1.eor then f1.copyrun(f3)

Else f2.copyrun(f3);

End;

Procedure Merge (f1,f2,f3,f4:TSequance;

Var len:integer);

Begin

F1\f2. startRead(len);

F3\f4.startWrite;

While(not f1.eof)or(not f2.eof) do begin

MergeRun(f1,f2,f3,len);

If not (f1.eof)or(not f2.eof) then

MergeRun(f1,f2,f3,len); end;

F1\f2\f3\f4. CloseFile;

Len:=len*2;

End;

Procedure Sort (filename:string);

Var f0,f1,f2,f3,f4 :TSequance;

N,len:ineteger; ok:Boolean;

Begin

F0:=TSequance.Create(filename);

N:=f0.SizeOf;

If N>1 then begin

F1\f2\f3\f4:= TSequance.Create(имя);

Len:=1; ok:=true;

Distribute (f0,f1,f2,len);

Repeat

Merge(f1,f2,f3,f4,len);

Ok:=not ok;

If len<N then begin

Merge(f3,f4,f1,f2,len);

Ok:=not ok; end;

Until len>=N

If ok then begin

F3.rename(filename); f3.erase; end;

Else begin

F3.rename(filename);

F1.erase; end;

F1\f2\f3\f4.free; end;

Fo.free;

End;