You are on page 1of 34

____Вінницький національний технічний університет___

(повне найменування вищого навчального закладу)

________________Кафедра комп’ютерних наук____________________


(повна назва кафедри, циклової політики)

КУРСОВА РОБОТА
з дисципліни «Алгоритмізація та програмування»
(назва дисципліни)

на тему: «Алгоритм побудови кодів Хаффмана та його візуалізація»

Студента 1 курсу, групи 1КН-22б

Спеціальності 122 Комп’ютерні науки


_______Якубишина Я. О.__________________
(прізвище та ініціали)
Керівник асист. каф. КН Папа А.А.
(посада, вчене звання, науковий ступінь, прізвище та ініціали)

_______Національна шкала______

Кількість балів:______ Оцінка:


ECTS_________

Члени комісії ________ __________________


(підпис) (прізвище та ініціали)

________ __________________
(підпис) (прізвище та ініціали)

м. Вінниця – 2023 рік

1
Міністерство освіти і науки України
Вінницький національний технічний університет
Факультет інтелектуальних інформаційних технологій та автоматизації
Кафедра комп’ютерних наук

ЗАТВЕРДЖУЮ
Зав.каф. КН, д.т.н., проф.
_________А.А. Яровий
«__» ________ 2023 р.

ІНДИВІДУАЛЬНЕ ЗАВДАННЯ
до курсової роботи з дисципліни «Алгоритмізація та програмування»

Студента ________ __ Якубишина Я. О._______ групи 1КН-22б Тема


курсової роботи «Візуалізація алгоритму Беллмана-Форда для пошуку
найкоротшого шляху в графі» , затверджена на засіданні кафедри комп’ютерних
наук, протокол № від _____.2023 р. Вихідні дані:
1. Розмір вхідних даних:
символів ,
2. Складність алгоритму в найкращому випадку: ,
3. Складність алгоритму в найгіршому випадку: ______,
4. Мова програмування: _ Phyton та C# +++
5. Технологія реалізації: __________ ,
6. Швидкодія: ,
7. Середовище розробки: __________,
8. Вимоги до обчислювальної машини: ._

Зміст до курсової роботи


Індивідуальне завдання
Анотація
Вступ
1. Аналіз предметної області
2. Розробка алгоритму
3. Програмна реалізація алгоритму
4. Тестування програмної реалізації
Висновки
Перелік джерел посилань
Додатки
Дата видачі «____» _________ 2022 р.
Керівник _____________________ ас. Папа А.А.
(підпис)
Завдання отримав_______________Якубишин Я. О.
(підпис)

2
АНОТАЦІЯ
Якубишин Я. О. Візуалізація алгоритму Беллмана-Форда. Курсова робота з
дисципліни «Алгоритмізація та програмування». Вінниця: ВНТУ, 2023. … с.
Українською мовою.

Рисунків 12 , таблиць 1.

У цій курсовій роботі було досліджено та програмно реалізовано алгоритм


Беллмана-Форда. Розроблено блок-схему та псевдокод алгоритму, на основі
якого виконано програмну реалізацію. Задачу реалізовано мовою
програмування … з використанням …- інтегрованого середовища розробки для
мов програмування .... Проведено тестування розробленої програми.

3
ЗМІСТ
ВСТУП………………….………………………………………….…...
1.АНАЛІЗ АЛГОРИТМУ БЕЛЛМАНА-ФОРДА ...............................
2.ДОСЛІДЖЕННЯ АЛГОРИТМУ БЕЛЛМАНА-ФОРДА………….
3.ПРОГРАМНА РЕАЛІЗАЦІЯ АЛГОРИТМУ БЕЛЛМАНА-ФОРДА.
4. ТЕСТУВАННЯ ТА АНАЛІЗ РОЗРОБЛЕНОЇ ПРОГРАМИ………..
ВИСНОВКИ…………………………………………………………….
ПЕРЕЛІК ДЖЕРЕЛ ПОСИЛАНЬ……………………………..………
Додаток А. Блок-схема алгоритму…………………………………….
Додаток Б. Лістинг програми………………………………………….

4
ВСТУП

Не буває дня в житті людини без виконання якогось алгоритму.


Прокинутись і зібратись на роботу або на навчання вже доволі затяжний
процес, який потребує правильної послідовності виконання дій, щоб в
подальшому наша працездатність та і самий день пройшов чудово і
продуктивно. Днями, місяцями та роками люди виконують низку
послідовних дій, які й називаються алгоритмами. Правильний алгоритм
дій – запорука успіху у всьому. Звісно, щоб був позитивний результат,
алгоритму потрібно дотримуватись, але на те ми і люди, щоб зробити
собі життя простіше і завжди знаходимо способи якось скоротити цю
послідовність дій, щось пропустити або поєднати в одне, щоб було
більше часу на відпочинок. До прикладу, їхати за кермом та снідати,
розмовляти по телефону, можливо це і небезпечно, але це економить
нащ час.
Алгоритм також використовується у математичних вирішення
проблем або задач. Кожен алгоритм передбачає
існування початкових (вхідних) даних та в результаті роботи
призводить до отримання певного результату. Робота кожного
алгоритму відбувається шляхом виконання послідовності деяких
елементарних дій. Ці дії називають кроками, а процес їхнього виконання
називають алгоритмічним процесом. В такий спосіб відзначають
властивість дискретності алгоритму.

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

Необхідною умовою, яка задовольняє алгоритм,


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

Вхідні дані алгоритму можуть бути обмежені


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

Так ось, якщо ми візьмемо американського вченого Лестера


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

6
1.АНАЛІЗ АЛГОРИТМУ БЕЛЛМАНА-ФОРДА

Алгоритм Беллмана-Форда є одним з основних алгоритмів для


пошуку найкоротших шляхів в графі. Він використовується для
знаходження найкоротших шляхів від заданої вершини до всіх інших
вершин в графі, включаючи графи з вагованими ребрами та можливими
від'ємними цінностями.
Основна ідея алгоритму Беллмана-Форда полягає у
відслідковуванні потенційно найкоротших шляхів у графі, які поступово
оновлюються з кожною ітерацією. Алгоритм повторюється N-1 разів, де
N - кількість вершин у графі, для забезпечення збіжності.
Основний крок алгоритму полягає у переборі всіх ребер графа та
оновленні потенційно найкоротшого шляху до кожної вершини. Якщо
знайдено коротший шлях, то він замінює попереднє значення шляху.
Цей процес повторюється N-1 раз, для того, щоб гарантувати
знаходження найкоротших шляхів в усіх вершинах.
Однак, якщо у графі є від'ємні цикли, алгоритм Беллмана-Форда
виявляє їх на останній ітерації. Це стає можливим, оскільки найкоротші
шляхи в таких циклах не існують, і алгоритм може зациклитись у
безкінечному циклі спроб оновити шляхи.
Алгоритм Беллмана-Форда має часову складність O(V*E), де V -
кількість вершин, а E - кількість ребер у графі. Він є мене ефективним,
ніж алгоритм Дейкстри, оскільки може працювати з графами, в яких є
від'ємні цінності ребер.

Цей алгоритм визначає найкоротші шляхи від однієї вершини


графу яка є вхідною до всіх інших вершин в зваженому орієнтованому
графі.
Якщо порівнювати цей алгоритм с алгоритмом Дейкстри, то
алгоритм Беллмана-Форда буде повільнішим, але є і переваги в тому, що
7
він є універсальний, оскільки може працювати с графами у яких вага
ребра може бути від’ємного значення. Але якщо граф має від’ємний
цикл, тоді для даного графу не існує дерево найкоротших шляхів.

Принцип роботи алгоритму Беллмана-Форда полягає в тому, щоб


знайти спочатку метрики найкоротших шляхів від вершини – джерела

до інших вершин, за умови, що вони містять не більше однієї дуги,


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

більше K дуг, має назву найкоротшого K -шляху. Нехай =0 –

метрика найкоротшого K -шляху від вершини до вершини .

Вважатимемо, що для вершини s v метрика =0 при всіх K .

Покроковий опис алгоритму Беллмана-Форда має такий вигляд.

На початковому кроці алгоритму (K =0) покладається для всіх


. На наступних кроках алгоритму (при кожному K >1) для всіх
виконується ітерація Беллмана-Форда [3]:

, (1.1)

де «вага» дуги між вузлами vj й vi .


Алгоритм закінчує роботу, коли значення K досягне номера
останнього вузла N, тобто в найгіршому випадку, дерево найкоротших
шляхів має вигляд ланцюжка довжиною ( N -1) дуг.
Необхідно сказати, що в наведеному описі алгоритму дозволяє
розрахувати тільки мінімальні метрики початкової вершин до всіх
інших. Маршрути при цьому не запам’ятовуються.
8
Тим не менш, цей алгоритм є дуже зручним для розв'язання задач
маршрутизації в комп'ютерних мережах, виявлення негативних циклів
та знаходження найкоротших шляхів у вагованих графах.
В наступних розділах з метою реалізації даного алгоритму, ми
виконаємо такі кроки:
1. Розглянемо його практичну реалізацію.
2. Дослідимо його часову та асимптотичну складність.
3. Реалізуємо цей алгоритм мовою Python та C#.
4. здійснемо аналіз особливостей програм виконання алгоритму,
реалізованих мовами Python та C#.

9
2. ДОСЛІДЖЕННЯ АЛГОРИТМУ БЕЛЛМАНА-ФОРДА

Алгоритм Беллмана-Форда був розроблений американськими


вченими Річардом Беллманом і Лестером Фордом у 1958 році. Вони
вперше описали цей алгоритм в своїх наукових статтях, де досліджували
задачу найкоротших шляхів у вагованих графах.
Цей алгоритм став значним внеском у теорію графів та
оптимізаційні алгоритми. Він названий на честь своїх авторів, Беллмана
і Форда, які зробили вагомий внесок у розробку теорії оптимальних
шляхів та динамічного програмування.
Початково алгоритм Беллмана-Форда був призначений для
знаходження найкоротших шляхів у вагованих графах, включаючи
випадки з від'ємними цінностями ребер. Це було важливо для
розв'язання різних практичних задач, наприклад, маршрутизації в
мережах з різними метриками, планування транспорту тощо.
Однак, важливою особливістю алгоритму Беллмана-Форда є
можливість виявлення негативних циклів. Це дозволяє виявити ситуації,
коли найкоротший шлях не існує через наявність циклу з від'ємною
сумарною вагою. Такі ситуації можуть мати велике значення в різних
задачах, де потрібно уникати циклів або знаходити оптимальні рішення.
Алгоритм Беллмана-Форда має широкий спектр застосувань. Він
використовується в маршрутизації пакетів у комп'ютерних мережах,
дослідженні соціальних мереж, аналізі фінансових ринків, проектуванні
транспортних мереж, плануванні маршрутів для транспортних засобів,
аналізі дорожнього руху та багатьох інших областях.
Алгоритм Беллмана-Форда є потужним інструментом для
вирішення задач оптимізації шляхів та розрахунку найкоротших шляхів
у вагованих графах. Його розробка відкрила нові можливості для
дослідників та інженерів у багатьох галузях, що стосуються аналізу
мереж та оптимізації ресурсів.
10
Звичайна послідовність дій при використанні алгоритму
Беллмана-Форда може бути розширена наступним чином:
1.Ініціалізація:
 Створюємо масив відстаней distance, де кожній вершині графа
присвоюємо значення "нескінченність", крім початкової вершини,
якій присвоюємо значення 0.
 Створюємо масив попередників prev, де будемо зберігати інформацію
про попередню вершину на найкоротшому шляху до кожної вершини.
2.Проходи по ребрах:
 Повторюємо наступні кроки (N-1) разів, де N - кількість вершин у
графі:
 Проходимо по кожному ребру (u, v) графа, де u - початкова вершина,
а v - кінцева вершина.
 Перевіряємо, чи можна скоротити шлях до вершини v, оновлюючи
відстань, якщо так. Перевірка виконується за умовою: distance[v] >
distance[u] + weight(u, v), де distance[v] - поточна відстань до вершини
v, distance[u] - відстань до вершини u, weight(u, v) - вага ребра між
вершинами u та v.
 Якщо знайдено коротший шлях до вершини v, оновлюємо відстань до
неї і зберігаємо в масиві prev попередню вершину, яка дає цей
коротший шлях.
3.Перевірка на негативні цикли:
 Після виконання (N-1) ітерацій, проводимо ще одну ітерацію та
перевіряємо, чи відбувається зміна відстаней.
 Якщо відбувається зміна відстаней на цій ітерації, це означає, що в
графі присутній негативний цикл. Цикл може бути знайдений,
наприклад, за допомогою додаткової ітерації, під час якої оновлення
відстаней відбувається ще раз.
 Якщо немає зміни відстаней, це означає, що найкоротші шляхи до всіх
вершин були знайдені.
4.Результат:
 Після завершення алгоритму, ми отримуємо найкоротші шляхи до всіх
вершин від початкової вершини.

11
 Можемо використовувати ці значення для подальшого аналізу,
виконання потрібних дій або відновлення найкоротших шляхів за
допомогою масиву prev, який зберігає попередники кожної вершини
на найкоротшому шляху.

Малюнок 1.1 – Блок-схема алгоритму Беллмана-Форда.

Розглянемо практичну реалізацію алгоритма Беллмана-Форда на


зваженому графі. Данний граф складається з дванадцяти вузлів,
зв’язаних між собою лініями зв’язку. Граф показано на таб. 1.1

12
Малюнок 1.2 – Зважений граф

У якості ваг ребер (вартості каналів) було обрано час середньої затримки пакетів при проходженні
відповідного каналу. Їх значеня наведено у графах табл. 1.1.

13
Таблиця 1.1 - Відстань між вершинами

Канал зв’язку між вершинами Вартість (відстань)


0-1 0,676

0-2 1
0-3 0,362
0-4 0,381

0-5 0,2
0-6 0,19
0-7 0,571

7-6 0,4
7-8 0,362
8-6 0,314
8-5 0,438
8-9 0,248

9-5 0,257
9-11 0,571
11-10 0,762
5-4 0,381
2-10 0,457
3-10 0,79
4-3 0,286
1-2 0,448

14
На даному графі знайдемо за допомогою алгоритмів, найкоротший
шлях між вершинами.
Приклад роботи алгоритму:

На початковому кроці алгоритму (K =0) покладається Di   для


(0)

всіх i  s . На наступних кроках алгоритму (при кожному K >1) для всіх


i  s виконується ітерація Беллмана-Форда (1.3):

i 
(
DK
) (K
min
D
i

1
) (
,DK
j
1
)
l
ji,
,  (1.3)

де l j ,i «вага» дуги між вузлами vj й vi .

K=0:

D1 min
(0)
D(0)
1 ,D
0 l0,2 min
(0)

,0,676
0,676
;
D(0)
2 D ,D
min(0)
2
(0)
0 min
l0,2 ,11;
D(0)
3 D ,D
min(0)
3
(0)
0 min
l0,3 ,0,3620,362;
D (0)
4 D ,D
min(0)
4
(0)
0 min
l0,4 ,0,3810,381;
D(0)
5 D ,D
min(0)
5
(0)
0 min
l0,5 ,0,20,2;
D(0)
6 D ,D
min(0)
6
(0)
0 min
l0,6 ,0,190,19;
D(0)
7 D ,D
min(0)
7
(0)
0 min
l0,7 ,0,5710,571.

K=1:

(
1
)
D
7
(
7
0
)(
0
min
D,D
6

)
l6
,
7 
min
0
,
571
,
0
, 
19
0
,
4
0
,
571
;

D
D(
1
)
min
,
D
8 
l
 

min
,0
,
190
,
314
0
,(
0
)(
504
. 0
)
86 6,
7

K=2:

15
(
2
)
D
9(
1
9
)(
,
D1
)
min
D 8l
8
,
9

min
,0
, 
504
0
,
248
0
,
752
. 

K=3:

(
3
)
D
11
(
2
)(
min
D ,
D
11
2
)
9
l9
,
11


min
,0
, 
752
0
,
571
1
,
323
. 

K=4:

(
4
)
D
10
(
3
)(
min
D ,
D
10
3
)

l
1111
,
10


min
,
1, 
323
0
,
762
2
,
085
. 

Результаті всі вершини та дуги утворюють орієнтоване дерево


найкоротших шляхів, який приведений на рисунку 1.4.

Малюнок 1.4 – Дерево найкоротших шляхів алгоритму Беллмана-Форда

16
Дослідження часової та асимптотичної складності алгоритму
Беллмана-Форда дають нам уявлення про його продуктивність та
швидкодію в різних сценаріях. Ось що можна сказати про ці
дослідження:
1.Часова складність: Часова складність алгоритму Беллмана-
Форда становить O(V*E), де V - кількість вершин, а E - кількість ребер
у графі. Це означає, що час виконання алгоритму залежить від кількості
вершин та ребер у графі. Якщо граф має багато вершин або ребер,
алгоритм може бути досить повільним.
2.Асимптотична складність: Асимптотична складність алгоритму
Беллмана-Форда також складає O(V*E). Це означає, що часова
складність алгоритму зростає пропорційно кількості вершин та ребер у
графі. Якщо граф має великий розмір, асимптотична складність може
бути значною, що може вплинути на продуктивність алгоритму.
3.Ефективність: Алгоритм Беллмана-Форда є ефективним у
випадку графів з невеликою кількістю вершин та ребер. Він добре
працює на графах з вагованими ребрами та може знаходити найкоротші
шляхи навіть у графах з негативними вагами (за умовки, що немає
негативних циклів).
4.Оптимізації: Існують різні оптимізації алгоритму Беллмана-
Форда, які можуть покращити його продуктивність. Наприклад, можна
використовувати чергу з вершинами для визначення порядку обходу, що
дозволяє пропустити вершини, для яких немає необхідності оновлювати
відстані.
5.Пам'ять: Алгоритм Беллмана-Форда також вимагає пам'яті для
зберігання відстаней між вершинами. У даному прикладі
використовується масив distance розміром V для зберігання відстаней від

17
початкової вершини до кожної вершини. Тому пам'ять, потрібна для
виконання алгоритму, становить O(V).

Загалом, алгоритм Беллмана-Форда є потужним і надійним


алгоритмом для знаходження найкоротших шляхів в графі. Однак, на
великих графах його часова складність може стати обмежуючим
фактором. У таких випадках можуть бути застосовані інші алгоритми,
такі як алгоритм Дейкстри або алгоритм Флойда-Воршелла, які мають
кращу асимптотичну складність.

18
3. ПРОГРАМНА РЕАЛІЗАЦІЯ АЛГОРИТМУ БЕЛЛМАНА-ФОРДА
Для цього пункту я обрав дві мови програмування – це Python та
C#. Python і C# є двома різними мовами програмування зі своїми
унікальними особливостями. Ось порівняння між цими двома мовами:
Синтаксис:
 Python має простий та зрозумілий синтаксис, що робить його
легким для вивчення та читання. Він використовує відступи
(пробіли або табуляцію) для визначення блоків коду.
 C# має більш формальний синтаксис, який вимагає
використання фігурних дужок для визначення блоків коду.
Типи даних:
 Python є динамічно типізованою мовою, що означає, що
типи даних змінних можуть змінюватись під час виконання
програми.
 C# є статично типізованою мовою, що означає, що типи
даних змінних визначаються на етапі компіляції і не можуть
змінюватись під час виконання.
Екосистема та бібліотеки:
 Python має велику та активну спільноту розробників, що
сприяє широкому вибору сторонніх бібліотек та
фреймворків. Він широко використовується у наукових
обчисленнях, аналізі даних, штучному інтелекті та веб-
розробці.
 C# є частиною .NET-екосистеми, яка надає широкий спектр
інструментів та бібліотек для розробки різноманітних
програмних застосунків. Він популярний для розробки
додатків під Windows, ігор, веб-серверів та мобільних
додатків.

19
Продуктивність:
 Python є інтерпретованою мовою, що може призводити до
меншої продуктивності порівняно з компільованими
мовами, такими як C#.
 C# компілюється в машинний код, що дозволяє досягти
високої продуктивності та швидкодії.
Вибір між Python та C# залежить від конкретних потреб проекту,
ваших особистих вподобань та досвіду. Python підходить для швидкої
прототипізації, обробки даних та наукових обчислень, тоді як C# є
хорошим вибором для розробки великих проектів, додатків для Windows
та мобільних платформ, а також для розробки ігор.

1.Python:
Ми маємо код, який використовує клас “Graph” для виконання
алгоритму Беллмана-Форда. Розглянемо кожну частину коду окремо:

Оголошення класу “Graph” та його конструктор “__innit__”:

Малюнок 1.5 – Оголошення класу “Graph” та його конструктор “__innit__”.

У цьому коді створюється клас “Graph”, який має один атрибут “V” для
зберігання кількості вершин у графі та атрибут “graph”, що представляє граф.
Метод “__innit__” ініціалізує об'єкт класу “Graph”, приймаючи кількість
вершин “vertices” та встановлюючи “self.V” на це значення. Він також
створює порожній список “self.graph”, який буде використовуватись для
зберігання ребер графа.

20
2. Метод “add_edge”:

Цей метод додає ребро до графа. Він приймає початкову вершину “U”,
кінцеву вершину “V” та вагу ребра “W”. Ребро представляється у
вигляді списку “[U, V, W]”, який додається до списку “self.graph”.

Малюнок 1.6 – Створюємо та задаємо параметри ребру.

3.Метод “bellman_ford”:

Цей метод виконує алгоритм Беллмана-Форда для знаходження


найкоротших шляхів у графі від заданої початкової вершини src.
Спочатку створюється список dist, який містить відстані до всіх
вершин, ініціалізовані як "нескінченні", окрім початкової вершини src,
яка має відстань 0.
Потім проводиться V-1 ітерацій для релаксації ребер графа. Кожне
ребро перевіряється, і якщо воно може покращити поточну найкоротшу
відстань до кінцевої вершини, вона оновлюється.
Після цього перевіряється наявність від'ємних циклів в графі.
Якщо під час останньої ітерації ще відбувається покращення відстані, це
означає, що граф містить від'ємний цикл.
Нарешті, викликається метод print_solution, який виводить
найкоротші шляхи до всіх вершин.

21
Малюнок 1.7 – Псведокод до методу Беллмана-Форда.

4.Метод “print_solution”:

Цей метод виводить найкоротші відстані від початкової вершини


src до всіх інших вершин графа.

Малюнок 1.8 – Виводимо найкоротші відстані від початкової верхини до інших.

Отже, ми реалізували програму, яка знаходить найкоротший шлях у графі


використовуючи мову програмування Python.Тепер перейдемо до наступного
кроку.

22
2. C#:

1. Підключення необхідних бібліотек:


Використовується System для доступу до стандартних класів
та функцій мови C#.
2. Оголошення класу Program:
Оголошується клас Program, який містить головну функцію
Main та інші методи.
3. Оголошення та ініціалізація змінної V:
Оголошується змінна V, яка вказує на кількість вершин у
графі та присвоюється значення 5.
4. Оголошення та визначення функції BellmanFord:
Визначається функція BellmanFord, яка приймає два
параметри: graph (граф у вигляді двовимірного масиву) та source
(початкова вершина для пошуку найкоротших шляхів).
5. Ініціалізація масиву distance:
Оголошується масив distance, який зберігатиме відстані від
початкової вершини до всіх інших вершин.
Використовується int.MaxValue для ініціалізації відстаней до
всіх вершин як нескінченність.
6. Встановлення початкової відстані:
Відстань від початкової вершини source до самої себе
встановлюється рівною 0.
7. Релаксація ребер V-1 разів:
Виконується V-1 ітерацій для релаксації ребер графа.
Використовуються вкладені цикли для перебору кожного
ребра графа та оновлення відстаней до вершин згідно з
алгоритмом Беллмана-Форда.
8. Перевірка наявності від'ємних циклів:
Виконується перевірка наявності від'ємних циклів після
релаксації ребер.

23
Знову використовуються вкладені цикли для перебору
кожного ребра графа та перевірки умови наявності від'ємного
циклу.
9. Виведення результатів:
Виконується виведення найкоротших відстаней від
початкової вершини source до всіх інших вершин графа.
Використовується Console.WriteLine для виведення
результатів.
10. Оголошення та виклик головної функції Main:
Оголошується головна функція Main, яка буде виконуватись
при запуску програми.
Оголошується та ініціалізується двовимірний масив graph,
який представляє граф.
Визначається початкова вершина source.
Викликається функція BellmanFord для пошуку найкоротших
шляхів у графі.

Виконавши цю послідовність ми зможемо отримати псевдокод, який


показано у Додатку “Б”.

24
4. ТЕСТУВАННЯ ПРОГРАМНОЇ РЕАЛІЗАЦІЇ

Для того, щоб перевірити правильність реалізації програми, протестуємо їх,


задавши значення графу.

Малюнок 1.9 – Задаємо значення графу.

Малюнок 1.10 – Отримуємо результат.

Отримавши результат ми можемо звірити його з власними


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

Тепер залишилось переконатись у правильності псевдокоду написаного


на мові C#.

25
Малюнок 1.11 – Задаємо значення графу.

Малюнок 1.12 – Отримуємо результат.


Після перевірки програми, ми можемо впевнетись у правильності
виконання алгоритму. Тепер коли в нас є обидна результати ми можемо
порівняти виконання алгоритму на мові Python та C#.Отже, виконавши
порівняння отриманих результатів, можемо зробити висновок, що алгоритм,
реалізований мовою С буде виконуватися значно швидше ніж аналогічний
йому, написаний на мові Python, причому різниця буде найбільш помітною зі
збільшенням розміру вхідних даних. В той час як синтаксис Python
характеризується високим рівнем абстракції, яка проявляється у наявності
великої кількості модулів, призначених для рішення найрізноманітніших
задач, відсутності потреби прямого управління 32 пам’яттю та іншими
атомарними процесами і т. і., для реалізації аналогічних програм мовою С
необхідно володіти принаймні елементарними знаннями щодо організації
пам’ятті, аби ефективно нею управляти (наприклад, динамічне виділення
пам’ятті), а також інших мікропроцесів. Як результат, відносно складний
синтаксис мови С компенсується швидкістю роботи реалізованих цією
мовою програм. Однак, незважаючи на значний поступок у швидкості для
Python, сьогодні він є затребуваний у значній кількості галузей, не в останню

26
чергу завдяки зручному набору інструментів, призначених для роботи в сфері
інтелектуальних систем та штучного інтелекту.

Таким чином, нашим останнім завданням буде проведення розширених


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

27
ВИСНОВКИ

Отже, у данній курсовій роботі ми дізнались історію виникнення алгоритму,


його практичне використання та змогли реалізувати алгоритм Беллмана-
Форда у вигляді програми мовами Python та C#.
У розділі під номером 1 ми проаналізували сам алгоритм і дізнались як
працює алгоритм, навчились його використовувати. Для закріплення знань
ми провели аналіз таблиць і використали здобуті знання для знаходження
найкоротшого шляху у таблиці.

У розділі номер 2 ми дослідили покрокове розв’язання алгоритму і виконали


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

У розділі номер 3 ми реалізували алгоритм мовою Python та C#. Розглянули


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

У розділі номер 4 ми перевірили псевдокод на правильність та порівняли


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

28
СПИСОК ВИКОРИСТАНИХ ДЖЕРЕЛ

1. Вікіпедія – Алгоритм Беллмана-Форда.


2. . Арсенюк І. Р. Теорія алгоритмів. / Арсенюк І. Р., Колодний В. В.,
Яровий А. А. // Навчальний посібник. – Вінниця: ВНТУ, 2006.
3. “An exploration of the Bellman-Ford shortest paths graph algorithm.” by Tim
Downey на сайті dev.to, 2019.
4. Routing, Dijkstra, Bellman-Ford and BFG! by Rusty Russell на сайті
medium.com, 2016.
5. Книги:
6. • "Introduction to Algorithms" by Thomas H. Cormen, Charles E. Leiserson,
Ronald L. Rivest, and Clifford Stein.
7. • "Algorithms" by Robert Sedgewick and Kevin Wayne.
8. • "Data Structures and Algorithms Made Easy" by Narasimha Karumanchi.
9. • "The Algorithm Design Manual" by Steven S. Skiena.
10. • Bellman, R. (1958). "On a Routing Problem". Quarterly of Applied
Mathematics.
11. • Ford, L.R., Fulkerson, D.R. (1956). "Maximal Flow Through a Network".
Canadian Journal of Mathematics.

29
Додаток А. Лістинг програми мовою С#.

using System;

class Program
{
static int V; // Кількість вершин у графі

static void BellmanFord(int[,] graph, int source)


{
int[] distance = new int[V];

// Ініціалізуємо відстані до всіх вершин як нескінченність


for (int i = 0; i < V; i++)
distance[i] = int.MaxValue;

// Відстань до самої себе - 0


distance[source] = 0;

// Релаксація ребер V-1 разів


for (int i = 0; i < V - 1; i++)
{
for (int j = 0; j < V; j++)
{
for (int k = 0; k < V; k++)
{
if (graph[j, k] != 0 && distance[j] != int.MaxValue && distance[j] + graph[j, k] <
distance[k])
{
distance[k] = distance[j] + graph[j, k];
}
}
30
}
}

// Перевірка наявності від'ємних циклів


for (int j = 0; j < V; j++)
{
for (int k = 0; k < V; k++)
{
if (graph[j, k] != 0 && distance[j] != int.MaxValue && distance[j] + graph[j, k] <
distance[k])
{
Console.WriteLine("Граф містить від'ємний цикл");
return;
}
}
}

// Виведення результатів
Console.WriteLine("Відстані від вершини {0} до всіх інших вершин:", source);
for (int i = 0; i < V; i++)
Console.WriteLine("Вершина {0} -> Відстань: {1}", i, distance[i]);
}

static void Main(string[] args)


{
V = 5; // Кількість вершин у графі

int[,] graph = {
{ 0, -1, 4, 0, 0 },
{ 0, 0, 3, 2, 2 },
{ 0, 0, 0, 0, 0 },
{ 0, 1, 5, 0, 0 },

31
{ 0, 0, 0, -3, 0 }
};

int source = 0; // Початкова вершина

BellmanFord(graph, source);
}
}

32
Додаток Б. Лістинг програми мовою Python.

class Graph:
def __init__(self, vertices):
self.V = vertices
self.graph = []

def add_edge(self, u, v, w):


self.graph.append([u, v, w])

def bellman_ford(self, src):


# Ініціалізуємо відстані до всіх вершин як "нескінченні", крім джерела
dist = [float("inf")] * self.V
dist[src] = 0

# Виконуємо релаксацію ребер V-1 разів


for _ in range(self.V - 1):
for u, v, w in self.graph:
if dist[u] != float("inf") and dist[u] + w < dist[v]:
dist[v] = dist[u] + w

# Перевіряємо наявність від'ємних циклів


for u, v, w in self.graph:
if dist[u] != float("inf") and dist[u] + w < dist[v]:
print("Граф містить від'ємний цикл")
return

# Виводимо найкоротші шляхи до всіх вершин


self.print_solution(dist)
33
def print_solution(self, dist):
print("Вершина \t Найкоротша відстань від джерела")
for i in range(self.V):
print(i, "\t\t", dist[i])

# Приклад використання
g = Graph(5)
g.add_edge(0, 1, -1)
g.add_edge(0, 2, 4)
g.add_edge(1, 2, 3)
g.add_edge(1, 3, 2)
g.add_edge(1, 4, 2)
g.add_edge(3, 2, 5)
g.add_edge(3, 1, 1)
g.add_edge(4, 3, -3)

g.bellman_ford(0)

34

You might also like