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

1.3. Построение алгоритмов

Есть много стандартных приемов, используемых при построении алгоритмов. Сортировка вставками является примером алгоритма, действующего по шагам (incremental approach): мы добавляем элементы один за другим к отсортированной части массива.

В этом разделе мы покажем в действии другой подход, который называют «разделяй и властвуй» (divide-and-conquer approach), и построим с его помощью значительно более быстрый алгоритм сортировки.

1.3.1. Принцип «разделяй и властвуй»

Многие алгоритмы по природе своей рекурсивны (recursive): решая некоторую задачу, они вызывают самих себя для решения её подзадач. Идея метода «разделяй и властвуй» состоит как раз в этом. Сначала задача разбивается на несколько подзадач меньшего размера. Затем эти задачи решаются (с помощью рекурсивного вызова–или непосредственно, если размер достаточно мал). Наконец, их решения комбинируются и получается решение исходной задачи.

Для задачи сортировки эти три этапа выглядят так. Сначала мы разбиваем массив на две половины меньшего размера. Затем мы сортируем каждую из половин отдельно. После этого нам остаётся соединить два упорядоченных массива половинного размера в один. Рекурсивное разбиение задачи на меньшие происходит до тех пор, пока размер массива не дойдёт до единицы (любой массив длины 1 можно считать упорядоченным).

Нетривиальным этапом является соединение двух упорядоченных массивов в один. Оно выполняется с помощью вспомогательной процедуры MERGE(A,p, q, r). Параметрами этой процедуры являются массив А и числа р, q. r, указывающие границы сливаемых участков. Процедура предполагает, что рq < r и что участки А[р ..q] и A[q+1 .. r] уже отсортированы, и сливает (merges) их в один участок А[р .. r].

Ясно, что время работы процедуры MERGE есть O(n), где n–общая длина сливаемых участков (n = r – р + 1). Это легко объяснить на картах. Пусть мы имеем две стопки карт (рубашкой вниз), и в каждой карты идут сверху вниз в возрастающем порядке. Как сделать из них одну? На каждом шаге мы берём меньшую из двух верхних карт и кладём её (рубашкой вверх) в результирующую стопку. Когда одна из исходных стопок становится пустой, мы добавляем все оставшиеся карты второй стопки к результирующей стопке. Ясно, что каждый шаг требует ограниченного числа действий, и общее число действий есть O(n).

Рис. 1.3. Сортировка слиянием для массива А = (5, 2,4, 6, 1. 3, 2. 6).

Теперь напишем процедуру сортировки слиянием MERGE-SORT(А, p, r), которая сортирует участок А [р..r] массива А, не меняя остальную часть массива. При рr участок содержит максимум один элемент, и тем самым уже отсортирован. В противном случае мы отыскиваем число q, которое делит участок на две примерно равные части А[р .. q] (содержит [n/2] элементов).

Весь массив теперь можно отсортировать с помощью вызова MERGE-SORT (A, I, length[A]). Если длина массива п = length[A] есть степень двойки, то в процессе сортировки произойдёт слияние пар элементов в отсортирован­ные участки длины 2. затем слияние пар таких участков в отсортированные участки длины 4 и так далее до п (на последнем шаге соединяются два отсортированных участка длины п/2). Этот процесс показан на рис. 1.3.