Úloha 21: Rekurze (stromové menu a faktoriál)
Cíl úlohy
Prozkoumejte koncept rekurze – situaci, kdy funkce volá sama sebe. V této úloze rekurzi uplatníme na dvou příkladech:
- Výpis hierarchického stromu menu z databáze (
strom.php): Každá položka má svéida odkaz na nadřazenou položkuparent. Rekurzivní funkce dokáže vypsat neomezeně hluboce zanořený strom kategorií. - Srovnání rychlosti rekurze vs. cyklus (
faktorial.php): Změříme přesný čas běhu skriptu pomocímicrotime(true)a porovnáme režii rekurzivního volání funkcí oproti iterativnímu cyklu.
Dva pilíře každé rekurzivní funkce
- 1. Ukončující podmínka (bázový případ): Podmínka, při jejímž splnění funkce už nevolá sama sebe, ale vrátí konkrétní hodnotu. Bez ukončující podmínky dojde k nekonečnému zacylení a přetečení zásobníku (Stack Overflow).
- 2. Rekurzivní krok: Funkce zavolá samu sebe s modifikovanými (zmenšenými) parametry, které se přibližují k ukončující podmínce.
Úvahy a doporučený postup řešení
- Hierarchie v databázi: Položky nejvyšší úrovně mají
parent = 0. FunkceGenerujMenu($parent, $uroven)vybere všechny potomky a pro každého z nich rekurzivně zavoláGenerujMenu($potomek['id'], $uroven + 1). - Měření času běhu: Funkce
microtime(true)vrací aktuální unixový čas s mikrosekundovou přesností jako číslo typu float. Rozdíl$konec - $startudává dobu výpočtu v sekundách.
Doplňující otázky k zamyšlení a náměty na rozšíření
- 1. Proč bývá iterativní cyklus
foru jednoduchých úloh (faktoriál, Fibonacci) rychlejší než rekurze? (Režie vytváření zásobníkového rámce / stack frame při každém volání funkce). - 2. Kde je rekurze naopak přirozeným a nejlepším řešením? (Procházení stromů a grafů, složky a soubory na disku, parsování HTML/XML/JSON stromů, třídicí algoritmy jako Quicksort a Mergesort).
- 3. Co je to tzv. koncová rekurze (tail recursion) a optimalizace koncového volání (TCO)?
Vzor 1: Stromové menu (strom.php) Vzor 2: Měření času rekurze vs. cyklus (faktorial.php)