Tail recursive maximum depth method of binary tree in Scala

情到浓时终转凉″ 提交于 2019-12-31 05:42:37

问题


I wrote a method to calculate the maximum depth of a binary tree.

I would like to write a tail recursive method.

I thought of using lists, but I didn't find solutions

This is my method that is not tail recursive:

def depth: Int = {

    def iter(f: FormulaWff): Int = f match {
      case Var(_) => 0
      case Not(e1) => 1 + iter(e1)
      case And(e1, e2)  => 1 + Math.max(iter(e1), iter(e2))
      case Or(e1, e2) => 1 + Math.max(iter(e1), iter(e2))
      case Implies(e1, e2) => 1 + Math.max(iter(e1), iter(e2))
    }

    iter(this)
  }

回答1:


Try

import scala.util.control.TailCalls.{TailRec, done, tailcall}

trait FormulaWff {
  def depth: Int = {
    def iter(f: FormulaWff): TailRec[Int] = {
      def hlp(e1: FormulaWff, e2: FormulaWff): TailRec[Int] = for {
        x <- tailcall(iter(e1))
        y <- tailcall(iter(e2))
      } yield 1 + Math.max(x, y)

      f match {
        case Var(_) => done(0)
        case Not(e1) => for {
          x <- tailcall(iter(e1))
        } yield 1 + x
        case And(e1, e2) => hlp(e1, e2)
        case Or(e1, e2) => hlp(e1, e2)
        case Implies(e1, e2) => hlp(e1, e2)
      }
    }

    iter(this).result
  }
}

case class Var(s: String) extends FormulaWff
case class Not(e: FormulaWff) extends FormulaWff
case class And(e1: FormulaWff, e2: FormulaWff) extends FormulaWff
case class Or(e1: FormulaWff, e2: FormulaWff) extends FormulaWff
case class Implies(e1: FormulaWff, e2: FormulaWff) extends FormulaWff

Direct solution

  sealed trait FormulaWff
  final case class Var(s: String) extends FormulaWff
  final case class Not(e: FormulaWff) extends FormulaWff
  final case class And(e1: FormulaWff, e2: FormulaWff) extends FormulaWff
  final case class Or(e1: FormulaWff, e2: FormulaWff) extends FormulaWff
  final case class Implies(e1: FormulaWff, e2: FormulaWff) extends FormulaWff

  sealed trait Result
  case object NotExpanded extends Result
  case object Expanded extends Result
  final case class Calculated(value: Int) extends Result

  final case class Frame(arg: FormulaWff, res: Result)

  def depth(f: FormulaWff): Int = step1(List(Frame(f, NotExpanded))) match {
    case Frame(arg, Calculated(res)) :: Nil => res
  }

  @tailrec
  def step1(stack: List[Frame]): List[Frame] = {
    val x = step(stack, Nil)
    x match {
      case Frame(arg, Calculated(res)) :: Nil => x
      case _ => step1(x)
    }
  }

  @tailrec
  def step(stack: List[Frame], acc: List[Frame]): List[Frame] = {
    stack match {
      case Frame(_, Calculated(res1)) :: Frame(_, Calculated(res2)) :: Frame(And(e1, e2), Expanded) :: frames =>
        step(frames, Frame(And(e1, e2), Calculated(1 + math.max(res1, res2))) :: acc)
      case Frame(_, Calculated(res1)) :: Frame(_, Calculated(res2)) :: Frame(Or(e1, e2), Expanded) :: frames =>
        step(frames, Frame(Or(e1, e2), Calculated(1 + math.max(res1, res2))) :: acc)
      case Frame(_, Calculated(res1)) :: Frame(_, Calculated(res2)) :: Frame(Implies(e1, e2), Expanded) :: frames =>
        step(frames, Frame(Implies(e1, e2), Calculated(1 + math.max(res1, res2))) :: acc)
      case Frame(_, Calculated(res1)) :: Frame(Not(e1), Expanded) :: frames =>
        step(frames, Frame(Not(e1), Calculated(1 + res1)) :: acc)
      case Frame(Var(s), _) :: frames =>
        step(frames, Frame(Var(s), Calculated(0)) :: acc)

      case Frame(Not(e1), NotExpanded) :: frames =>
        step(frames, Frame(Not(e1), Expanded) :: Frame(e1, NotExpanded) :: acc)
      case Frame(And(e1, e2), NotExpanded) :: frames =>
        step(frames, Frame(And(e1, e2), Expanded) :: Frame(e1, NotExpanded) :: Frame(e2, NotExpanded) :: acc)
      case Frame(Or(e1, e2), NotExpanded) :: frames =>
        step(frames, Frame(Or(e1, e2), Expanded) :: Frame(e1, NotExpanded) :: Frame(e2, NotExpanded) :: acc)
      case Frame(Implies(e1, e2), NotExpanded) :: frames =>
        step(frames, Frame(Implies(e1, e2), Expanded) :: Frame(e1, NotExpanded) :: Frame(e2, NotExpanded) :: acc)

      case Frame(arg, Expanded) :: frames => step(frames, Frame(arg, Expanded) :: acc)
      case Frame(arg, Calculated(res)) :: frames => step(frames, Frame(arg, Calculated(res)) :: acc)

      case Nil => acc.reverse
    }
  }

How to make tree mapping tail-recursive?



来源:https://stackoverflow.com/questions/55784859/tail-recursive-maximum-depth-method-of-binary-tree-in-scala

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!