Ради большей наглядности мы пожертвовали эффективностью и воспользовались алгоритмом ПрВст, а не ПрВстБар или БинВст. Дотошному же читателю предоставляется возможность самостоятельно улучшить предлагаемую реализацию:
program shell_sort;
const n=18;
a:array[1..n] of integer
=(18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1);
var ii,m,x,s,p,t,k,r,i,j: integer;
begin
t:= trunc(ln(n)/ln(2));
repeat
t:= t-1;
k:= (1 shl t)-1;
p:= n mod k;
s:= n div k;
if p=0 then
p:= k
else
s:= s+1;
writeln(k,'-сортировка');
for i:= 1 to k do {берем и длинные, и короткие подпоследовательности}
begin
if i= p+1 then s:= s-1; (для коротких - уменьшаем длину}
for j:= 1 to s-1 do {метод ПрВст с шагом k}
if a[i+(j-1)*k]>a[i+j*k] then begin
x:= a[i+j*k];
m:= i+(j-1)*k;
while (m>0) and (a[m]>x) do begin
a[m+k]:= a[m];
m:= m-k;
end;
a[m+k]:= x;
end;
for ii:= 1 to n do
write(a[ii],' ');
writeln;
end;
until k=1;
end.
7-сортировки
4 17 16 15 14 13 12 11 10 9 8 7 6 5 18 3 2 1
4 3 16 15 14 13 12 11 10 9 8 7 6 5 18 17 2 1
4 3 2 15 14 13 12 11 10 9 8 7 6 5 18 17 16 1
4 3 2 1 14 13 12 11 10 9 8 7 6 5 18 17 16 15
4 3 2 1 7 13 12 11 10 9 8 14 6 5 18 17 16 15
4 3 2 1 7 6 12 11 10 9 8 14 13 5 18 17 16 15
4 3 2 1 7 6 5 11 10 9 8 14 13 12 18 17 16 15
3-сортировки
1 3 2 4 7 6 5 11 10 9 8 14 13 12 18 17 16 15
1 3 2 4 7 6 5 8 10 9 11 14 13 12 18 17 16 15
1 3 2 4 7 6 5 8 10 9 11 14 13 12 15 17 16 18
1-сортировка
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
Довольно сложными методами, в изложение которых мы не будем углубляться, показано, что алгоритм Шелла имеет сложность ~N3/2. И хотя это несколько хуже, чем N*logN, все-таки эта сортировка относится к улучшенным.
Пример сравнения сортировок:
Вновь возьмем последовательность, для сортировки которой методом простых вставок ПрВст потребовалось 15 сдвигов (25 пересылок и 20 сравнений):
5 3 4 3 6 2 1
Теперь применим к ней метод Шелла.
Здесь N = 7, поэтому:
t= trunc(log 7) = 2
k= 22-1 = 3 {начнем с 3-сортировки}
p= 7 mod 3 = 1 {кол-во длинных подпоследовательностей}
s= (7 div 3)+1 = 3 {длина длинной подпоследовательности}
Состояние массива Сдвиги Сравнения Пересылки данных
0 шаг: 1323645
1 шаг: 1323645 0 1 0
2 шаг: 1323645 1 1+1 1+2
3 шаг: 1233645 0 1 0
4 шаг: 1233645 0 1 0
5 шаг: 1233645 1 1+1 1+2
6 шаг: 1233465 1 1+1 1+2
результат: 1233456 3 9 9
При сортировке методом Шелла в сумме получилось 7 сдвигов (19 пересылок и 17 сравнений). Выигрыш по сравнению с методом простых вставок составляет 53% (24% экономится на пересылках и 15% - на сравнениях). Если вместо метода простых вставок ПрВст использовать метод бинарных вставок БинВст, то выигрыш по количеству сравнений будет ощутимее.
Кроме того, не нужно забывать, что в нашем примере последовательность очень коротка: N = 7. Для больших N (скажем, N = 10000) преимущество метода Шелла станет еще заметнее.
Попытаемся теперь усовершенствовать другой рассмотренный выше простой алгоритм: сортировку простым выбором ПрВыб.
Р. Флойд предложил перестроить линейный массив в пирамиду - своеобразное бинарное дерево, - а затем искать минимум только среди тех элементов, которые находятся непосредственно "под" текущим вставляемым.