Prolog中的PreOrder树遍历

时间:2014-11-26 14:37:56

标签: prolog binary-tree tree-traversal preorder

我有一个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]

为什么停止做空?

2 个答案:

答案 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].