Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
методички.C++ / Конспект Лекций - Части 1,2.pdf
Скачиваний:
275
Добавлен:
24.02.2016
Размер:
1.97 Mб
Скачать

14.8. Быстрая сортировка

Все рассмотренные ранее методы обмена не столь эффективны при реализации на ЭВМ из-за сравнений и возможных обменов только соседних элементов. Лучшие результаты дают методы, в которых пересылки выполняются на большие расстояния. Рассмотрим два наиболее быстрых алгоритмов.

Метод Хоара

Метод Хоара (Charles Antony Richard Hoare, 1962 г.), называемый также методом быстрой сортировки (Quicksort) основывается на следующем: находится такой элемент, который разбивает множество на два подмножества так, что в одном все элементы больше, а в другом – меньше делящего. Каждое из подмножеств также разделяется на два, по такому же признаку. Конечным итогом такого разделения станет рассортированное множество. Рассмотрим один из вариантов реализации сортировки Хоора.

В самой процедуре сортировки сначала выберем средний элемент. Потом, используя переменные i (цикл i=0, i++) и j (цикл j=n-1, j--), пройдемся по массиву, отыскивая в левой части элементы больше среднего, а в правой – меньше среднего. Два найденных элемента переставим местами. Будем действовать так, пока i не станет больше j. Тогда мы получим два подмножества, ограниченные с краев индексами l и r, а в середине – j и i. Если эти подмножества существуют (т.е. i<r и j>l), то выполняем их сортировку.

Например, необходимо рассортировать массив: 13, 3, 23, 19, 7, 53, 29, 17 Переставляемые элементы будем подчеркивать, средний – выделим жирным шрифтом (19), а элемент, попавший на свое место и не участвующий в последующих сравнениях – наклонным шрифтом. Индекс i будет задавать номер элемента слева от среднего, а j справа от среднего.

1)13 3 23 19 7 53 29 17

i → . . . ←j

ищем в левой части элемент больший среднего, а в правой – меньший среднего,

это 23 и

17, переставляем их;

 

2)

13 3 17 19 7 53 29 23

– переставили (19 и 7);

3)13 3 17 7 | 19 53 29 23

справа все большие среднего (19), слева – меньшие, теперь делим совокупность на два подмножества:

-------

 

А -------

 

 

 

---------- В -----------

 

13

3

17

7

 

 

19

53

29

23

---А1---

 

-----А2-----

 

 

19

23

29

53 – здесь

Выделяем подмножество

3

 

13 17

7

 

13

17

7

 

 

 

7

17

 

Выделяем подмножество

13

 

Результат:

 

3

 

7 13

17

19 23 29 53

Как искать точку деления:

 

 

 

 

 

 

19

53

24

 

23

 

 

 

 

 

i=left

 

 

 

j=right

 

210

19 < 23

– обмен не требуется: j = j-1

 

19

53

24

23

19 < 24

– обмен не требуется: j = j-1

 

19

53

24

23

Метод Шелла

Сортировка Шелла (Donald Lewis Shell), предложенная в 1959 г., называется также «слиянием с обменом» и является расширением челночной сортировки.

Основная идея алгоритма состоит в том, что на начальном этапе реализуется сравнивание и перемещение далеко отстоящих друг от друга элементов. Интервал между сравниваемыми элементами (h) постепенно уменьшается до единицы, что приводит к перестановке соседних элементов на последних стадиях сортировки (если это необходимо).

Реализуем метод Шелла следующим образом. Начальный шаг сортировки примем равным h=n/2, т.е. 0,5 от общей длины массива, и после каждого прохода будем уменьшать его в два раза. Каждый этап сортировки включает в себя проход всего массива и сравнение отстоящих на h элементов (i=0; j=n/2; i++; j++; до тех пор, пока j<n). Проход с тем же шагом повторяется, если элементы переставлялись. Заметим, что после каждого этапа отстоящие на h элементы отсортированы.

Таким образом, вначале сравниваются (и, если нужно, переставляются) далеко стоящие элементы, а на последнем проходе – соседние элементы

Рассмотрим пример. Рассортировать массив: 41, 53, 11, 37, 79, 19, 7, 61.

В строке после массива в круглых скобках указаны индексы сравниваемых элементов и указан номер внешнего цикла.

Цикл

0

1

2

3

4

5

6

7

– индексы элементов

 

41

53

11

37

79

19

7

61

– исходный массив

1-ый

41

19

11

37

79

53

7

61

– (0,4),(1,5)

 

41

19

7

37

79

53

11

61

– (2,6),(3,7)

2-ой

7

19

41

37

11

53

79

61

– (0,2),(1,3),(2,4),(3,5),(4,6),(5,7)

 

7

19

11

37

41

53

79

61

– (0,2),(1,3),(2,4),(3,5),(4,6),(5,7)

3-ий

7

11

19

37

41

53

61

79

– сравнивались соседние

Алгоритм метода Шелла

Внешний цикл (1): от h=n/2 до h>0; h=h/2

Вложенный внутренний цикл (2): do (выполнять пока end_sort =1):

1)end_sort = 0

2)цикл (3): для i от 0 до h; j от h; до тех пор, пока j<n; i++, j++ выполнить сравнение:

если x[i] > x[j] то переставить местами, т.е. buf = x[j], x[j] = x[i], x[i] = buf;

211

изменить признак:

end_sort = 1;

3) конец цикла (3)

 

Конец циклов (2 и 1): выполнять пока end_sort =1, каждый выход будет уменьшать h в два раза.

Выигрыш получается за счет того, что на каждом этапе сортировки либо участвует сравнительно мало элементов, либо эти элементы уже довольно хорошо упорядочены, и требуется небольшое количество перестановок. Последний просмотр сортировки Шелла выполняется по тому же алгоритму, что и в челночной сортировке. Предыдущие просмотры подобны просмотрам челночной обработки, но в них сравниваются не соседние элементы, а элементы, отстоящие на заданное расстояние h. Большой шаг на начальных этапах сортировки позволяет уменьшить число вторичных сравнений на более поздних этапах.

При анализе данного алгоритма возникают достаточно сложные математические задачи, многие из которых еще не решены. Например, неизвестно, какая последовательность расстояний дает лучшие результаты, хотя выяснено, что расстояния hi не должны быть множителями один другого.

Сортировка методом Шелла может быть реализована, например, в следующем виде:

#include <iostream.h> #include <conio.h>

void sort_Sh ( int *x, int n)

{

int i, j, buf, h, end_sort; for( h = n/2; h>0; h/=2) do

{

end_sort = 0;

for( i=0, j=h; j<n; i++, j++)

if( *(x+i)> *(x+j) )

// Сравниваем отстоящие на h элементы

{

 

buf = *(x+j);

// Переставляем элементы

*(x+j) = *(x+i);

 

*(x+i) = buf;

 

end_sort = 1;

// Есть еще не рассортированные данные

}

 

} while (end_sort);

// Окончание этапа сортировки

}

 

void main()

 

{

int x[ ] = { 41, 53, 11, 37, 79, 19, 7, 61}; // задали явно sort_Sh(x,8);

cout<<”Array: “; for (int i=0; i<8; i++)

cout << x[i] << “ “; cout<<endl;

212

Соседние файлы в папке методички.C++