我是新來的Scala,有一種更好的方式來表達這個可能的最基本的知識嗎?在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))))
}
}
我是新來的Scala,有一種更好的方式來表達這個可能的最基本的知識嗎?在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))))
}
}
這裏有兩個問題。首先,你調用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
註釋是可選的,它只是確保我們確實定義一個尾遞歸函數。這樣做的好處是,如果列表非常長,我們不能產生堆棧溢出。
空列表將產生Int.MinValue,與Int.MinValues的非空列表相同。 –
@userunknown是的,這是一個任意的選擇。你可以添加'if(xs.isEmpty)throw new UnsupportedOperationException(「findMax(empty)」)'。另請參閱@ elm的三路模式匹配答案。 –
使用模式匹配的遞歸,
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
表示。我們在列表的其餘部分進行遞歸,並在每個遞歸階段比較列表頭項上的最大值。爲了使案例窮舉(做一個明確定義的函數),我們也考慮空列表(Nil
)。
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)
}
你好Rahul,你可以試着解釋你的解決方案,爲什麼它比其他答案更好。它將幫助其他人決定這個答案是否值得加價。 –
@VlastimilOvčáčík我不認爲我的方法比別人更好,我給出的回答是基於我對Scala的初始階段(我仍然試圖學習它)。現在我喜歡Chris Martin的答案,它是List(3,7,1).fold(Int.MinValue)(Math.max) –
如果你得到一個空的列表,你應該返回一個Option(Int)。 –