Prolog 如何检查二叉树是否完整?

Prolog 如何检查二叉树是否完整?,prolog,binary-tree,Prolog,Binary Tree,如何在prolog中检查完整的二叉树?我有两个基本情况 1如果是空树,则返回yes 2如果只是根目录,则返回yes 我被第三个卡住了,我不知道该怎么办。我们只允许使用1个arity:fullT btree([]). btree([H|T]):-btree(T). btree([H|T]):-btree(H),btree(T). full([]). full([H]). full([H|T]):- 任何人都可以指引我。我的想法是一棵树没有两棵非空树,那么它就是一棵完整的二叉树

如何在prolog中检查完整的二叉树?我有两个基本情况

1如果是空树,则返回yes

2如果只是根目录,则返回yes

我被第三个卡住了,我不知道该怎么办。我们只允许使用1个arity:fullT

btree([]).
btree([H|T]):-btree(T).
btree([H|T]):-btree(H),btree(T).

full([]).
full([H]).
full([H|T]):-        
任何人都可以指引我。我的想法是一棵树没有两棵非空树,那么它就是一棵完整的二叉树


附言:我对stackoverflow还是个新手。如果我问了一些愚蠢或不恰当的问题,请告诉我。我想学习如何使用stackoverflow,并以正确的方式确保它。

我将假设您表示树,如下所示:

?- full_btree(nil).
true.

?- full_btree(bt(x, nil, nil)).
true.

?- full_btree(bt(x, bt(y, nil, nil), nil)).
false.

?- full_btree(bt(x, bt(y, nil, nil), bt(z, nil, nil))).
true.

?- full_btree(T), numbervars(T).
T = nil ;
T = bt(A, nil, nil) ;
T = bt(A, bt(B, nil, nil), bt(C, nil, nil)) ;
T = bt(A, bt(B, bt(C, nil, nil), bt(D, nil, nil)), bt(E, bt(F, nil, nil), bt(G, nil, nil))) . % and so on
叶子是一个空列表。 非叶节点是一个三元素列表,其最后两个元素是子树。 然后:

这是因为完整的二叉树可以归纳定义如下:

?- full_btree(nil).
true.

?- full_btree(bt(x, nil, nil)).
true.

?- full_btree(bt(x, bt(y, nil, nil), nil)).
false.

?- full_btree(bt(x, bt(y, nil, nil), bt(z, nil, nil))).
true.

?- full_btree(T), numbervars(T).
T = nil ;
T = bt(A, nil, nil) ;
T = bt(A, bt(B, nil, nil), bt(C, nil, nil)) ;
T = bt(A, bt(B, bt(C, nil, nil), bt(D, nil, nil)), bt(E, bt(F, nil, nil), bt(G, nil, nil))) . % and so on
叶节点是高度为0的完整二叉树。 其子节点都是高度为G的完全二叉树的非叶节点本身就是高度为G+1的完全二叉树。
我可能会首先为二叉树选择不同的表示形式。在Prolog中,使用简单的原子(如nil)作为nil节点,以及类似于btreeValue的东西(如左、右)作为树项,通常更为常规和高效。除此之外,解决方案与@pyon建议的非常相似

% full_btree succeeds if `Tree` is a full binary tree

full_btree(Tree) :-
    full_btree(Tree, _).

full_btree(nil, 0).
full_btree(b(_, LeftTree, RightTree), Depth) :-
    Depth #> 0,
    SubDepth #= Depth - 1,
    full_btree(LeftTree, SubDepth),
    full_btree(RightTree, SubDepth).

条件深度>0确保,无论输入如何,深度都不会变为负值,从而有助于确保终止。

好的,因为已经有一个答案不能从表面上回答问题,这是我的答案。它没有增加太多的内容,只是提供了太多的细节和解释,难以评论。它还完全避免了CLPFD,这就是为什么我觉得它应该是一个单独的答案

您可以像@lowerer一样使用更传统的二叉树表示法。空树是nil,非空树是btValue,Left,Right,其中Value是这个节点上的值,Left和Right是Left和Right子树。这是传统的表示法,因为它至少更节省内存。在原始表示中,没有子树的树的叶子是:

.(Value, .([], .([], [])))
而不是:

bt(Value, nil, nil)
在不同的Prolog实现中,表示这两个函数所需的内存量是不同的,但我不知道如何使第一个函数小于第二个函数

然后:作为一个例子,列表通常是一个事物的集合,通常具有以下属性:

收藏中不能有任何东西,也不能有任何数量的东西; 事物的顺序很重要; 所有的东西都是一样的。 像您这样使用列表打破了上一个约定:第一个参数是值,而第二个和第三个参数是树

这并不排除使用列表表示二叉树,但并不熟悉

有了这一点:后继算法是执行实际算法的一种愚蠢的方法,但是如果您想对非负整数使用模式匹配,它是非常方便的。您不能使用内置的整型Prolog,比如0或-23之类的。后续算术为您提供:

结构上不同于所有正整数的零:0对s_ 加法和减法是通过模式匹配完成的,两者都是通过相同的操作完成的:X+1是sX。 负数是不可能的 因此,您可以这样定义完整的树:

full_btree(T) :-
    full_btree(T, _).

full_btree(nil, 0).
full_btree(bt(_, L, R), s(D)) :-
    full_btree(L, D),
    full_btree(R, D).
sD和两个Ds表示第一个参数中的树比子树深一层,并且两个子树的深度相同。空树nil的深度为0,如full_btree/2的第一个子句中所定义

这项工作如下:

?- full_btree(nil).
true.

?- full_btree(bt(x, nil, nil)).
true.

?- full_btree(bt(x, bt(y, nil, nil), nil)).
false.

?- full_btree(bt(x, bt(y, nil, nil), bt(z, nil, nil))).
true.

?- full_btree(T), numbervars(T).
T = nil ;
T = bt(A, nil, nil) ;
T = bt(A, bt(B, nil, nil), bt(C, nil, nil)) ;
T = bt(A, bt(B, bt(C, nil, nil), bt(D, nil, nil)), bt(E, bt(F, nil, nil), bt(G, nil, nil))) . % and so on
还有一件事:为了结束这个循环,你也可以对列表进行后续运算。对于sX,只需使用[]而不是0和[|X]。有了这个,您将:

full_tree(nil, []).
full_tree(bt(_, L, R), [_|D]) :-
    full_tree(L, D),
    full_tree(R, D).

这会稍微降低内存效率,而不是您可能需要的sss0。然而现在,从后继符号整数中生成实际整数要容易得多,反之亦然:只需使用length/2即可。正在编写在ss之间转换的谓词。。。在纯Prolog中双向工作的整数并不是那么简单。我认为可以在Stackoverflow中搜索此类问题。

制作一个谓词helperT,H,用于测试T是否是高度为H的完整树。然后定义fullT:-helperT,H。对不起,我可以从您那里得到一些示例吗?不是答案,只是一些例子,可以给我一些想法做什么。可以吗?我怎么做?我现在想的是,如果其中一棵树缺少一个孩子,那么它就不是满的,但是,我不知道该怎么做,因为我缺乏关于prolog的示例或知识@pyon P/S:对不起,我猜我不小心删除了你的评论……你使用的是什么二叉树的具体表示法?根据你的问题,我无法判断一棵树是什么样子。我只看到简单的列表。您是否已确定有效的树是什么样子的数据报告
宣判?如果没有它,就无法编写谓词。虽然这基本上是可行的,但是有几个注释。您应该使用更具描述性的谓词和变量名。G和H表示不包含字母G的深度。深度和亚深度之类的东西会更好。full_tree比full更不通用。辅助对象也可以称为full_tree,因为arity不同,Prolog可以区分full_tree/1和full_tree/2。此外,这在一般情况下不起作用,因为fullT查询将导致堆栈溢出。在递归helper/2调用之前使用Depth=SubDepth+1。@潜伏者:我选择H作为“高度”,选择G是因为它是字母表中H的前身。至于全名,它似乎是问题规范的一部分,所以我没有自己更改它。我同意完整的树会更好。在这种情况下,H0,H1等更容易掌握。@潜伏者:你为什么不自己写答案呢?将需要深度>=0,但缺少.H>=1!这将改善termination properties.sX单独用于不同表示的性能。但是。。。与其说是效率,不如说是惯例:列表应该包含相似的元素,并且可能是空的,或者长度与3不同。@false同意,但我也听说它比列表更有效,或者不是?这种表示法更节省内存,没有任何明显的缺点。将bx、nil、nil与.x、[]、[]、[]、[].@Boris:对!然而,sX被称为使用sX的+1.sX。这将在很长一段时间内保持最快的版本。是的,因为性能原因,后继算法!