"Информатика (базовый и углублённый уровень)", Гейн А.Г., Сенокосов А.И.
Поиск в глубину — алгоритм обхода графа, который из выбранной вершины последовательно уходит к непосещённым соседям, стараясь пройти по одной ветви как можно дальше. Когда продолжать движение нельзя, алгоритм возвращается назад и исследует другие ветви. Он нужен для поиска путей, компонент связности и циклов. Главное — отмечать вершины посещёнными и правильно организовать возврат.
Текст подготовлен нейронной сетью по теме параграфа и не заменяет учебник — важные факты и формулировки сверяйте с ним.
Поиск в глубину — алгоритм обхода графа, при котором из текущей вершины переходят как можно глубже, а затем возвращаются назад. Он позволяет систематически исследовать связанные объекты, не пропуская доступные ветви.
Вершина и ребро графа — объекты, между которыми строится маршрут обхода. Вершина обозначает объект или состояние, а ребро — связь между двумя вершинами; именно по рёбрам алгоритм переходит от одной вершины к другой.
Метка посещения — признак, показывающий, что вершина уже обработана и повторно посещать её не нужно. Такая отметка нужна, чтобы не ходить по одному и тому же циклу бесконечно и не тратить время на повторную работу.
Стек вызовов — структура, в которой сохраняются вершины для возврата при рекурсивной реализации поиска. Последним сохранённый вызов завершается первым, поэтому возврат естественно идёт от дальней вершины к ближайшей развилке.
Обход начинается с выбранной вершины, потому что алгоритму нужна точка, от которой он будет исследовать граф. Её сразу помечают посещённой и просматривают список соседей. Если найден непосещённый сосед, переходят в него и повторяют ту же процедуру. Так формируется одна ветвь маршрута, уходящая всё дальше от старта.
Метка посещения нужна потому, что в графе могут быть циклы и несколько разных путей к одной вершине. Например, из вершины можно попасть в уже пройденную вершину по обратному ребру. Если не проверить метку, алгоритм снова начнёт исследование этой вершины и может зациклиться. Отметка до перехода к соседям сразу закрывает такую возможность.
Когда у текущей вершины нет непосещённых соседей, продолжать путь из неё нельзя. Поэтому алгоритм возвращается к вершине, из которой пришёл, и проверяет, остались ли там другие направления. Возврат необходим для исследования боковых ветвей: без него поиск остановился бы на конце первой найденной ветви.
При рекурсивной реализации процедура обработки вершины вызывает саму себя для каждого подходящего соседа. Перед новым вызовом в стеке вызовов сохраняется незавершённая работа текущей вершины. Когда нижний вызов заканчивается, управление возвращается к сохранённому вызову, поэтому стек автоматически организует обратный путь.
Порядок обхода определяется двумя решениями: откуда начать и какого соседа выбирать первым. Если соседей просматривать по возрастанию номеров, порядок будет одним, а при обратном порядке — другим. При этом для связной достижимой части графа набор посещённых вершин не изменится, если не меняются сам граф и начальная вершина.
Таблица показывает, из каких шагов складывается алгоритм и какие данные нужны для его реализации. Ею удобно пользоваться как кратким планом перед написанием программы или проверкой готового решения.
| Параметр | Характеристика |
|---|---|
| Начальные данные | Граф, начальная вершина и способ хранения связей |
| Основной шаг | Выбор непосещённого соседа и переход в него |
| Условие возврата | У текущей вершины нет непосещённых соседей |
| Способ предотвращения повторов | Метка посещения вершины |
| Реализация | Рекурсия или явный стек |
| Результат | Порядок посещения вершин и найденные связи |
| Временная сложность | O(V + E) при представлении графа списками смежности |
Условие. Для заданного графа нужно выписать порядок посещения всех вершин из начальной вершины, просматривая соседей по возрастанию их номеров. Числа вершин и связи задаются условием, поэтому порядок нужно получить не угадыванием, а последовательной имитацией алгоритма.
Ответ. Полученная запись является порядком обхода. Для самопроверки убедитесь, что каждая вершина в ней встречается один раз, а переход между соседними элементами допустим по графу или объясняется возвратом.
Условие. Нужно определить, существует ли путь из вершины A в вершину B. Поиск в глубину подходит, потому что он просматривает все вершины, достижимые из A, пока не найдёт цель или не исчерпает возможные ветви.
Ответ. Ответ «да» получают при посещении B, ответ «нет» — после полного исчерпания обхода без неё. При необходимости сам путь восстанавливают, сохраняя для каждой вершины её предшественника.
Условие. Для неориентированного графа требуется найти группы вершин, соединённых путями внутри группы. Один запуск поиска в глубину из непосещённой вершины как раз собирает все вершины её компоненты.
Ответ. Число запусков, выполненных из непосещённых вершин, равно числу компонент связности, а собранные при каждом запуске вершины дают их состав.
Поздняя отметка. Если пометить вершину только после обхода соседей, цикл может вернуть алгоритм в неё раньше этого момента. Отмечайте вершину сразу при входе и проверьте, что метка ставится до рекурсивного вызова.
Путаница с поиском в ширину. Иногда сначала перебирают всех соседей одного уровня, потому что такой порядок кажется более привычным. Проверьте себя: в глубину после выбора соседа нужно сразу продолжать ветвь, а не откладывать её.
Отсутствие возврата. Обработка конца ветви без перехода к предыдущей вершине оставляет другие направления неисследованными. Убедитесь, что завершение вызова возвращает управление к месту, где ещё могли остаться соседи.
Ожидание единственного порядка. Один и тот же граф может дать разные последовательности при другом старте или порядке соседей. Сначала зафиксируйте эти условия, а затем сравнивайте полученный результат с ожидаемым.
До поиска в глубину нужно знать представление графа списками смежности или матрицей смежности, а также условные операторы, циклы и рекурсию. Алгоритм используется для поиска путей, компонент связности, циклов и анализа структуры графов. После его освоения легче изучать поиск в ширину, топологическую сортировку и другие алгоритмы на графах.
Зачем отмечать вершины посещёнными, если алгоритм уже возвращается назад?
Возврат назад не защищает от повторного входа в вершину по другой ветви. Метка посещения предотвращает бесконечный обход циклов и лишнюю обработку уже исследованной вершины.
Чем поиск в глубину отличается от поиска в ширину?
Поиск в глубину сначала полностью исследует одну ветвь, используя рекурсию или стек. Поиск в ширину обрабатывает вершины слоями, то есть сначала всех соседей начальной вершины, затем их соседей.
Можно ли выполнить поиск в глубину без рекурсии?
Да. Для этого используют явный стек: в него помещают вершины и извлекают их в порядке, обратном добавлению. Результат зависит от того, в каком порядке помещаются соседи.
Почему порядок обхода меняется при изменении порядка соседей?
Алгоритм выбирает первого доступного непосещённого соседа и углубляется через него. Если список соседей изменить, первой будет выбрана другая ветвь, поэтому изменится порядок, хотя множество достижимых вершин останется тем же.
Как с помощью поиска в глубину найти все компоненты связности?
Сначала запускают обход из первой непосещённой вершины и собирают все вершины этого запуска. Затем выбирают следующую непосещённую вершину и повторяют процедуру. Каждая группа, полученная одним запуском, является компонентой связности.
Лабораторная работа № 22 (к § 53) Поиск в глубину