Автор работы: Пользователь скрыл имя, 26 Апреля 2012 в 21:22, курсовая работа
За время существования профессии программиста сущность его труда изменилась коренным образом. В 50-х годах программы писали в командах ЭВМ (в “машинных кодах”). При этом вся информация переводилась в двоичную систему счисления. Это очень тяжелый и напряженный труд, требующий от человека особой аккуратности. Облегченно вздохнули программисты при появлении в 1956 г. специального языка для решения вычислительных задач. Это был FORTRAN (Formula Translator). С тех пор были разработаны другие, более совершенные языки, или специализированные применительно к какой-то конкретной области: КОБОЛ, АЛГОЛ, ПЛ/1, ЛИСП, СИМУЛА, ПАСКАЛЬ, СИ, АДА, ПРОЛОГ и др.
В основе алгоритма лежит цикл, определяющий, для какого элемента ищем место в упорядоченной левой части последовательности.
Ввод (последовательность А);
BEGIN
END;
Вывод (последовательность А);
Детализируем п. 2.1. Нужно сравнивать AI последовательно со всеми левыми соседями до элемента AK ≤ AI. Если такового не окажется, остановиться на первом элементе. Это циклические действия, причем удобнее оформить цикл по текущему номеру элемента. Тогда получим:
2.1.1. Инициализация цикла;
2.1.2. WHILE J>0 DO
BEGIN
2.1.2.1. сравнить элементы AI и AJ;
END;
При реализации п.2.1.1 мы должны предусмотреть 3 момента:
2.1.1. X:=A[I];
J:=I-1;
K:=0;
2.1.2.1. По результатам сравнения нужно сделать вывод: продолжать его или закончить цикл. Закончить цикл можно, положив J = 0.
2.1.2.1.IF A[J]<=A[I] THEN
BEGIN
K:=J;
J:=0;
END;
ELSE J:=J-1;
2.2. Для сдвига последовательности нужно просматривать ее из конца в начало и последовательно сдвигать элементы. Это делается так:
J:=I;
WHILE J>K+1 DO
BEGIN
A[J]:=A[J-1];
J:=J-1;
END;
2.3. A[K+1]:=X;
Теперь запишем весь алгоритм.
Ввод (последовательность А);
I:=2;
WHILE I ≤ N DO
BEGIN
X:=A[I];
J:=I-1;
K:=0;
WHILE J>0 DO
BEGIN
IF A[J]<=A[I] THEN
BEGIN
K:=J;
J:=0;
END
ELSE J:=J-1;
END;
J:=I;
WHILE J>K+1 DO
BEGIN
A[J]:=A[J-1];
J:=J-1;
END;
A[K+1]:=X;
I:=I+1;
END;
Вывод (последовательность А);
Проведем анализ трудоемкости простых алгоритмов сортировки на примере алгоритма простых вставок.
Число сравнений ключей Ci на i-ом просмотре последовательности:
Сi min = 1, Ci max = i-1, тогда Ci cp = .
Общее число сравнений (по формуле для суммы арифметической прогрессии ) равно
C min = N-1,
C cp = ,
C max = .
Число же перестановок (присваиваний элементов) Mi = Ci +2.
Поэтому общее число присваиваний равно
M min = 3(N –1), (Mi min = 3)
M cp = , (Mi cp = ),
M max = , (Mi max = i + 4).
Аналогично можно проанализировать и два других. Самый медленный – пузырек.
Везде получим, что
С ~ N 2, M ~ N 2.
Для больших N это слишком много. Поэтому возникли улучшенные алгоритмы. Один из них – алгоритм Шелла.
Алгоритм предложен в 1959 году как усовершенствование метода простых вставок. Является самым простым среди улучшенных алгоритмов сортировки. Может работать и как улучшенный метод простого обмена («пузырька»).
В «пузырьке» сравниваем соседние элементы. Но если в массиве элементы стоят очень далеко от своего истинного места, то придется совершить очень
Идея метода состоит в следующем: сначала переставлять элементы на большие расстояния, а затем расстояния сужать. Расстояние между сравниваемыми элементами задается с помощью вспомогательной величины h – шага перестановки элементов. На каждом этапе рассматриваются ai и ai+h.
При заданных
h и начальном значении i все рассматриваемые
на данном этапе элементы образуют цепочку.
Если изменить i, то получим другие цепочки:
При уменьшении шага h количество цепочек уменьшается, а длина их возрастает. На самом последнем этапе h=1 (обязательно!), и весь массив представляет собой одну цепочку. «Пузырек» - частный случай алгоритма Шелла при h=1.
Для нашего массива получим следующий процесс сортировки (табл.2.7).
Номер элемента | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
Исходная последовательность | 72 | 14 | 6 | 98 | 17 | 51 | 25 | 33 |
После сортировки при h=4 | 17 | 14 | 6 | 33 | 72 | 51 | 25 | 98 |
h=2 | 6 | 14 | 17 | 33 | 25 | 51 | 72 | 98 |
h=1 | 6 | 14 | 17 | 25 | 33 | 51 | 72 | 98 |
Упорядоченная последовательность | 6 | 14 | 17 | 25 | 33 | 51 | 72 | 98 |
Таким образом, мы видим, что внешне процесс существенно усложняется: вместо одной сортировки необходимо несколько (при каждом h – несколько цепочек и для каждой нужно провести сортировку). В чем же преимущество?
Дело в том, что на каждом шаге либо сортируется относительно мало элементов (на первых этапах), либо элементы уже довольно хорошо упорядочены и требуют сравнительно немного перестановок (на последующих этапах). Это важно, так как перестановки (присваивания) – более медленные операции, чем сравнения. Почему в конце концов массив окажется упорядоченным? Потому что последнее значение шага h=1 и весь массив окончательно упорядочивается как одна цепочка.
Алгоритм Шелла запишем теперь в виде процедуры. В ней следует учесть два важных момента.
hj-1 = 2hj +1 (в обратном порядке: 1, 3, 7, 15, …)
или
hj-1 = 3hj +1 (1, 4, 13, 40, …)
Теперь запишем весь алгоритм.
CONST N = …;
TYPE MAS = ARRAY [1..N] OF REAL;
PROCEDURE SHELL (N: INTEGER; VAR A: MAS);
VAR H, I: INTEGER;
BEGIN
H:=(N+2) DIV 3;
WHILE H>0 DO
BEGIN
FOR I:=1 TO H DO
BEGIN
Упорядоч
END;
IF H>5
THEN H:= (H-1) DIV 2;
ELSE IF H=1
THEN H:=0
ELSE H:=1
END
END;
Алгоритм Шелла до сих пор полностью не исследован. Его анализ поставил ряд трудных математических проблем, которые пока так и не решены (как, например, проблема выбора h).
При надлежащем выборе h трудоемкость алгоритма Шелла в худшем случае ~ n3/2. В среднем ~ (log2 n)2n. Это намного лучше, чем n2.
n = 100, n2 = 104, n3/2 = 103, (log2 n)2n ~ 49n = 49*102
n = 10000, n2 = 108, n3/2 = 106, (log2 n)2n ~ 142n = 142*104
n ≤ (1÷5)103 элементов. Теоретически показано, что трудоемкость оптимального алгоритма сортировки должна быть ~ n log2 n.
Для небольших n нецелесообразно применять сложные алгоритмы. Но при больших n улучшенные алгоритмы имеют преимущества.
Рассмотрим алгоритм, который является в среднем оптимальным. Это алгоритм Хоара.
Алгоритм Хоара был разработан в 1961 – 62 гг. Это так называемая быстрая сортировка, представляющая собой улучшенный метод, основанный на обмене. Несмотря на то, что обычный обмен в среднем является самой неэффективной процедурой, его улучшение, о котором будем говорить, приводит к самому лучшему в настоящий момент алгоритму сортировки для массивов. Алгоритм основан на разделении массива опорным элементом.
Возьмем из массива какой-либо элемент Z (опорный) и будем сравнивать его поочередно со всеми остальными. Если Mi ≤ Z – переставляем Mi в начало последовательности.
Mi ≥ Z – в конец. В результате получим:
Z
стоит на своем месте.
Получим массив, частично упорядоченный. К его левой и правой части применим ту же операцию и т.д. Продолжаем действия до тех пор, пока части не станут пустыми или состоящими из одного элемента. Теперь массив полностью упорядочен.
Алгоритм Хоара запишем в виде процедуры.
PROCEDURE HOARE (A, B: INTEGER; VAR M: MAS);