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

osn_progr_final

.pdf
Скачиваний:
37
Добавлен:
12.02.2016
Размер:
3.27 Mб
Скачать
t'(n)

Повертаючись до прикладу 2 можна сказати, що ефективність алгоритму безпосереднього сумування n елементів відповідає лінійній складності, оскільки його швидкодія, тобто кількість кроків, згідно властивості (1), є О(n).

Приклад 3. Для набору з n відрізків підрахувати кількість всіх "трійок", з яких виходять невироджені трикутники.

Очевидно, належить перевірити n(n-1)(n-2) варіантів, що відповідає кубічній складності - О(n3).

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

Використання О-оцінювання дозволяє нам позбавити себе від врахування конкретного обчислювального пристрою для аналізу складності.

Нехай є деяка віртуальна машина М, яка обчислює функцію f, і визначені вхідні дані: х — деяке двійкове слово, n - довжина цього слова. Тоді визначимо функцію t(n) — як кількість операцій, які потрібні машині М для роботи на вхідному слові х до зупинки. Справедлива така теорема.

Теорема (Блюм, 1971). Існує алгоритмічна задача, яку можна розв’язати, та для якої справедливо наступне. Для будь-якого алгоритму, що розв’язує цю задачу і що має складність в найгіршому випадку t(n) , можна знайти інший алгоритм із складністю такий, що майже для всіх n виконується t'(n) log2 t(n) .

Іншими словами, будь-який алгоритм, що розв’язує деяку задачу, можна суттєво прискорити.

Теорема про прискорення не дає нам можливості дати визначення математичному терміну “оптимальний“ алгоритм. Тому виникла необхідність розглядати класи складності. Так ми будемо називати сукупність задача, для яких існує хоча б один алгоритм із заданими властивостями складності.

2.4 СКЛАДНІСТЬ ЗАДАЧ.

Поняття складності алгоритму пов'язане з поняттям складності задачі. З теореми Блюма можна зробити висновок, що визначати складність задачі через складність якнайкращого алгоритму для її розв’язання не найкращий спосіб.

31

Приклад 4. Нехай нам

треба

побудувати

алгоритм для

розв’язання наступного класу задач:

 

 

 

 

обчислити значення виразу

a

 

xn ... a x a

, в точці x=b, де a R,

 

 

 

 

 

 

 

n

 

1

0

 

i

b R, де R - множина дійсних чисел.

 

 

 

 

Множина вхідних даних: an ,.......,a0 ,

де ai R, b R, an , an 1,..., a1, a0

вектор з n+1 дійсних чисел, b - дійсне число.

 

Результат: r f

 

 

f

 

b

 

n

... a1b a0 .

 

 

 

b , де

 

anb

 

 

Змінні: i - цілого типу; х, r - дійсного типу.

Константи: {ai|i=0,..., n}, п.

Неважко побачити, що ми маємо справу з класом задач. Нижче наведений алгоритм для цього класу задач.

Алгоритм:

1.Покласти i рівним n, s рівним 0, х рівним b;

2.Піднести х до степеня i

3.Помножити ai на степінь;

4.Покласти s рівній сумі s і добутку ai на степінь.

5.Якщо i = 0, то s - результат (стоп)

інакше покласти i=i -1, перейти до кроку 2.

Організацію обчислень згідно цього алгоритму описує вираз

an xn ... a1 x a0 .

Є і інший алгоритм для розв’язання задач цього класу. Вхідні дані: ті ж, що і в попередньому прикладі. Результат: такий самий.

Змінні: r, s, x – дійсного типу, i – цілого типу.

Константи: ai , п.

Алгоритм:

1.Покласти i рівним п, x рівним b;

2.Покласти r рівним ai ;

3.Помножити r на x;

4.Покласти r рівним добутку;

5.Покласти i рівним i -1;

6.Покласти r рівним r+ ai ;

7.Якщо i = 0, то r - результат інакше перейти до кроку 3;

32

Організацію обчислень за цим алгоритмом можна пояснити ось таким виразом:

... an x an 1 x an 2 x an 3 x ... a1 x a0

Цей метод обчислення значення полінома в точці називається схемою Горнера.

Виразимо складність дії піднесення до степеня i як (i - 1) операцій множення. Тоді, складність другого алгоритму (по схемі Горнера) у вигляді кількості операцій додавання і множення буде

рівна 2п.

Для прямого алгоритму вона буде рівна:

n

 

 

 

n 1

 

 

n2 3n 2

 

n2

 

 

i 1

n

 

n 2

n

 

n

 

2n 2n .

2

2

2

i 0

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Таким чином, другий алгоритм ефективніший першого. Тепер можна дати визначення ефективному алгоритму.

Визначення 7. Алгоритм, трудомісткість якого обмежена поліномом від характерного розміру задачі, називається ефективним.

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

Визначення 8. Клас складності складається з функцій f, для яких існує обчислююча f машина М, така що функція Т(М,х) за часом обмежена функцією t(n) з точністю до мультиплікативної константи, тобто

 

C(t(n)) f

 

M :(M обчислює

f) & (t M (n) O(t(n))) .

 

 

t(n) - називається порядком класу.

 

 

Тобто класом задач складності t(n) назвемо сукупність задач, які

розв’язуються за час порядку t(n) .

 

 

O-оцінки виражають відносну швидкість алгоритму залежно від

початкових даних. Розглянемо класи O-складності алгоритмів. Нехай

N - кількість даних, що обробляються.

 

 

 

Класи складності

 

Опис програм

О(1)

 

 

 

Більшість операцій в програмі виконується тіль-

 

 

 

 

ки один раз або лише кілька разів. Будь-який ал-

33

 

горитм, що завжди вимагає (незалежно від роз-

 

міру даних) одного і того ж часу, має константну

 

складність.

О(N)

Час роботи програми лінійно залежить від N .

 

Властиво алгоритмам, які обробляють кожен

 

елемент вхідних даних кількість разів, що про-

 

порційна лінійній функції.

О(N2), О(N3),

Поліноміальна складність. О(N2) -квадратична

О(Nк)

складність, О(N3) - кубічна складність. Час робо-

 

ти програми пропорційний поліноміальній фун-

 

кції.

О(Log(N))

Час роботи програми логарифмічний. Такий час

 

роботи зустрічається зазвичай в програмах, які

 

ділять велику задачу на маленькі і розв’язують їх

 

окремо.

О(N*log( N))

Такий час роботи мають ті алгоритми, які ділять

 

велику задачу на маленькі, а потім, розв’язавши

 

їх, сполучають їх розв’язки.

О(eN)

Експоненціальна складність. Такі алгоритми

 

найчастіше виникають в результаті підходу іме-

 

нованого як “метод грубої сили”.

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

Ми пам'ятаємо, що до управляючих структур відносяться: лінійні вирази, умовні вирази, цикли.

Управляюча структура

Складність

Простий вираз

О(1)

Лінійний вираз S1,…Sn

Домінанта О(С1),…, О(Cn), де C1,…, Сn

 

– складність обчислення виразів S1,…Sn

Якщо <умова> то дія1

Домінанта О(С1), О(С2), О(С3), де С1,

Інакше дія2

С2, С3 складність обчислень дій і умови

 

відповідно

Цикл з n повтореннями

О(n*C1), де С1 складність обчислення S1

тіла S1

 

34

Якщо немає рекурсії і циклів, то всі управляючі структури можуть бути зведені до структур константної складності. Отже, і весь алгоритм також характеризується константною складністю.

Тому визначення складності алгоритму в основному зводиться до аналізу циклів і рекурсивних викликів.

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

Для i=1 до N виконувати початок {Простий вираз} кінець;

Складність цього алгоритму О(N), оскільки тіло циклу виконується N раз, і складність тіла циклу рівна О(1).

Якщо один цикл вкладений в іншій і обидва цикли мають однакову кількість повторень, то вся конструкція характеризується квадратичною складністю.

Для i=1 до N виконувати Для j=1 до N виконувати початок {Простий вираз} кінець;

Складність цієї програми О(N2).

Давайте оцінимо складність програми "Трійки Піфагора". Суть задачі в наступному. Знайти всі трійки натуральних чисел (х;y;z), що задовольняють рівнянню x2 + y2= z2. Піфагор знайшов формули, які в сучасному формалізмі можуть бути записані так: x= 2п +1, y=2п(п +1), z= 2п2 + 2п +1, де п – ціле число. Їх називають «Піфагоровимі трійками»

А

B

З

3

4

5

5

1 2

13

8

15

17

7

24

25

20

21

29

12

35

37

35

9

40

41

28

45

53

11

60

61

Трикутники з такими сторонами є прямокутними. Таке почате Піфагором дослідження «нешкідливого» рівняння x2 + y2= z2 призвело до складної проблеми сучасної теорії чисел – дослідження в цілих числах рівняння xn + yn= zn.

Перед аналізом складності програми, яка знаходить трійки Піфагора, відзначимо, що існують два способи аналізу складності: висхідний (від внутрішніх управляючих структур до зовнішніх) і низхідний (від зовнішніх до внутрішніх). Ми користуватимемося висхідним.

Розглянемо алгоритм і запишемо саму програму:

 

А

 

 

 

 

 

Вхід: n

 

 

 

 

 

 

1. Small=1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

2.

Поки small<n виконувати

 

 

 

 

 

 

 

початок

 

 

B

 

 

 

 

3. next=small

 

 

 

 

 

 

 

4.

Поки next<=n виконувати

 

 

 

 

 

 

 

початок

 

 

 

С

 

 

 

5. last=next

 

 

 

 

 

 

 

6.

Поки last<n виконувати

D

E

 

 

 

 

 

початок

G

 

 

 

 

7.

Якщо last<=2*small і next<=2*small і

 

 

 

 

 

 

 

 

 

 

 

 

last*last=small*small+next*next

 

 

 

I

 

 

 

 

 

 

F

 

 

8.

то друк(small)

 

 

 

 

 

 

 

 

 

 

 

H

 

 

друк(next)

 

 

 

 

 

 

 

 

друк(last)

 

 

 

 

J

 

 

9.

last=last+1 кінець циклу last

 

 

 

К

 

 

 

10.next=next+1 кінець циклу next

 

 

 

 

 

 

 

11.small=small+1 кінець циклу small

 

 

 

 

 

 

 

12. Кінець

 

 

 

 

 

 

 

Вихід: роздруковані значення small, next,last

Підрахуємо її складність:

О(H)=O(1)+O(1)+O(1)=O(1); О(I)=O(N)*(О(F)+O(J))=O(N)*O(домінанти умови)=О(N);

36

О(G)=O(N)*(О(C)+O(I)+O(K))=O(N)*(О(1)+O(N)+O(1))=O(N2) О(E)=O(N)*(О(B)+O(G)+O(L))=O(N)* О(N2)= О(N3); О(D)=O(A)+O(E)=O(1)+ О(N3)= О(N3)

Таким чином, складність даного алгоритму О(N3). Проаналізувавши програму можна зробити висновок, що основ-

ну оцінку складності забезпечують вкладені цикли.

Тому для зменшення складності, перш за все можна спробувати скоротити глибину вкладеності циклів. Потім слід розглянути можливість скорочення кількості операторів в циклах з найбільшою глибиною вкладеності. Але дані рекомендації не завжди можна виконати.

Давайте оцінимо алгоритм бінарного пошуку ключа у впорядкованому масиві.

Суть алгоритму: розглядаємо серединний елемент масиву і перевіряємо відповідність ключа цьому значенню. Якщо нам не вдається знайти відповідності, ми порівнюємо ключ і значення серединного елементу і потім переміщаємося в нижню половину списку, якщо ключ менший і верхню – якщо більший. У цій половині знову шукаємо середину і знову порівнюємо з ключем. Якщо не виходить, знову ділимо на дві частини поточний інтервал.

Вхід: low, high – змінні, що задають нижню і верхню межі масиву, key – шукане число;

початок

поки low<=high виконувати початок

mid=(low+high) / 2; data=a[mid];

якщо key=data

тоді початок search=mid; закінчити роботу

кінець

інакше якщо key < data

то high=mid-1 інакше low=mid+1;

кінець; search=-1;

кінець;

37

Перша ітерація циклу має справу із всім списком елементів. Кожна подальша ітерація ділить список навпіл. Так, розмірами списку для послідовних кроків алгоритму є

n n/21 n/22 n/23 n/24 ... n/2m

Врешті-решт, знайдеться таке ціле m, що n/2m<2 або n<2m+1. Оскільки m - це перше ціле, для якого n/2m<2, то повинне бути вірним n/2m-1>=2 або 2m=<n. З цього виходить, що 2m=<n<2m+1.

Візьмемо логарифм кожної частини нерівності і одержимо m=<log2(n)=x<m+1. Значення m - це найбільше ціле, яке менше чи дорівнює х. Отже, складність дорівнює О(log2n).

Як математикам, нам би хотілося одержати вираз для часу, необхідного програмі для обробки даних розміру N, як функцію від N. Зазвичай нас цікавить середній випадок - очікуваний час роботи програми на "типових" вхідних даних, і гірший випадок - очікуваний час роботи програми на найгірших вхідних даних.

Через труднощі, що пов'язані з проведенням аналізу тимчасової складності алгоритму "в середньому", часто доводиться задовольнятися оцінками для гіршого і кращого випадків. Ці оцінки, по суті, визначають нижню і верхню межі складності "в середньому". У такому разі оцінка, одержана для якнайгіршого випадку, може служити хорошою апроксимацією складності "в середньому".

Основним недоліком O-оцінювання є його надмірна грубість. Якщо алгоритм А виконує деяку задачу за 0.001*N, тоді як для її ж розв’язання за допомогою алгоритму В потрібен 1000*Nз, то В в мільйон раз швидше, ніж А. Однак А і В мають одну і ту ж складність О(N).

Отже, тепер можна умовно розділити задачі наступним чином. Прості – задачі, які мають поліноміальний час розв’язання (на-

приклад, розв’язання СЛАР в раціональних числах).

Складні (важкі, що не мають розв’язку) – задачі, які не розв'язуються за поліноміальний час, або алгоритм розв’язання за поліноміальний час не знайдений.

Крім цього, існують принципово нерозв'язні задачі. Дане твердження доведене А.Тьюрінгом.

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

38

Теза Колмогорова. Проблеми, які не можуть бути розв’язані без повного перебору, залишаться за межами можливостей машини на скільки завгодно високому ступені розвитку техніки і культури.

На думку Тюрінга, все те, “що природно визнали б обчислюваним, могло б, принаймні у принципі, бути обчисленим в природі”. Тому справедлива така теза.

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

Це означає:

1.Наявність відповідної програми.

2.Наявність необхідних обчислювальних ресурсів (швидкодія, розмір пам'яті).

39

3. МЕТОДОЛОГІЯ ОПИСУ МОВ ПРОГРАМУВАННЯ

3.1 ГРАМАТИКИ

Нехай єпрограма, яка призначена для виконання на комп'ютері, написана за допомогою деякої мови програмування. Щоб комп'ютер зрозумів призначені інструкції, необхідно перекласти їх зрозумілою йому мовою. Таким перекладом займаються програми, що називаються компіляторами. Для реалізації перекладу необхідно мати точний опис правил побудови вхідних текстів, які називаються синтаксисом мови, і правил тлумачення, що описують зміст текстів, які називаються семантикою мови. Для опису синтаксису і семантики використовуються різні засоби. Так опис синтаксису мови може бути виконаний із застосуванням формальних граматик, а опис його семантики – за допомогою атрибутних граматик.

У даному розділі розглядаються питання, пов'язані з описом синтаксису.

Визначення 1. Скінченна множина символів, неподільних при даному розгляді, називається алфавітом чи словником , а символи, що входять у множину, - буквами алфавіту.

Наприклад, алфавіт A = {a, b, c, +, !} містить 5 букв, а алфавіт B = {00, 01, 10, 11} містить 4 букви, кожна з яких складається з двох символів.

Визначення 2. Послідовність букв алфавіту називається словом чи ланцюжком у цьому алфавіті. Кількість букв, що входять у слово, називається його довжиною.

Наприклад, в алфавіті A слово =ab++c має довжину l( ) = 5, а слово =00110010 в алфавіті B має довжину l( ) = 4.

Якщо задано алфавіт A, то позначимо A* множину усіх ланцюжків, що можуть бути побудовані з букв алфавіту A. При цьому передбачається, що порожній ланцюжок, що позначимо знаком $, також входить у множину A*. Порожній ланцюжок – це ланцюжок, що не містить жодної букви. Приєднання до деякого ланцюжка порожнього ланцюжка праворуч чи ліворуч від нього не змінює ланцюжок

:

$ = $ =

Для визначення множини всіх ланцюжків, побудованих із символів алфавіту А, що не містять порожнього ланцюжка, використовують позначення А+.

40

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