我有一个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]
。
为什么停止做空?
答案 0 :(得分:1)
看看Prolog产生的答案。它不是一个单一的:
| ?- 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
您的每条规则都独立于其他规则描述了某些部分。但是你需要一起描述它们。
解决此问题的最佳方法是to use DCGs
答案 1 :(得分:-1)
它停止了,因为你有两个递归子句,每个子句只到树的一侧。 你也有两个基本案例,但不需要第二个案例。
所以你要删除第二个子句,只在一个子句中加入两个递归子句,这两个子句追加两个分支的结果。
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].