Rekurzia (z latinského recurrere = bežať znovu) je základný koncept v matematike a informatike, ale svoje uplatnenie nachádza aj v biológii. Ide o využitie časti vlastnej vnútornej štruktúry, napríklad definovanie funkcie pomocou seba samej. V informatike rekurzívna funkcia volá samú seba. Obsahuje "základný prípad", v ktorom je funkčná hodnota pevne daná, čo zabraňuje nekonečnému volaniu. Hlavnou výhodou rekurzie je, že nám umožňuje rozdeliť problém na podproblémy, kde lepšie dokážeme pochopiť riešenie.

Princípy Rekurzívneho Volania Funkcií
Keď metóda volá samú seba, nazývame to rekurzívne volanie. Pri tomto procese sa odovzdá riadenie volanej funkcii a čaká sa na jej návratovú hodnotu. Hoci sa môže zdať, že rekurzívne volanie sa vykonáva "donekonečna", v skutočnosti to tak nie je. Volanie metódy zaberá isté množstvo pamäte (tzv. zásobníkový rámec) a táto pamäť sa nám pri príliš hlbokej rekurzii minie, čo vedie k chybe pretečenia zásobníka. Preto je kľúčové zaistiť, aby sa volanie metódy za istých podmienok skončilo. Rekurzia často nasleduje LIFO schému (Last In, First Out), čo znamená, že volanie, ktoré začalo ako posledné, končí ako prvé.
Definícia a Vyhodnocovanie Funkcií vo Výrazoch
Funkcia je hodnota, ktorá predstavuje mapovanie z množiny hodnôt argumentu na jednu hodnotu. Výsledkom vyhodnocovania výrazu function-expression je vytvoriť hodnotu funkcie (nie vyhodnotiť telo funkcie function-body). Telo funkcie function-body sa vykoná vyvolaním hodnoty funkcie pomocou výrazu invoke-expression. Zoznam argument-list sa používa na určenie pevného počtu argumentov priamo ako zoznamu výrazov.
Prostredie používané na vyhodnocovanie tela funkcie function-body obsahuje premennú, ktorá zodpovedá každému parametru, s rovnakým názvom ako tento parameter. Počet argumentov vytvorených zo zoznamu argument-list musí byť kompatibilný s parametrami funkcie, inak sa vyskytne chyba s kódom "Expression.Error".
- Povinný parameter označuje, že pri vyvolaní funkcie musí byť vždy zadaný argument zodpovedajúci parametru. Povinné parametre musia byť v zozname parametrov zadané ako prvé.
- Voliteľný parameter označuje, že pri vyvolaní funkcie môže byť zadaný argument zodpovedajúci parametru, ale jeho zadanie sa nevyžaduje. Ak argument, ktorý zodpovedá voliteľnému parametru, nie je zadaný, použije sa hodnota null. Voliteľné parametre sa musia v zozname parametrov uviesť po všetkých povinných parametroch.
Podobne je možné zapísať aj vzájomne rekurzívne funkcie, pokiaľ každá funkcia, ku ktorej je potrebný prístup, má názov. Funkcia môže ako hodnotu vrátiť aj inú funkciu. Táto funkcia môže zasa závisieť od jedného alebo viacerých parametrov pre pôvodnú funkciu. Okrem parametrov môže aj telo funkcie function-body výrazu function-expression odkazovať na premenné, ktoré sa nachádzajú v prostredí pri inicializácii funkcie.
Toto je lepší spôsob, ako pochopiť rekurziu
Rekurzia pri Analýze a Vyhodnocovaní Výrazov
V programovaní mnohokrát potrebujeme analyzovať určitý text, matematické výrazy alebo umelo vytvorený počítačový jazyk. Analýza ("parsovanie") výrazov predstavuje komplexný problém, najmä pri práci so zátvorkami, ktoré definujú hierarchiu operácií a podvýrazov.
Riešenie Zložitosti Výrazov Pomocou Rekurzie
Nevýhodou jednoduchých parserov je často fakt, že nepoznajú zátvorky. Použitie zátvoriek nám parsovanie robí zložitejším, lebo nestačí si pamätať iba posledný medzivýsledok - potrebujeme si pamätať medzivýsledok pre každú zátvorku. Jednou z hlavných možností, ako efektívne spracovať štruktúrované výrazy s vnorenými zátvorkami, je rozdeliť výraz na podvýrazy (podľa zátvoriek) a použiť rekurziu. Každý podvýraz sa potom vyhodnotí samostatne, pričom výsledok sa stane súčasťou nadradeného výrazu. Toto je kľúčový koncept v rekurzívnom určovaní výrazov, kde sa syntaktické pravidlá pre definíciu výrazu rekurzívne odvolávajú na samotné pravidlo pre výraz.
Alternatíva: Spracovanie Výrazov Pomocou Zásobníka (Stack)
Druhou možnosťou spracovania zložitých výrazov je pamätať si medzivýsledky pomocou dátovej štruktúry. Najvýhodnejší spôsob, ako mať medzivýsledky organizované v pamäti, je použiť zásobník (Stack). Zásobník pracuje na princípe LIFO (Last In, First Out), čo znamená, že prvky, ktoré boli do zásobníka pridané ako prvé, sa z neho vyberajú ako posledné, a tie, čo boli pridané ako posledné, sa vyberajú ako prvé. Vyberanie aj pridávanie sa vykonáva do/z "vrchu" zásobníka.

Pri parsovaní výrazov si môžeme operácie pamätať v zásobníku - vždy, keď prečítame nejakú operáciu, tak ju vložíme do zásobníka stOp. Keď budeme robiť medzivýpočet, budeme ho robiť s operáciou, ktorú vyberieme z tohto zásobníka. Okrem klasických operácií je možné do zásobníka vložiť špeciálny znak, napríklad '|', ktorý bude signalizovať, že sme na začiatku výrazu/podvýrazu. Tento znak vložíme hneď pri začiatku parsovania a vždy, keď narazíme na otváraciu zátvorku '(', ktorá signalizuje začiatok nového podvýrazu.
Medzivýsledky si budeme pamätať v samostatnom zásobníku st. Keď narazíme na nové číslo, tak ho vložíme do zásobníka st. A keď narazíme na operáciu, vypočítame medzivýsledok (vyberieme posledné dve čísla zo zásobníka st, operáciu zo zásobníka stOp, vypočítame medzivýsledok a vložíme ho späť do zásobníka st). Ak sme boli na začiatku nejakého podvýrazu (teda na vrchu zásobníka stOp je zapísaný znak '|'), tak nemusíme nič počítať - nemusíme vyberať ani vkladať žiadne čísla do zásobníka st, kým sa nedostaneme k ukončujúcej zátvorke alebo konci podvýrazu.
Príklady Rekurzívnych Funkcií
Rekurziou je možné naprogramovať správanie niektorých matematických funkcií alebo javov v prírode. Hoci mnohé z týchto úloh sa dajú ľahko vyriešiť aj pomocou cyklov, rekurzívna definícia môže byť často intuitívnejšia a lepšie odráža podstatu problému.
Faktoriál
Klasickým príkladom rekurzívnej funkcie je výpočet faktoriálu. Faktoriál čísla N (označovaný N!) je súčin všetkých celých kladných čísel od 1 po N. Matematicky sa definuje takto: N! = N * (N-1)! pre N > 1, so základným prípadom 1! = 1 a 0! = 1.
Rekurzívne spracovanie reťazcov
Pomocou rekurzie je možné implementovať aj komplexné operácie s reťazcami. Napríklad funkciu, ktorá násobí reťazec číslom, čo znamená, že vráti N po sebe idúcich reťazcov A$. Aj táto funkcia môže byť písaná rekurzívne. Použitie tejto funkcie je veľmi rozmanité, napríklad na vypísanie N znakov '#' na obrazovku alebo na zarovnávanie vypisovaných čísiel podľa pravého okraja.
Ďalším zložitým príkladom je funkcia na obrátenie poradia znakov v reťazci. Pre reťazec "abcd" by bol na výstupe "dcba". Logika tejto rekurzívnej funkcie spočíva v tom, že vezmeme prvý znak reťazca a zapíšeme ho za "reverznutý" zvyšok reťazca. Funkcia by teda rekurzívne volala samú seba na podreťazec bez prvého znaku, a keď sa vráti výsledok, pripojí k nemu pôvodný prvý znak.
Toto je lepší spôsob, ako pochopiť rekurziu
Zabezpečenie Rekurzie pri Vyhodnocovaní Výrazov
Pri definovaní rekurzívnych funkcií, ktoré sa podieľajú na vyhodnocovaní výrazov, je dôležité zabezpečiť ich robustnosť. Napríklad, ak by sme mali funkciu, ktorá pracuje s logaritmom (LN), musíme zabrániť vyhodnocovaniu LN X pre X <= 0, inak dôjde k chybe "Invalid argument". V niektorých programovacích prostrediach, kde nie je priama podpora pre podmienené rekurzívne volania, je potrebné použiť "špinavý trik" - napríklad podhodiť reťazec "x*x" alebo použiť konštrukciu ako "reťazec" AND podmienka. Týmto spôsobom zabezpečíme, aby sa nevhodné časti výrazu nevyhodnocovali za podmienok, ktoré by viedli k chybám.
tags: #rec #obrad #opakovanim #urc #vyrazu