- •Тема 2. ЕТАПИ РОЗВИТКУ ТЕОРІЇ АЛГОРИТМІВ ТА ЇЇ ЗАСНОВНИКИ
- •Тема 3. МОДЕЛІ ОБЧИСЛЕНЬ
- •Тема 4. ПОНЯТТЯ СТРУКТУР ДАНИХ
- •Тема 5 СТРУКТУРНІСТЬ ДАНИХ І ТЕХНОЛОГІЯ ПРОГРАМУВАННЯ
- •Тема 6. ІНФОРМАЦІЙНА МОДЕЛЬ
- •Тема 7. ПОКАЖЧИКИ ТА ОПЕРАЦІЇ НАД НИМИ
- •Тема 8. ФІЗИЧНА СТРУКТУРА ПОКАЖЧИКА
- •Тема 9. ПРЕДСТАВЛЕННЯ ПОКАЖЧИКІВ У МОВАХ ПРОГРАМУВАННЯ
- •Тема 10. ВИДІЛЕННЯ ТА ЗВІЛЬНЕННЯ ДИНАМІЧНОЇ ПАМ'ЯТІ
- •Тема 11. ПРИКЛАДИ РОБОТИ З ДИНАМІЧНИМИ ЗМІННИМИ
- •Тема 12. ЗАГАЛЬНА ХАРАКТЕРИСТИКА СПИСКОВИХ СТРУКТУР ДАНИХ
- •Тема 13. ЗВ’ЯЗНЕ ПРЕДСТАВЛЕННЯ ДАНИХ В ПАМ'ЯТІ КОМП’ЮТЕРА
- •Тема 14. СТЕКИ
- •Тема 15. МАШИННЕ ПРЕДСТАВЛЕННЯ СТЕКА І РЕАЛІЗАЦІЯ ОПЕРАЦІЙ
- •Тема 16. ЧЕРГИ
- •Тема 17. МАШИННЕ ПРЕДСТАВЛЕННЯ ЧЕРГИ. ЧЕРГИ З ПРІОРИТЕТАМИ. ДЕКИ.
- •Тема 18. ЛІНІЙНІ СПИСКИ
- •Тема 19: ДВОНАПРЯМЛЕНІ ЛІНІЙНІ СПИСКИ
- •Тема 20. ДЕРЕВА. СТВОРЕННЯ ТА ОБХІД БІНАРНОГО ДЕРЕВА
- •Тема 21: ЕЛЕМЕНТИ ТА ВЛАСТИВОСТІ БІНАРНОГО ДЕРЕВА
- •Тема 22. ОПЕРАЦІЇ З ВУЗЛАМИ ДЕРЕВА
- •Тема 23: АЛГОРИТМИ ВИЗНАЧЕННЯ ВЛАСТИВОСТЕЙ БІНАРНОГО ДЕРЕВА
- •Тема 24. ПОНЯТТЯ ГРАФА ТА ЙОГО ЗОБРАЖЕННЯ В ПАМ'ЯТІ КОМП'ЮТЕРА
- •Тема 26. ОБХІД ГРАФУ: ПОШУК ВГЛИБИНУ
- •Тема 27. ОБХІД ГРАФУ: ПОШУК УШИР
- •Тема 28. КЛАСИЧНІ АЛГОРИТМИ СОРТУВАННЯ ОДНОРІДНИХ ДАНИХ
- •Тема 29. ШВИДКІ АЛГОРИТМИ СОРТУВАННЯ ОДНОРІДНИХ ДАНИХ
- •Тема 30. КЛАСИЧНІ АЛГОРИТМИ ПОШУКУ ДАНИХ ЗА ЗАДАНИМИ КРИТЕРІЯМИ
- •Тема 31. КЛАСИФІКАЦІЯ КРИТЕРІЇВ ПОШУКУ ДАНИХ У МАСИВАХ
- •Тема 32. КРИПТОГРАФІЧНІ ЗАСОБИ ЗАХИСТУ ІНФОРМАЦІЇ
- •Тема 33. ПРОБЛЕМИ І ПЕРСПЕКТИВИ КРИПОТГРАФІЧНИХ СИСТЕМ
- •Тема 34. АЛГОРИТМИ ШИФРУВАННЯ
- •Тема 36. ПОКАЗНИКИ СКЛАДНОСТІ АЛГОРИТМІВ
Тема 26. ОБХІД ГРАФУ: ПОШУК ВГЛИБИНУ
Численна кількість алгоритмів на графах ґрунтується на переборі всіх або частини їх вершин. Такий перебір називається обходом графу. Найвідоміші алгоритми обходу графу – це пошук вглибину і вшир.
Пошук вглибину
Алгоритм пошуку вглибину розглядатиметься для зв’язного неорієнтованого графу. Пошук починається із заданої стартової вершини і триває доти, доки не буде знайдено певної кінцевої вершини або поки є вершини, що утворюють маршрут пошуку. Нехай стартова вершина позначена літерою v. Обирається довільне ребро (v,u), інцидент не v. Якщо вершина u вже відвідана, то обирається інше ребро, що є інцидентним v. У протилежному випадку вершина u вважається стартовою і повторюється процедура пошуку. Якщо пошук з вершини u завершується безуспішно, то відбувається повернення до вершини v і продовжується пошук ребер, інцидентних вершині v і таких, що раніше не відвідувалися. Вибір нових ребер триває доти, доки не вичерпаються всі ребра, що є інцидентними v, або пошук кінцевої вершини не завершиться успішно.
Слід зауважити, що під час пошуку вглибину в орієнтованому графі переглядаються лише ті дуги, що виходять зі стартової вершини.
Оцінки часової складності алгоритму пошуку вглибину
Нехай граф має n вершин і m ребер. Пошук вершини, що не була відвідана, виконується не більше ніж за О(n) кроків, а кількість кроків, що їх необхідно здійснити для перебору всіх інцидентних певній вершині ребер, становить не більше ніж О(m). Отже, часова складність пошуку вглибину становить О(n+m).
Приклад.
Нехай структура графу зберігається в текстовому файлі, перший рядок якого містить кількість вершин графу, а кожний наступний рядок – два числа, що є номерами певних суміжних вершин. Тобто кожен рядок файлу, починаючи з другого, визначає ребро графу. Номери стартової та кінцевої вершин користувач вводить з клавіатури.
Для зображення графу використовується список суміжності. Тип вершини називається TVer. Запис типу TVer містить такі поля: поточний номер вершини, кількість суміжних із нею вершин, масив покажчиків на суміжні вершини, ознаку відвідування вершин. Сам граф задається масивом a, елементи якого будуть покажчиками на записи TVer.
Ініціалізація масиву вершин даними, що зчитані з текстового файлу. Виконується у процедурі Init, з якої викликається процедура зв’язування суміжних вершин LinkVertex. Слід звернути увагу на те, що одному ребру відповідають два зв’язки між вершинами, оскільки алгоритм розглядається для неорієнтованого графу.
Власне пошук вглибину здійснює рекурсивна процедура Search, яка є локальною щодо процедури DepthFirstSearch (пошук вглибину). У процедурі DepthFirstSearch запрограмовані введення початкової та кінцевої вершин для пошуку, помітка початкової вершини, як такої. Що вже опрацьована, і всіх інших вершин, як таких, що потребують перегляду, а також виклик процедури Search.
program Yrok12_1; |
{пошук вглибину} |
{$APPTYPE CONSOLE} |
|
uses SysUtils; |
|
type |
|
PtrVer=^TVer; |
{тип покажчика на вершину} |
TVer=record |
{тип вершини графу} |
93
vertex: array[1..50] of PtrVer; |
{масив покажчиків на суміжні вершини} |
|||
k, |
|
|
|
{кількість суміжних вершин } |
number: integer; |
|
|
{номер вершини} |
|
mark: boolean; |
|
|
{ознака відвідування вершини} |
|
end; |
|
|
|
|
var a: array[1..50] of PtrVer; |
|
{масив покажчиків на вершини графу} |
||
n: integer; |
|
|
|
{кількість вершин графу} |
t: text; |
|
|
|
{файлова змінна} |
key: char; |
|
|
|
{символ обраної користувачем дії} |
start, finish: integer; |
|
{номери стартової та кінцевої вершин обходу графу} |
||
{Встановлення зв’язків між вершинами графу} |
||||
procedure LinkVertex(var v,u: PtrVer); |
||||
begin |
|
|
|
|
inc(v^.k); |
v^.vertex[v^.k]:=u; |
{включити u в список суміжності v} |
||
inc(u^.k); |
u^.vertex[u^.k]:=v; |
{ включити v в список суміжності u } |
||
end; |
|
|
|
|
{Ініціалізація графу з файлу} |
|
|||
procedure Init; |
|
|
|
|
var i, |
|
{параметр циклу} |
||
iv,iu: integer; |
{номери суміжних вершин} |
|||
Ver: PtrVer; |
{покажчик на фершину графу} |
|||
begin |
|
|
|
|
assign(t,'graph.txt'); |
|
|
|
|
reset(t); |
|
{відкриття файлу для читання суміжних вершин} |
||
readln(t,n); |
{читання кілкості вершин графу} |
|||
for i:=1 to n do |
{створення масиву покажчиків на вершини графу} |
|||
begin |
|
|
|
|
new(Ver); |
{виділення пам'яті для покажчика на вершину} |
|||
Ver^.number:=i; |
{визначення номеру вершини} |
|||
Ver^.k:=0; |
{задання кількості суміжних вершин} |
|||
a[i]:=Ver; |
{запис покажчика на вершину в масив} |
|||
end; |
|
|
|
|
while not eof(t) do |
{поки не досягнуто кінця файлу} |
|||
begin |
|
|
|
|
readln(t,iv,iu); |
{читання номерів суміжних вершин} |
|||
LinkVertex(a[iv],a[iu]); |
{зв’язування вершин} |
|||
end; |
|
|
|
|
close(t); |
|
{закриття файлу} |
||
end; |
|
|
|
|
{пошук вглибину} |
|
|
|
|
procedure DepthFirstSearch; |
|
|
||
var w: array[1..50] of integer; |
{масив номерів вершин маршруту} |
|||
i,j: integer; |
|
{лічильники циклів} |
||
{алгоритм пошуку вглибину} |
|
|||
procedure Search(V: PtrVer); {v – покажчик на початкову вершину} |
||||
var i: integer; |
|
{ лічильник циклу} |
||
begin |
|
|
|
|
94
if V^.number=finish |
{якщо досягнуто кінцевої вершини} |
||||
then begin |
|
|
|
|
|
write('Path: >> '); |
{виведення маршруту} |
||||
for i:=1 to j do |
|
|
|
||
|
begin |
|
|
|
|
|
write(w[i]); |
|
|
|
|
|
if i<j then write('->'); |
|
|
||
|
end; |
|
|
|
|
writeln; |
|
|
|
|
|
exit; |
|
|
|
|
|
end |
|
|
|
|
|
else |
|
{ якщо не досягнуто кінцевої вершини } |
|||
for i:=1 to v^.k do |
{перегляд усіх суміжних вершин} |
||||
|
begin |
|
|
|
|
|
if not V^.vertex[i]^.mark |
{якщо поточна суміжна вершина не позначена} |
|||
|
then begin |
|
|
|
|
|
|
v^.vertex[i]^.mark:=true; |
|
{позначення вершини} |
|
|
|
j:=j+1; |
{збільшення лічильника позначених вершин} |
||
|
|
w[j]:=v^.vertex[i]^.number; |
{збереження номеру вершини} |
||
|
|
Search(v^.vertex[i]); |
{перехід до наступних вершин} |
||
|
|
j:=j-1; |
{ зменшення лічильника позначених вершин } |
||
|
|
v^.vertex[i]^.mark:=false; |
|
{ зняття позначення вершини } |
|
|
end; |
end; |
|
|
|
end; |
|
|
|
|
|
|
|
|
|
|
|
{основний блок процедури пошуку вглибину} |
|||||
begin |
|
|
|
|
|
writeln('<<<<depth first search>>>>'); |
|
|
|||
writeln('**************************'); |
|
|
|||
write('initial vertex: '); readln(start); |
|
|
|||
write('terminal vertex: '); readln(finish); |
|
||||
for i:=1 to n do |
{зняття позначення вершин} |
||||
a[i]^.mark:=false; |
|
|
|
||
a[start]^.mark:= true; |
{позначення стартової вершини} |
||||
j:=1; |
|
|
|
|
|
w[j]:=start; |
{збереження номеру стартової вершини} |
||||
Search(a[start]); |
{виклик рекурсивної процедури пошуку} |
||||
readln; |
|
|
|
|
|
end; |
|
|
|
|
|
{основний блок програми} |
|
|
|||
begin |
|
|
|
|
|
Init; |
{створення графу} |
|
|
||
Repeat |
|
{нескінчений цикл} |
|
|
writeln('Number of vertexes=',n); writeln('**************************'); writeln('press <Enter> to solution'); writeln('<x> - to exit');
95
readln(key); case key of
#13: DepthFirstSearch; {натиснуто клавішу Enter}
‘x’: halt; |
{ натиснуто клавішу ‘x’} |
end; |
|
until false; |
|
end. |
|
Для даних: 5
13
14
23
25
34
отримано наступний рез ультат:
96