Еще одна модификация пузырьковой сортировки носит название

шейкер-сортировки. Суть ее состоит в том, что направления прос-

мотров чередуются: за просмотром от начала к концу следует прос-

мотр от конца к началу входного множества. При просмотре в прямом

направлении запись с самым большим ключом ставится на свое место

в последовательности, при просмотре в обратном направлении - за-

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

восстановления упорядоченности, когда исходная последовательность

уже была упорядочена, но подверглась не очень значительным изме-

нениям. Упорядоченность в последовательности с одиночным измене-

нием будет гарантированно восстановлена всего за два прохода.

СОРТИРОВКА ШЕЛЛА. Это еще одна модификация пузырьковой сор-

тировки. Здесь выполняется сравнение ключей, отстоящих один от

другого на некотором расстоянии d. Исходный размер d обычно выби-

рается соизмеримым с половиной общего размера сортируемой после-

довательности. Выполняется пузырьковая сортировка с интервалом

сравнения d. Затем величина d уменьшается вдвое и вновь выполня-

ется пузырьковая сортировка, далее d уменьшается еще вдвое и т.д.

Последняя пузырьковая сортировка выполняется при d=1. Качествен-

ный порядок сортировки Шелла остается O(N^2), среднее же число

сравнений, определенное эмпирическим путем - log2(N)^2*N. Ускоре-

ние достигается за счет того, что выявленные "не на месте" эле-

менты при d>1, быстрее "всплывают" на свои места.

Пример 3.10 иллюстрирует сортировку Шелла.

{===== Программный пример 3.10 =====}

Procedure Sort( var a : seq);

Var d, i, t : integer;

k : boolean; { признак перестановки }

begin d:=N div 2; { начальное значение интервала }

while d>0 do begin { цикл с уменьшением интервала до 1 }

k:=true; { пузырьковая сортировка с интервалом d }

while k do { цикл, пока есть перестановки }

begin k:=false; i:=1;

for i:=1 to N-d do {сравнение эл-тов на интервале d}

begin if a[i]>a[i+d] then

begin t:=a[i]; a[i]:=a[i+d]; a[i+d]:=t; {перестановка}

k:=true; { признак перестановки }

end; { if ... } end; { for ... } end; { while k }

d:=d div 2; { уменьшение интервала }

end; { while d>0 } end;

Результаты трассировки программного примера 3.10 представле-

ны в таблице 3.7.

Таблица 3.7

┌─────────┬───┬─────────────────────────────────────────────────┐

│ шаг │ d │ содержимое массива a │

├─────────┼───┼─────────────────────────────────────────────────┤

│исходный │ │ 76 22 4 17 13 49 4 18 32 40 96 57 77 20 1 52 │

│ 1 │ 8 │ 32 22 4 17 13 20 1 18 76 40 96 57 77 49 4 52 │

│ 2 │ 8 │ 32 22 4 17 13 20 1 18 76 40 96 57 77 49 4 52 │

│ 3 │ 4 │ 13 20 1 17 32 22 4 18 76 40 4 52 77 49 96 57 │

│ 4 │ 4 │ 13 20 1 17 32 22 4 18 76 40 4 52 77 49 96 57 │

│ 5 │ 2 │ 1 17 13 20 4 18 32 22 4 40 76 49 77 52 96 57 │

│ 6 │ 2 │ 1 17 4 18 13 20 4 22 32 40 76 49 77 52 96 57 │

│ 7 │ 2 │ 1 17 4 18 4 20 13 22 32 40 76 49 77 52 96 57 │

│ 8 │ 2 │ 1 17 4 18 4 20 13 22 32 40 76 49 77 52 96 57 │

│ 9 │ 1 │ 1 4 17 4 18 13 20 22 32 40 49 76 52 77 57 96 │

│ 10 │ 1 │ 1 4 4 17 13 18 20 22 32 40 49 52 76 57 77 96 │

│ 11 │ 1 │ 1 4 4 13 17 18 20 22 32 40 49 52 57 76 77 96 │

│ 12 │ 1 │ 1 4 4 13 17 18 20 22 32 40 49 52 57 76 77 96 │

│результат│ │ 1 4 4 13 17 18 20 22 32 40 49 52 57 76 77 96 │

└─────────┴───┴─────────────────────────────────────────────────┘