Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции по МОИ (глава2).doc
Скачиваний:
8
Добавлен:
05.11.2018
Размер:
397.82 Кб
Скачать

Алгоритм 10.1. Построение сортирующего дерева

Вход. Массив элементов Array[i], 1in.

Выход. Элементы массива Array, организованные в виде сортирующего дерева, т.е. для которых выполняются соотношения (2.1).

Метод. В основе алгоритма лежит рекурсивная процедура Heapify (Пересыпка). Её параметры Initial и Final задают область ячеек массива Array, обладающую свойством сортирующего дерева; корень строящегося дерева помещается в Initial. Параметр Last используется, чтобы определить, является ли Initial листом и имеет ли он одного или двух сыновей. Если Initial > Final/2, то Initial – лист, и процедуре Heapify ничего не нужно делать, поскольку Array[i] – уже сортирующее дерево.

Процедура Build_heap(Array, n)

for (index=n/2; index=1; Heapify(Array, index--,n));

Процедура Heapify(Array, Initial, Final)

if((Initial<=(Final>>1))&&(Array[Initial]<{Array[k]=max(Array[2*Initial],Array[2*Initial+1])})

{

Переставить Array[Initial] и Array[k];

Heapify(Array, k, Final);

}

Лемма 1. Если узлы i+1, i+2,, n являются корнями сортирующих деревьев, то после вызова процедуры Heapify(Array, Initial, Final) все узлы i, i+1, i+2,, n будут корнями сортирующих деревьев.

Доказательство. Доказательство проводится возвратной индукцией по i. Случай i=n тривиален, т.к. узел n должен быть листом, и условие, проверяемое в строке 1, гарантирует, что Heapify(Array, n, n) ничего не делает.

Заметим, что если i – лист или у него нет сына с бóльшим элементом, то доказывать нечего (как и в предыдущем случае i=n). Но если у узла i есть один сын (т.е. если 2i=n) и Array[i] < Array[2i], то строка 2 процедуры Heapify переставляет Array[i] и Array[2i]. В строке 3 вызывается Heapify(Array, 2i, n); поэтому из предположения индукции вытекает, что дерево с корнем 2i будет переделано в сортирующее. Что касается узлов i+1, i+2,, 2i–1, то они не переставали быть корнями сортирующих деревьев. Так как после этой новой перестановки в массиве Array выполняется неравенство Array[i] > Array[2i], то дерево с корнем i также оказывается сортирующим.

Аналогично, если узел i имеет двух сыновей (т.е. если 2i+1 n), и наибольший из элементов Array[2i] и Array[2i+1] больше элемента Array[i], то, рассуждая, как и выше, можно показать, что после вызова процедуры Heapify(Array, i, n); все узлы i, i+1, i+2,, n будут корнями сортирующих деревьев.

Теорема 4. Алгоритм 10.1 преобразует массив Array в сортирующее дерево за линейное время.

Доказательство. Применяя лемму 1, можно с помощью простой возвратной индукции по i показать, что узел i становится корнем какого-нибудь сортирующего дерева для всех i, 1 i n.

Пусть T(h) – время выполнения процедуры Heapify на узле высоты h. Тогда T(h)  T(h–1) + с для некоторой постоянной c. Отсюда вытекает, что T(h) есть O(h). Алгоритм 10.1 вызывает процедуру Heapify один раз для каждого узла, если не считать рекурсивных вызовов. Поэтому время, затрачиваемое на Build_heap, имеет тот же порядок, что и сумма высот всех узлов. Но узлов высоты i не больше, чем n/2i+1 (x – означает потолок x или наименьшее целое, большее или равное x). Следовательно, общее время, затрачиваемое процедурой Build­_heap, имеет порядок , т.е. O(n). 

Теперь можно завершить описание алгоритма Сортдеревом. Элементы массива Array преобразованы уже в сортирующее дерево, поэтому можно удалить из него самый максимальный, поменяв местами Array[1] и Array[n] и рассматривая только n–1 элементов массива. Получающийся массив размера n–1 снова преобразуется в сортирующее дерево. Далее переставляются Array[1] и Array[n–1] и т.д. Процесс продолжается до тех пор, пока в сортирующем дереве не останется всего один элемент. Тогда Array[1], Array[2], , Array[n] – упорядоченная последовательность.