
- •1. Цели и задачи курса «Теоретические основы информатики».
- •2. Асимптотическое сравнение целочисленных функций.
- •31. Основные понятия теории графов.
- •33. Внутреннее представление графа.
- •34. Алгоритм обхода вершин графа "в глубину".
- •35. Алгоритм обхода вершин графа "в ширину".
- •36. Сравнение свойств алгоритмов обхода "в глубину" и "в ширину".
- •38. Построение остовного дерева с заданной корневой вершиной.
35. Алгоритм обхода вершин графа "в ширину".
При решении многих графовых задач возникает необходимость систематического перебора вершин графа. Это означает, что ни одна вершина не должна быть пропущена и не должна рассматриваться (посещаться) дважды.
Такая необходимость возникает, например, при поиске пути между двумя заданными вершинами (кратчайшего или любого первопопавшего) или при выборе наилучшей в каком-то смысле вершины из всех вершин графа.
Девизом этого алгоритма обхода можно объявить фразу: «Не удалять подысходные вершины, пока не рассмотрены все ближние вершины по отношению к исходной». При обходе в глубину чем позже посещалась вершина (переставала быть новой), тем раньше она становилась использованной (переставали быть новыми все ее соседи). иными словами при обходе в глубину каждая просмотренная вершина помещается в стек, а каждая использованная вершина удаляется из стека. обход в ширину основывается на замене стека для просмотренных вершин очередью, в которой записаны все просмотренные вершины (не новые), а из очереди удаляются использованные.
Чем раньше просмотрена некоторая вершина, тем раньше она становится использованной, благодаря тому, что после просмотра очередной вершины, все ее новые соседи записываются в конец очереди. Тем самым гарантируется, что они наверняка будут просмотрены, т.е. перестанут быть новыми, поэтому только что просмотренную вершину можно сразу объявить использованной и удалять из очереди.
Очевидное свойство: если отыскивается путь от исходной вершины до некоторой заданной, то когда дойдет очередь до просмотра этой заданной конечной вершины, можно утверждать, что найденный путь к ней является кратчайшим (т.к. все более близкие вершины были рассмотрены раньше).
Алгоритм:
1. Начало. Поиск начинается с некоторой заданной вершины v0. Она вносится в пустую очередь и рассматривается. Затенм в конец очереди вписываются все ее соседи, а сама исходная вершина объхявляется использованной и удаляется из очереди.
2. Общий шаг. Рассматривается первая в данный момент в очереди вершина, а все ее новые соседи записываются в конец очереди. Т.о. неучтенных новых соседей у нее не остается и следовательно ее можно считать использованной и удалить из очереди.
3. Конец. Поиск заканчивается, когда а) будет рассмотрена заданная конечная вершина и следовательно определен путь к ней, или, б) когда в очереди не останется ни одной вершины. Следовательно все вершины графа рассмотрены.
Запишем алгоритм на условном Паскале. Будем использовать операции:
1) создание очереди
2) очередь пуста – логическая функция
3) Первый – доступ к первому (функция)
4) в очередь (u) – процедура
5) из очереди – процедура
Признаки новизны вершины хранятся в логическом массиве
НОВАЯ: Array[v] of Boolean
Будем использовать цепные списки соседних вершин для каждой вершины графа
Соседи: Array[v] of P_Spisok;
Procedure В_ширину(v:V);
Begin
Создание_очереди;
В_очередь(v); НОВАЯ[v]:=False;
While Not Oч_пуста Do
Begin
P:=первый;
Из_очереди;
Обработка (р);
For u Соседи[p] Do
If НОВАЯ[u] Then
Begin
В_очередь(u);
НОВАЯ[u]:= False;
End; end; end;
Основная программа, которая использует процедуру В_ширину для просмотра всех вершин графа имеет вид:
Begin
{инициализация}
For v V Do НОВАЯ[v]:= True;
{обход}
For v V Do
If НОВАЯ[v] Then
Begin
Inc(k);
В_ширину(v);
End;
End.
Второй цикл по перебору всех вершин графа нужен в связи с тем что один запуск процедуры в_ширину позволяет просмотреть все вершины в пределах 1 компоненты связности. Если граф состоит из нескольких компонент связи, то процедуру В_ширину нужно запустить для каждой из этих компонент связности. Следовательно, этот алгоритм как и алгоритм В_глубину можно применять для подсчета компонент связности в заданном графе.