这是一个基本的解决方案。它不使用惰性 val 或除List
、Option
和之外的任何数据结构Either
。您可能会因此更容易理解,或者因为冗长而更难理解。
我Tree
这样定义,只是为了让事情更容易。
sealed trait Tree[+T]
case class Node[+T](data: T, left: Tree[T], right: Tree[T]) extends Tree[T]
case object Empty extends Tree[Nothing]
另外,Array[Int]
我使用的是 a List[Option[T]]
(其中T
是makeTree
方法的类型参数),而不是 a。Some
意味着有一个节点,None
就像-1
在你的代码中一样。这更惯用,也适用于Int
.
做这种广度优先的事情是你需要不断地将输入列表传递给孩子们。首先,您尝试制作左孩子,然后在完成后,您尝试制作右孩子。然后你尝试让左孩子的孩子,然后是右孩子的孩子,然后是他们的孩子,等等。
在不使用的情况下处理此问题的一种方法var
是获取包含序列化二叉树的输入列表并查看列表的头部是什么。如果它是 a None
,我们可以只返回一个Empty
,因为我们知道它是树的末端。但是,如果是 a Some
,我们还不能返回树,但我们可以返回另一个函数,该函数接受下一轮输入并返回树。
由于可以返回 2 种不同的类型,因此这些函数的类型为List[Option[T]] => Either[List[Option[T]] => ThisFunctionsType, Tree[T]]
. 由于函数可能返回相同类型的另一个函数,我们必须定义一个可以返回自身的新类型:
trait RecFun[T] extends ((List[Option[T]]) => (List[Option[T]], Either[RecFun[T], Tree[T]]))
它的原因List[Option[T]] => (List[Option[T]], Either[RecFun[T], Tree[T]])
不仅仅是List[Option[T]] => Either[RecFun[T], Tree[T]]
因为如果一个孩子变成了列表中间某处的叶子,我们仍然需要继续,所以返回的元组的第一个元素包含处理后的列表的其余部分。
现在我们可以定义它了。该helper
函数是这样的,只要RecFun
返回 a Left[RecFun]
,它就会继续将剩余的输入传递给该函数。
def makeTree[T](list: List[Option[T]]): Tree[T] = {
def helper(f: RecFun[T], l: List[Option[T]]): Tree[T] =
f(l) match {
case (_, Right(tree)) => tree
case (next, Left(f)) => helper(f, next)
}
list match {
case Some(x) :: tail => helper(createRec(x), tail)
case _ => Empty
}
}
def createRec[T](data: T): RecFun[T] = {
case None :: Nil | Nil => (Nil, Right(Node(data, Empty, Empty)))
case Some(l) :: Nil => (Nil, Right(Node(data, Node(l, Empty, Empty), Empty)))
case lo :: ro :: rest =>
(rest, (lo, ro) match {
case (Some(l), Some(r)) =>
Left(waitForChildren(data, createRec(l), createRec(r)))
case (Some(l), None) =>
Left(waitForChild(Node(data, _, Empty), createRec(l)))
case (None, Some(r)) =>
Left(waitForChild(Node(data, Empty, _), createRec(r)))
case (None, None) => Right(Node(data, Empty, Empty))
})
}
def waitForChildren[T](data: T, leftF: RecFun[T], rightF: RecFun[T]): RecFun[T] =
input => {
val (next, res) = leftF(input)
res match {
case Right(tree) =>
(next, Left(waitForChild(Node(data, tree, _), rightF)))
case Left(leftF2) => {
val (next2, res2) = rightF(next)
(next2, Left(res2 match {
case Right(tree) => waitForChild(Node(data, _, tree), leftF2)
case Left(rightF2) => waitForChildren(data, leftF2, rightF2)
}))
}
}
}
def waitForChild[T](ctor: Tree[T] => Node[T], f: RecFun[T]): RecFun[T] =
input => {
val (next, res) = f(input)
(next, res match {
case Right(tree) => Right(ctor(tree))
case Left(recFun) => Left(waitForChild(ctor, recFun))
})
}
斯卡斯蒂