繁体   English   中英

在序言中按顺序遍历树

[英]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中,逻辑术语可以更好地表示树木。 可以在此处找到详尽的讨论,包括对问题的答案(请参阅解决方案)

https://sites.google.com/site/prologsite/prolog-problems/4

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM