【问题标题】:Recursion to enumerate an infinite tree left to right递归枚举从左到右的无限树
【发布时间】:2016-06-24 05:20:26
【问题描述】:

我有一棵树表示为

type LazyTree<'T> =
    | LazyBranch of 'T * ('T LazyTree list Lazy) 

我想为每个节点分配一个编号n,从左到右计数。

更正式的

已编辑:

对于节点a,如果a 没有子节点,则h(a)=0

对于具有父节点ph(a)=h(p+1) 的节点a

对于没有父节点的节点aL(a) 是一个空集。

对于具有父节点的节点 aL(a) 是所有节点的集合,其中对于每个节点 i,从根到它的路径不包含 a

对于节点aS(a)L(a) 的所有元素,其中对于每个元素i 持有h(i)&lt;=h(a)

我需要将每个节点a 的值替换为S(a) 的大小

我无法为我的问题想出一个不涉及副作用的解决方案。

我的函数应该返回一棵树。

它的节点依赖于左兄弟节点。所以,函数应该得到一个'T LazyTree Option作为参数。

但是它最左边的孩子依赖于依赖于我们的最右边的兄弟姐妹。看来,我们有一个无限循环。

我不是在问如何在有限树上解决它。


我不是在问一个抽象的概念。 以下是我如何从另一棵树返回一棵无限树:

type LazyTree<'T> =
    | LazyBranch of 'T * ('T LazyTree list Lazy)
with
    member this.Item = match this with LazyBranch(item,_) -> item
    member this.Children = match this with LazyBranch(_,children) -> children
member this.Map func =
        let children =
            lazy
            (
                this.Children.Force()
                |> List.map (fun child -> child.Map func)
            )
        LazyBranch(func this.Item, children)

【问题讨论】:

  • 您提出了哪些解决方案,有哪些副作用?
  • 我想出了一个有限树的解决方案。我只是将它作为一个列表遍历,然后从该列表中恢复树结构。不会在那里工作。我没有尝试用副作用解决它。
  • 如果您投票结束,请在 cmets 中告知,如果您能解决它,至少不要提出解决方案。
  • 我想我可以解决它,但不能用递归。我在写想法,因为目前还不清楚你到底想达到什么目的。从一个角度来看,您以分层方式将数字分配给节点,从另一个角度来看,您告诉该函数应该返回一棵树,而无需解释您期望什么树。
  • 感谢您注意到我的“正式”描述中的错误。我纠正了它。我仍然认为,这个问题确实属于这个网站。

标签: algorithm recursion tree f# purely-functional


【解决方案1】:

您说得对,这里所需的递归结构有些复杂。这是一种方法。我将使用一个辅助函数number,它对给定紧接在前面的编号树以及该列表和该列表中第一棵树的第一个子节点之间的所有编号树的树列表进行编号。那么,如果列表非空:

  1. 所需列表的尾部可以递归计算,将要计算的结果传递给列表头部作为前一棵树,并将该列表的子项附加到“中间”列表,因为它们位于第二个元素的子元素之前。
  2. 与列表头对应的编号树只取其前身之后的下一个数字作为其值。该节点的子节点也可以递归计算。考虑在对应于头部的一棵树及其子树之间的所有编号树;这与现有的中间序列略有不同,后者只有在此列表尾部之后开始的元素,因此我们需要将步骤 1 中计算的列表尾部附加到现有的“中间”列表前面.如果有这样的节点,则紧接在头节点的第一个子节点之前的节点只是这个新的中间序列的最后一个元素,或者如果没有,则为编号树本身(如果在 a 之间没有节点,则可能发生这种情况)节点及其子节点)。子节点和他们的第一个子节点之间的节点只是这个新的中间序列的子节点。

对不起,如果这个描述没有启发性,但画一张图片可能会有所帮助。无论如何,这是相应的代码:

// These help with type inference
let value (LazyBranch(v,_)) = v
let children (LazyBranch(_,ts)) = ts.Value

let numberedTree =
    let rec number prev between = function
    | [] -> []
    | t::ts ->
        let rec rest = number first (seq { yield! between; yield! children first }) ts
        and first =
            let between' = seq { yield! rest; yield! between }
            LazyBranch(value prev + 1, lazy (children t |> number (defaultArg (Seq.tryLast between') first) (between' |> Seq.collect children)))
        first::rest
    fun t ->
        let rec result = LazyBranch(0, lazy number result [] (children t))
        result

【讨论】:

    【解决方案2】:

    不可能分配这样的数字,因为它需要(非惰性)遍历无限树。 你需要的是广度优先遍历,就像这个伪代码一样:

    let traverse (node:LazyTree<'T>) =
         let q = System.Collections.Generic.Queue()
         q.Enqueue node
         let mutable i = 0
         while 0 < q.Count do // always TRUE
            let node = q.Dequeue ()
            printfn "Node #%i: %A" i node.Map
            i <- i + 1
            for child in node.Children.Force() do
                q.Enqueue child
    

    【讨论】:

    • 我可以懒惰地在纸上制作这样的树,所以可以编程。这段代码不会产生任何树,所以它是无关紧要的。此外,也可以用惰性代码替换它:pastebin.com/FwnWnjCt
    猜你喜欢
    • 2014-07-13
    • 1970-01-01
    • 2014-06-26
    • 1970-01-01
    • 1970-01-01
    • 2020-12-22
    • 2014-06-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多