【问题标题】:Enumerating binary trees in Prolog在 Prolog 中枚举二叉树
【发布时间】:2015-03-26 07:20:12
【问题描述】:

我正在尝试创建 Prolog 规则以在 Prolog 中以列表形式枚举“二叉树”。我是 Prolog 的新手。

一棵有 0 个节点的树是一个空列表:

[]

一棵有 1 个节点的树是:

[[],[]]

一棵有 2 个节点的树有 2 种可能性:

[[],[[],[]]]

[[[],[]],[]]

等等。

这是我的规则:

bintree(0,[]).
bintree(1,[[],[]]).
bintree(N,[Lc,Rc]) :-
  N > 1,
  bintree(N1,Lc),
  bintree(N2,Rc),
  N1 >= 0,
  N2 >= 0,
  N3 is N1+N2+1,
  N==N3.

0 和 1 的查询显然有效。对于 N = 2,它会打印一种可能性,但在我输入分号以获得另一种可能性后会出错。 N>2 的查询直接报错。错误总是一样的:

ERROR: >/2: Arguments are not sufficiently instantiated

我在一些网站上读到过这个错误,但在这里我无法弄清楚是什么导致了这个错误。

提前感谢您的帮助。

【问题讨论】:

  • 不,这会使其进入无限循环。
  • 要在 Prolog 中使用表达式比较器,所有表达式都必须完全实例化(值已知)。您收到错误是因为当您尝试N > 1N 没有任何价值。您要满足什么样的查询?你的问题一点都不清楚。
  • 它需要一对。第一个是一个正整数,它是树中的节点数。第二个是具有这么多节点的给定格式的树。前任。宾树(2,A)。应该给 A=[[],[[],[]]] ; A=[[[],[]],[]] 表示两棵有 2 个节点的二叉树。对于作为第一个参数给出的所有正整数,它应该终止。
  • 在您的子句中,表达式 bintree(N1, Lc)bintree(N2, Rc) 使用 N1N2 未实例化的变量调用。因此子序列N > 1 将在该错误消息上失败。
  • 我正在尝试满足诸如 bintree(5,X) 之类的查询类型。这将使 prolog 打印具有 5 个节点的二叉树的表示。每个空列表 [] 就像 C 中的 NULL 指针。具有 2 个元素 [L,R] 的列表是具有两个元素 L 和 R 作为子节点的节点。当用分号提示时,prolog 应该打印出具有这么多节点的 X 的所有可能的树,然后打印 false。

标签: prolog logic-programming catalan instantiation-error


【解决方案1】:

使用 CLPFD 库将有助于为生成尺寸提供简洁的解决方案。那么你就不需要一个不稳定的 (;)) integer/1 谓词,这可能是有问题的:

:- use_module(library(clpfd)).

bintree(0,[]).
bintree(1,[[],[]]).
bintree(N, [L, R]) :-
    N #> 1,
    N #= N1 + N2 + 1,
    N1 #>= 0, N2 #>= 0,
    bintree(N1, L), bintree(N2, R).

或者更简单(感谢@repeat的建议):

bintree(0,[]).
bintree(N, [L, R]) :-
    N #> 0,
    N #= N1 + N2 + 1,
    N1 #>= 0, N2 #>= 0,
    bintree(N1, L), bintree(N2, R).

?- bintree(4, L).
L = [[], [[], [[], [[], []]]]] ;
L = [[], [[], [[[], []], []]]] ;
L = [[], [[[], []], [[], []]]] ;
L = [[], [[[], [[], []]], []]] ;
L = [[], [[[[], []], []], []]] ;
L = [[[], []], [[], [[], []]]] ;
L = [[[], []], [[[], []], []]] ;
L = [[[], [[], []]], [[], []]] ;
L = [[[], [[], [[], []]]], []] ;
L = [[[], [[[], []], []]], []] ;
L = [[[[], []], []], [[], []]] ;
L = [[[[], []], [[], []]], []] ;
L = [[[[], [[], []]], []], []] ;
L = [[[[[], []], []], []], []] ;
false.

?-

CLPFD 是一种很好的声明性方式来表达数字约束。

【讨论】:

  • 谢谢。如果没有这个库,这可能只使用纯 prolog 吗?
  • 这个库纯的。尝试例如 GNU Prolog 或 B Prolog,您无需导入任何库即可使用有限域约束等基本功能。很好的解决方案,+1!
【解决方案2】:

我知道我在一年前发布了这个问题,但后来我设法在不使用任何库的情况下解决了这个问题。这是我的解决方案:

%binary tree generator
bintree(0,[]). %0 nodes - empty list
bintree(1,[[],[]]). %1 node - list containing 2 empty lists
bintree(N,[Cl,Cr]) :-
    N>=2, %check only if at least 2 nodes
    between(0,N,Nl), %let Nl be in [0,N]
    between(0,N,Nr), %similarly for Nr
    Ns is Nl+Nr+1, %total no. of nodes should add up correctly
    N==Ns, %so check for that
    bintree(Nl,Cl), %children should also be valid binary trees
    bintree(Nr,Cr).

【讨论】:

  • 这是一个非常糟糕的“生成器”。例如,尝试最一般的查询:?- bintree(N, Tree). 它产生两个解决方案,然后说:ERROR: Arguments are not sufficiently instantiated。我强烈建议您使用 CLP(FD) constraints 来推理整数,就像在 lurker 的程序中一样。这将使您的解决方案更通用,如我们对关系所期望的那样在各个方向上都可用。在您的解决方案中,措辞(“检查”)和行为都非常必要,并且您的代码只能在非常有限的一组使用模式下工作。再举一个例子,试试?- bintree(N, [_,_]).,然后比较一下!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-20
  • 1970-01-01
  • 1970-01-01
  • 2013-01-31
  • 2019-04-29
  • 1970-01-01
相关资源
最近更新 更多