
- •1.Побудова і аналіз алгоритмів
- •1.1.Формалізація алгоритмів.
- •1.2.Покрокове проектування алгоритмів.
- •1.3.Характеристики алгоритму
- •1.4.Складність алгоритму
- •1.5.Ефективність алгоритмів
- •1.6.Правила аналізу складності алгоритмів.
- •2.Алгоритми сортування
- •2.1.Задача сортування
- •2.2.Сортування вибіркою
- •2.2.1.Сортування простою вибіркою
- •2.2.2.Обмінне сортування простою вибіркою
- •2.2.3.Бульбашкове сортування
- •2.2.4.Сортування Шелла
- •2.3.Сортування включенням
- •2.3.1.Сортування простим включенням
- •2.3.2.Бульбашкове сортування включенням
- •2.3.3.Турнірне сортування
- •2.3.4.Сортування впорядкованим бінарним деревом
- •2.3.5.Сортування частково впорядкованим деревом
- •2.4.Сортування розподілом
- •2.4.1.Порозрядне цифрове сортування
- •2.4.2.Швидке сортування Хоара
- •2.5.Сортування злиттям
- •2.5.1.Сортування попарним злиттям
- •2.6.Рандомізація
- •3.Алгоритми пошуку
- •3.1.Послідовний (лінійний) пошук
- •3.2.Бінарний пошук
- •3.3.Метод інтерполяції
- •3.4.Метод „золотого перерізу”
- •3.5.Алгоритми пошуку послідовностей
- •3.5.1.Прямий алгоритм пошуку
- •3.5.2.Алгоритм Кнута, Моріса, Пратта
- •3.5.3.Алгоритм Боуєра та Мура
- •4.Методи швидкого доступу до даних
- •4.1.Хешування даних
- •4.1.1.Методи розв’язання колізій
- •4.1.2.Переповнення таблиці і повторне хешування
- •4.1.3.Оцінка якості хеш-функції
- •4.2.Організація даних для прискорення пошуку за вторинними ключами
- •4.2.1.Інвертовані індекси
- •4.2.2.Бітові карти
- •5.Мережеві алгоритми
- •5.1.Представлення мереж
- •5.2.Операції з вузлами і зв’язками
- •5.2.1.Обхід мережі
- •5.2.2.Найменші стовбурні дерева
- •5.3.Найкоротший маршрут
- •5.3.1.Інші задачі пошуку найкоротшого маршруту
- •5.3.1.1.Двох-точковий найкоротший маршрут
- •5.3.1.2.Обчислення найкоротшого маршруту для всіх пар
- •5.3.1.3.Штрафи за повороти
- •5.3.2.Застосування методу пошуку найкоротшого маршруту
- •5.3.2.1.Розбиття на райони
- •5.3.2.2.Складання плану робіт
- •5.3.2.3.Планування колективної роботи
- •5.4.Максимальний потік
- •5.4.1.Застосування максимальних потоків
- •5.4.1.1.Непересічні шляхи
- •5.4.1.2.Розподіл робіт
- •6.Методи розробки алгоритмів
- •6.1.Метод частинних цілей
- •6.2.Динамічне програмування
- •6.3.Метод сходження
- •6.4.Дерева розв’язків
- •6.4.1.Мінімаксний пошук
- •6.4.2.Покращення пошуку в дереві гри
- •6.4.3.Метод відпрацювання назад
- •6.5.Програмування з поверненнями назад
- •6.5.1.Метод спроб та помилок
- •6.5.2.Реалізація пошуку з поверненням
- •6.5.3.Альфа-бета відсікання
- •6.5.4.Метод гілок і границь
- •6.6.Евристичні алгоритми
- •6.7.Імовірнісні алгоритми
- •6.8.Генетичні алгоритми
- •6.8.1.Розв’язок діофантового рівняння.
- •6.8.2.Програмна реалізація
1.3.Характеристики алгоритму
Охарактеризуємо поняття алгоритму не формально, а дескриптивно за допомогою таблиці:
|
Вирішення гарантоване |
||
Так |
Ні |
||
Чи обов’язкове оптимальне вирішення |
Так |
Алгоритм |
Імовірнісний алгоритм |
Ні |
Приблизний алгоритм |
Евристичний алгоритм |
Як бачимо, алгоритм – це механізм, який не тільки повинен гарантувати те, що вирішення колись буде знайдене, але й те, що буде знайдене саме оптимальне, тобто найкраще вирішення. Крім того, алгоритм повинен мати наступні п’ять якостей:
Обмеженість в часі – робота алгоритму обов’язково повинна завершитись через деякий розумний період часу.
Правильність – алгоритм повинен знаходити правильне, а не будь-яке рішення.
Детермінованість – скільки б разів не виконувався алгоритм з однаковими вхідними даними, результат повинен бути однаковим.
Скінченність – опис роботи алгоритму повинен мати скінчену кількість кроків.
Однозначність – кожний крок алгоритму повинен інтерпретуватися однозначно.
Як видно з таблиці, евристика – це пряма протилежність класичному алгоритму, так як вона не дає ніяких гарантій на те, що рішення буде знайдене, так само, як і на те, що воно буде оптимальним. Між ними є два перехідні стани, назв яким, на жаль, ще не придумали, і тому їх називають приблизними алгоритмами (рішення гарантоване, але його оптимальність – ні) і імовірнісні алгоритми (рішення не гарантоване, але якщо воно буде знайдене, то обов’язково буде оптимальним).
1.4.Складність алгоритму
У процесі вирішення прикладних задач вибір потрібного алгоритму викликає певні труднощі. І справді, на чому базувати свій вибір, якщо алгоритм повинен задовольняти наступні протиріччя.
Бути простим для розуміння, перекладу в програмний код і наладки.
Ефективно використовувати комп’ютерні ресурси і виконуватися швидко.
Якщо написана програма повинна виконуватися лише декілька разів, то перша вимога найбільш важлива. Вартість робочого часу програміста, звичайно, значно перевищує вартість машинного часу виконання програми, тому вартість програми оптимізується за вартістю написання (а не виконання) програми. Якщо мати справу з задачею, вирішення якої потребує значних обчислювальних затрат, то вартість виконання програми може перевищити вартість написання програми, особливо якщо програма повинна виконуватися багаторазово. Тому, з економічної точки зору, перевагу буде мати складний комплексний алгоритм (в надії, що результуюча програма буде виконуватися суттєво швидше, ніж більш проста програма). Але і в цій ситуації розумніше спочатку реалізувати простий алгоритм, щоб визначити, як повинна себе вести більш складна програма. При побудові складної програмної системи бажано реалізувати її простий прототип, на якому можна провести необхідні виміри й змоделювати її поведінку в цілому, перш ніж приступати до розробки кінцевого варіанту. Таким чином, програмісти повинні бути обізнані не тільки з методами побудови швидких алгоритмів, але й знати, коли їх потрібно застосувати.
Існує декілька способів оцінки складності алгоритмів. Програмісти, звичайно, зосереджують увагу на швидкості алгоритму, але важливі й інші вимоги, наприклад, до розмірів пам’яті, вільного місця на диску або інших ресурсів. Від швидкого алгоритму може бути мало толку, якщо під нього буде потрібно більше пам’яті, ніж встановлено на комп’ютері.
Важливо розрізняти практичну складність, яка є точною мірою часу обчислення і об’єму пам’яті для конкретної моделі обчислювальної машини, і теоретичну складність, яка більш незалежна від практичних умов виконання алгоритму і дає порядок величини вартості.
Більшість алгоритмів надає вибір між швидкістю виконання і ресурсами. Задача може виконуватися швидше, використовуючи більше пам’яті, або навпаки – повільніше з меншим обсягом пам’яті.
Прикладом в даному випадку може слугувати алгоритм знаходження найкоротшого шляху. Задавши карту вулиць міста у вигляді мережі, можна написати алгоритм, що обчислює найкоротшу відстань між будь-якими двома точками цієї мережі. Замість того, щоб кожного разу заново перераховувати найкоротшу відстань між двома заданими точками, можна наперед прорахувати її для всіх пар точка і зберегти результати в таблиці. Тоді, щоб знайти найкоротшу відстань для двох заданих точка, достатньо буде просто взяти готові значення з таблиці. При цьому отримують результат, практично, миттєво, але це зажадає великий обсяг пам’яті. Карта вулиць для великого міста може містити сотні тисяч точок. Для такої мережі таблиця найкоротших відстаней містила б більше 10 мільярдів записів. В цьому випадку вибір між часом виконання і обсягом необхідної пам’яті очевидний.
Із цього зв’язку випливає ідея просторово-часової складності алгоритмів. При цьому підході складність алгоритму оцінюється в термінах часу і простору, і знаходиться компроміс між ними.
При порівнянні різних алгоритмів важливо розуміти, як складність алгоритму співвідноситься із складністю вирішуваної задачі. При розрахунках за одним алгоритмом сортування тисячі чисел може зайняти 1 секунду, а сортування мільйона – 10 секунд, тоді як розрахунки за іншими алгоритмами можуть зайняти 2 і 5 секунд відповідно. У цьому випадку не можна однозначно сказати, яка із двох програм краща – це буде залежати від вихідних даних.