Россия, Пошатово |
Обход дерева. Перебор с возвратами
3.1.4. Написать программу обхода дерева, использующую процедуру перехода в следующий лист (с выходным параметром, сообщающим, удалось ли это сделать или лист оказался последним).
3.1.5. Решить задачу об обходе дерева, если мы хотим, чтобы обрабатывались все вершины (не только листья).
Решение. Пусть - некоторая вершина. Тогда любая вершина относится к одной из четырех категорий. Рассмотрим путь из корня в . Он может:
(а) быть частью пути из корня в ( );
(б) свернуть налево с пути в ( );
(в) пройти через ( );
(г) свернуть направо с пути в ( );
В частности, сама вершина относится к категории (в). Условия теперь будут такими:
(ОНЛ) обработаны все вершины ниже и левее;
(ОНЛН) обработаны все вершины ниже, левее и над.
Вот как будет выглядеть программа:
procedure вверх_до_упора_и_обработать; | {дано: (ОНЛ), надо: (ОНЛН)} begin | {инвариант: ОНЛ} | while есть_сверху do begin | | обработать; | | вверх_налево; | end | {ОНЛ, Робот в листе} | обработать; | {ОНЛН} end;
дано: Робот в корне, ничего не обработано надо: Робот в корне, все вершины обработаны {ОНЛ} вверх_до_упора_и_обработать; {инвариант: ОНЛН} while есть_снизу do begin | if есть_справа then begin {ОНЛН, есть справа} | | вправо; | | {ОНЛ} | | вверх_до_упора_и_обработать; | end else begin | | {ОЛН, не есть_справа, есть_снизу} | | вниз; | end; end; {ОНЛН, Робот в корне => все вершины обработаны}
3.1.6.Приведенная только что программа обрабатывает вершину до того, как обработан любой из ее потомков. Как изменить программу, чтобы каждая вершина, не являющаяся листом, обрабатывалась дважды: один раз до, а другой раз после всех своих потомков? (Листья по-прежнему обрабатываются по разу.)
Решение. Под "обработано ниже и левее" будем понимать "ниже обработано по разу, слева обработано полностью (листья по разу, остальные по два)". Под "обработано ниже, левее и над" будем понимать " ниже обработано по разу, левее и над - полностью".
procedure вверх_до_упора_и_обработать; | {дано: (ОНЛ), надо: (ОНЛН)} begin | {инвариант: ОНЛ} | while есть_сверху do begin | | обработать; | | вверх_налево; | end | {ОНЛ, Робот в листе} | обработать; | {ОНЛН} end;
дано: Робот в корне, ничего не обработано надо: Робот в корне, все вершины обработаны {ОНЛ} вверх_до_упора_и_обработать; {инвариант: ОНЛН} while есть_снизу do begin | if есть_справа then begin {ОНЛН, есть справа} | | вправо; | | {ОНЛ} | | вверх_до_упора_и_обработать; | end else begin | | {ОЛН, не есть_справа, есть_снизу} | | вниз; | | обработать; | end; end; {ОНЛН, Робот в корне => все вершины обработаны полностью}