如何在Prolog中将树转换为列表?
实现谓词treeToListX,List,其中X是给定的有序非空二叉树,List是树节点中元素的有序列表如何在Prolog中将树转换为列表?,prolog,Prolog,实现谓词treeToListX,List,其中X是给定的有序非空二叉树,List是树节点中元素的有序列表 4 / \ 2 6 / \ / \ 1 3 5 7 是作为谓词树列表的输入给定的有序树。 您的程序必须计算列表[1,2,3,4,5,6,7] 以下是我目前掌握的代码: treeToListX,List:-binaryT
4
/ \
2 6
/ \ / \
1 3 5 7
是作为谓词树列表的输入给定的有序树。
您的程序必须计算列表[1,2,3,4,5,6,7]
以下是我目前掌握的代码:
treeToListX,List:-binaryTreeX,convertX,List
转换treeElement,void,void,List:-List=[Element]
如果X是给定的非空树,则帮助谓词convertX,List为true,并且List是该树的有序列表表示形式
但是我不知道如何写这个问题的递归部分
转换treeRoot、左、右、列表:-
有人能帮我完成这部分吗?您从未在Prolog中明确说明数据结构的外观,但我可以推断您基本上有两种树节点: 树元素,左,右 无效的 要处理任何递归数据结构,需要编写一个递归谓词。通常但并非总是需要针对每种元素的子句。在Haskell中,这一点更为明确,因为您必须定义类型及其构造函数,但是您可以在这里应用相同的推理。因此,convert/2谓词将为每种元素都有一个子句:
convert(void, ...) :- ...
convert(tree(Element, Left, Right), ...) :- ...
你可以马上看到第一条非常简单:
convert(void, []).
第二条是事情变得更有趣的地方。关键是递归地将convert/2应用于左侧和右侧的子树,然后需要对现有的元素执行一些操作:
convert(tree(Element, Left, Right), Rest) :-
convert(Left, LeftList),
convert(Right, RightList),
append(LeftList, [Element|RightList], Rest).
请注意,在追加之前,我将当前元素预先添加到右侧列表中。这是将元素插入到列表中的适当位置,以便按顺序遍历,以获得所需的结果:
?- convert(tree(4, tree(2, tree(1, void, void), tree(3, void, void)),
tree(6, tree(5, void, void), tree(7, void, void))),
List).
List = [1, 2, 3, 4, 5, 6, 7].
这将为您提供顺序遍历。如果您希望进行预序或后序遍历,您可以将元素放置在另一个位置,例如结果的开头或结尾。您从未在Prolog中明确说明数据结构的外观,但我可以推断您基本上有两种树节点: 树元素,左,右 无效的 要处理任何递归数据结构,需要编写一个递归谓词。通常但并非总是需要针对每种元素的子句。在Haskell中,这一点更为明确,因为您必须定义类型及其构造函数,但是您可以在这里应用相同的推理。因此,convert/2谓词将为每种元素都有一个子句:
convert(void, ...) :- ...
convert(tree(Element, Left, Right), ...) :- ...
你可以马上看到第一条非常简单:
convert(void, []).
第二条是事情变得更有趣的地方。关键是递归地将convert/2应用于左侧和右侧的子树,然后需要对现有的元素执行一些操作:
convert(tree(Element, Left, Right), Rest) :-
convert(Left, LeftList),
convert(Right, RightList),
append(LeftList, [Element|RightList], Rest).
请注意,在追加之前,我将当前元素预先添加到右侧列表中。这是将元素插入到列表中的适当位置,以便按顺序遍历,以获得所需的结果:
?- convert(tree(4, tree(2, tree(1, void, void), tree(3, void, void)),
tree(6, tree(5, void, void), tree(7, void, void))),
List).
List = [1, 2, 3, 4, 5, 6, 7].
这将为您提供顺序遍历。如果您希望进行预排序或后排序遍历,您可以将元素放置在另一个位置,例如结果的开头或结尾。根据问题,您的树有两个数据族: 永恒的空虚;和 一个复合术语,其树/3以值和左右子树作为参数。 我们可以实现类似的谓词。通过定义谓词convert/3,我们可以稍微优化它,其中第一个参数是要转换的树,第二个参数是列表的头,第三个参数是列表的尾 因此,我们可以将谓词定义为:
convert(void, L, L).
convert(tree(V, L, R), H, T2) :-
convert(L, H, [V|T1]),
convert(R, T1, T2).
如果我们因此遇到一个空白,那么列表的开始和结束保持不变。如果我们遇到一个treeV,L,R,我们将首先递归地调用convertL,H,[V | T1]。通过将[V | T1]写为tail,我们迫使Prolog在结果中产生V值。然后,尾部T1是第二个子树的convert/3的开始
然后,我们可以根据convert/3定义convert/2:
根据问题,您的树有两个数据族: 永恒的空虚;和 一个复合术语,其树/3以值和左右子树作为参数。 我们可以实现类似的谓词。通过定义谓词convert/3,我们可以稍微优化它,其中第一个参数是要转换的树,第二个参数是列表的头,第三个参数是列表的尾 因此,我们可以将谓词定义为:
convert(void, L, L).
convert(tree(V, L, R), H, T2) :-
convert(L, H, [V|T1]),
convert(R, T1, T2).
如果我们因此遇到一个空白,那么列表的开始和结束保持不变。如果我们遇到一个treeV,L,R,我们将首先递归地调用convertL,H,[V | T1]。通过将[V | T1]写为tail,我们迫使Prolog在结果中产生V值。然后,尾部T1是第二个子树的convert/3的开始
我们
然后可以根据convert/3定义convert/2:
在Java/C++/….这样的语言中,您将如何做到这一点?在Java/C++/….这样的语言中,您将如何做到这一点?感谢您的清晰解释!这对我来说是一个很有帮助的回答。@Allenl我很高兴我能帮上忙!享受序言!顺便说一下,我有一个关于递归部分的问题。我们是不是先遍历左边的子树,然后把它们都放到一个列表中,然后对右边的子树做同样的事情,最后把它们附加在一起?我说得对吗?@AllenLi是的,那就是那里发生的事情。谢谢你的清楚解释!这对我来说是一个很有帮助的回答。@Allenl我很高兴我能帮上忙!享受序言!顺便说一下,我有一个关于递归部分的问题。我们是不是先遍历左边的子树,然后把它们都放到一个列表中,然后对右边的子树做同样的事情,最后把它们附加在一起?我说得对吗?@AllenLi是的,这就是那里正在发生的事情。谢谢你的回答!谢谢你的回答!