1.4. Вставки с убывающим шагом (метод Шелла)
Идея алгоритма состоит в обмене элементов, расположенных не только рядом, как в алгоритме простых вставок (п.1), но и далеко друг от друга, что значительно сокращает общее число операций перемещения элементов. Для примера возьмем файл из 16 элементов. Сначала просматриваются пары с шагом 8. Это пары элементов 1-9, 2-0, 3-11, 4-12, 5-13, 6-14, 7-15, 8-16. Если значения элементов в паре не упорядочены по возрастанию, то элементы меняются местами. Назовем этот этап 8-сортировкой. Следующий этап - 4-сортировка, на котором элементы в файле делятся на четверки: 1-5-9-13, 2-6-10-14, 3-7-11-15, 4-8-12-16. Выполняется сортировка в каждой четверке. Сортировка может выполняться методом простых вставок (п.1). Следующий этап - 2-сортировка, когда элементы в файле делятся на 2 группы по 8: 1-3-5-7-9-11-13-15 и 2-4-6-8-10-12-14-16. Выполняется сортировка в каждой восьмерке. Наконец весь файл упорядочивается методом простых вставок. Поскольку дальние элементы уже переместились на свое место или находятся вблизи от него, этот этап будет значительно менее трудоемким, чем при сортировке вставками без предварительных "дальних" обменов. Для данного примера результаты представлены в следующей таблице. Исходный файл. На нем выполняется 8-сортировка.Пары для возможного обмена соединены одинарными или двойными линиями. Двойными линиями обозначены пары, в которых произошел обмен.
503 87 512 61 908 170 897 275 653 426 154 509 612 677 765 703
└──┼───╫──┼──╫────┼───╫───┼───┘ │ ║ │ ║ │ ║ │
└───╫──┼──╫────┼───╫───┼───────┘ ║ │ ║ │ ║ │
╙──┼──╫────┼───╫───┼───────────╜ │ ║ │ ║ │
└──╫────┼───╫───┼───────────────┘ ║ │ ║ │
╙────┼───╫───┼───────────────────╜ │ ║ │
└───╫───┼───────────────────────┘ ║ │
╙───┼───────────────────────────╜ │
└───────────────────────────────┘
Файл после 8-сортировки. Линиями соединены четверки для следующего этапа.
503 87 154 61 612 170 765 275 653 426 512 509 908 677 897 703
└───┼──┼──┼───┴───┼───╫───┼───┴───┼───╫───┼───┘ │ │ │
└──┼──┼───────┴───╫───┼───────┴───╫───┼───────┘ │ │
└──┼───────────╨───┼───────────╨───┼───────────┘ │
└───────────────┴───────────────┴───────────────┘
Файл после 4-сортировки. Линиями соединены восьмерки для следующего этапа.
503 87 154 61 612 170 512 275 653 426 765 509 908 677 897 703
╙──╫───╨──╫───╨───┼───╨───┼───┴───┼───┴───┼───╨───┼───╜ │
╙──────╨───────┴───────┴───────┴───────┴───────┴───────┘
Файл после 2-сортировки:
154 61 503 87 512 170 612 275 653 426 765 509 897 677 908 703
Файл после окончательной сортировки (1-сортировки):
61 87 154 170 275 426 503 509 512 612 653 677 703 765 897 908
Время работы алгоритма t примерно оценивается формулой:
t=a*N**1.25
где a - неизвестная константа, зависящая от программной реализации алгоритма.
Альтернативное описание:
Суть метода в том, что в отличие от обычной сортировки вставками, а метод Шелла это не что иное, как модификация метода простых вставок, здесь происходит упорядочивание элементов стоящих друг от друга на шаге d, т.е. упорядочиваются элементы с индексами отличающимися на d. Затем элементов стоящих друг от друга на шаге h (с индексами отличающимися на h причем h
Время работы алгоритма в худшем случае t примерно оценивается формулой:
t=a*N**1.5 ,
где a - неизвестная константа, зависящая от программной реализации алгоритма.
Сетевые ресурсы:
1. http://ru.wikibooks.org/wiki/Примеры_реализации_сортировки_Шелла - (здесь исходные коды на множество популярных языков программирования таких как Java, C#, C++, PHP, Python).
2. http://algolist.manual.ru/sort/shell_sort.php - (довольно популярно объяснено описание алгоритма).
3. http://ru.wikipedia.org/wiki/Сортировка_Шелла - более детальное описание.
4. http://www.sorting-algorithms.com/shell-sort - визуализация (из инвертированного состояния, почти упорядоченного состояния, с часто повторяющимися элементами, произвольного состояния)
1.5. Вставки в связанный список
Среди общих способов улучшения алгоритма простых вставок можно рассмотреть способ, основанный на изменении структуры данных. Сортировка простыми вставками состоит из двух основных операций:
просмотра исходного файла со сравнением переменной Х с элементами K[i] файла;
вставки нового элемента путем сдвига оставшихся элементов вправо.
Файл до сих пор рассматривался как линейный список и для выполнения операции вставки в нем необходимо переместить в среднем половину элементов. Известно, что для операций вставки идеально подходит связанный список, так как в этом случае вставка требует всего лишь изменения нескольких связей. Операция последовательного просмотра для связанного списка почти так же проста, как и для линейного списка. Поскольку файл всегда просматривается в одном направлении, то достаточно иметь список только с одной связью. С другой стороны связанное распределение делает невозможным бинарный поиск, поэтому приобретая преимущество в выполнении операции вставки, мы теряем по сравнению с бинарным поиском в эффективности операции просмотра и сравнения. Рассмотрим алгоритм простых вставок на связанном вперед списке.
Дан файл в виде связанного списка, каждый элемент которого содержит кроме ключа K[i] еще и указатель на следующий элемент L[i]. Кроме того есть еще дополнительная переменная L[0], содержащая указатель на последний N-й элемент файла. Указатель L[N] равен нулю, что является признаком конца списка элементов.
K[1]
L[1]
K[2]
L[2]
K[N]
L[N]
…
L[0]
= 0
Упорядоченная часть файла формируется в конце списка и L[0] всегда указывает на начало упорядоченной части, в конце алгоритма - на логическое начало списка.
Алгоритм имеет следующий вид:
for j = N - 1 to 1
P = L[0]; q = 0; X = K[j];
Продвижение по списку
q = p;
p = L[p];
вставка
L[q] = j;
L[j] = p;
while(p > 0 & X > K[p])
q
p
L[q]
K[q]
K[p]
L[p]
Переменные p и q служат указателями на текущий элемент, причем =l[q] (q всегда на один шаг отстает от p). Если p=0, то Х - наибольший элемент и должен попасть в конец списка.
Время работы алгоритма t примерно оценивается формулой:
где a, b - неизвестные константы, зависящие от программной реализации алгоритма.
1.6. Вставки в несколько связанных списков
Идея метода основывается на предположении, что ключи в исходном файле имеют значения в некотором известном диапазоне MAX и в этом диапазоне они распределены довольно равномерно. Тогда по аналогии с методом вставки в один связанный список можно организовать несколько, например, Q списков. Величина Q зависит от ожидаемого среднего количества элементов M в каждом списке, то есть Q=N/M, N - количество ключей. При разработке программы нужно проанализировать зависимость времени работы метода от параметра М для различных исходных файлов и дать рекомендации по выбору оптимального значения.
Схема алгоритма имеет следующий вид. Через Q обозначено количество списков, массив B[1]...B[Q] служит для хранения указателей на начала отдельных списков. Перед началом работы алгоритма элементы массива В предполагаются равными 0. Каждый i-й элемент исходного файла содержит ключ K[i] и указатель L[i] на следующий элемент списка. Значение L[i]=0 соответствует последнему элементу в списке, указатель B[1] указывает на начало первого подсписка и одновременно на начало всего списка. Через minK обозначено минимальное значение ключа в файле, через М - среднее выбранное значение количества элементов в подсписке. d - номер текущего списка, в который должен быть вставлен элемент K[j]. Величина R=MAX/Q есть диапазон значений ключей, приходящийся на один список.
for j = N - 1 to 1
X = K[j];
d = (X - minK) / R + 1; (деление нацело)
p = B[d];
q = 0;
Продвижение по списку
q = p;
p = L[p];
Вставка элемента Х
if(q=0) B[d]=j; else L[q]=j;
L[j]=p;
while(p > 0 & X > K[p])
Время работы алгоритма t примерно оценивается формулой:
где a,b - неизвестные константы, зависящие от программной реализации алгоритма.
|