Kotlin Academy · Pelajaran

Fungsi tailrec

Optimumkan rekursi

Pelajaran 3 daripada 413 langkah

Fungsi tailrec ialah pelajaran Kotlin Academy percuma di CoddyKit. Ini ialah pelajaran 3 daripada 4. Sebanyak 3 pelajaran dalam laluan pembelajaran ini boleh dibaca sepenuhnya secara percuma — selepas itu, CoddyKit PRO membuka akses kepada semua pelajaran, serta latihan praktikal dengan penyunting kod terbina dalam dan tutor kecerdasan buatan yang tersedia 24/7. Pelajaran ini merupakan sebahagian daripada laluan pembelajaran Kotlin Academy, dan kemajuan anda disegerakkan merentas web serta aplikasi CoddyKit. Kursus Kotlin Academy merangkumi sejumlah 4 pelajaran.

Apakah Rekursi Ekor

Sesuatu fungsi ialah rekursif ekor apabila panggilan rekursifnya merupakan operasi terakhir. Kotlin kemudiannya boleh mengoptimumkannya menjadi gelung, sekali gus mengelakkan limpahan tindanan.

tailrec fun countdown(n: Int) {
    if (n < 0) return
    println(n)
    countdown(n - 1)
}

fun main() {
    countdown(3)
}

Pengubah Suai tailrec

Tambahkan pengubah suai tailrec dan pengompil menulis semula rekursi sebagai lelaran dengan menggunakan ruang tindanan yang malar.

tailrec fun sum(n: Int, acc: Int = 0): Int {
    if (n == 0) return acc
    return sum(n - 1, acc + n)
}

fun main() {
    println(sum(100))
}

Corak Accumulator

Untuk menjadikan rekursi berbentuk ekor, bawa hasil dalam parameter penumpuk supaya tiada pengiraan yang tertinggal selepas panggilan.

tailrec fun factorial(n: Int, acc: Long = 1): Long {
    if (n <= 1) return acc
    return factorial(n - 1, acc * n)
}

fun main() {
    println(factorial(10))
}

Mengapa Panggilan Mesti Menjadi Operasi Terakhir

Jika sesuatu berlaku selepas panggilan rekursif (seperti mendarab hasilnya), panggilan itu tidak berada pada kedudukan ekor dan tidak boleh dioptimumkan.

tailrec fun length(s: String, acc: Int = 0): Int {
    if (s.isEmpty()) return acc
    return length(s.drop(1), acc + 1)
}

fun main() {
    println(length("hello"))
}

Contoh Balas Rekursi Bukan Ekor

Faktorial ini bukan rekursif ekor kerana pendaraban berlaku selepas panggilan dikembalikan. Menandakannya dengan tailrec akan menghasilkan amaran.

fun badFactorial(n: Int): Long {
    if (n <= 1) return 1
    return n * badFactorial(n - 1)
}

fun main() {
    println(badFactorial(5))
}

Mengelakkan Limpahan Tindanan

Rekursi mendalam tanpa tailrec boleh menyebabkan ranap. Dengannya, input yang besar sekalipun berjalan dengan ruang tindanan yang malar.

tailrec fun count(n: Int, acc: Int = 0): Int {
    if (n == 0) return acc
    return count(n - 1, acc + 1)
}

fun main() {
    println(count(100000))
}

Pengesahan oleh Pengompil

Jika anda menandakan fungsi dengan tailrec tetapi panggilan itu tidak berada pada kedudukan ekor, pengompil mengeluarkan amaran dan tidak mengoptimumkannya. Beri perhatian kepada amaran tersebut.

tailrec fun gcd(a: Int, b: Int): Int {
    if (b == 0) return a
    return gcd(b, a % b)
}

fun main() {
    println(gcd(48, 18))
}

Rekursi Ekor berbanding Gelung

Fungsi tailrec dikompilkan menjadi kod yang lebih kurang sama dengan gelung yang setara, tetapi menyatakan algoritma secara rekursif.

tailrec fun powerOfTwo(n: Int, acc: Long = 1): Long {
    if (n == 0) return acc
    return powerOfTwo(n - 1, acc * 2)
}

fun main() {
    println(powerOfTwo(10))
}

Berbilang Parameter

Fungsi rekursif ekor sering meneruskan beberapa parameter keadaan, yang semuanya dikemas kini dalam panggilan rekursif.

tailrec fun fib(n: Int, a: Long = 0, b: Long = 1): Long {
    if (n == 0) return a
    return fib(n - 1, b, a + b)
}

fun main() {
    println(fib(20))
}

Menterbalikkan dengan tailrec

Penumpuk boleh membina hasil seperti rentetan yang diterbalikkan.

tailrec fun reverse(s: String, acc: String = ""): String {
    if (s.isEmpty()) return acc
    return reverse(s.drop(1), s.first() + acc)
}

fun main() {
    println(reverse("kotlin"))
}

Carian Praktikal

Carian berlelaran boleh dipetakan dengan mudah kepada rekursi ekor.

tailrec fun indexOf(list: List<Int>, target: Int, i: Int = 0): Int {
    if (i >= list.size) return -1
    if (list[i] == target) return i
    return indexOf(list, target, i + 1)
}

fun main() {
    println(indexOf(listOf(5, 6, 7), 7))
}

Semakan Pantas

Uji pemahaman anda tentang fungsi tailrec.

Ringkasan

Anda telah mempelajari fungsi tailrec:

  • tailrec menukar rekursi pada kedudukan ekor menjadi gelung, sekali gus mengelakkan limpahan tindanan.
  • Panggilan rekursif mestilah operasi terakhir.
  • Gunakan parameter penumpuk untuk mencapai bentuk ekor.
  • Pengompil memberikan amaran apabila fungsi tidak boleh dioptimumkan.
tailrec fun sum(n: Int, acc: Int = 0): Int =
    if (n == 0) acc else sum(n - 1, acc + n)

fun main() {
    println(sum(50))
}
Percuma untuk bermula

Pelajari Kotlin dengan tutor kecerdasan buatan — percuma

Tulis dan jalankan kod sebenar dalam pelayar anda, dapatkan bantuan segera daripada tutor kecerdasan buatan yang tersedia 24/7, dan sambung semula dari tempat anda berhenti di web atau dalam aplikasi.

Kursus
51
Pelajaran
203

Soalan Lazim

Adakah pelajaran “Fungsi tailrec” percuma?

Ya — sebanyak 3 pelajaran dalam laluan pembelajaran Kotlin Academy, termasuk “Fungsi tailrec”, boleh dibaca sepenuhnya secara percuma di web ini. Selepas itu, CoddyKit PRO membuka akses kepada semua pelajaran, serta latihan interaktif dengan penyunting kod terbina dalam dan tutor kecerdasan buatan yang tersedia 24/7. Kursus Kotlin Academy merangkumi sejumlah 4 pelajaran.

Apakah yang akan saya pelajari dalam “Fungsi tailrec”?

Optimumkan rekursi Anda berlatih Kotlin Academy menggunakan kod praktikal yang dijalankan terus dalam pelayar, manakala tutor kecerdasan buatan 24/7 menjawab soalan anda semasa anda mengikuti pelajaran.

Adakah saya memerlukan pengalaman untuk memulakan Kotlin Academy?

Tiada pengalaman terdahulu diperlukan. Pembelajaran Kotlin Academy di CoddyKit disusun untuk pelajar daripada peringkat pemula hingga lanjutan, jadi anda boleh bermula di sini atau dari awal dan belajar mengikut kadar anda sendiri. Ini ialah pelajaran 3 daripada 4.

Berapa lamakah pelajaran “Fungsi tailrec” diambil?

Kebanyakan pelajaran CoddyKit mengambil masa kira-kira 5–10 minit. Setiap pelajaran ringkas dan interaktif, jadi anda boleh membuat kemajuan secara berterusan dan menyambung tepat dari tempat anda berhenti di web atau aplikasi.

Bolehkah saya menulis dan menjalankan kod dalam pelajaran Kotlin Academy ini?

Ya. Setiap pelajaran Kotlin Academy menyertakan penyunting kod terbina dalam, jadi anda boleh menulis dan menjalankan kod sebenar terus dalam pelayar serta menerima maklum balas kecerdasan buatan serta-merta — tanpa memerlukan persediaan setempat.

Semua pelajaran dalam kursus ini

  1. Fungsi infiks
  2. Membina API seperti DSL
  3. Fungsi tailrec
  4. Bila setiap satu digunakan
← Kembali ke Kotlin Academy