Алгоритмы обхода вершин в графах общего вида

ЛЕКЦИЯ № 14

При реализации многих алгоритмов на графах возникает необходимость организовать систематический перебор вершин графа, при котором каждая вершина просматривается точно один раз. Такой перебор можно организовать двумя способами: поиском в глубину или поиском в ширину. При этом программы, реализующие оба поиска, имеют одинаковую структуру и отличаются лишь процедурой, выполняющей перебор вершин.

Основная идея алгоритма поиска в глубину состоит в последовательном движении из заданной вершины вдоль одного из ребер вглубь графа до тех пор, пока не дойдем до вершины, из которой нельзя попасть ни в какую непросмотренную вершину. После этого возвращаемся в предыдущую вершину и повторяем поиск. Если после возврата в начальную вершину останутся непросмотренные вершины, то повторим поиск, начиная из любой оставшейся вершины.

 

 
 

 


Рис. 3.1

Пусть в каждом списке инцидентности все смежные вершины упорядочены по возрастанию их номеров. Тогда, например, для графа, изображенного на рис. 3.1 последовательность обхода вершин из начальной вершины 1 имеет вид: 1, 2, 4, 5, 3, 5, 6, 5, 4, 7, 4, 2, 1.

Повтор вершин в списке обхода объясняется тем, что во время обратного шага приходится возвращаться в уже просмотренную вершину. Но обработка каждой вершины (т.е. какая-то длительная операция) производится ровно один раз при первом переходе к данной вершине. Поэтому, последовательность обработки вершин для графа рис. 3.1 имеет вид: 1, 2, 4, 5, 3, 6, 7. Если граф является связным, то будут просмотрены все вершины графа.

В алгоритме каждой вершинеставится в соответствие логическая переменная Nowy[v], которая равна True, если данная вершина еще не просмотрена, и False, если вершина просмотрена. Вначале поиска считаем все вершины непросмотренными. Операцию обработки вершины будем символизировать печатью ее номера.

Описанный в алгоритме порядок работы с вершинами, при котором вершина, просмотренная последней, обрабатывается первой, реализуется с помощью механизма стека. Он автоматически реализуется в Паскале рекурсивной процедурой, поэтому рекурсивный вариант алгоритма обычно проще, чем нерекурсивный.

При построении алгоритмов мы будем пользоваться неформальным языком описания алгоритмов. Такой язык по синтаксису похож на язык программирования Паскаль, но он разрешает использование математических обозначений, не предусмотренных в Паскале. Это позволяет сосредоточиться на сути алгоритма и уйти от технических вопросов его реализации. Для реализации алгоритма на одном из языков программирования необходимо формализовать его в соответствии с правилами языка.

Будем использовать обозначения

1) СПИСОК [ v ] – список инцидентности вершины v;

2) for uÎА – для всех элементов массива А.

Опишем рекурсивную процедуру.

procedure DEPTH_R(v) ;

begin NOWY[v]:= False; write(v) ;

for u Î СПИСОК[v] do

if NOWY[u] then DEPTH_R(u) ;

end ;

Основная программа поиска имеет вид.

var NOWY : array [1..n] of boolean;

begin for vÎV do NOWY[v]:= True ;

for vÎV do

if NOWY[v] then DEPTH_R(v)