Предварительный обход дерева в Прологе

У меня есть этот предикат Prolog для обхода дерева PreOrder:

preOrder(nil, []).
preOrder(node(X, nil, nil), [X]).
preOrder(node(X, L, _), [X|T]) :- preOrder(L, T).
preOrder(node(X, _, R), [X|T]) :- preOrder(R, T).

Проблема в том, что он возвращает неполный список. Например, я получаю:

?- preOrder(node(1, node(2, node(3,nil,nil), node(4,nil,nil)), node(5,nil,nil)), L). 
L = [1,2,3]

Когда должно быть L=[1,2,3,4,5].

Почему он останавливается?


person Bobazonski    schedule 26.11.2014    source источник


Ответы (2)


Посмотрите на ответы, которые дает Пролог. Это не один:

| ?- preOrder(node(1,node(2,node(3,nil,nil),node(4,nil,nil)),node(5,nil,nil)),L).
L = [1,2,3] ? ;
L = [1,2,3] ? ;
L = [1,2,3] ? ;
L = [1,2,4] ? ;
L = [1,2,4] ? ;
L = [1,2,4] ? ;
L = [1,5] ? ;
L = [1,5] ? ;
L = [1,5] ? ;
no

Каждое из ваших правил описывает какую-то часть независимо от других. Но вам нужно описать их все вместе.

Лучший способ решить эту проблему — использовать DCG.

person false    schedule 26.11.2014

Это останавливается, потому что у вас есть два рекурсивных предложения, каждое из которых идет только к одной стороне дерева. У вас также есть два базовых случая, хотя второй не нужен.

Таким образом, вы удалите второе предложение и соедините два рекурсивных предложения только в одном предложении, которое добавляет результаты из обеих ветвей.

E.g.:

preOrder(nil, []).
preOrder(node(X, L, R), [X|T]) :- 
  preOrder(L, LT), 
  append(LT, RT, T), 
  preOrder(R, RT).

Вы также можете использовать аккумулятор для обхода:

preOrder(Tree, List):-
  preOrder(Tree, [], RList),
  reverse(RList, List).

preOrder(nil, List, List).
preOrder(node(X, L, R), List, NList) :- 
    preOrder(L, [X|List], MList), 
    preOrder(R, MList, NList).

Обратите внимание, что, как сказал один комментатор, эти определения для preOrder не работают правильно для создания деревьев с учетом обхода.

Вы можете использовать DCG для определения процедуры, которая будет обратимой, внутренне используя открытые списки:

preOrder(nil)-->[].
preOrder(node(X, L, R))-->[X], preOrder(L), preOrder(R).

И вы бы назвали это, используя phrase/2:

?- phrase(preOrder(node(1, node(2, node(3,nil,nil), node(4,nil,nil)), node(5,nil,nil))), L).
L = [1, 2, 3, 4, 5].
person gusbro    schedule 26.11.2014
comment
Первая версия: для всех непустых списков L и T неконкретных, preOrder(T, L) не завершается. Вторая версия: Циклы также для L = []. - person false; 27.11.2014
comment
Верно, но @OP хочет пройти по заданному дереву, а не генерировать деревья из обхода списка. - person gusbro; 27.11.2014