Sie sind zwei Probleme hier. Zuerst rufen Sie tail.length
an, was eine Operation der Bestellung O(N)
ist, also kostet Sie das im schlimmsten Fall N * N Schritte, wobei N die Länge der Sequenz ist. Die zweite ist, dass Ihre Funktion nicht tail-rekursiv ist - Sie verschachteln die findMax
Aufrufe "von außen nach innen".
Die übliche Strategie die richtige rekursive Funktion zu schreiben, ist
- über jedes mögliche Muster Fall zu denken: hier gibt es entweder die leere Liste
Nil
oder die nicht-leere Liste head :: tail
haben. Dies löst dein erstes Problem.
- , um das temporäre Ergebnis (hier die aktuelle Schätzung des Maximalwerts) als weiteres Argument der Funktion mitzuführen. Dies löst Ihr zweites Problem.
Das gibt:
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)
Wenn Sie das zusätzliche Argument nicht verfügbar machen möchten, können Sie eine innere Hilfsfunktion schreiben.
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)
Zur Vereinfachung kehren wir Int.MinValue
, wenn die Liste leer ist. Eine bessere Lösung könnte darin bestehen, eine Ausnahme für diesen Fall auszulösen.
Die @tailrec
Anmerkung hier optional ist, versichert es einfach, dass wir in der Tat einen Schwanz rekursive Funktion definiert. Dies hat den Vorteil, dass wir keinen Stack-Overflow erzeugen können, wenn die Liste extrem lang ist.
Sie sollten eine Option (Int) zurückgeben, falls Sie eine leere Liste erhalten. –