【问题标题】:Binary tree folding二叉树折叠
【发布时间】:2016-09-27 06:35:29
【问题描述】:

我得到了以下二叉树的定义

abstract class Tree[+A]
case class Leaf[A](value: A) extends Tree[A]
case class Node[A](value: A, left: Tree[A], right: Tree[A]) extends Tree[A]

还有下面的函数

def fold_tree[A,B](f1: A => B)(f2: (A, B, B) => B)(t: Tree[A]): B = t match {
    case Leaf(value) => f1(value)
    case Node(value, l, r) => f2(value, fold_tree(f1)(f2)(l), fold_tree(f1)(f2)(r)) //post order
  }

我被要求使用 fold 方法返回树中最右边的值。这将如何工作?我不确定我是否完全理解折叠,但我认为折叠的目的是对树中的每个元素进行一些操作。如何使用它只返回树的最右边的值?

我也不确定如何调用该方法。我不断遇到未指定参数类型的问题。有人可以告诉我调用这个 fold_tree 方法的正确方法吗?

【问题讨论】:

  • 你能告诉我们你到目前为止所做的尝试吗?
  • 当然。我很迷茫。我首先想尝试调用该函数并查看结果。我对 scala 很陌生,我不确定如何输入正确的变量/类型。我已经搞砸了 fold_tree[A,Int]( t => 1)(t,t,t => 1)(t) 之类的东西,只是为了看看我是否可以让该方法完全运行并以某种方式返回一个但我不认为我理解正确。
  • 其实我可能已经想好怎么做了。你能确认/否认这个推理吗? fold_tree[A,A]( t => t)((t,x,z) => z)(t) 这应该可以工作,因为该方法接受类型 A 并返回类型 A。它告诉方法我们是否在一片叶子,只返回叶子值。如果我们有一个节点和一棵左树和一棵右树,则返回右树的值。对吗?
  • 是的!将其发布为答案并接受它!情侣风格的 cmets:t => t 定义为 identity,通常最好将下划线放在您不会使用的参数位置:(_,_,z) => z
  • 您是否打算在 SO 上发布您在作业中遇到的所有问题?

标签: scala tree fold


【解决方案1】:

这将如何工作?我不确定我是否完全理解 fold

你的foldTree 方法正在做的是递归地遍历树,将自身应用于它在途中遇到的每个NodeLeaf。该方法还有两个类型参数需要应用,AB,具体取决于提供的树的类型。

为了这个例子,假设我们有一个 Tree[Int] 定义如下:

val n = Node(1, Leaf(2), Node(3, Leaf(5), Node(4, Leaf(42), Leaf(50))))

这棵树的结构如下所示:

我们想要获得最正确的值,即 50。为了使用当前实现的 foldTree 来做到这一点,我们需要为其提供两种方法:

  1. f1: A => B:给定一个A,投影一个B
  2. f2: (A, B, B) => B:给定一个A 和两个B 值,投影一个B

我们可以看到f1 应用于Leaff2 应用于Node(因此为每种方法提供的元素数量不同)。所以这给了我们一个提示,我们提供给foldTree 的函数将分别应用于每个函数。

鉴于我们的树,包含了这些知识:

val n = Node(1, Leaf(2), Node(3, Leaf(55), Node(4, Leaf(42), Leaf(50))))

我们提供以下方法:

println(foldTree[Int, Int](identity)((x, y, z) => z)(n))

意思如下:

  1. 如果我们遇到Leaf 节点并对其进行映射(通过在其上应用f1),我们只想提取它的值。
  2. 当遇到Node 元素(并对其应用f2)时,我们希望采用最右边的元素,该元素在我们的方法中由第三个元素z 投影。

运行它,产生预期的结果:50

如果我们想对任何A 进行通用扩展,我们可以说:

def extractRightmostValue[A](tree: Tree[A]) =
  foldTree[A, A](identity)((x, y, z) => z)(tree)

【讨论】:

  • 谢谢!只是为了确认一下,我们在这里说 [Int, Int] 的原因是因为这个二叉树只包含整数,对吗?我在我的代码中使用 [A,A] 并且有效。那是因为树/节点/叶子和函数都使用A吗?
  • @Vandexel 是的,没错。如果我创建一个Tree[A],这意味着我可以应用任何A。在这种情况下,我选择将其应用于Tree[Int]。但是,如果您想将其通用地应用于任何A,那么您可以照常进行。
  • 我在理解另一个问题时遇到了一些麻烦。这个要求我返回一棵树的镜像,其中左右子树递归翻转。所以 Node(4,Leaf(1),Leaf(2)) 会产生 Node(4,Leaf(2),Leaf(1)) 例如。我不确定为什么这不起作用: fold_tree[A,A](t => t)((x,y,z) => (x,z,y)(t) 对我来说,这说:需要类型 A 并返回类型 A。我们传入一棵树,它表示如果它是叶子,则返回自身,它是一个节点,返回自身并翻转 lt 和 rt。但这给了我类型不匹配:必需的 A,找到(A ,A,A)。这是什么意思?我怎么会想到这个错误?
  • 我将在另一个问题中问这个问题以使其更清楚
【解决方案2】:
fold_tree[A,A](identity)((_,_,z) => z)(t)

这应该可以工作,因为该方法接受类型 A 并返回类型 A。它告诉方法我们是否在叶子处,只需返回叶子值。如果我们有一个节点和一棵左树和一棵右树,则返回右树的值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-04
    • 2013-07-20
    • 2021-05-04
    • 1970-01-01
    • 2021-09-17
    • 1970-01-01
    • 2018-05-14
    • 1970-01-01
    相关资源
    最近更新 更多