Обходы ордерева в глубину и в ширину
Во многих задачах необходимо обойти некоторое ордерево в глубину или в ширину, посещая каждую его вершину в точности один раз и выполняя при этом некоторую систематическую обработку информации, относящейся к этой вершине. Посещение каждой вершины дерева может быть связано или с выполнением простой операции, например с распечаткой пометки вершины дерева, или со сложной, например, с вычислением некоторой функции.
Рис. 20. Дерево
При префиксном обходе ордерева T, сначала нужно посетить его корень v, а затем, если v не является листом, то реализовать префиксный обход всех ее поддеревьев в порядке их упорядоченности. Например, для дерева, показанного на рис. 20, вершины будут проходиться в следующем порядке: A,B,C,D,E,F,G,H,I,J,K,L. Следующая рекурсивная процедура реализует префиксный обход ордерева:
procedure ПРЕФИКСНЫЙ-ОБХОД(T: ордерево); begin Посетить корень v ордерева T; if v не лист then Пусть T1,…,Tk – поддеревья корня v; for i := 1 to k do ПРЕФИКСНЫЙ-ОБХОД(Ti) end end end.
Если использовать стек S для хранения текущего пути по дереву, т.е. пути, который начинается в корне дерева и кончается в вершине, посещаемой в данный момент, то можно предложить следующий нерекурсивный алгоритм префиксного обхода ордерева:
Посетить корень дерева и поместить его в пустой стек S ; while стек S не является пустым do Пусть p – вершина, находящаяся на верху стека S ; if Сыновья вершины p еще не посещались then Посетить старшего сына вершины p и поместить его в стек S else Удалить вершину p из стека S; if p имеет братьев then Посетить брата вершины p и поместить его в стек S end end end
Способ обхода ордерева в ширину предполагает посещение вершин ордерева по старшинству, уровень за уровнем, отправляясь от корня. Например, при обходе в ширину изображенного на рис. 20 дерева вершины проходятся сверху вниз и слева направо и посещаются в следующем порядке: A,B,C,G,H,D,E,F,I,L,J,K. Приведенный ниже алгоритм реализует обход дерева в ширину, используя очередь О.
Поместить корень в пустую очередь O; while очередь O не пуста do Пусть p – первая вершина очереди O; Посетить вершину p и удалить ее из O; Поместить всех сыновей вершины p в очередь O, начиная со старшего сына end
Следует заметить, что обход дерева поиска в ширину позволяет обходить дерево поиска одновременно с его построением. Таким образом, можно решать задачу нахождения какого-нибудь одного решения в форме вектора (а1, а2,…) неизвестной длины (не зная r), если только известно, что существует конечное решение задачи.
Обходы графа в глубину и в ширину
Алгоритмы обхода дерева в глубину и в ширину можно модифицировать таким образом, чтобы их можно было использовать для систематического обхода всех вершин произвольного графа.
Например, используя рекурсивную процедуру, линейный по временной сложности алгоритм обхода графа G в глубину можно записать следующим образом:
procedure ОБХОД-В-ГЛУБИНУ(р: вершина); begin Посетить вершину р ; for all q from множества вершин, смежных с р do if q еще не посещалась then ОБХОД-В-ГЛУБИНУ(q) end end end; begin for all р from множества вершин G do if р еще не посещалась then ОБХОД-В-ГЛУБИНУ(р) end end end.
В результате работы алгоритма, пройденные ребра графа образуют вместе с посещенными вершинами одно или несколько деревьев (по одному дереву для каждой компоненты связности графа). Если приписать пройденным ребрам ориентацию в соответствии с тем направлением, в каком они проходятся при выполнении алгоритма, то мы получим совокупность ордеревьев, причем их корнями будут служить все те вершины, которые в процессе работы алгоритма помещались в пустой стек.
Например, для графа, изображенного на рис. 21,а, описанным способом будут получены два ордерева, приведенных на рис. 21,б. Порядок на всем множестве вершин графа, а также порядок вершин, смежных всякой его вершине, соответствует алфавитному порядку букв, помечающих вершины.
Нерекурсивный вариант алгоритма обхода графа G в глубину может иметь следующий вид:
procedure ОБХОД-В-ГЛУБИНУ-1(р : вершина); begin Посетить вершину р и поместить ее в пустой стек S; while Стек S непуст do Пусть р – вершина, находящаяся на верхушке стека S; if у р есть непосещенные смежные вершины then Пусть q – непосещенная вершина, смежная вершине р; Пройти по ребру (р, q), посетить вершину q и поместить ее в стек S else Удалить вершину р из стека S end end end;
Рис. 21. Граф и его обход в глубину
Обход в ширину связного графа предполагает рассмотрение всех его вершин в порядке возрастания расстояния от некоторой вершины, с которой начался данный обход графа. Например, в результате обхода графа G (рис. 21) в ширину возможен следующий порядок посещения вершин: C,A,B,D,H,K,L,E,F,G.
Следующий алгоритм позволяет осуществить обход в ширину любого связного графа G:
procedure ОБХОД-В-ШИРИНУ(р: вершина); begin Поместить вершину р в пустую очередь O; while очередь O не пуста do Взять первую вершину р из очереди O; if р еще не посещалась then Посетить вершину р и поместить в очередь O все вершины, смежные с р end end end;
