V tem članku se boste naučili ustvarjati rekurzivne funkcije; funkcija, ki se sama pokliče. Spoznali boste tudi rekurzivno funkcijo repa.
Funkcija, ki sama kliče, je znana kot rekurzivna funkcija. Ta tehnika je znana kot rekurzija.
Primer fizičnega sveta bi bil postavitev dveh vzporednih ogledal drug proti drugemu. Vsak predmet vmes bi se odseval rekurzivno.
Kako deluje rekurzija pri programiranju?
fun main (args: Array) (… repeatse ()…) fun repeatse () (… repeatse ()…)
Tu se recurse()
funkcija pokliče iz telesa recurse()
same funkcije. Ta program deluje tako:
Tu se rekurzivni klic nadaljuje za vedno in povzroči neskončno rekurzijo.
Da bi se izognili neskončni rekurziji, se lahko uporabi… če (ali podoben pristop), kjer ena veja izvede rekurzivni klic, druga pa ne.
Primer: Poiščite faktorijev števila z uporabo rekurzije
fun main(args: Array) ( val number = 4 val result: Long result = factorial(number) println("Factorial of $number = $result") ) fun factorial(n: Int): Long ( return if (n == 1) n.toLong() else n*factorial(n-1) )
Ko zaženete program, bo rezultat:
Faktorijev od 4 = 24
Kako deluje ta program?
Rekurzivni klic factorial()
funkcije je razložen na naslednji sliki:
Tu so navedeni koraki:
factorial (4) // 1. klic funkcije. Argument: 4 4 * faktorijel (3) // 2. klic funkcije. Argument: 3 4 * (3 * faktorijel (2)) // 3. klic funkcije. Argument: 2 4 * (3 * (2 * factorial (1))) // 4. klic funkcije. Argument: 1 4 * (3 * (2 * 1)) 24
Kotlinova repna rekurzija
Rekurzija repa je splošen pojem in ne značilnost jezika Kotlin. Nekateri programski jeziki, vključno s Kotlinom, ga uporabljajo za optimizacijo rekurzivnih klicev, medtem ko jih drugi jeziki (npr. Python) ne podpirajo.
Kaj je rekurzija repa?
V običajni rekurziji najprej izvedete vse rekurzivne klice in rezultat izračunate nazadnje iz vrnjenih vrednosti (kot je prikazano v zgornjem primeru). Zato ne dobite rezultata, dokler niso opravljeni vsi rekurzivni klici.
V repni rekurziji se najprej izvedejo izračuni, nato se izvedejo rekurzivni klici (rekurzivni klic posreduje rezultat vašega trenutnega koraka v naslednji rekurzivni klic). S tem je rekurzivni klic enakovreden zanki in se izogne nevarnosti prelivanja skladov.
Pogoj za rekurzijo repa
Rekurzivna funkcija je primerna za rekurzijo repa, če je klic funkcije zadnja operacija, ki jo izvede. Na primer
Primer 1: Ni primerno za rekurzijo repa, ker klic funkcije sam n*factorial(n-1)
ni zadnja operacija.
fun factorial (n: Int): Long (if (n == 1) (return n.toLong ()) else (vrni n * factorial (n - 1)))
Primer 2: Primerno za rekurzijo repa, ker je klic funkcije sam sebi fibonacci(n-1, a+b, a)
zadnja operacija.
zabavno fibonacci (n: Int, a: Long, b: Long): Long (vrne, če (n == 0) b drugo fibonacci (n-1, a + b, a))
Če želite prevajalniku povedati, da izvede rekurzijo repa v Kotlinu, morate funkcijo označiti z tailrec
modifikatorjem.
Primer: Rekurzija repa
import java.math.BigInteger fun main(args: Array) ( val n = 100 val first = BigInteger("0") val second = BigInteger("1") println(fibonacci(n, first, second)) ) tailrec fun fibonacci(n: Int, a: BigInteger, b: BigInteger): BigInteger ( return if (n == 0) a else fibonacci(n-1, b, a+b) )
Ko zaženete program, bo rezultat:
354224848179261915075
Ta program izračunal 100 th izraz serije Fibonaccijevega. Ker je rezultat lahko zelo veliko celo število, smo iz standardne knjižnice Java uvozili razred BigInteger.
Tu je funkcija fibonacci()
označena z tailrec
modifikatorjem in je primerna za rekurzivni klic. Zato prevajalnik v tem primeru optimizira rekurzijo.
Če poskusite najdejo 20000 th izraz (ali katero koli drugo veliko celo število) serije Fibonaccijevega brez uporabe rep rekurzije, bo prevajalnik vrže java.lang.StackOverflowError
izjemo. Vendar naš zgornji program deluje v redu. Ker smo uporabili repno rekurzijo, ki namesto tradicionalne rekurzije uporablja učinkovito različico, ki temelji na zanki.
Primer: Faktorska uporaba rekorzije repa
Primera za izračun faktorja števila v zgornjem primeru (prvi primer) ni mogoče optimizirati za rekurzijo repa. Tukaj je drug program za izvajanje iste naloge.
fun main(args: Array) ( val number = 5 println("Factorial of $number = $(factorial(number))") ) tailrec fun factorial(n: Int, run: Int = 1): Long ( return if (n == 1) run.toLong() else factorial(n-1, run*n) )
Ko zaženete program, bo rezultat:
Faktorijev od 5 = 120
Prevajalnik lahko v tem programu optimizira rekurzijo, saj je rekurzivna funkcija primerna za repno rekurzijo, zato smo uporabili tailrec
modifikator, ki prevajalniku pove, naj optimizira rekurzijo.