Recursion 计算树中的节点数

Recursion 计算树中的节点数,recursion,f#,tree,continuations,Recursion,F#,Tree,Continuations,与f#战斗-战斗是在树的领域-特别是计算节点的数量。这是我真正感兴趣的,因为我想最终用F#编写的程序涉及到多向树,不幸的是,它的开始有点麻烦-我希望您能够提供帮助 99 f#系列的问题61要求计算二叉树的叶子数。解决方案(如下所示)计算节点数,但我的问题是无法理解 双递归如何在左循环中工作(有趣的lacc->右循环..) cont(branchF x lacc racc)是什么,我的印象是cont是“abc”函数,但这只需要两个参数 循环t idid是unit类型-我看不出这是怎么暗示的 基

与f#战斗-战斗是在树的领域-特别是计算节点的数量。这是我真正感兴趣的,因为我想最终用F#编写的程序涉及到多向树,不幸的是,它的开始有点麻烦-我希望您能够提供帮助

99 f#系列的问题61要求计算二叉树的叶子数。解决方案(如下所示)计算节点数,但我的问题是无法理解

  • 双递归如何在左循环中工作(有趣的lacc->右循环..)

  • cont(branchF x lacc racc)是什么,我的印象是cont是“abc”函数,但这只需要两个参数

  • 循环t id
    id是unit类型-我看不出这是怎么暗示的

基本上不理解这一点,或者它在树中的顺序(调试和逐步执行证明没有帮助),如果有更简单的示例、预读建议等,请指导我

非常感谢您的帮助,问题的解决方案代码如下:

干杯

运输署


顾名思义,
foldTree
定义了自定义
类型上的折叠函数

定义
折叠树的简单方法可以是:

let rec foldTreeNaive accFun init = function
    | Empty -> init
    | Branch (x, left, right) ->
        let lacc = foldTreeNaive accFun init left
        let racc = foldTreeNaive accFun init right
        accFun x lacc racc
此函数的问题在于,如果折叠的树很深,它可能会进行非常深的递归调用,因为在调用累加器函数之前,必须完成节点的递归调用。例如,以下情况会导致堆栈溢出异常:

let unbalanced = [1..100000] |> List.fold (fun t i -> Branch(i, t, Empty)) Empty
let nodeCount = foldTreeNaive (fun _ lc rc -> lc + rc + 1) 0 unbalanced
避免此类堆栈溢出的通常方法是使函数尾部递归,但是在这种情况下这似乎是不可能的,因为要进行两个递归调用,而不是折叠列表时所需的一个递归调用

foldTree
是使用本地
loop
函数定义的。这个函数很有趣,因为它是使用定义的。在CPS中,每个函数接受一个附加的“延续”函数,该函数传递计算结果,并负责决定接下来发生什么。请注意,
loop
是尾部递归的,因此避免了
foldTreeNaive
的溢出问题

循环
功能的类型为:

Tree<'a> -> ('b -> 'c) -> 'c
功能。这个continuation所做的是对右子树进行递归调用,传递另一个continuation以接收该折叠的结果。调用该延续时,左子树和右子树的结果在
lacc
racc
中可用。此时,可以使用当前节点的值以及左右子树的结果调用节点的累积函数。然后将此函数的结果传递给传递给
循环的原始延续

然后,
foldTree
函数在以下行中调用
loop
函数:

loop t id
这里,
id
是将接收树的根节点的折叠结果的延续。由于这是所需的值,
id
只返回其参数而不进行修改


你可能也会发现这很有用。

我不知道我在写解决方案时是怎么想的,但是Lee是wright,Counleef中的“如果”没有任何作用。解决方案应该是让counLeaves tree=tree |>foldTree(fun ; lc rc->1+lc+rc)0。如果你想了解更多关于褶皱和连续体的知识。我在此推荐Brian McNamara的关于变形的系列文章。这就是我得到fodlTree函数的地方。嗨,塞萨尔,我只是想说谢谢你发布99个问题系列-非常棒的学习工具-特别是多重解决方案。干杯由于没有人回答您关于id的问题,“id”是身份操作员。对于相同的效果,您可以将id替换为(funx->x)。请看这里:另外,这段代码有严重的错误-我创建了一个简单的4节点树,它告诉我大小是32!一旦我弄清楚了所有的细微差别,我会发布一个正确的实现(我正在工作)。
(fun lacc -> 
    loop right (fun racc ->
        cont (branchF x lacc racc))
loop t id