加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

scala – BinaryTree的尾递归函数

发布时间:2020-12-16 18:06:20 所属栏目:安全 来源:网络整理
导读:我坚持实现tail递归foreach,reduce,map和toList函数,以实现二叉树的非常简单的实现. sealed trait Tree[+A]case object EmptyTree extends Tree[Nothing]case class Node[A](value: A,left: Tree[A],right: Tree[A]) extends Tree[A]object Tree { def apply
我坚持实现tail递归foreach,reduce,map和toList函数,以实现二叉树的非常简单的实现.

sealed trait Tree[+A]
case object EmptyTree extends Tree[Nothing]
case class Node[A](value: A,left: Tree[A],right: Tree[A]) extends Tree[A]

object Tree {

  def apply[A]: Tree[A] = EmptyTree
  def apply[A](value: A): Tree[A] = Node(value,EmptyTree,EmptyTree)
  def apply[A](value: A,right: Tree[A]): Tree[A] = Node(value,left,right)

  def foreach[A](tree: Tree[A],f: (A) => Unit): Unit = {
    //@tailrec
    def iter[A](tree: Tree[A],f: (A) => Unit): Unit = tree match {
      case EmptyTree =>
      case Node(v,l,r) =>
        iter(l,f)
        f(v)
        iter(r,f)
    }
    iter(tree,f)
  }

  def reduce[A](tree: Tree[A],value: A,f: (A,A) => A): A = {
    //@tailrec
    def loop(tree: Tree[A],value: A): A = tree match {
      case Node(v,r) => loop(l,f(loop(r,value),v))
      case EmptyTree => value
    }
    loop(tree,value)
  }

  def map[A,B](tree: Tree[A],f: A => B): Tree[B] = {
    //@tailrec
    def iter[A](tree: Tree[A],f: A => B): Tree[B] = tree match {
      case Node(v,r) => Node(f(v),iter(l,f),iter(r,f))
      case EmptyTree => EmptyTree
    }
    iter(tree,f)
  }

  def toList[A](t: Tree[A]): List[A] = {
    //@tailrec
    def iter[A](t: Tree[A]): List[A] = t match {
      case Node(v,r) => v :: iter(l) ::: iter(r)
      case EmptyTree => List.empty
    }
    iter(t)
  }
}

测试代码:

val tree = Tree(1,Tree(2,Tree(3),Tree(4)),Tree(5,Tree(6),Tree(7)))
Tree.foreach(tree,(x: Int) => println(x))
Tree.reduce(tree,(x: Int,y: Int) => x + y)
Tree.map(tree,(x: Int) => x + 1)
Tree.toList(tree)

我不能使用@tailrec属性,因为你可以看到,递归调用不是函数中的最后一次调用,我不知道如何重写它,因为在一个函数中有几个调用,例如

v :: iter(l) ::: iter(r)

我知道我可以使用累加器来实现内部递归函数,但是如果要多次调用我应该如何使用它?

提前致谢.

更新:

def toListRec[A](tree: Tree[A]): List[A] = {
  @tailrec
  def iter(result: List[A],todo: List[Tree[A]]): List[A] = todo match {
    case x :: tail => x match {
      case Node(v,r) => iter(v :: result,l :: r :: tail)
      case EmptyTree => iter(result,tail)
    }
    case Nil => result.reverse
  }
  iter(List.empty,List(tree))
}

解决方法

没有尾递归,(/)栈用于跟踪调用函数.如果你想使用尾递归,你必须找到一种在其他地方跟踪这些信息的方法.在更简单的“线性”情况下,例如阶乘,这种信息非常有限,并且通常可以通过使用累加器来轻松处理.

在您的情况下,问题是递归不是线性的.在一次递归调用之后,该函数不仅计算结果,而且在能够获得结果之前进行另一次递归调用.

为了在这种情况下应用尾递归,您必须明确地跟踪必须进行的剩余递归调用.一种简单的方法是简单地保留“待办事项”列表.例如:

def toList[A](t: Tree[A]): List[A] = {
  @tailrec def iter[A](todo: List[Tree[A]],r: List[A]): List[A] =
  todo match {
    case t :: rest => t match {
      case Node(v,r) => iter(l :: r :: rest,v :: r)
      case EmptyTree => iter(rest,r)
    }
    case List.empty => reverse(r)
  }
  iter(List(t),List.empty)
}

免责声明:我对scala一无所知.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读