Сортировка
4.1. Квадратичные алгоритмы
4.1.1.
Пусть
- целые числа. Требуется
построить массив
, содержащий те
же числа, для которого
.
Замечание. Среди чисел
могут быть
равные. Требуется, чтобы каждое целое число входило
в
столько же раз, сколько и в
.
Решение.
Удобно считать, что числа
и
представляют собой начальное
и конечное значения массива x. Требование " a
и b содержат одни и те же числа" будет заведомо
выполнено, если в процессе работы мы ограничимся
перестановками элементов x.
k := 0;
{k наименьших элементов массива установлены на свои места}
while k <> n do begin
| s := k + 1; t := k + 1;
| {x[s] - наименьший среди x[k+1]...x[t] }
| while t<>n do begin
| | t := t + 1;
| | if x[t] < x[s] then begin
| | | s := t;
| | end;
| end;
| {x[s] - наименьший среди x[k+1]..x[n] }
| ... переставить x[s] и x[k+1];
| k := k + 1;
end;4.1.2.
Дать другое решение задачи сортировки, использующее
инвариант "первые k элементов упорядочены"
(
).
Решение.
k:=1;
{первые k элементов упорядочены}
while k <> n do begin
| t := k+1;
| {k+1-ый элемент продвигается к началу, пока не займет
| надлежащего места, t - его текущий номер}
| while (t > 1) and (x[t] < x[t-1]) do begin
| | ...поменять x[t-1] и x[t];
| | t := t - 1;
| end;
end;Замечание. Дефект программы: при ложном выражении (t>1)
проверка
требует несуществующего
значения x[0].
Оба предложенных решения требуют числа действий,
пропорционального
. Существуют более эффективные
алгоритмы.
4.2. Алгоритмы порядка n log n
4.2.1.
Предложить алгоритм сортировки за время
(число
операций при сортировке
элементов не больше
для некоторого
и для
всех
).
Мы предложим два решения.
Решение 1 (сортировка слиянием).
Пусть k - положительное целое число. Разобьем массив
на отрезки
длины k. (Первый -
, затем
и так
далее.) Последний отрезок будет неполным, если n не
делится на k. Назовем массив k-упорядоченным,
если каждый из этих отрезков в отдельности упорядочен.
Любой массив 1-упорядочен. Если массив k-упорядочен и
, то он упорядочен.
Мы опишем, как преобразовать k-упорядоченный массив в 2k-упорядоченный (из тех же элементов). С помощью этого преобразования алгоритм записывается так:
k:=1;
{массив x является k-упорядоченным}
while k < n do begin
| ...преобразовать k-упорядоченный массив в 2k-упорядоченный;
| k := 2 * k;
end;Требуемое преобразование состоит в том,что мы многократно "сливаем" два упорядоченных отрезка длины не больше k в один упорядоченный отрезок. Пусть процедура

сливает отрезки
и
в упорядоченный отрезок
(не
затрагивая других частей массива x ).Тогда преобразование k -упорядоченного массива в 2k -упорядоченный осуществляется так:
t:=0;
{t кратно 2k или t = n, x[1]..x[t] является
2k-упорядоченным; остаток массива x не изменился}
while t + k < n do begin
| p := t;
| q := t+k;
| r := min (t+2*k, n);
| {min(a,b) - минимум из a и b}
| слияние (p,q,r);
| t := r;
end;Слияние требует вспомогательного массива для записи результатов слияния - обозначим его b. Через p0 и q0 обозначим номера последних элементов участков, подвергшихся слиянию, s0 - последний записанный в массив b элемент. На каждом шаге слияния производится одно из двух действий:
b[s0+1]:=x[p0+1]; p0:=p0+1; s0:=s0+1;
или
b[s0+1]:=x[q0+1]; q0:=q0+1; s0:=s0+1;
(Любители языка C написали бы в этом случае b[++s0]=x[++p0] и b[++s0]=x[++q0].)
