
- •ТЕОРІЯ АЛГОРИТМІВ
- •Мета курсу
- •Основна література
- •Додаткова література
- •Структура курсу
- •Оцінювання роботи
- •Атестація
- •Рейтинги дифзаліку
- •Розділ 1.
- •1.1. Від задачі до програми
- •Постановка задачі
- •Приклад
- •Що дано?
- •Що ми хочемо знайти?
- •Тому ми повертаємося до Андрія і вимагаємо в нього додаткову інформацію. Він повідомляє,
- •Побудова моделі
- •На вибір відповідної математичної структури будуть впливати такі фактори:
- •Зробивши пробний вибір математичної структури, задачу слід переформулювати в термінах відповідних математичних об’єктів.
- •Приклад.
- •Що ми шукаємо в задачі?
- •Розробка алгоритму
- •Алгоритм повинен задовольняти вимогам, які дещо суперечать одна одній:
- •Якщо маємо справу із завданням, рішення якого вимагає значних обчислювальних витрат, то вартість
- •Приклад.
- •Алгоритм ETS (вичерпний комівояжер)
- •Правильність алгоритму
- •Приклад.
- •Реалізація алгоритму
- •По-друге, реалізація може виявитися складним процесом тому, що перед написанням програми потрібно побудувати
- •По-третє, одна справа – довести правильність конкретного алгоритму, описаного в словесній формі, інша
- •Аналіз алгоритму та його складності
- •Нехай А – алгоритм для розв’язку певного класу задач, а n – розмірність
- •Наступне позначення стандартне в багатьох математичних дисциплінах, в тому числі в аналізі алгоритмів.
- •Математичне визначення порядку зростання функції
- •Класи складності алгоритмів
- •Будемо користуватися критерієм оцінки часу виконання для оцінки якості алгоритму А.
- •Звичайно, хотілося б провести якомога точніший аналіз, тобто знати якомога більше про функцію
- •Важливо також знати, наскільки погано працює експоненційний алгоритм. Існує багато важливих задач, для
- •Приклад. Розглянемо алгоритм ETS.
- •Припустимо, що у нашого комівояжера 20 міст і що у нас є феноменальний
- •Необхідно підкреслити, що ступінь зростання якнайгіршого часу виконання - не єдиний або найважливіший
- •2.Якщо програма працюватиме тільки з "малими" вхідними даними, то степінь зростання часу виконання
- •3.Ефективні, але складні алгоритми можуть бути небажаними, якщо готові програми підтримуватимуть особи, що
- •Коли варто проводити аналіз алгоритму?
- •Перевірка програми
- •Перевірка правильності підтверджує, що програма робить саме те, для чого вона була призначена.
- •Міри безпеки.
- •Локальні перевірки.
- •Перевірка на неприпустимі значення. В кожному операторі, якщо це можливо, розгляньте можливість появи
- •Перевірка усіх частин програми.
- •Тестові дані.
- •Перевіряйте програму на даних, що лежать на границях допустимих діапазонів. Якщо діапазон для
- •Перевіряйте програму на даних, що виходять за межі припустимого діапазону вхідних даних. Остерігайтеся
- •Пошук скритих помилок.
- •Повторна перевірка.
- •Перевірка ефективності реалізації направлена на відшукання способів змусити правильну програму працювати швидше або
- •Методи підвищення ефективності програми машинно незалежні:
- •Порядок в логічних виразах.
- •Профілі виконання.
- •Профілі виконання корисні не тільки для перевірки ефективності реалізації, але і для інших
- •Перевірка обчислювальної складності зводиться до експериментального аналізу складності алгоритму або до експериментального порівняння
- •Документація
- •Зовнішня документація.
- •Програмна документація.
- •Слід використовувати мнемонічні імена для змінних та підпрограм. Вони повинні натякати на їх
- •Уникайте поганого або заплутаного тексу програми.
- •Уникайте нестандартних засобів версії мови. Якщо ви передбачаєте, що програма повинна використовуватися широким
- •Можна стверджувати, що вихідна інформація є найбільш важливим документом будь-якої програми, оскільки вона
- •Розробник програми повинен допомагати користувачу, складаючи осмислені повідомлення про помилки. Слід намагатися передбачити
- •Обслуговування
- •На простоту та якість обслуговування впливають такі фактори:
- •1.2. Час виконання програм
- •На час виконання програми впливають наступні чинники:
- •Розглянемо, як виконуються операції додавання і множення з використанням О-символіки.
- •Приклад. Правило сум використовується для обчислення часу послідовного виконання програмних фрагментів з циклами
- •Правило добутків. Якщо T1(n) і Т2(n) мають степені зростання O(f(n)) і O(g(n)) відповідно,
- •Приклад. Визначення часу виконання програми. procedure bubble ( var A: array [1.. n]
- •Число елементів n, що підлягають сортуванню, може служити мірою об'єму вхідних даних.
- •Тепер підрахуємо час виконання умовних і циклічних операторів. Оператори if і for вкладені
- •Далі розглянемо групу (2)–(6) операторів внутрішнього циклу. Загальне правило обчислення часу виконання циклу
- •Тепер перейдемо до зовнішнього циклу, який містить всі виконувані оператори програми. Оператор (1)
- •Загальні правила обчислення часу виконання програми
- •3.Час виконання умовних операторів складається з часу виконання умовно виконуваних операторів і часу
- •4.Час виконання циклу є сумою часу всіх виконуваних ітерацій циклу, операторів тіла циклу,
- •5.Для програм, що містять декілька процедур (серед яких немає рекурсивних), можна підрахувати загальний
- •Домашнє завдання

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

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

Обслуговування
Багато програмістів вважає, що не існує великих програм, вільних від помилок або повністю протестованих. Виправляти такі програми важко, якщо вони були документовані погано. Існує багато інших причин, коли програми потрібно оновлювати, розвивати або модифікувати з часом. Ця діяльність відноситься до категорії обслуговування програми. Це важлива робота, що збільшує час корисного життя програми.

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

1.2. Час виконання програм
Література для самостійного читання:
Асимптотичні співвідношення |
с.28-32 |
[1] |
Обчислення часу виконання програм |
с.32-37 |
[1] |
Обчислення часу виконання |
|
|
рекурсивних процедур |
с.265-272 |
[1] |
Повний приклад |
с.181-185 |
[2] |

На час виконання програми впливають наступні чинники:
–Введення початкової інформації в програму (зокрема, її розмір).
–Якість скомпільованого коду програми.
–Машинні інструкції (природні і прискорюючі), використані для виконання програми.
–Складність алгоритму відповідної програми (кількість кроків алгоритму).

Розглянемо, як виконуються операції додавання і множення з використанням О-символіки.
Правило сум. Нехай T1(n) і Т2(n) - час виконання двох програмних фрагментів Р1 і Р2 , T1(n) має ступінь
зростання O(f(n)), а Т2(n) - O(g(n)). Тоді T1(n)+Т2(n), тобто час послідовного виконання фрагментів Р1 і Р2,
має ступінь зростання O(max(f(n), g(n))).
Для доказу цього пригадаємо, що існують константи с1, с2, n1 і n2 такі, що при n≥n1 виконується нерівність T1(n)≤с1f(n), і, аналогічно, Т2(n)≤с2g(n), якщо n≥n2. Хай n0=max(n1, n2). Якщо n≥n0, то, очевидно, що T1(n)+Т2(n)≤с1f(n)+с2g(n). Звідси витікає, що при n≥n0 справедлива нерівність T1(n) +Т2(n)≤(с1+с2)max(f(n),g(n)). Остання нерівність і означає, що T1(n)+Т2(n) має порядок зростання O(max(f(n),g(n))).

Приклад. Правило сум використовується для обчислення часу послідовного виконання програмних фрагментів з циклами і галуженнями.
Хай є три фрагменти з часом виконання відповідно O(n3), O(n2) і О(n log n). Тоді час послідовного виконання перших двох фрагментів має порядок O(max(n2, n3)), тобто О(n3). Час виконання всіх трьох фрагментів має порядок
O(max(n3, n log n)), це те ж саме, що О(n3).
У загальному випадку час виконання кінцевої послідовності програмних фрагментів, без урахування констант, має порядок фрагмента з найбільшим часом виконання.
З правила сум також виходить, що якщо g(n)≤f(n) для всіх n, що перевищують n0, то вираз O(f(n)+ g(n))
еквівалентний O(f(n)). Наприклад, О(n2+n) те ж саме, що О(n2).

Правило добутків. Якщо T1(n) і Т2(n) мають степені зростання O(f(n)) і O(g(n)) відповідно, то добуток T1(n)Т2(n) має ступінь зростання O(f(n) g(n)).
З правила добутків витікає, що O(cf(n)) еквівалентно O(f(n)), якщо с - додатна константа. Наприклад, О(n2/2) еквівалентно О(n2).

Приклад. Визначення часу виконання програми. procedure bubble ( var A: array [1.. n] of integer );
{Процедура впорядковує массив А в зростаючому порядку }
var i, j, temp: integer; begin
(1) |
for i:=1 to n-l do |
(2) |
for j:=n downto i+1 do |
(3) |
if A[j-1] > A[j] then |
|
begin {перестановка A[j-1] и A[j] } |
(4) |
temp:= A[j-1] ; |
(5) |
A[j-1]:= A[j]; |
(6) |
A[j]:= temp; |
|
end; |
end; { bubble }