Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Алгоритмы и структуры данных.doc
Скачиваний:
0
Добавлен:
01.03.2025
Размер:
1.14 Mб
Скачать

2.5Сравнение простых сортировок

Для таких сортировок известны точные аналитические формулы. Пусть n – количество сортировок, C – количество сравнений, M – количество перестановок.

Таблица 1.1

Тип сортировки

Тип действия

Количество действий

Min

Avg

Max

Прямое включение

C =

n-1

(n2+n–2)/4

(n2–n)/2–1

M =

2(n–1)

(n2-9n–10)/4

(n2–3n-4)/2

Прямой выбор

C =

(n2-n)/2

(n2-n)/2

(n2–n)/2

M =

3(n–1)

n*(ln n+0.57)

n2/4+3(n-1)

Прямой обмен

C =

(n2-n)/2

(n2-n)/2

(n2–n)/2

M =

0

(n2-n)*0.75

(n2-n)*1.5

Для усовершенствованных сортировок точные формулы неизвестны, поэтому в последующем будут даны относительные временные характеристики простых и усовершенствованных сортировок.

2.6 Сортировка шелла

Алгоритм был предложен Д.Л. Шеллом в 1959г. и долгое время рассматривался как наиболее совершенный.

Предложенный метод сортировки основан на модификации метода сортировки простым включением. Его можно охарактеризовать как сортировка включением с убывающим приращением.

Суть предложенного метода в том, что первоначально сортируется не вся исходная последовательность элементов целиком, а отдельные её небольшие группы, на которые разбита вся последовательность.

Эти группы формируются из элементов, отстоящих друг от друга на определённом расстоянии, например, с шагом 4-ре. В пределах группы выполняется сортировка простым включением. Этот процесс называется "4"-сортировкой.

Затем размер групп увеличивается, для этого в каждую группу включаются элементы, отстоящие друг о друга, например, с шагом 2. Для каждой группы выполняется СПВкл. Этот процесс называется "2"-сортировкой.

И, наконец, ко всей результирующей последовательности применяется СПВкл. Получаем "1"-сортировку.

Этот способ иллюстрируется следующим примером.

" 4"-Сортировка: 44 55 11 33 99 22 01 77

Первая группа включает элементы 44 и 99, а последняя 33 и 77.

Результатом является последовательность:

" 2"-Сортировка: 44 22 01 33 99 55 11 77

Получим результат:

"1"-Сортировка: 01 22 11 33 44 55 99 77

И окончательно получим:

01 11 22 33 44 55 77 99

Вначале может показаться, что необходимость нескольких проходов сортировки, в каждом из которых всё равно участвуют все элементы, потребует работы больше чем сэкономит. Однако на каждом шаге сортировки либо участвует сравнительно мало элементов, либо они уже довольно хорошо упорядочены и требуют относительно мало перестановок.

Очевидно, что этот метод даёт в результате упорядоченный массив, а каждый последующий проход использует результаты предыдущего прохода, поскольку каждая i-тая сортировка использует результаты предыдущей 2i‑сортировки.

В принципе может быть выбрана любая последовательность приращений, а не только степень числа 2. Лишь бы последнее приращение было равно 1. Более того, опыт показал, что лучше, когда приращения не являются степенью числа 2.

При разработке алгоритма рассматривается последовательность приращений

h1, h2, ..., ht

с условием

ht = 1 и hi+1 < hi

Каждая h-сортировка программируется как СПВкл, а для определения условия окончания поиска используется барьер. Причем барьер нужен для каждой h-сортировки, а программ должна определять его как можно проще.

Перед описанием процедуры сортировки сделаем следующее замечание. При объяснении алгоритма для достижения ясности мы исходим из того, что при очередной h-сортировке сначала обрабатывается первая группа этой сортировки, затем вторая и т.д. Но при написании процедуры в этом нет необходимости. При выполнении h-сортировки, начиная с элемента на позиции h+1 и до конца массива, последовательно выбираются элементы и для каждого выбранного элемента алгоритмически “восстанавливается” его группа, точнее все предшествующие ему элементы в группе, что и необходимо для СПВкл.

Так как размер массива элементов заранее не известен, то используем специальную процедуру GenH, которая определяет возможное количество приращений CntH и формирует массив H соответствующих приращений. В этом массиве на первом месте стоит максимальное приращение, а на последнем месте – минимальное, т.е. 1, приращение. О выборе возможных значений приращений см. ниже.

Процедура сортировки для любого количества приращений имеет вид:

type TH = array of integer; {динамический массив констант для описания приращений. Внимание! H[1] < N}

TArr = array of Item;

var I: integer;

CountH: integer; {количество приращений}

Ar: TArr; {Массив данных}

procedure GenH (var H: TH; var CntH: CountH; N: integer); {формирование массива приращений}

var J: integer;

begin

CntH := (Ln(N) div Ln(3) - 1); {размер массива H равен Log3N}

SetLength (H, CntH); {выделяется место для массива приращений}

H[CntH-1] := 1; {в последний элемент массива заносится минимальное приращение}

for j := CntH –2 to 0 do

H[j] := 3*H[j +1] + 1; {формирование оставшихся шагов приращений}

end; {GenH}

procedure ShellSort (var A: TArr);

var I, J: integer;

K: integer; {размер текущего приращения}

N: integer; {количество элементов сортируемой последовательности}

X: Item;

H: TH; {массив приращений}

CntH: CountH; {размер массива приращений H}

begin

N := Length (A); {размер массива элементов А}

GenH (H, CntH, N); {формирование массива приращений}

for M := 0 to CntH-1 do {управление приращениями}

begin

K := H[M]; {установка m-го приращения}

for I := K + 1 to N-1 do {формирование (переменная i) -сортировки}

begin

X := A[I]; {подготовка барьера очередной группы}

J := I - K; {координата предыдущего элемента в группе}

{Обработка очередной H[CntH] группы}

while X.Key < A[J].Key and (J >= 0) do

begin

A[J+K] := A[J];

J := J - K; {координата очередного обрабатываемого элемента в группе}

end;

A[J+K] := X; {размещение элемента на своём месте в группе}

end;

end;

end; {ShellSort}

begin

{формирование и заполнение массива А}

ShellSort (A); {сортировка массива}



end.

Для пояснения алгоритма выше использовалась последовательность приращений, являющаяся степенью числа 2.

В процедуре использована другая последовательность приращений, реализуемая процедурой GenH.

На сегодня неизвестна идеальная последовательность приращений. Однако отмечен удивительный факт, что они не должны быть кратны друг другу. Это позволяет избежать явления, которое видно для примеров приращений, образующих степень числа 2, когда каждый проход сортировки объединяет две цепочки, которые ранее никак не взаимодействовали.

В действительности желательно, чтобы взаимодействие между разными цепочками происходило как можно чаще. Справедлива такая теорема:

Если k-рассортированая (например 9-сортировкой) последовательность затем i-сортируется (например 5-сортировкой), то она по-прежнему остаётся k-отсортированной (т.е. 9-отсортированной).

Предлагаются разные схемы приращений. Одна из них имеет вид (записанная в обратном порядке):

1, 4, 13, 40, 121, . . .,

где h1 = 1 и hk+1 = 3hk+1

а общее количество требуемых приращений t = [log3n]-1, где [log3n] означает взятие целой части числа log3n.

Другая последовательность имеет вид:

1, 3, 7, 15, 31, . . .,

где hk+1 = 2hk+1, h1 = 1

а общее количество требуемых приращений t = [log2n]-1, где [log2n] означает взятие целой части числа log2n.

Проведенный анализ показал, что для последовательности

1, 3, 7, 15, 31, . и т.д.

затраты, требуемые для сортировки n элементов, пропорциональны числу n1.2. Это намного лучше по сравнению с n2, но известны алгоритмы, работающие ещё лучше. Поэтому сортировка Шелла сейчас практически не используется.