Prolog 序言:求和值;二叉树中叶子的形状
我有一个二叉树,对于这个二叉树,我必须加上值包含在叶子中,给出了一个类似的谓词:Prolog 序言:求和值;二叉树中叶子的形状,prolog,Prolog,我有一个二叉树,对于这个二叉树,我必须加上值包含在叶子中,给出了一个类似的谓词: sum_leafs ([Node, Left, Right], Sum). 我不明白我该怎么做,必须计算叶子的值,我应该计算节点的和,以防左边和右边都为零 [Node, nil, nil] 所以我有点像: sum_leafs([Node, Left, Right], Sum):- sum_leafs(Left, Sum_Left), sum_leafs(Right, Sum_Right),
sum_leafs ([Node, Left, Right], Sum).
我不明白我该怎么做,必须计算叶子的值,我应该计算节点的和,以防左边和右边都为零
[Node, nil, nil]
所以我有点像:
sum_leafs([Node, Left, Right], Sum):-
sum_leafs(Left, Sum_Left),
sum_leafs(Right, Sum_Right),
Sum is (Sum_Left + Sum_Right).
我的尝试:
sum_leafs(nil, 0).
sum_leafs([Node, nil, nil], Node).
sum_leafs([_, Left, Right], Sum):-
sum_leafs(Left, Sum_Left),
sum_leafs(Right, Sum_Right),
Sum is (Sum_Left + Sum_Right).
我怎样才能做到这一点
谢谢你我已经这样做了:
sum_leafs(nil, 0).
sum_leafs([Node, nil, nil], Node).
sum_leafs([_, Left, Right], Sum):-
sum_leafs(Left, Sum_Left),
sum_leafs(Right, Sum_Right),
Sum is (Sum_Left + Sum_Right).
对于二叉树来说,列表是一种糟糕的表示形式。让我们开始改变这一点:
- 空树:
nil
- 非空树:
t(左、值、右)
sum_leaves(Tree, Sum) :-
sum_leaves(Tree, 0, Sum).
sum_leaves(nil, Sum, Sum).
sum_leaves(t(nil,Value,nil), Sum0, Sum) :-
!,
Sum is Sum0 + Value.
sum_leaves(t(Left,_,Right), Sum0, Sum) :-
sum_leaves(Left, Sum0, Sum1),
sum_leaves(Right, Sum1, Sum).
但这第一个版本不是尾部递归的。我们可以改进它:
sum_leaves(Tree, Sum) :-
sum_leaves(Tree, 0, Sum).
sum_leaves(nil, Sum, Sum).
sum_leaves(t(nil,Value,nil), Sum0, Sum) :-
!,
Sum is Sum0 + Value.
sum_leaves(t(Left,_,Right), Sum0, Sum) :-
sum_leaves(Left, LeftSum),
Sum1 is Sum0 + LeftSum,
sum_leaves(Right, Sum1, Sum).
两件事:命名有点混乱,因为“节点”不是真正的节点,而是节点的“值”。更重要的是:这段代码有一些不需要的“替代解决方案”。如果您点击了一个叶子(一个有两个
nil
子项的节点),那么第二个子句适用,但第三个子句也适用。第二个解决方案总是给出0,而不是预期的“叶上和”。为了避免这种情况,如果第二个子句与之匹配,请在正文中插入一个cut:sum\u leafs([Value,nil,nil],Value]:-
或在第三个子句中添加一个保护:(左\==nil;右\==nil)
。稍等保罗。因此,两个版本都在将值累加到Sum0
中,以得到Sum
。第一个版本不是尾部递归的,因为我们在左和右子代上有双重递归下降(但是编译器可能仍然能够沿着右子代在递归下降上构建一个循环)。但第二个版本真的比第一个版本“更”具有尾部递归性吗?在所有调用之后,sum_leaves(Left,Sum0,Sum1)
就隐藏在对sum_leaves(Left,LeftSum)
的中间调用后面,该调用最后只在sum_leaves(Left,0,LeftSum)
处结束,在SWI Prolog中没有太多变化,我们可以使用sum\u leaves/3
最后一句中的谓词prolog\u current\u frame/1
检查TCO:sum\u leaves(t(左,右),Sum0,sum):-prolog\u current\u frame(frame),writeln(frame),…
。通过这种修改,查询?-sum_leaves(t(t(t(t(t(t(nil,1,nil)))产生3倍相同的帧编号(=堆栈没有增长),但查询?-sum_leaves(t(t(t(nil,1,nil)),2,nil),3,nil),4,nil),S)。
产生3个不同的帧编号(=堆栈确实增长)。