logo

Rekurziós fa módszer

A rekurzió az informatika és a matematika alapvető fogalma, amely lehetővé teszi a függvények önmaguk elnevezését, lehetővé téve összetett problémák iteratív lépéseken keresztüli megoldását. A rekurzív függvények végrehajtásának megértésére és elemzésére általánosan használt vizuális ábrázolás a rekurziós fa. Ebben a cikkben megvizsgáljuk a rekurziós fák mögött meghúzódó elméletet, felépítésüket és a rekurzív algoritmusok megértésében betöltött jelentőségüket.

Mi az a rekurziós fa?

A rekurziós fa egy grafikus ábrázolás, amely egy rekurzív függvény végrehajtási folyamatát szemlélteti. A rekurzív hívások vizuális lebontását nyújtja, bemutatva az algoritmus előrehaladását, amint az elágazik, és végül eléri az alapesetet. A fastruktúra segít az idő bonyolultságának elemzésében és a rekurzív folyamat megértésében.

Fa szerkezete

A rekurziós fa minden csomópontja egy adott rekurzív hívást képvisel. A kezdeti hívás felül látható, alatta pedig a következő hívások ágaznak ki. A fa lefelé nő, hierarchikus struktúrát alkotva. Az egyes csomópontok elágazási tényezője a függvényen belüli rekurzív hívások számától függ. Ezenkívül a fa mélysége megfelel az alapeset elérése előtti rekurzív hívások számának.

Alap helyzet

Az alapeset a rekurzív függvény lezárási feltételeként szolgál. Meghatározza azt a pontot, ahol a rekurzió leáll, és a függvény elkezd értékeket visszaadni. A rekurziós fában az alapesetet reprezentáló csomópontok általában levélcsomópontként jelennek meg, mivel ezek nem eredményeznek további rekurzív hívásokat.

Rekurzív hívások

A rekurziós fa gyermekcsomópontjai a függvényen belül végrehajtott rekurzív hívásokat képviselik. Minden gyermek csomópont egy külön rekurzív hívásnak felel meg, ami új alproblémákat eredményez. Az ezeknek a rekurzív hívásoknak átadott értékek vagy paraméterek eltérőek lehetnek, ami az alproblémák jellemzőinek eltéréseit eredményezheti.

Végrehajtási folyamat:

A rekurziós fa bejárása betekintést nyújt a rekurzív függvény végrehajtási folyamatába. A gyökércsomópont kezdeti hívásától kezdve követjük az ágakat, hogy elérjük a következő hívásokat, amíg nem találkozunk az alapesettel. Az alapesetek elérésekor a rekurzív hívások elkezdenek visszatérni, és a fa megfelelő csomópontjait megjelölik a visszaadott értékekkel. A bejárás addig folytatódik, amíg az egész fát be nem járták.

Időkomplexitás-elemzés

A rekurziós fák segítenek a rekurzív algoritmusok időbeli összetettségének elemzésében. A fa szerkezetét megvizsgálva meghatározhatjuk az egyes szinteken végrehajtott rekurzív hívások számát és az elvégzett munkát. Ez az elemzés segít megérteni az algoritmus általános hatékonyságát, és azonosítani a potenciális hatástalanságokat vagy az optimalizálási lehetőségeket.

Bevezetés

  • Gondolj egy programra, amely meghatározza egy szám faktoriálisát. Ez a függvény egy N számot vesz fel bemenetként, és eredményeként adja vissza az N faktoriálisát. Ennek a függvénynek a pszeudokódja hasonlít majd
 // find factorial of a number factorial(n) { // Base case if n is less than 2: // Factorial of 0, 1 is 1 return n // Recursive step return n * factorial(n-1); // Factorial of 5 => 5 * Factorial(4)... } /* How function calls are made, Factorial(5) [ 120 ] | 5 * Factorial(4) ==> 120 | 4. * Factorial(3) ==> 24 | 3 * Factorial(2) ==> 6 | 2 * Factorial(1) ==> 2 | 1 */ 
  • A rekurzió példája a korábban említett függvény. Egy függvényt hívunk meg egy szám faktoriálisának meghatározására. Ezután, ha ugyanannak a számnak kisebb értéke van, ez a függvény meghívja magát. Ez addig folytatódik, amíg el nem érjük az alapesetet, amelyben már nincs függvényhívás.
  • A rekurzió bonyolult problémák kezelésére szolgáló technika, amikor az eredmény ugyanazon probléma kisebb példányainak kimenetelétől függ.
  • Ha függvényekre gondolunk, egy függvényt rekurzívnak mondunk, ha addig hívja magát, amíg el nem éri az alapesetet.
  • Minden rekurzív függvénynek két elsődleges összetevője van: az alapeset és a rekurzív lépés. Ha elérjük az alapesetet, abbahagyjuk a rekurzív fázisba lépést. A végtelen rekurzió megelőzése érdekében az alapeseteket megfelelően meg kell határozni, és ezek kulcsfontosságúak. A végtelen rekurzió definíciója olyan rekurzió, amely soha nem éri el az alapesetet. Ha egy program soha nem éri el az alapesetet, a veremtúlcsordulás továbbra is előfordul.

Rekurziós típusok

Általánosságban elmondható, hogy a rekurziónak két különböző formája van:

  • Lineáris rekurzió
  • Fa rekurzió
  • Lineáris rekurzió

Lineáris rekurzió

  • Azt a függvényt, amely minden egyes végrehajtáskor csak egyszer hívja meg magát, lineárisan rekurzívnak nevezzük. A lineáris rekurzió szép példája a faktoriális függvény. A „lineáris rekurzió” elnevezés arra a tényre utal, hogy egy lineárisan rekurzív függvény végrehajtása lineárisan sok időt vesz igénybe.
  • Vessen egy pillantást az alábbi pszeudokódra:
 function doSomething(n) { // base case to stop recursion if nis 0: return // here is some instructions // recursive step doSomething(n-1); } 
  • Ha megnézzük a doSomething(n) függvényt, az elfogad egy n nevű paramétert, és elvégzi a számításokat, mielőtt még egyszer meghívná ugyanazt az eljárást, de alacsonyabb értékekkel.
  • Ha a doSomething() metódust n argumentumértékkel hívjuk meg, tegyük fel, hogy T(n) a számítás befejezéséhez szükséges teljes időt jelenti. Ehhez egy ismétlődési relációt is megfogalmazhatunk, T(n) = T(n-1) + K. Itt K konstansként szolgál. A K konstans azért van benne, mert időbe telik, amíg a függvény memóriát lefoglal vagy lefoglal egy változóhoz, vagy végrehajt egy matematikai műveletet. K-t használunk az idő meghatározására, mivel az nagyon kicsi és jelentéktelen.
  • Ennek a rekurzív programnak az időbonyolultsága egyszerűen kiszámítható, mivel a legrosszabb esetben a doSomething() metódust n-szer hívják meg. Formálisan a függvény időbeli összetettsége O(N).

Fa rekurzió

  • Ha egynél többször indít rekurzív hívást a rekurzív esetben, azt fa rekurziónak nevezzük. A fa rekurzió hatásos illusztrációja a fibonacci sorozat. A fa rekurzív függvényei exponenciális időben működnek; időbeli összetettségükben nem lineárisak.
  • Vessen egy pillantást az alábbi pszeudokódra,
 function doSomething(n) { // base case to stop recursion if n is less than 2: return n; // here is some instructions // recursive step return doSomething(n-1) + doSomething(n-2); } 
  • Az egyetlen különbség ez a kód és az előző között az, hogy ez még egy hívást hajt végre ugyanarra a függvényre alacsonyabb n értékkel.
  • T(n) = T(n-1) + T(n-2) + k tegyük ennek a függvénynek az ismétlődési relációját. K még egyszer konstansként szolgál.
  • Ha ugyanannak a függvénynek egynél több hívása történik kisebb értékekkel, akkor ezt a fajta rekurziót farekurziónak nevezzük. Az érdekes szempont most: mennyire időigényes ez a funkció?
  • Az alábbi rekurziós fa alapján tippeljen ugyanarra a függvényre.
    DAA rekurziós fa módszer
  • Előfordulhat, hogy nehéz megbecsülni az időbonyolultságot egy rekurzív függvény közvetlen megtekintésével, különösen, ha az egy fa rekurzió. A rekurziós fa módszer egyike azon technikák közül, amelyekkel kiszámítható az ilyen függvények időbeli összetettsége. Vizsgáljuk meg részletesebben.

Mi az a rekurziós fa módszer?

  • Az olyan ismétlődési relációkat, mint a T(N) = T(N/2) + N, vagy a kettő, amelyet korábban a rekurzió típusainál tárgyaltunk, a rekurziós fa megközelítéssel oldjuk meg. Ezek az ismétlődő kapcsolatok gyakran az oszd meg és uralkodj stratégiát alkalmaznak a problémák megoldására.
  • Időbe telik a válaszok integrálása a kisebb részproblémákra, amelyek akkor jönnek létre, amikor egy nagyobb problémát kisebb részproblémákra bontanak.
  • Az ismétlődési reláció például T(N) = 2 * T(N/2) + O(N) az összevonási rendezésnél. A két részprobléma T(N/2) kombinált méretű válaszainak kombinálásához szükséges idő O(N), ami igaz a megvalósítás szintjén is.
  • Például, mivel a bináris keresés ismétlődési relációja T(N) = T(N/2) + 1, tudjuk, hogy a bináris keresés minden iterációja egy olyan keresési teret eredményez, amely felére van vágva. Az eredmény meghatározása után kilépünk a függvényből. Az ismétlődési reláció +1 hozzáadva, mert ez egy állandó idejű művelet.
  • A T(n) = 2T(n/2) + Kn ismétlődési összefüggést érdemes figyelembe venni. Kn az n/2-dimenziós részfeladatok válaszainak kombinálásához szükséges időt jelöli.
  • Ábrázoljuk a rekurziós fát a fent említett ismétlődési relációhoz.
DAA rekurziós fa módszer

A fenti rekurziós fa tanulmányozásából levonhatunk néhány következtetést, többek között

1. Egy csomópont értékének meghatározásához csak a probléma nagysága minden szinten számít. A kiadás mérete n a 0. szinten, n/2 az 1. szinten, n/2 a 2. szinten stb.

2. Általánosságban a fa magasságát log (n) értékkel definiáljuk, ahol n a probléma mérete, és ennek a rekurziós fának a magassága megegyezik a fában lévő szintek számával. Ez igaz, mert amint azt az imént megállapítottuk, az oszd meg és uralkodj stratégiát az ismétlődő relációk használják problémák megoldására, és az n-es problémaméretről az 1-es problémaméretre való eljutáshoz egyszerűen log (n) lépések megtétele szükséges.

  • Vegyük például az N = 16 értékét. Ha megengedjük, hogy minden lépésben elosztjuk N-t 2-vel, hány lépésre van szükség ahhoz, hogy N = 1 legyen? Tekintettel arra, hogy minden lépésben osztunk kettővel, a helyes válasz 4, ami a log(16) 2-es bázis értéke.

log(16) 2. alap

A karakterlánc java-t tartalmaz

log(2^4) 2. bázis

4 * log(2) bázis 2, mivel log(a) bázis a = 1

tehát 4 * log(2) bázis 2 = 4

3. Minden szinten az ismétlődés második tagját tekintjük gyökérnek.

Bár a „fa” szó szerepel ennek a stratégiának a nevében, nem kell a fák szakértőjének lenni ahhoz, hogy megértse.

Hogyan használjunk rekurziós fát az ismétlődési kapcsolatok megoldására?

A részprobléma költsége a rekurziós fa technikában a részprobléma megoldásához szükséges idő. Ezért, ha észreveszi a „költség” kifejezést a rekurziós fával kapcsolatban, az egyszerűen egy bizonyos részprobléma megoldásához szükséges időre utal.

Nézzük meg ezeket a lépéseket néhány példával.

Példa

Tekintsük az ismétlődési összefüggést,

T(n) = 2T(n/2) + K

Megoldás

Az adott ismétlődési reláció a következő tulajdonságokat mutatja:

távolítsa el az utolsó karaktert a karakterláncból

Egy n méretű probléma két részproblémára van osztva, amelyek mindegyike n/2 méretű. Ezen részproblémák megoldásainak kombinálásának költsége K.

Minden n/2 problémaméret két részproblémára van osztva, amelyek mindegyike n/4 és így tovább.

Az utolsó szinten a részprobléma mérete 1-re csökken. Vagyis végre eltaláltuk az alapesetet.

Kövesse az ismétlődési reláció megoldásának lépéseit,

1. lépés: Rajzolja meg a rekurziós fát

DAA rekurziós fa módszer

2. lépés: Számítsa ki a fa magasságát

Mivel tudjuk, hogy ha egy számot folyamatosan osztunk 2-vel, eljön az idő, amikor ez a szám 1-re csökken. Ugyanúgy, mint az N feladatnál, tegyük fel, hogy K 2-vel való osztás után N egyenlő lesz 1-gyel, ami azt jelenti, ( n/2^k) = 1

Itt n / 2^k a probléma mérete az utolsó szinten, és mindig egyenlő 1-gyel.

Most már könnyen kiszámíthatjuk k értékét a fenti kifejezésből, ha mindkét oldalra felvesszük a log()-t. Az alábbiakban egy egyértelműbb levezetés látható,

n = 2^k

  • log(n) = log(2^k)
  • log(n) = k * log(2)
  • k = log(n) / log(2)
  • k = log(n) bázis 2

Tehát a fa magassága log (n) bázis 2.

3. lépés: Számítsa ki a költségeket minden szinten

  • Költség a 0. szinten = K, két részprobléma összevonásra kerül.
  • Költség az 1. szinten = K + K = 2*K, két részprobléma kétszer összevonásra kerül.
  • Költség a 2. szinten = K + K + K + K = 4*K, két részprobléma négyszer összevonásra kerül. stb....

4. lépés: Számítsa ki a csomópontok számát minden szinten

dateformat.format

Először határozzuk meg a csomópontok számát az utolsó szinten. A rekurziós fából erre következtethetünk

  • A 0. szintnek 1 (2^0) csomópontja van
  • Az 1. szintnek 2 (2^1) csomópontja van
  • A 2. szintnek 4 (2^2) csomópontja van
  • A 3. szint 8 (2^3) csomóponttal rendelkezik

Tehát a log(n) szintnek 2^(log(n)) csomópontja kell, hogy legyen, azaz n csomópont.

5. lépés: Adja össze az összes szint költségét

  • A teljes költség így írható fel,
  • Teljes költség = az utolsó szint kivételével az összes szint költsége + az utolsó szint költsége
  • Teljes költség = 0. szint költsége + 1. szint költsége + 2. szint költsége +.... + log(n) szint költsége + utolsó szint költsége

Az utolsó szint költsége külön kerül kiszámításra, mivel ez az alapeset, és az utolsó szinten nem történik összevonás, így ezen a szinten egyetlen probléma megoldásának költsége valamilyen állandó érték. Vegyük O-nak (1).

Tegyük az értékeket a képletekbe,

  • T(n) = K + 2*K + 4*K + .... + log(n)' szor + 'O(1) * n
  • T(n) = K(1 + 2 + 4 + .... + log(n)-szor)' + 'O(n)
  • T(n) = K(2^0 + 2^1 + 2^2 + ....+ log(n)-szor + O(n)

Ha alaposan megnézi a fenti kifejezést, geometriai progressziót alkot (a, ar, ar^2, ar^3 ...... végtelen idő). A GP összegét S(N) = a / (r - 1) adja meg. Itt van az első tag, és r a közös arány.