WWW.REFERATCENTRAL.ORG.UA - Я ТУТ НАВЧАЮСЬ

... відкритий, безкоштовний архів рефератів, курсових, дипломних робіт

ГоловнаІнформатика, Компютерні науки → Швидкі алгоритми сортування - Курсова робота

Швидкі алгоритми сортування - Курсова робота

a3
Просівання елементів відбувається доти, поки весь вихідний масив не буде заповнений символами M, тобто n раз:
For I := 1 to n do begin
Відзначити шлях від кореня до листка символом M;
Просіяти елемент уздовж відзначеного шляху;
B[I] := корінь дерева
end;
Обґрунтування правильності алгоритму очевидно, оскільки кожне чергове просівання викидає в масив У найменший з елементів масиву А, що залишилися.
Сортуюче дерево можна реалізувати, використовуючи або двовимірний масив, або одномірний масиві ST[1..N], де N = 2n-1 (див. наступний розділ). Оцінимо складність алгоритму в термінах M(n), C(n). Насамперед відзначимо, що алгоритм TreeSort працює однаково на усіх входах, так що його складність у гіршому випадку збігається зі складністю в середньому.
Припустимо, що n - ступінь 2(n = 2l). Тоді сортуюче дерево має l + 1 рівень (глибину l). Побудова рівня I вимагає n / 2I порівнянь і пересилань. Таким чином, I-ий етап має складність:
C1(n) = n/2+n/4+ ... + 2+1 = n-1, M1(n) = C1(n) = n - 1
Для того, щоб оцінити складність II-го етапу З2(n) і M2(n) помітимо, що кожен шлях просівання має довжину l, тому кількість порівнянь і пересилань при просіванні одного елемента пропорційно l. Таким чином, M2(n) = O(l n), C2(n) = O(l n).
Оскільки l = log2n, M2(n)=O(n log2 n)), C2(n)=O(n log2 n), Але З(n) = C1(n) + C2(n), M(n) = M1(n) + M2(n). Тому що C1(n) < C2(n), M1(n) 1,
то A[i mod 2] - вузол - "батько" вузла A[i];
Приклад: Нехай A = [45 13 24 31 11 28 49 40 19 27] - масив. Відповідне йому дерево має вид:
Зверніть увагу на те, що всі рівні дерева, за винятком останнього, цілком заповнені, останній рівень заповнений ліворуч і індексація елементів масиву здійснюється вниз і праворуч. Тому дерево упорядкованого масиву відповідає наступним властивостям:
A[i] ( A[2*i], A[i] ( A[2*i+1], A[2*i] ( A[2*i+1].
Як це не дивно, алгоритм HeapSort спочатку будує дерево, що відповідає прямо протилежним співвідношенням:
A[i] A[2*i], A[i] A[2*i+1]
а потім змінює місцями A[1] (найбільший елемент) і A[n].
Як і TreeSort, алгоритм HeapSort працює в два етапи:
I. Побудова сортуючого дерева;
II. Просівання елементів по сортуючому дереву.
Дерево, що представляє масив, називається сортуючим, якщо виконуються умови (6). Якщо для деякого i ця умова не виконується, будемо говорити, що має місце (сімейний) конфлікт у трикутнику i.
Як на I-ом, так і на II-ому етапах елементарна дія алгоритму полягає в вирішенні сімейного конфлікту: якщо найбільший із синів більше, ніж батько, то переставляються батько і цей син (процедура ConSwap).
У результаті перестановки може виникнути новий конфлікт у тому трикутнику, куди переставлений батько. У такий спосіб можна говорити про конфлікт (роду) у піддереві з коренем у вершині i. Конфлікт роду вирішується послідовним вирішенням сімейних конфліктів проходом по дереву вниз. (На мал шлях вирішення конфлікту роду у вершині 2 відзначений). Конфлікт роду вирішено, якщо прохід закінчився (i > n div 2), або ж в результаті перестановки не виник новий сімейний конфлікт (процедура Conflict).
Procedure ConSwap(i, j : Integer);
Var b : Real;
Begin
If a[i] < a[j] then begin
b := a[i]; a[i] := a[j]; a[j] := b
end
End;
Procedure Conflict(i, k : Integer);
Var j : Integer;
Begin
j := 2*i;
If j = k
then ConSwap(i, j)
else if j a[j] then j := j + 1;
ConSwap(i, j); Conflict(j, k)
end
End;
I етап - побудова сортуючого дерева - оформимо у виді рекурсивної процедури, використовуючи визначення:
Якщо ліве і праве піддерева T(2i) і T(2i+1) дерева T(i) є сортуючими, то для перебудови T(i) необхідно вирішити конфлікт роду в цьому дереві.
Procedure SortTree(i : Integer);
begin
If i <= n div 2 then begin
SortTree(2*i); SortTree(2*i+1); Conflict(i, n)
end
end;
На II-ом етапі - етапі просівання - для k від n до 2 повторюються наступні дії:
1.Переставити A[1] і A[k];
2.Побудувати сортуюче дерево початкового відрізка масиву A[1..k-1], усунувши конфлікт роду в корені A[1]. Відзначимо, що 2-а дія вимагає введення в процедуру Conflict параметра k.
Program HeapSort;
Const n = 100;
Var A : Array[1..n] of real;
k : Integer;
{процедури ConSwap, Conflict, SortTree, введення, виведення}
Begin
{ введення }
SortTree(1);
For k := n downto 2 do begin
ConSwap(k, 1); Conflict(1, k - 1)
end;
{ виведення }
End.
Нескладно підрахувати, що С(n) = O( n log2 n ), М(n) = O( n log2 n )
1.3 Швидке сортування Хоара
Удосконаливши метод сортування, який грунтується на обмінах, К. Хоар запропонував алгоритм QuickSort сортування масивів, що дає на практиці відмінні результати і дуже просто програмується. Автор назвав свій алгоритм швидким сортуванням.
Ідея К. Хоара полягає в наступному:
1 Виберемо деякий елемент x масиву A випадковим образом;
2.Переглядаємо масив у прямому напрямку (i = 1, 2,...), шукаючи
в ньому елемент A[i] не менший за x;
3.Переглядаємо масив у зворотньому напрямку (j = n, n-1,..),
шукаючи в ньому елемент A[j] не більший за x;
4.Змінюємо місцями A[i] і A[j];
Пункти 2-4 повторюємо доти, поки i < j;
У результаті такого зустрічного проходу початок масиву A[1..i] і кінець масиву A[j..n] виявляються розділеними "бар'єром" x: A[k] ( x при k j , причому на поділ ми затратимо не більш n/2 перестановок. Тепер залишилося проробити ті ж дії з початком і кінцем масиву, тобто застосувати їх рекурсивно.
Таким чином, описана нами процедура Hoare залежить від параметрів k та m - початкового і кінцевого індексів відрізка масиву, який обробляється.
Procedure Swap(i, j : Integer);
Var b : Real;
Begin
b := a[i]; a[i] := a[j]; a[j] := b
End;
Procedure Hoare(L, R : Integer);
Var left, right : Integer;
x : Integer;
Begin
If L < R then begin
x := A[(L + R) div 2]; {вибір бар'єра x}
left := L; right := R ;
Repeat {зустрічний прохід}
While A[left] x do Dec(right); {перегляд назад}
If left
Loading...

 
 

Цікаве