如何在prolog中编写关于树的谓词?

时间:2016-12-03 03:46:28

标签: prolog

我需要帮助定义一个prolog谓词treeMax(T,X),如果X是存储在树T中的最大数字,而不使用"是"谓词。

我使用函数术语来表示树:node1(X,T)表示存储数字X且有一个孩子node2(X,T1,T2)node3(X,T1,T2,T3)的节点 术语leaf(X)表示存储数字X的叶子。

例如:node2(1,leaf(1),node3(9,leaf(9),leaf(10),leaf(11)))是一棵树。

任何帮助都表示赞赏:)

编辑:最大子项数为3:因此可能的数据库为node1(X,T)node2(X,T1,T2)node3(X,T1,T2,T3)leaf(X)

2 个答案:

答案 0 :(得分:0)

很抱歉,我不认为leaf/1node1/2node2/3node3/4解决方案很好。

开发maxTree/2很简单但是......

treeMax(leaf(M), M).

treeMax(node1(V0, N1), M) :-
  treeMax(N1, V1),
  M is max(V0, V1).

treeMax(node2(V0, N1, N2), M) :-
  treeMax(N1, V1),
  treeMax(N2, V2),
  M is max(V0, max(V1, V2)).

treeMax(node3(V0, N1, N2, N3), M) :-
  treeMax(N1, V1),
  treeMax(N2, V2),
  treeMax(N3, V3),
  M is max(V0, max(V1, max(V2, V3))).

...但是,正如您所看到的,对于node4/5,您必须制定另一个treeMax子句,另一个用于node5/6,另一个用于node6/7, USW。

建议:保持节点和叶子之间的区别,但是对于节点,只实现一个带有值的结构和一个列表的子节点

所以你对子节点的数量没有限制;因此,您的maxTree/2不需要与更多子树的附加条款集成。

所以你的例子变成了

node(1, [leaf(1), node(9, [leaf(9), leaf(10), leaf(11)])])

maxTree/2成为

treeMax(leaf(M), M).

treeMax(node(V0, LN), M) :-
  treeMax(LN, V1),
  M is max(V0, V1).

treeMax([N], M) :-
  treeMax(N, M).

treeMax([Nh | Nt], M) :-
  treeMax(Nh, V0),
  treeMax(Nt, V1),
  M is max(V0, V1).

---编辑---

抱歉:我现在看到你的"没有使用'是'谓词"

这是一个奇怪的要求,但可以做到。

您的解决方案非常痛苦(leaf/1node1/2node2/3node3/4);我之前的解决方案变为

treeMax(leaf(M), M).

treeMax(node1(V0, N1), V0) :-
  treeMax(N1, V1),
  V1 =< V0.

treeMax(node1(V0, N1), V1) :-
  treeMax(N1, V1),
  V1 > V0.

treeMax(node2(V0, N1, N2), V0) :-
  treeMax(N1, V1),
  treeMax(N2, V2),
  V1 =< V0,
  V2 =< V0.

treeMax(node2(V0, N1, N2), V1) :-
  treeMax(N1, V1),
  treeMax(N2, V2),
  V1 >  V0,
  V2 =< V1.

treeMax(node2(V0, N1, N2), V2) :-
  treeMax(N1, V1),
  treeMax(N2, V2),
  V2 > V0,
  V2 > V1.

treeMax(node3(V0, N1, N2, N3), V0) :-
  treeMax(N1, V1),
  treeMax(N2, V2),
  treeMax(N3, V3),
  V1 =< V0,
  V2 =< V0,
  V3 =< V0.

treeMax(node3(V0, N1, N2, N3), V1) :-
  treeMax(N1, V1),
  treeMax(N2, V2),
  treeMax(N3, V3),
  V1 >  V0,
  V2 =< V1,
  V3 =< V1.

treeMax(node3(V0, N1, N2, N3), V2) :-
  treeMax(N1, V1),
  treeMax(N2, V2),
  treeMax(N3, V3),
  V2 >  V0,
  V2 >  V1,
  V3 =< V2.

treeMax(node3(V0, N1, N2, N3), V3) :-
  treeMax(N1, V1),
  treeMax(N2, V2),
  treeMax(N3, V3),
  V3 > V0,
  V3 > V1,
  V3 > V2.

如您所见,treeMax/2需要leaf/1条款,node1/2需要两个条款,node2/3需要三个条款,等等。 N+1需要nodeN/N+1个条款。

如果您使用基于单个node/2结构的解决方案以及子节点列表,那么我之前的解决方案将成为

treeMax(leaf(M), M).

treeMax(node(V0, LN), V0) :-
  treeMax(LN, V1),
  V1 =< V0.

treeMax(node(V0, LN), V1) :-
  treeMax(LN, V1),
  V1 > V0.

treeMax([N], M) :-
  treeMax(N, M).

treeMax([Nh | Nt], V0) :-
  treeMax(Nh, V0),
  treeMax(Nt, V1),
  V1 =< V0.

treeMax([Nh | Nt], V1) :-
  treeMax(Nh, V0),
  treeMax(Nt, V1),
  V1 > V0.

答案 1 :(得分:0)

这是一个比@ max66,&#34;折叠&#34;更简单的解决方案。树上的max/3谓词。简化来自使用accumulator参数来存储中间结果。

tree_max(Tree, Max) :-
    tree_max(Tree, 0, Max).

tree_max(leaf(N), Acc, Max) :-
    max(N, Acc, Max).
tree_max(node1(Value, Subtree), Acc, Max) :-
    max(Value, Acc, Acc1),
    tree_max(Subtree, Acc1, Max).
tree_max(node2(Value, Left, Right), Acc, Max) :-
    max(Value, Acc, Acc1),
    tree_max(Left, Acc1, Acc2),
    tree_max(Right, Acc2, Max).
tree_max(node3(Value, Child1, Child2, Child3), Acc, Max) :-
    max(Value, Acc, Acc1),
    tree_max(Child1, Acc1, Acc2),
    tree_max(Child2, Acc2, Acc3),
    tree_max(Child3, Acc3, Max).

max(A, B, Max) :-
    Max is max(A, B).

max/3 的这种实现使用is/2,但是(a)这是一种愚蠢的人为约束,而且(b)它很容易在没有max/3的情况下重写is/2。整个事情可以(也应该)推广到一般的tree_fold/4谓词。

一些测试:

?- tree_max(node2(1,leaf(1),node3(9,leaf(9),leaf(10),leaf(11))), Max).
Max = 11.

?- tree_max(node2(1,leaf(1),node3(9,leaf(9),leaf(10),leaf(7))), Max).
Max = 10.

?- tree_max(node2(1,leaf(1),node3(9,leaf(42),leaf(10),leaf(7))), Max).
Max = 42.

?- tree_max(node2(1,leaf(23),node3(9,leaf(3),leaf(10),leaf(7))), Max).
Max = 23.