Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
SAOD..doc
Скачиваний:
142
Добавлен:
11.05.2015
Размер:
959.49 Кб
Скачать

8.2 Поиск в глубину в графе

Основные требования к методам поиска в графе:

  1. метод должен легко реализовываться алгоритмом решения интересующей нас задачи;

  2. каждое ребро графа анализируется один раз (или ограниченное число раз, что существенно не меняет ситуации).

Существует много алгоритмов на графах, в основе которых лежит систематический перебор вершин гра­фа, причем каждая вершина просматривается точно один раз.

Рассмотрим один метод поиска в неориентированном графе, который является основой многих графовых алгоритмов. Этот метод называется поиском в глубину (depth first search).

Общая идея метода состоит в следующем. Начинаем поиск с некоторой фиксированной вершины v0. Затем выбираем произвольную вершину u, смежную с v0, и повторяем наш просмотр от u . В общем случае предпо­ложим, что мы находимся в некоторой вершине v. Если существует новая (ещё не просмотренная) вершина u, u-v, то мы рассматриваем эту вершину (она перестает быть новой), начиная с неё, продолжаем поиск. Если же не существует новой вершины, смежной с v, мы говорим, что вершина v использована, возвращаемся в верши­ну, из которой мы попали в v, и продолжаем поиск (если v=v0, то поиск закончен).

Иначе говоря, поиск в глубину из вершины v основывается на поиске в глубину из всех новых вершин, смежных с v.

Это можно легко записать с помощью рекурсивной процедуры WG(v):

PROCEDURE WG(v); {поиск в глубину из вершины v}

{перемен. НОВЫЙ, СПИСОК – глобальные}

BEGIN рассмотреть v; НОВЫЙ[v] := false; FOR u∈СПИСОК[v] DO

IF НОВЫЙ[u] THEN WG(u)

END {вершина использована}

Весь процесс поиска в глубину в произвольном, необязательно связном графе производится по следую­щему алгоритму:

BEGIN

FOR v∈V DO НОВЫЙ[v] := true; {инициализация} FOR v∈V DO

IF НОВЫЙ[v] THEN WG(v)

END.

Можно убедиться в том, что этот алгоритм просмотрит каждую вершину ровно один раз и его сложность порядка О(n+m). Дополнительно каждый вызов WG(v) влечет за собой просмотр всех вершин компоненты связности графа, содержащей v (если они ещё не просмотрены, т.е. НОВЫЙ[u]=true для каждой вершины u, принадлежащей этой компоненте). При этом каждая вершина просматривается не более одного раза.

Сам алгоритм начинает поиск поочередно от каждой ещё не просмотренной вершины, следовательно, просматриваются все вершины графа (необязательно связного).

Чтобы оценить сложность алгоритма, заметим, что число шагов в обоих циклах FOR (строки 2,3) ≈ n (не считая шагов, выполненных при вызове WG). Эта программа выполняется не более чем n раз во втором цикле сразу после посещения каждой из вершин для каждого из её новых соседей, суммарно не более чем (n+m) раз. Полное число шагов, выполняемых циклом в третьей строке процедуры WG (не считая шагов, выполняемых WG(n)), для всех вызовов этой процедуры будет порядка m, где m – число ребер. Это дает общую сложность алгоритма О(n+m).

Т.к. поиск в глубину играет важную роль в разработке алгоритмов на графах, представим также нерекур­сивную версию процедуры WG.

Стандартным способом устранения рекурсии является использование стека. Каждая просмотренная вер­шина помещается в стек и удаляется из него после использования.

8(6) [13]

{нерекурсивная версия процедуры WG;

предполагаем, что в начале поиска P[u] – указатель на 1-ую за­пись списка СПИСОК[u] для каждой вершины u; массивы Р, НОВЫЙ – глобальные}

  1. PROCEDURE WG1(v); {поиск в глубину в графе, начиная с вершины v}

  2. BEGIN СТЕК := 0; СТЕК <= v; рассмотреть v; НОВЫЙ[v] := false;

  3. WHIKE СТЕК ≠ 0 DO

  1. BEGIN t := top(СТЕК); {t – верхний элемент стека} {найти первую новую вершину в списке СПИСОК[t]}

  2. IF P[t] = nil THEN b := false

6 ELSE b := not НОВЫЙ[P[t]^.строка];

7 WHILE b DO BEGIN

  1. P[t] := P[t]^.след;

  2. IF P[t] = nil THEN b := false

  3. ELSE b := not НОВЫЙ[P[t]^.строка]

  1. END;

  2. IF P[t] ≠ nil THEN {найдена новая вершина}

  1. BEGIN t := P[t]^.строка; СТЕК <= t;

  2. рассмотреть t; НОВЫЙ[t] := false

  1. END

  2. ELSE {вершина t использована}

17 t <= СТЕК {удалить верхний элемент стека}

18 END

Примечание. В круглых скобках пронумеруем вершины графа в той очередности, в которой они просмат­риваются в процессе поиска в глубину.

3(9) [12]

2(2) [2]

5(5) [9]

1(1) [1]

9(7) [10]

13(10) [11]

11(13) [8]

10(12) [7]

19 END

Метод легко переносится и на ориентированные графы. Нетрудно проверить, что и в этом случае резуль­татом вызова процедуры WG(v), а также WG1(v), будет посещение за О(n+m) шагов всех вершин u таких, что существует путь из v и u.

Таким образом можно считать, что при поиске в глубину чем позднее будет посещена вершина, тем рань­ше она будет использована. Это связано с тем, что просмотренные, но еще не использованные вершины скап­ливаются в стеке.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]