
Сортировка прямым слиянием
Принцип сортировки поясняется следующим примером.
Пусть дан массив
5 |
9 |
4 |
6 |
1 |
8 |
7 |
3 |
В первой фазе сортировки массив делится пополам, половинки удобно считать расположенными одна над другой
5 |
9 |
4 |
6 |
1 |
8 |
7 |
3 |
Производится слияние (с сортировкой) одиночных чисел, расположенных одно над другим. Из этих пар вновь составляется один общий массив
1 |
5 |
8 |
9 |
4 |
7 |
3 |
6 |
который состоит из подряд идущих упорядоченных пар.
В второй фазе сортировки массив вновь делится пополам, половинки удобно считать расположенными одна над другой
1 |
5 |
8 |
9 |
4 |
7 |
3 |
6 |
Производится слияние (с сортировкой) теперь уже пар чисел, расположенных одна над другой. Из этих четверок вновь составляется один общий массив
1 |
4 |
5 |
7 |
3 |
6 |
8 |
9 |
который состоит из подряд идущих упорядоченных четверок.
Длина упорядоченных фрагментов растет «в геометрической прогрессии» и за короткое число фаз достигает длины всего массива.
Ниже приведен полный текст процедуры StraightMergeSort – процедуры сортировки прямым слиянием.
procedure StraightMergeSort;
var
i,j,k,L,t,h,m,p,q,r:
integer;
bUp:
boolean;
begin
nMove:=0;
nCompare:=0;
bUp:=true;
p:=1;
repeat
h:=1;
m:=nCurr;
if bUp then
begin i:=1; j:=nCurr; k:=nCurr+1; L:=2*nCurr; end
else
begin k:=1; L:=nCurr; i:=nCurr+1; j:=2*nCurr; end;
repeat
if m>=p then q:=p else q:=m;
m:=m-q;
if m>=p then r:=p else r:=m;
m:=m-r;
while (q<>0) and (r<>0) do
begin
nCompare:=nCompare+1;
if A[i]<A[j] then
begin
A[k]:=A[i];
i:=i+1; q:=q-1;
end
else
begin
A[k]:=A[j];
j:=j-1; r:=r-1;
end;
nMove:=nMove+2;
k:=k+h;
end;
while r>0 do
begin
A[k]:=A[j];
nMove:=nMove+2;
k:=k+h; j:=j-1; r:=r-1;
end;
while q>0 do
begin
A[k]:=A[i];
nMove:=nMove+2;
k:=k+h; i:=i+1; q:=q-1;
end;
h:=-h; t:=k; k:=L; L:=t;
until m=0;
bUp:=not bUp;
p:=2*p;
until p>=nCurr;
if not bUp then
for i:=1 to nCurr do
begin
A[i]:=A[i+nCurr];
// nMove:=nMove+2;
end;
end;
Сортировка естественным слиянием
Идея сортировки состоит в следующем.
Сортируемый массив из элементов разбивается на подмассивы, каждый из которых «случайно» оказался отсортированным. Пусть имеется в виду сортировка по возрастанию Тогда правая граница подмассива – это индекс элемента массива, который является последним или после которого возрастание «вдруг» сменяется убыванием.
Такой частично упорядоченный массив получается простым соединением в одну длинную цепь таких наборов элементов, где каждый набор уже был сознательно отсортирован.
Даже если массив не упорядочивался частично, вероятность, что все отсортированные подмассивы состоят из одного элемента, достаточно мала.
Слушателям предлагается самостоятельно оценить, чему именно равна такая вероятность.
Пример.
Исходный массив:
3 5 16 18 1 13 17 2 9 11 4 12 7 10 15
Поиск упорядоченных подмассивов и их слияние (по два)
Ниже приведен полный текст процедуры NaturalMergeSort – процедуры сортировки слиянием.
procedure NaturalMergeSort;
var
i, nB: integer;
mB: array[0..2] of integer;
bBound, bSorted: boolean;
procedure Merge(p, q, r: integer);
var
i, j, k: integer;
begin
i:=p;
j:=q+1;
k:=n;
while (i<=q) and (j<=r) do
begin
Inc(k);
Inc(nC);
if A[i]<A[j] then
begin
A[k]:=A[i];
Inc(i);
end
else
begin
A[k]:=A[j];
Inc(j);
end;
Inc(nM);
end;
while i<=q do
begin
Inc(k);
A[k]:=A[i];
Inc(nM);
Inc(i);
end;
while j<=r do
begin
Inc(k);
A[k]:=A[j];
Inc(nM);
Inc(j);
end;
k:=n;
for i:=p to r do
begin
Inc(k);
A[i]:=A[k];
end;
end;
begin
while True do
begin
nB:=0;
mB[0]:=1;
bSorted:=True;
for i:=1 to n do
begin
bBound:=False;
if i=n then
bBound:=True
else
if A[i]>A[i+1] then
begin
bBound:=True;
bSorted:=False;
end;
if bBound then
begin
Inc(nB);
mB[nB]:=i;
end;
if nB=2 then
begin
Merge(mB[0], mB[1], mB[2]);
nB:=0;
mB[0]:=mB[2];
end;
end;
if bSorted then Break;
end;
end;