Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
О.О.П / ооп / 4_кол / К курсовой / Методи побудови алгоритмів та їх аналіз / Інформатика_1 (методи побудови алгоритмівта та їх аналіз).doc
Скачиваний:
87
Добавлен:
30.05.2020
Размер:
2.5 Mб
Скачать

Метод природного злиття

При прямому злитті не можна скористатися тією перевагою, що дані, можливо, вже частково впорядковані, оскільки весь час зливали підпослідовності, однакові за кількістю елементів. Ми не звертали уваги на те, що більші за кількістю фрагменти масиву, можливо, уже утворюють упорядковану підпослідов-ність.

Пропонується метод NaturalMerge, в якому в групи виді-ляються вже впорядковані підпослідовності, які ще носять на-зву серій, або максимальних сєрій. Отже, максимальною серією називатимемо підпослідовність а,,..., а., що задовольняє умову:

(а1Л > a) n(ak<ak^(i<k<. j)) П (aj >а/ + 1).

Завдання полягатиме у виділенні таких послідовних серій та їх наступному злитті.

Нехай с - задана послідовність, а та b - сусідні серії. Схема­тично алгоритм методу природного злиття можна зобразити так (мал. 82):

191

фаза фаза

розподілу злиття

прохід 1

прохід 2

Мал. 82

прохід п

Отже, за кожний прохід заданого масиву зчитуємо дві сусід-ні серії (а( та Ь(), зливаємо їх і записуємо на свое місце в с і т. д.

Що може статися? Може виникнути ситуація, коли отри-маемо непарну кількість серій. Тоді остання непарна серія буде переписана у с без змін.

Розглянемо такий приклад (мал. 83).

ПроХІД 1 -* U7|3/|05|59|/3|4;U3|67l/il23|29U7|03|07|7/|02|/9J57|37|6/|

прохІД 2 -» [05\17\31 \59\ll 13 23 29 41 43 47 67 02 03 07 19 57 7l\37\6l\

проХІД 3 — \05 11 13 17 23 29 31 41 43 47 59 67 02 03 07 19\37 57\6l\71

прохід 4 -* 02 03 05 07 11 13 17 19 23 29 31 37 41 43 47 57 59 61 67 71

Мал. 83

Сформулюемо алгоритм природного злиття у вигляді ок-ремих пунктів:

  1. розділити елементи заданого масиву на окремі серії, ви-значивши індекси початку й кінця кожної з них;

  2. злити визначені серії, переписавши результати злиття в заданий масив;

  3. зменшити кількість серій удвічі;

  4. якщо кількість серій більша за 1, то визначити нові ін-декси початку й кінця кожної із серій і перейти до пункту 2.

Згідно з нашим алгоритмом треба на першому кроці сорту-вання визначати кількість серій, що зливаються, а потім лише

192

вдвічі зменшувати їх кількість. Ознакою завершения сортуван-ня є «кількість серій дорівнює 1». Взагалі з кожним наступним проходом кількість серій справді зменшується вдвічі (або т/2 + 1), і саме це може бути визнано критерієм завершения алгоритму. Однак може скластися ситуація, що кількість кро-ків ще не вичерпана, а послідовність уже впорядкована. Роз-глянемо такий приклад (мал. 84).

прохІД 1 -* 03 02 05 07\іі\із\і9 17 23 29 31 37 43 41 47 59 57 61 67 71

vnnn;v ^

\02\03\05\07\іі\\з\п\і9\23\29\зі\37\4і\43\47 59 57 61 67 7і\

Мал. 84

Бачимо, що вже після першого проходу послідовність еле-ментів стала впорядкованою. Тому все-таки ефективніше на кожному кроді сортування заданої послідовності визначати реальну кількість серій і, коли вона досягне значения 1, завер-шити роботу алгоритму.

Якою може бути реалізація описаного алгоритму? Це за-лежить від уподобань кожного окремого програміста.

На першому кроці реалізації алгоритму (під час уведення елементів масиву) можна визначати індекси початку й кінця кожної серії. Цю інформацію можна записувати в масив, кож­ним елементом якого буде запис із двох значень.

У класичному варіанті алгоритму після кожного проходу злиття двох сусідніх серій приводить до того, що початком но­во! серії буде індекс початку першої з них, а кінцем - кінець другої. Таким чином приберемо одну із серій. Зверніть увагу на те, що поки що ми не говоримо про те, як це зробити на рівні програмування!

Чи зменшувати при цьому кількість серій удвічі? На при­клад! (мал. 83) бачимо, що в цьому немае сенсу, оскільки це мо­же спричинити виконання зайвих проходів при сортуванні. Для того щоб обійти таку недоречність, можна після визначен-ня нових меж серій, що будуть надалі зливатися, перевірити наявність відношення о» < ajkrV Це означатиме, що останній елемент fe-ї серії не більший за перший елемент (ft + 1)-ї серії, тобто їх зливати немае потреби, оскільки вони вже утворюють злиту підпослідовність. Цей факт необхідно врахувати під час підрахунку кількості серій для поточного проходу масиву. Якщо в результата кількість серій стане 1, то це означатиме, що алгоритм природного злиття завершено, а отримана послідов-ність буде впорядкованою.

193

Запишемо реалізацію алгоритму сортування послідовності методом природного злиття у виг ляд і тексту Pascal-програми.

Спочатку розглянемо реалізацію частини алгоритму, яка виконує введения елементів послідовності й одночасно визна-чає межі впорядкованих серій за неспаданням. Для цього ре-зервується масив k: array[1..n] of record st, en: <тип> end.

{Початок першої серії.}

count := 1; read(a[1]); k[count].st := 1; i:=2;

while i <= n do begin

read (a[i]);

while (a[i - 1] <= a[i]) and (i <= n) do {Визначення поточно? cepil.} begin inc(i); read (a[i]) end; if i <= n then begin

k[count] .en := i - 1; {Кінець поточноі серії.)

inc(count); {Збільшення лічильника кількості серій.}

k[count] .st := і; {Початок наступноТ серії.}

Іпс(і) {Перехід до наступного елемента послідовності.)

end

{Кінець останньоі серії.}

else k[count].en := n;

end;

Алгоритм злиття серій, що визначені в поточному масиві one i записуються у масив two, можна реалізувати у вигляді та-кої процедури:

procedure merging (var one, two: mas); varq, x, у: <тип > ; begin

X := k[i].St; {Початок/-Ї cepii.}

у := k[i + 1 ].st; {Початок [I + 1 )-i cepii.)

for q :=k[i].stto k[i + 1].endo {Злиття і'-їта (/+1)-їсерій.)

{Умова наявності елементів в /'-й та (/ + 1 )-й серіях.)

if (x<=k[i].en)and(y<=k[i + 1].en)

then

if (опе[х]<ОПЄ[у]) {Результатом злиття на g-му кроці є)

{елемент /-Ї серіі;) then begin two[q] := one[x]; inc (x) end

{елемент (/' + 1 )-i cepii.) else begin two[q] := one[y]; inc (y) end else {Коли відсутні елементи в)

if X > к[І].ЄП {/-й серії, то дописуємо елементи (/ + 1)-їсерГІ.}

then begin two[q] := one[y]; inc (y) end

194

end;

{(/ + 1 )-й серії, то дописуємо елементи і-ї серіТ.} else begin two[q] := onefx]; inc (x) end;

Остаточний варіант алгоритму природного злиття може ви-глядати так:

flag := true;

{Повторения алгоритму злиття, поки кількість серій більша за 1.} while count > 1 do begin

{new_count - лічильник ново! кількості серій після злиття.) і := 1; newcount := 1;

while Kcount do {Перегляд i злиття поточної кількості серій.)

begin if flag

then merger (a, b) {Злиття серій з масиву а в масив to.)

else merger (b, а); {Злиття серій з масиву b в масив а.)

{Початок серії, що є результатом поточного злиття.) k[new_count].st := k[i].st;

{Кінець серіі. що є результатом поточного злиття.) k[new_count].en := k[i + 1].en;

inc(i, 2); {Перехіддонасгупноїпари серій.)

inc(newcount); (Збільшення лічильника злитих серій.)

end;

{Якщо лишився незлитий фрагмент масиву, то) if k[new_count - 1 ] .en < n {фіксуємо його початок i кінець у масиві к) then begin

k[new_count].st := k[new_count - 1].en + 1; k[new_count].en := n; if flag

then for j := k[new_count - IJ.en + 1 to n do

b[j] := a[j] {i дописуемо його елементи в масив to}

else for j := k[new_count - 1].en + 1 to n do

a[j] := b[j] {або в масив a.)

end

{У протилежному випадку зменшуємо кількість серій.) else dec(newcount); item := 1; {Підготовка до перерахунку поточної кількості серій.)

for q := 2 to newcount do {Якщо останній елемент не більший, ніж перший елемент сусідніх серій, то) if a[k[item].en] <= a[k[q].st]

then k[item].en := k[q].en {вважатимемо ці серіїоднією серією,)

else inc(item); {інакше переходимо до наступно? серії.)

new_COUnt := item; {Фіксація остаточного підрахунку кількості серій.)

{Перенесения остаточної кількості серій у відповідну змінну.)

count := new_count;

flag := not flag {Перемикання «вхідного» та «вихідного» масивів.)

end;

195

Перейдемо до оцінки ефективності роботи алгоритму, що реалізує метод природного злиття. Як уже пересвідчилися, при кожному проході в загальному випадку кількість серій змен-шується вдвічі, тому загальна кількість пересилань елементів у найгіршому випадку дорівнює п ■ [log2n], а в середньому може бути навіть і меншою. Однак насправді кількість порівнянь значно більша, ніж зазначена для пересилань. Це обумов-люється тим, що, крім порівнянь, необхідних для відбору еле-ментів при злитті, потрібні ще додаткові: між послідовними елементами кожної серії для того, щоб визначити її межі. Тому в загальному випадку можна вважати оцінку ефективності виконання алгоритму природного злиття такою: 0(п ■ [log2n]).

Оскільки метод природного злиття особливо чутливий до частково впорядкованих послідовностей вхідних даних, то при його тестуванні необхідно пересвідчитися саме у цьому на таких вхідних даних:

  • вхідний масив уже впорядкований необхідним чином;

  • вхідний масив є частково впорядкованим;

  • вхідний масив упорядкований у зворотному порядку;

  • елементи вхідного масиву розміщені випадковим чином. При формуванні вхідних послідовностей різної довжини

треба врахувати специфіку використання додаткових масивів при сортуванні методом природного злиття та узгодити типи вхідних даних із значениям п(п> 100).

/ Запитання для самоконтролю

1.У чому полягає ідея алгоритму сортування послідовності еле-ментів методом природного злиття?

  1. Що називається серією послідовності? Якими мають бути від-ношення між сусідніми елементами максимально! серії послі-довності?

  2. Зобразіть схематично алгоритм сортування послідовності ме­тодом природного злиття.

  3. Обґрунтуйте призначення фаз розподілу та злиття елементів послідовності при кожному м проході.

  4. Наведіть власний приклад послідовності та продемонструйте покроково роботу алгоритму природного злиття.

  5. Сформулюйте алгоритм природного злиття у словесній формі.

  6. Як у класичному випадку змінюватиметься кількість серій при кожному наступному проході?

  7. За рахунок чого можна покращити ефективність роботи алго­ритму природного злиття? Обґрунтуйте свою відповідь, запро-понувавши власний приклад послідовності.

  8. Запишітьалгоритм методу природного злиття елементів посл-довності у вигляді тексту Pascal-програми.

196

10. Якою є оцінка ефективності роботи алгоритму природного злиття? Обґрунтуйте свою відповідь.

Завдання

  1. Реалізувати у вигляді програми алгоритм сортування за­дано! послідовності за зростанням методом природного злиття.

  2. Модифікувати алгоритм, реалізований у завданні 1, так, щоб сортування відбувалося за спаданиям.

  3. Протестувати реалізовані в завданнях 1-2 алгоритми для масиву 15, 4, 10, 8, 6, 9, 16, 1, 7, 3, 11, 14, 2, 5, 12, 13.

  4. Проаналізувати покрокове виконання завдання 3 щодо кількості виконуваних дій.

  5. Шдібрати власні тести, які доводить переваги й показу-ють нєдоліки методу природного злиття при л > 100.

  6. Зробити письмовий аналіз завдань 3-5.

СОРТУВАННЯ ЗА ЛІНІЙНИЙ ЧАС

Ми розглянули достатню кількість різних методів сортуван­ня. Усі воыи мають певні переваги й недоліки. Аналізуючи кожний із цих методів, ми намагалися оцінювати доцільність їх використання у кожній конкретній ситуації, давали оцінку ефективності виконання алгоритмів, що реалізують метод. Найгіршою була оцінка 0(п2), а найкращою - 0(п ■ \og2n).

Але виявляється, що це не найкращий варіант ефективності алгоритму. Розглянемо два методи, які виконують сортування за лінійний час, тобто оцінка їх ефективності О(п).

Чому ж ми не почали відразу з цих алгоритмів? Чому напи-сані цілі трактата стосовно аналізу та порівняння різних іс-нуючих методів сортування? Чому продовжуються пошуки ін-ших, кращих методів? Справа в тому, що ці методи, крім такої значної переваги, як виконання сортування за лінійний час, мають досить суттєві недоліки. Краще назвемо ці недоліки об-меженнями на застосування даних алгоритмів до тих чи інших масивів значень.

Соседние файлы в папке Методи побудови алгоритмів та їх аналіз