如何在prolog中检查完整的二叉树?我有2个基本案例
1)如果是空树,则返回是
2)如果只是root,则返回yes
我被困在第三个,我不知道该怎么办。我们只允许使用1 arity:full(T)。
btree([]).
btree([H|T]):-btree(T).
btree([H|T]):-btree(H),btree(T).
full([]).
full([H]).
full([H|T]):-
任何人都可以指导我。我的想法是一棵树没有两棵非空树,那么它就是一棵完整的二叉树。
P / S:我仍然是stackoverflow的新手。如果我确实问了一些愚蠢或不正确的方式,请告诉我。我想学习如何使用stackoverflow并以正确的方式确保它。
答案 0 :(得分:3)
我首先可能会为二叉树选择不同的表示形式。在Prolog中,使用简单原子(例如nil
)作为nil节点,使用btree(Value, Left, Right)
作为树术语,通常更常规和有效。除此之外,该解决方案看起来非常像@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).
条件Depth #> 0
确保无论输入如何,深度都不会变为负值,从而有助于确保终止。
答案 1 :(得分:2)
我将假设你代表树木如下:
然后:
helper([], 0).
helper([_,L,R], H) :- H #= G + 1, helper(L, G), helper(R, G).
/* Old version: helper([_,L,R], H) :- helper(L, G), helper(R, G), H is G + 1.
* The improvement in the new version was suggested by lurker. Thanks!
*/
full(T) :- helper(T, _).
这是有效的,因为完整的二叉树可以按如下方式归纳定义:
G
的完整二叉树,它本身就是一个高度为G + 1
的完整二叉树。答案 2 :(得分:2)
好的,既然已经有一个答案没有以面值回答这个问题,那么这就是我的。它没有为the answer by @lurker添加任何东西,它只是提供了太多的评论细节和解释。它也完全避免了CLP(FD),这就是为什么我认为它应该是一个单独的答案。
您可以使用更传统的二叉树表示来启动(如@lurker所示)。空树为nil
,非空树为bt(Value, Left, Right)
,其中Value
为此节点的值,Left
和Right
为左侧,正确的子树。这是传统的表示,因为它至少具有更高的内存效率。一个“叶子”(没有子树的树)是你的原始代表:
.(Value, .([], .([], [])))
而不是:
bt(Value, nil, nil)
表示两者所需的内存量在不同的Prolog实现之间会有所不同,但我不知道如何使第一个小于而不是第二个。
然后:作为@false commented above,列表通常是物品的集合,通常具有以下属性:
使用像你这样的列表会打破最后一个约定:第一个参数是一个值,而第二个和第三个参数是树。
这并不排除使用列表来表示二叉树,但它不熟悉。
有了这个方法:后继算术是一种实际算术的愚蠢方式,但如果你想对非负整数使用模式匹配,这是非常方便的。你不能使用内置的整数类型的Prolog,比如0
或-23
或其他什么。后继算术为您提供:
0
vs s(_)
X + 1
为s(X)
。所以,你可以像这样定义你的“完整树”:
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).
s(D)
和两个D
表示第一个参数中的树比子树更深,并且两个子树的深度相同。空树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
还有一件事:要关闭圆圈,你也可以使用列表进行后继算术。只需使用[]
代替0 [_|X]
代替s(X)
。有了这个,你会得到:
full_tree(nil, []).
full_tree(bt(_, L, R), [_|D]) :-
full_tree(L, D),
full_tree(R, D).
内存效率略低,而不是s(s(s(0)))
.(_, .(_, ,(_, [])))
。然而!现在使用后继符号整数制作实际整数更容易,反之亦然:只使用length/2
。在纯Prolog中编写一个在s(s(...))
和整数之间转换的谓词的谓词并不是那么简单。我认为可以在Stackoverflow中搜索这些问题。