我是Scala的新手,有更好的方法可以用最基本的知识表达这一点吗?
def findMax(xs: List[Int]): Int = {
xs match {
case x :: tail => (if (tail.length==0) x else (if(x>findMax(tail)) x else (findMax(tail))))
}
}
答案 0 :(得分:10)
这是两个问题。首先,你调用tail.length
这是一个O(N)
的操作,所以在最坏的情况下,这将花费你N * N步,其中N是序列的长度。第二个是你的函数不是尾递归 - 你将findMax
调用从外部嵌入到内部“。
编写正确的递归函数的通常策略是
Nil
或非空列表head :: tail
。这解决了您的第一个问题。这给出了:
import scala.annotation.tailrec
@tailrec
def findMax(xs: List[Int], max: Int): Int = xs match {
case head :: tail => findMax(tail, if (head > max) head else max)
case Nil => max
}
val z = util.Random.shuffle(1 to 100 toList)
assert(findMax(z, Int.MinValue) == 100)
如果您不想公开这个附加参数,可以编写一个辅助内部函数。
def findMax(xs: List[Int]): Int = {
@tailrec
def loop(ys: List[Int], max: Int): Int = ys match {
case head :: tail => loop(tail, if (head > max) head else max)
case Nil => max
}
loop(xs, Int.MinValue)
}
val z = util.Random.shuffle(1 to 100 toList)
assert(findMax(z) == 100)
为简单起见,如果列表为空,则返回Int.MinValue
。更好的解决方案可能是为这种情况抛出异常。
这里的@tailrec
注释是可选的,它只是确保我们确实定义了一个尾递归函数。这样做的好处是,如果列表非常长,我们就不会产生堆栈溢出。
答案 1 :(得分:5)
每当您将集合缩减为单个值时,请考虑使用fold函数之一而不是显式递归。
List(3,7,1).fold(Int.MinValue)(Math.max)
// 7
答案 2 :(得分:2)
即使我也是Scala的新手(尽管我已经进入了Haskell!)。
我对此的尝试如下:
请注意,我假设一个非空列表,因为空列表的最大值没有意义。
我首先定义一个辅助方法,它只返回最多2个数字。
def maxOf2 (x:Int, y:Int): Int = {
if (x >= y) x
else y
}
有了这个简单的功能,我们可以建立一个递归函数来找到最大值的' max'如下:
def findMax(xs: List[Int]): Int = {
if (xs.tail.isEmpty)
xs.head
else
maxOf2(xs.head, findMax(xs.tail))
}
我认为这是一个非常明确的方式(虽然不是高效的#);这样做。
我想让递归的概念变得明显。
希望这有帮助!
答案 3 :(得分:1)
详细说明@ fritz的答案。如果您传递一个空列表,它将抛出java.lang.UnsupportedOperationException:空列表的尾巴
因此,在保持算法完好无损的情况下,我进行了以下调整:
def max(xs: List[Int]): Int = {
def maxOfTwo(x: Int, y: Int): Int = {
if (x >= y) x else y
}
if (xs.isEmpty) throw new UnsupportedOperationException("What man?")
else if (xs.size == 1) xs.head
else maxOfTwo(xs.head, max(xs.tail))
}
@ fritz谢谢您的回答
答案 4 :(得分:0)
使用模式匹配递归,
def top(xs: List[Int]): Int = xs match {
case Nil => sys.error("no max in empty list")
case x :: Nil => x
case x :: xs => math.max(x, top(xs))
}
模式匹配用于将列表分解为头部和休息。单个元素列表用x :: Nil
表示。我们递归列表的其余部分,并在每个递归阶段比较列表的head项目的最大值。为了使案例详尽无遗(以制定明确定义的函数),我们还考虑空列表(Nil
)。
答案 5 :(得分:0)
def maxl(xl: List[Int]): Int = {
if ( (xl.head > xl.tail.head) && (xl.tail.length >= 1) )
return xl.head
else
if(xl.tail.length == 1)
xl.tail.head
else
maxl(xl.tail)
}