[英]In Order Tree Traversal in Prolog
我是Prolog的新手,我正尝试编写有序树遍历,其中给出了一系列事实,例如:
leftSubtree(9, 7).
leftSubtree(7, 1).
leftSubtree(1, -2).
leftSubtree(11, 9).
leftSubtree(16, 13).
leftSubtree(3, 2).
rightSubtree(9, 11).
rightSubtree(7, 6).
rightSubtree(1, 3).
rightSubtree(11, 16).
rightSubtree(16, 19).
我可以使用inOrder(9,X)。 按顺序打印出一棵树。 我尝试使用下面的代码有效,但希望有一些简单的方法。 任何提示或帮助,将不胜感激。
inOrder(Root, X):-
\+ leftSubtree(Root,Left),
\+ rightSubtree(Root,Left) ->
X = [Root];
leftSubtree(Root,Left),
rightSubtree(Root,Right)->
inOrder(Left, LeftNode),
inOrder(Right, RightNode),
append(LeftNode,[Root|RightNode],X);
leftSubtree(Root,Left),
inOrder(Left, LeftNode),
append(LeftNode,[Root],X);
rightSubtree(Root,Right)->
inOrder(Right, RightNode),
append([Root],RightNode,X).
试试看:
inOrder(N,X) :- traverseLeft(N,L), traverseRight(N,R), append(L,[N|R],X).
traverseLeft(N,L) :- leftSubtree(N,M) -> inOrder(M,L); L=[].
traverseRight(N,R) :- rightSubtree(N,M) -> inOrder(M,R); R=[].
仍有改进的空间。 append / 3非常昂贵,但是您可以通过使用累加器避免这种情况。
累加器的想法是, inOrder(N,X)
编写谓词inOrder(N,X)
,而不是写“以N为根的树的有序遍历为X”,而是编写inOrder(N,A,X)
,意思是“ the以N为根的树的有序遍历是X“。 然后,您只需调用inOrder(Root,[],X)
。
这样做的目的是,您可以递归调用以在现有列表的顶部构建其解决方案,并避免在每一步进行线性时间列表串联。
inOrder(N,X) :- inOrder_aux(N,[],X).
inOrder_aux(N,A,X) :- traverseLeft(N,[N|R],X), traverseRight(N,A,R).
traverseLeft(N,A,L) :- leftSubtree(N,M) -> inOrder_aux(M,A,L); L=A.
traverseRight(N,A,R) :- rightSubtree(N,M) -> inOrder_aux(M,A,R); R=A.
因此,它与原始解决方案几乎相同,不同之处在于基本案例返回累加器而不是空列表,并且您将右遍历的结果作为左侧的累加器传入(在发生右遍历之前,看起来很奇怪)。
您的代码可以简化,避免负面测试,并使用Prolog的一些自反性。
inOrder(Root, [Left, Root, Right]) :-
inOrder(leftSubtree, Root, Left),
inOrder(rightSubtree, Root, Right).
inOrder(BranchToExplore, Root, Subtree) :-
call(BranchToExplore, Root, Branch)
-> inOrder(Branch, Subtree)
; Subtree = [].
这样可以将树的结构恢复为嵌套的三元列表,然后按一次调用flatten / 2就足够了,就像原来的要求一样,使其平坦 。
?- inOrder(8, Tree), flatten(Tree, L).
Tree = [[[[[], -2, []], 1, [[[], 2, []], 3, []]], 5, [[], 6, []]], 8, [[[], 9, [[], 10|...]], 11, [[[], 13|...], 16, [...|...]]]],
L = [-2, 1, 2, 3, 5, 6, 8, 9, 10|...].
如果您的Prolog中没有call / N,则可以使用univ建立可调用的术语:
inOrder(BranchToExplore, Root, Subtree) :-
( Callable =.. [BranchToExplore, Root, Branch], call(Callable) )
-> inOrder(Branch, Subtree)
; Subtree = [].
如果我们交换Left和Root,我们将拥有更有用的preOrder表示形式: preOrder(Root, [Root, Left, Right]) :- ...
将树的结构设置为preOrder可能对进一步处理有用:一个“准备就绪”并且在SWI-Prolog中是有用的实现,它是XML,其中树表示为element(Tag,Attributes,Subtrees),并且可以由库(xpath) 更改inOrder / 2和inOrder / 3可能都是有用的练习,以恢复XML。
在Prolog中,逻辑术语可以更好地表示树木。 可以在此处找到详尽的讨论,包括对问题的答案(请参阅解决方案)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.