Skip to content

Commit

Permalink
Update GeneralDepthFirstSearch.rst
Browse files Browse the repository at this point in the history
  • Loading branch information
Natalie committed Oct 21, 2014
1 parent c3ddd0d commit 677786a
Showing 1 changed file with 8 additions and 8 deletions.
16 changes: 8 additions & 8 deletions pythonds/source/Graphs/GeneralDepthFirstSearch.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@
Поиск в глубину: общий случай
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

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

Весьма вероятно, что поиск в глубину создаст больше, чем одно дерево. В этом случае мы называем их **лесом поиска в глубину**. Как и в поиске в ширину, здесь при создании дерева используется ссылка на предшественника. Также дополнительно требуются две новых поля в классе ``Vertex``: "время" входа и "время" выхода. Первое будет отслеживать, сколько шагов сделал алгоритм до того, как вершина была впервые обнаружена, а второе - количество шагов алгоритма до того, как вершину окрасили в чёрный цвет. В процессе изучения мы увидим, что оба "времени" обладают весьма любопытными свойствами, которые можно использовать в других алгоритмах.
Весьма вероятно, что при этом получится больше, чем одно дерево. Мы называем их **лесом поиска в глубину**. Как и в поиске в ширину, здесь используется ссылка на предшественника при создании дерева. Также дополнительно требуются две новых поля в классе ``Vertex``: "время" входа и "время" выхода. Первое будет отслеживать, сколько шагов сделал алгоритм до того, как вершина была впервые обнаружена, а второе - количество шагов алгоритма до того, как вершину окрасили в чёрный цвет. В процессе изучения мы увидим, что оба "времени" обладают весьма любопытными свойствами, которые можно использовать в других алгоритмах.

Код нашего поиска в глубину показан в :ref:`листинге 5 <lst_dfsgeneral>`. Поскольку функции ``dfs`` и её помощница ``dfsvisit`` используют переменную для отслеживания "времени" в процессе вызовов ``dfsvisit``, мы выбрали реализацию кода как методов класса, наследующего классу ``Graph``. Она расширяет класс графа, добавляя атрибут ``time`` и два метода ``dfs`` и ``dfsvisit``. Если вы посмотрите на строку 11, то заметите, что метод ``dfs`` проходит по всем вершинам графа, вызывая ``dfsvisit`` на тех из них, которые открашены в белый. Причина, по которой мы проходим по всем узлам, заключается в том, что требуется выполнить не просто поиск из выбранного стартового узла, но и убедиться, что рассмотрены все вершины графа и ни одна из них не выпала из леса поиска. Оператор ``for aVertex in self`` может необычно смотреться, но вспомните, что в этом случае ``self`` - объект класса ``DFSGraph``. Поэтому проход по всем вершинам графа абсолютно естественнен.
Код нашего поиска в глубину показан в :ref:`листинге 5 <lst_dfsgeneral>`. Поскольку функции ``dfs`` и её помощница ``dfsvisit`` используют переменную для отслеживания "времени" в процессе вызовов ``dfsvisit``, мы выбрали реализацию кода как методов класса, наследующего классу ``Graph``. Она расширяет класс графа, добавляя атрибут ``time`` и два метода ``dfs`` и ``dfsvisit``. Если вы посмотрите на строку 11, то заметите, что метод ``dfs`` проходит по всем вершинам графа, вызывая ``dfsvisit`` на окрашенных в белый цвет. Причина, по которой мы проходим по всем узлам, заключается в том, что требуется выполнить не просто поиск из выбранного стартового узла, но и убедиться, что рассмотрены все вершины графа и ни одна из них не выпала из леса поиска. Оператор ``for aVertex in self`` может необычно смотреться, но вспомните: в этом случае ``self`` - объект класса ``DFSGraph``. А проход по всем вершинам графа абсолютно естественнен.

.. highlight:: python
:linenothreshold: 5
Expand Down Expand Up @@ -58,17 +58,17 @@

Метод ``dfsvisit`` начинает работу с единичной вершины ``startVertex`` и исследует всех её соседей, окрашенных в белый, настолько глубоко, насколько это возможно. Если вы внимательно посмотрите на код ``dfsvisit`` и сравните его с поиском в ширину, то заметите, что эти два алгоритма во многом похожи, за исключением последней строки вложенного цикла ``for``. В ней ``dfsvisit`` вызывает сама себя, чтобы продолжить поиск на более глубоком уровне, в то время как ``bfs`` добавляет узел в очередь для дальнейшего исследования. Интересно заметить, что там где ``bfs`` использует очередь, ``dfsvisit`` пользуется стеком. Вы не видите его в коде, но он неявно присутствует в рекурсивном вызове ``dfsvisit``.

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

Поиск начинается с вершины А (:ref:`рисунок 14 <fig_gdfsa>`). Поскольку все узлы в начале поиска окрашены в белый, её алгоритм посещает. Первый шаг при посещении узла - окрасить его в серый (вершина была исследована) и установить "время" входа равным единице. Поскольку А имеет две смежные вершины (B, D), то каждую из них тоже требуется посетить. Мы принимаем произвольное решение заходить в узлы в алфавитном порядке.
Поиск начинается с вершины А (:ref:`рисунок 14 <fig_gdfsa>`). Поскольку все узлы в начале поиска окрашены в белый, алгоритм в неё заходит. Первый шаг при посещении узла - окрасить его в серый (вершина была исследована) и установить "время" входа равным единице. Поскольку А имеет две смежные вершины (B, D), то каждую из них тоже требуется посетить. Мы принимаем произвольное решение заходить в узлы в алфавитном порядке.

Следующей посещаем вершину B (:ref:`рисунок 15 <fig_gdfsb>`). Её цвет устанавливается серым, а "время" входа равным 2. Этот узел также имеет два смежных (C, D), поэтому далее мы посещаем узел С - в соответствии с алфавитом.

Визит в C (:ref:`рисунок 16 <fig_gdfsc>`) приводит нас к концу ветки дерева. После окрашивания её в серый и присвоения "времени" входа 3, алгоритм находит отсутствие у С смежных вершин. Это означает, что мы завершили её исследование, так что можно окрасить С в чёрный и задать ей "время" выхода равным 4. Состояние поиска на данный момент вы можете видеть на :ref:`рисунке 17 <fig_gdfsd>`.

Поскольку С является концом первой ветви, мы возвращаемся в вершину B и продолжаем исследовать смежные с ней узлы. Единственная дополнительная вершина для исследования из В - это D, так что мы посещаем её (:ref:`рисунок 18 <fig_gdfse>`) и продолжаем поиск уже из D. Эта вершина быстро приводит нас в E (:ref:`рисунок 19 <fig_gdfsf>`). Узел Е имеет два смежных - B и F. Обычно мы исследовали их в алфавитном порядке, но сейчас В уже окрашен в серый. Алгоритм распознаёт, что ему не следует туда заходить, чтобы не загнать себя в цикл. Поэтому исследование продолжается для следующей вершины из списка - F (:ref:`рисунок 20 <fig_gdfsg>`).
Поскольку С является концом первой ветви, мы возвращаемся в вершину B и продолжаем исследовать смежные с ней узлы. Единственная дополнительная вершина для исследования из В - это D, так что мы посещаем её (:ref:`рисунок 18 <fig_gdfse>`) и продолжаем поиск. Эта вершина быстро приводит нас в E (:ref:`рисунок 19 <fig_gdfsf>`), который имеет два смежных - B и F. Обычно мы исследовали их в алфавитном порядке, но сейчас В уже окрашен в серый цвет. Алгоритм распознаёт, что ему не следует туда заходить, чтобы не загнать себя в цикл, поэтому исследование продолжается для следующей вершины из списка - F (:ref:`рисунок 20 <fig_gdfsg>`).

F имеет единственный смежный узел - С. Но поскольку он уже окрашена в чёрный, то больше исследовать нечего, и алгоритм достигает конца другой ветви. Отсюда вы можете видеть на :ref:`рисунках с 21-го <fig_gdfsh>` по :ref:`25-й <fig_gdfsl>`, как алгоритм возвращается обратно к первому узлу, устанавливает ему "время" выхода и окрашивает его в чёрный.
F имеет единственный смежный узел - С. Но поскольку он уже окрашен в чёрный, то больше исследовать нечего, и алгоритм достигает конца другой ветви. Отсюда вы можете видеть на :ref:`рисунках с 21-го <fig_gdfsh>` по :ref:`25-й <fig_gdfsl>`, как алгоритм возвращается обратно к первому узлу, устанавливает ему "время" выхода и окрашивает его в чёрный.

.. _fig_gdfsa:

Expand Down Expand Up @@ -154,7 +154,7 @@ F имеет единственный смежный узел - С. Но пос

Рисунок 25: Создание дерева поиска в глубину - 21

"Времена" входа и выхода для каждого узла показывают так называемое **свойство скобок**. Оно означает, что все потомки данного узла в дереве поиска имеют более позднее "время" входа и раннее "время" выхода, чем их предки. :ref:`Рисунок 26 <fig_dfstree>` показывает дерево, сконструированное алгоритмом поиска в глубину.
"Времена" входа и выхода для каждого узла показывают так называемое **свойство скобок**. Оно означает, что все потомки данного узла в дереве поиска имеют более позднее "время" входа и раннее "время" выхода, чем их предки. :ref:`Рисунок 26 <fig_dfstree>` демонстрирует дерево, сконструированное алгоритмом поиска в глубину.

.. _fig_dfstree:

Expand Down

0 comments on commit 677786a

Please sign in to comment.