
- •Затверджено на засіданні
- •Редактор л.М. Тонкошкур
- •1. Введення в теорію алгоритмів.
- •2. Складність алгоритмів.
- •3. Структури даних.
- •3.1 Статичні та динамічні структури даних.
- •3.2. Стеки
- •3.3. Списки.
- •Блок-схема програми
- •3.4. Черги.
- •Блок-схема програми
- •3.5 Графи.
- •3.6. Дерева.
- •4. Методи побудови ефективних алгоритмів
- •4.1 Метод «розподіляй та володій».
- •Способ 1. Алгоритм пошуку мінімального та максимального значень елементів масиву.
- •Функція MinMax
- •Блок-схема
- •4.4. Жадібні алгоритми
- •5. Алгоритми сортування
- •5.1. Задача сортування та класифікація методів сортування.
- •5.2. Складність алгоритмів сортування.
- •5.3. Швидке сортування (OuickSort).
- •5.4. Сортування деревом (HeapSort) Алгоритм.
- •5.5. Cортування Шелла (ShellSort)
- •5.6. Сортування злиттям (MergeSort)
- •Лінійний пошук - це пошук підряд в неупорядкованій послідовності.
- •7. Алгоритми на графах.
- •Список літератури
4. Методи побудови ефективних алгоритмів
4.1 Метод «розподіляй та володій».
Для рішення задачі її часто розбивають на частини, знаходять їх рішення, потім з них отримують рішення всієї задачі. Цей метод, особливо якщо його застосовувати рекурсивно, часто приводить до ефективного рішення задачі, підзадачі якої представляють її менші версії.
Розглянемо задачу пошуку мінімального та максимального значень елементів множини двома способами – звичайним алгоритмом пошуку мінімального та максимального значень елементів масиву та з застосуванням методу «розподіляй та володій».
Способ 1. Алгоритм пошуку мінімального та максимального значень елементів масиву.
+
-
-
+
Min=Si
Кількість порівнянь:
(n-1) – пошук максимального значення;
(n-2) – пошук мінімального значення;
(2n-3) – всього порівнянь.
Способ 2. Алгоритм з застосуванням методу «розподіляй та володій».
Множина S разбивається на дві однакових підмножини S1 и S2, кожна з яких також розбивається на підмножини, доки в кожній з них не залишеться по два елементи, один з яких- мінімальний, інший - максимальний. Знайдені рішення об’єднуються, серед них знову обчислюються мінімум та максимум, і так далі. Потім з них отримують рішення всієї задачі (рекурсивна функція MinMax).
Функція MinMax
+ -
Обчислимо кількість порівнянь.
Нехай Т(n) - число порівнянь у функції MinMax.
Відомо, що Т(2)=1, тоді Т(n) можна представити наступним чином:
1
, при n
=2
T(n) =
,
при n>2
Рішенням
цих
рекурсивних
рівнянь
є
функція
Докажемо це методом математичної індукції.
Відомо, що при n = 2 Т(2) =1.
Припустимо,
що
при n
=m це
рішення
вірно,
тобто
Докажемо, що при n=2*m функція T(n) задовільняє рекурентному рівнянню:
.
Що і потрібно було доказати.
Звідси кількість порівнянь алгоритму з застосуванням методу «розподіляй та володій» дорівнює
Порівняємо
алгоритм 1 і алгоритм 2. Алгоритм 1 має
(2n-3)
порівнянь, а алгоритм 2 має
порівнянь. Таким чином,
алгоритм з
застосуванням методу «розподіляй та
володій» ефективніший.
4.2. Рекурсія.
Рекурсія - це можливість ввести в визначення об’екту посилання на сам об’єкт. Рекурсія є одним з фундаментальних концептуальних інструментів, наявних в розпорядженні програміста.
Приклад.
Визначити рекурсивну функцію обчислення xn для x>0 і n>0.
Блок-схема програми
Блок-схема функції EX
так
ні
Текст програми:
#include <iostream.h>
int EX(int, int);
void main()
{
int x,n;
cout<<”input x,n”<<endl;
cin>>x>>n;
cout<<”Result:”<<endl;
cout<<EX(x, n)<<endl;
}
int EX(int x, int n)
{
if (n==0)
return 1;
else
return EX(x, n-1);
}
4.3. Метод динамічного програмування
Динамічне програмування - це табличний метод, при якому використовується одна й та же схема для обчислення всіх підзадач даної задачі. В цьому методі одного разу знайдений результат записується в таблицу и далі повторно не обчислюється.
Динамічне програмування застосовується до задач оптимізації.
Приклад. Знайти добуток чотирьох матриць з мінімальною складністю, тобто необхідно вибрати оптимальний порядок множення матриць.
Припустимо, що множення матриці розміром p*q на матрицю розміром q*r потребує p*q*r операцій.
Знайдемо добуток чотирьох матриць М = М1*М2*М3*М4 розміром
М1 = [10*20] , М2 =[20*50] , М3 = [50*1] , М4 = [1*100].
Позначимо r0 =10, r1 =20 , r2 =50 , r3 =1 , r4 =100.
Обчислення матриць в порядку М1*(M2*(M3*M4)) потребує таку кількість операцій:
50*1*100+20*50*100+10*20*100 =125000
Обчислення в порядку (М1*(M2*M3))*M4 потребує таку кількість операцій:
20*50*1+10*20*1+10*1*100 = 2200.
Ці результати отримані шляхом перебору варіантів порядку множення матриць.
Розглянемо алгоритм, що дозволить відразу обрати оптимальний порядок множення матриць.
Алгоритм динамічного програмування для обчислення порядку, що мінімізує складність множення ланцюжку з n матриць:М1*М2*М3*…*Мn.
Позначимо:
r0, r1 , … , rn , де ri-1 и ri - кількість рядків і стовпців матриці Мі, i=1,n;
mij -мінімальна складність обчислення добутку матриць Мі * Мі+1 * …* Мj;
mik - мінімальна складність обчислення добутку матриць Мі * Мі+1 * …* Мk=M';
mk+1,j - мінімальна складність обчислення добутку матриць Мk+1 * Мk+2 * …* *Мj = M".
ri-1 * rk * rj - - складність множення M' * M".
Тоді:
mij
=
,
якщо j>i,
mij = 0, якщо i = j.
Алгоритм динамічного програмування для обчислення порядку, що мінімізує складність множення ланцюжку з n матриць:М1*М2*М3*…*Мn, наведений на блок-схемі.
Результат обчислення значень mij заносимо в таблицю:
m11 = 0 |
m22 = 0 |
m33 = 0 |
m44 = 0 |
m12 = 10000 |
m23 = 1000 |
m34 = 5000 |
|
m13 = 1200 |
m24 = 3000 |
|
|
m14 = 2200 |
|
|
|
Порядок, в якому можна виконати множення матриць, визначається таким чином: ожній клітині таблиці приписується те значення k, при якому досягається мінімум. Таким чином, мінімальна кількість операцій дорівнює 2200.