Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Programmirovanie_i_osnovyi_algo

.pdf
Скачиваний:
10
Добавлен:
05.03.2016
Размер:
9.5 Mб
Скачать

при i-oM просеивании составляет самое большее /, а самое меньшее - 1. Число М, пересылок (присваиваний) элементов при /-ом

просеивании равно

(С,-1) + 3 = С,+2

Это объясняется тем, что тело цикла while выполняется на один раз меньше, чем число проверок условия повтора цикла. Три других пересылки при /-ом просеивании есть:

сору =

агг1[ 1 ];

arrl [ О ] = сору/ arrl [ j+1 ] = copy;

Поэтому обш^ее число сравнений и пересылок есть

где (size-2)

- число повторов цикла по /,

 

 

 

v/rc'-l

 

^МАХ ~

2 1 ' ~ (size +1) • (size - 2) / 2,

QpEfl = (CM,N + С

^

) / 2 = ((size - 2) + (size +1) • (size - 2) / 2) / 2,

 

 

 

uze-\

 

^MiN = 3 • (size -

2), MMAX = X (' "^ ^) = ^^^^^ "^ ^) * ^^^^^ " 2) / 2,

Л^сРЕд=(Л^м1м+^мАх)/2 = (3-(^/2е-2) + С9/2еч-5)-(^/^^-2)/2)/2.

C^^iM и Л/^д,^, имеют место, если элементы массива с самого на­ чала упорядочены, а С^^дх и Л/^АХ встречаются, если элементы масси­ ва расположены в обратном порядке.

15.4. Сортировка массива простым обменом (метод "пузырька")

Данный алгоритм основан на принципе сравнения и обмена пары соседних элементов до тех пор, пока не будут отсортированы все элементы массива. Пример сортировки массива методом "пу­ зырька" приведен на рис. 66.

Очевидно, что в наихудшем случае, когда минимальное значе­ ние ключа элемента имеется у самого правого элемента, число про­ смотров равно size-\.

Прототип функции сортировки массива простым обменом, ее определение и пример вызова даны в примере, приведенном в подразд. 15.2. Внимательно изучите их.

250

Начальные значения ключей

44

55

12

42

94

18

06

6

элементов массива (size = 8)

 

12

55

 

18

94

 

 

 

 

 

 

 

 

 

 

 

 

42

55

 

06

94

 

Конец первого просмотра

44

12

42

55

18

06

<— •

67 I 94

Обратите внимание как «пузырек» 94 «всплыл» вправо!

 

 

 

 

 

<

 

м

 

 

 

 

 

12

44

 

18

55

 

 

 

 

 

12

42

44

18

06

55

 

94

Конец второго просмотра

42

44

06

55 I 67

 

 

 

 

18

44

 

 

 

 

Конец третьего просмотра

12

42

18

06

44

 

 

 

06

44 I 55

67

94

 

 

 

18

-•

 

 

 

 

 

 

 

 

42

 

 

 

 

 

Конец четвертого просмотра

12

18

06

42

 

55

67

 

06

42 ( 44

94

Конец пятого просмотра

12

06

18

I 42

44

55

 

 

06

18

67

94

 

 

^4-

12

 

 

 

 

 

 

Конец шестого просмотра

06

| 18

42

44

55

67

 

06

12

94

И конец сортировки, так как больше перестановок нет!

 

 

 

Рис. 66. Пример сортировки массива простым обменом

 

Эффективность

сортировки.

За один проход среднее число

сравнений С^СРЕД равно size/2 (на первом

проходе -

size-\,

а на по­

следнем - 1). При этом среднее

число возможных

пересылок

А/ксРЕд =l-5*QcpEA (в

предположении,

что

проверяемое условие

вы­

полняется в половине случаев). Минимальное количество проходов

равно 1, максимальное - size-l,

а среднее - size/2. Следовательно,

СсРЕд =size^

/4, Л/сРЕд =1.5-5/ze^ / 4

15.5. Выводы по простым методам сортировки

1. в простых методах сортировки массивов время сортировки пропорционально size^.

2. Более точные оценки производительности простых методов

251

сортировки массивов показывают, что наиболее быстрой является

сортировка вставками, а наиболее медленной - сортировка обме­ ном.

3.Несмотря на плохое быстродействие, простые алгоритмы сортировки следует применять при малых значениях size.

4.Наряду с простыми алгоритмами сортировки массивов су­ ществуют сложные алгоритмы сортировки, обеспечивающие время сортировки, пропорциональное не size^, а size-logjisize). При больших значениях size они обеспечивают существенный выигрыш. К их рас­ смотрению мы и переходим.

15.6.Сортировка массива сложным выбором

(с помощью двоичного дерева)

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

/ . Идея алгоритма. Исходное состояние двоичного дерева (ключи исходного массива структур агг с числом элементов size) показано на рис. 67.

а Вначале двоичное дерево подготавливаем таким образом, чтобы элемент массива с максимальным значением ключа (94) находился в корне дерева.

• Выбираем элемент с максимальным значением ключа, меня­ ем его местами с последним элементом массива и затем восстанав­ ливаем двоичное дерево (рис. 68). Вновь найденный элемент с мак­ симальным значением ключа (67), который после восстановления двоичного дерева оказывается опять в его корне, меняется местами с предпоследним элементом массива и т.д. (всего size-\ раз).

Таким образом, получаем общее число сравнений

С= {size -1) • log 2 {size)

иКакие в связи с этим возникают проблемы?

Как построить двоичное дерево (пирамиду) без дополнитель­ ных затрат памяти с тем, чтобы обеспечить сортировку "на месте", т.е. обойтись в дереве size вершинами вместо (5/z^*2-l) вершин?

Как организовать дерево в самом начале работы?

252

Всего ( 2*size-1 ) вершин

94

/

.55^ \

/

. 42,

 

/

, 9 4

 

/

67

\

42

\

18

\

44

55

12

 

94

 

06

67

Рис. 67. Исходное состояние двоичного дерева

Вместо выбранного элемента с максимальным значением ключа (94) появились «дырки»

На восстановление двоичного дерева потребовалось 1од2( size ) сравнений претендентов на заполнение «дырок»: 1, 2, 3

Рис. 68. Двоичное дерево после первой замены и восстановления

2. Построение пирамиды (двоичного дерева) **на месте'* и ее начальное заполнение,

2.1. Представление двоичного дерева из size элементов в од­ номерном массиве из size элементов. Из вершины двоичного дерева, в обш;ем случае, идут две дуги вниз (см. выше рис. 57), отсюда тер­ мин - двоичное дерево.

В двоичном дереве могут встретиться следующие случаи:

• у 1 > size - вершина / есть лист дерева;

j \ ~ size - нет7*2;

yi < size - есть у 1 иу2.

Таким образом, для представления массива из size элементов

253

требуется дерево с size вершин. У каждой вершины может быть О, 1 или 2 дуги вниз (О -лист, 1 или 2 дуги вниз - промежуточная верши­ на или корень).

Для рассмотренного выше примера мы получаем следующее

дерево из size

вершин (рис. 69).

 

 

 

 

44

 

 

55

 

12

^

^ о \..^^

 

 

42

94

18

06

/ А

с:

 

 

67

 

 

 

 

Рис. 69. Двоичное дерево из size

вершин

В отличие от первого дерева из (2*^/ze-l)=15 вершин ключ 94 встречается один, а не четыре раза. Ключ 55 встречается один, а не три раза и т.д. Выигрыш налицо!

2.2. Как подготовить дерево в самом начале, когда в массиве царит беспорядок?

В первую очередь рассмотрим поддеревья-листья 5, 6, 7, 8 (нижний слой на рис. 69). Каждое из поддеревьев-листьев из одной вершины и, следовательно, они упорядочены.

Вершина с максимальным номером, у которой есть следующие снизу вершины, имеет номер size/2 (при size=^ такая вершина имеет номер 4). Поэтому подготовку дерева надо начинать с вершины с

номером size/2,

потом - продолжать с вершины size/2'l и т.д., закон­

чив вершиной

1 (см. рис. 70-73).

Рассмотренный на рисунках процесс будем называть "просеи­

ванием дыры"

(sift).

254

Size/2=4

В корне соответствующего поддерева образуем «дыру» путем копирования соответствующего корню элемента в сору. Ищем подходящее место для вставки сору и помещаем в него сору.

 

 

 

1) Г — ;

 

«Дыра»

 

 

 

 

 

42

 

 

 

1 42 j

 

 

67

67

 

-•

j

1

67

4

^

42

4

 

 

 

W

3)

сору

4

 

 

 

 

сору

 

 

^^^^

 

 

 

 

 

 

 

 

 

8

 

 

 

 

8

 

 

Рис,

70. Подготовка двоичного дерева для вершины 4

 

 

 

 

 

 

 

Size/2

- 1 = 3

 

 

 

 

 

12

 

1) Г

1

 

 

12

 

 

18

 

 

 

-• 1

1

 

 

 

 

 

/

3

\

сору

 

3

сору

 

 

 

 

18

 

 

06

 

^

18

<;

06

w

 

12

06

 

 

 

 

 

3)

 

 

 

 

 

 

 

 

 

 

6

 

 

 

 

6

 

 

Рис.

71. Подготовка двоичного дерева для вершины 3

 

 

 

 

 

 

 

Size/2 - 2= 2

 

 

 

 

 

55

 

1) Г

:

 

2

сору

 

 

94

 

 

 

 

 

1 55

1

 

 

X

2

\

 

^ сору ^_д

X

2)^\Ч 3)

 

 

/4"^

67

 

 

94

 

W

67

 

94

^

 

67

55

 

 

 

 

 

 

Рис. 72. Подготовка двоичного дерева для вершины 2

В ходе первоначальной подготовки дерева и в ходе восстанов­ ления дерева после выбора элемента с максимальным значением ключа из корня выполнялась одна и та же операция, которую мы на­ звали "просеивание". После выбора максимального ключа за каждый шаг просеивания "дырка" перемещается на один уровень вниз, а число уровней есть \og2{size). Поскольку выбор элемента с макси­ мальным значением ключа и последующее восстановление дерева проводятся {size-\) раз, то, как уже указывалось выше, общее коли­ чество сравнений ключей элементов массива пропорционально

{size -1) • log2 {size).

255

3.функция просеивания

3.1.Идея функции (см. рис. 57)

±ль

root^

//

Корень

дерева

ими

поддерева

 

last;

//

Номер

последней

вершины

дерева

 

 

//

или

поддерева

 

 

 

 

Возможны следующие ситуации:

 

 

 

 

 

 

а

у 1 > last

- претендент на заполнение дыры есть

сору\

 

 

 

а

yi = last

- j2

нет и претендент на заполнение дыры есть

 

 

 

 

 

 

тах{

сору.key.,

arr[J\

].кеу

};

 

 

 

 

 

yi < last

- претендент на заполнение дыры есть

 

 

 

 

 

 

 

тах{

сору. key,

arr[j\

].key,

arr[j2

].key

}.

 

 

 

 

 

a)

 

 

 

Size/2 - 3 == 1

 

в)

 

 

 

 

 

 

 

 

6)

copy

 

 

copy

 

 

 

 

1)

Г - - 1

 

 

 

 

 

 

 

 

44

 

 

(

i

 

94

1

44 1

 

 

 

 

 

 

 

 

i 44 i

 

 

 

 

1

 

copy к

 

1

18 ^

 

• ^ " ^

l

" ^

" " ^

 

94

 

18

 

94

 

 

^)ш\

 

 

 

18

 

1

1

1

1

1

1

1

1

L

 

 

1

1

 

2

 

3

 

2

 

 

3

- ^

2 ^ ; ^

 

3

 

 

 

 

с)) в итогеnonvЧИМ

 

67

 

55

 

 

 

 

 

 

 

 

 

 

 

 

 

 

67

 

2

44

55

/ 4

fS

42

Рис. 73. Подготовка двоичного дерева для вершины 1

256

3.2. Функции

просеивания и сортировки

сложным выбором.

Прототипы

функций просеивания (Sift),

сортировки сложным

выбором с помощью двоичного дерева (TreeSort), их определения и

примеры вызовов содержатся в примере программы, приведенном выше в подразд. 15.2. Обратите внимание на то, что функция про­ сеивания используется только для внутренних целей и, таким обра­ зом, не является интерфейсной (вызывается из функции сортировки сложным выбором). Функция же сортировки сложным выбором, на­ против, является интерфейсной. Это означает, что она вызывается

пользователем для сортировки массива.

Эффективность сортировки. Ранее было показано, что чис­

ло сравнений пропорционально

{size-\)'\og2isize). Проанализируем

эффективность сортировки более детально.

В функции просеивания Sift

цикл while в среднем выполняется

{logjisize))/2 раз, содержит одну пересылку в теле цикла и две пере­ сылки за пределами цикла. В функции TreeSort сортировки сложным

выбором в теле цикла

по templast делается три пересылки и пере­

сылки в функции sift,

а сам цикл выполняется (size-\)

раз. В функ­

ции TreeSort

в теле цикла по temproot выполняется

функция sift, а

тело цикла

повторяется (size/2)

раз. Таким образом,

число пересы­

лок

 

 

 

 

Л/ = (3 + 2 + (log2 (size)) 12) - (size -1) + (2 + (logj (size))/2) size/2

пропорционально size • logj (size).

 

 

В функции просеивания Sift

в цикле while производится в сред­

нем 2'(\og2(size))/2 = \og2(size) сравнений. Поэтому общее число сравне­ ний

С = (log2 (size))' (size -1) + (log2 (size)) • size 12,

что также пропорционально size*\og2(^ize).

15.7. Сложная сортировка вставками (сортировка Шелла)

Идея алгоритма,

1.Используется несколько проходов.

2.На первом проходе отдельно группируются и сортируются

вставками элементы, отстоящие друг от друга на (i = size/2

позиций.

3. На втором проходе аналогично группируются и сортируют­

ся вставками элементы, отстоящие друг от друга иг. d = d/2

позиций.

4. Аналогично выполняются последующие проходы

и сорти-

257

ровка заканчивается последним проходом

при d -

I

(как при

про­

стой сортировке вставками).

 

 

 

 

 

 

 

Иллюстрирующий пример дан на рис. 74.

 

 

 

 

Следует

подчеркнуть,

что ускорение

сортировки

происходит

на первых

этапах, когда

сортировка вставками

производится

среди

элементов,

отстоящих

друг

от друга

на

болыиие

расстояния.

По

этой причине

на втором

и последующих

этапах

перестановки

эле­

ментов почти

отсутствуют.

 

 

 

 

 

 

Текст функции. Прототип функции ShellSort сложной сорти­ ровки вставками, ее определение и пример вызова приведены выше в программе, текст которой дан подразд. 15.2.

О выборе

последовательности

значений

d. У нас в примере

использовалась

последовательность

значений d,

равная

1, 2, 4,

...,

d<size (в обратном порядке) и число этапов составляло \og^{size).

 

Начальные значения ключей

44

55

12

42

94

18

06

67

элементов массива

 

 

 

 

 

 

 

 

Первый этап при d=size/2=4

 

 

 

 

 

 

 

 

 

 

 

18

 

 

 

55

 

 

 

 

 

 

06

 

 

 

12

 

В результате получаем

44

18

06

42

94

55

12

67

Второй этап при d = d/2 = 2

 

 

 

 

 

 

 

 

06

 

44

 

 

 

 

 

 

06

 

12

 

44

 

94

 

В результате получаем

06

18

12

42

44

55

94

67

Третий этап при d = d/2 = 1 (последний): сортировка производится как

 

В результате получаем

06

12

простая сортировка вставками

94

18

42

44

55

67

Рис. 74. Иллюстрирующий пример для сортировки Шелла

Вместе с тем выявлено, что лучшие результаты получаются, когда последовательные значения d не кратны друг другу. По этой причине Д. Кнут (Кнут Д. Искусство программирования для ЭВМ. Т. 3. - М.: Мир, 1978. С. 342) указывает, что дистанцию нужно вы­ бирать так:

258

^ , = 1 ,

J, =3-^,_,+1

(A: = 2,3,...)

1,4, 13, 40, 121, ... (в обратном порядке)

Анализ показывает, что число сравнений при этом пропорцио­ нально size^'^, а не size^'^ ^ как в нашем варианте. И то, и другое при больших size хуже, чем size-Xogj^size),

15.8. Сложная сортировка обменом (сортировка Хоора)

/. Идея алгоритма (рис. 75). Исходный массив разбивается на два сегмента - левый, элементы которого агг[ i ].кеу <= median.key, и правый сегмент с элементами arr[j [.key >= median.key. Далее, каж­ дый из полученных сегментов можно сортировать автономно, ана­ логично предыдущему, до получения сегментов единичной длины. Тогда массив в целом будет отсортирован.

Исходные значения ключей

left

hpht

элементов массива агг[ i ].кеу

44 55

12 1 42 1 94 18 06 67

(i = О, 1, 2, . ., size-1 ), size = 8

 

 

п

median

median = arr[ (left+right )/2 ]

Рис. 75. Идея алгоритма сортировки Хоора

2. Как выполнить разделение на сегменты? Решение этой задачи представлено на рис. 76.

Анализ рисунка показывает, что за size сравнений {size - число элементов массива) исходный массив разделяется на два сегмента, которые можно сортировать автономно. Всего потребуется Xo^^i^ize) таких разделений, в результате которых получатся сегменты еди­ ничной длины. Следовательно, общее число сравнений пропорцио­ нально size • 1о§2 {size).

259

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]