Funkce, která v sekvenci příkazů volá sama sebe s jinými (menšími) parametry
Musí existovat ukončovací podmínka, která zastavuje větvení
Pracuje směrem shora-dolů
Každé rekurzivní volání vytváří rámec na zásobníku (Stack Frame), do něj se ukládají lokální proměnné, parametry a návratová adresa
Pokud je rekurze příliš hluboká, může dojít k zaplnění zásobníku a program spadne (Stack Overflow)
Lze vždy převést na iteraci
Nejzákladnější forma
Funkce v těle volá sama sebe nejvýše jednou (případně obsahuje více disjunktních volání, ale volá se jen jedno z nich)
Až narazí na ukončovací podmínku, začne se výsledek "probublávat" směrem zpátky
Časová složitost:
Paměťová složitost:
int faktorial(int n) {
if (n <= 1) return 1; // Ukončovací podmínka
return n * faktorial(n - 1);
}
Speciální poddruh lineární rekurze
Nastává tehdy, když je rekurzivní volání úplně poslední operací, kterou funkce provádí, nečeká se další "odložené" operace
Výsledek poté "neprobublává" zpátky, výsledek posledního volání je rovnou výsledkem celé funkce
Snadno převeditelná na iteraci (ale rekurzivní zápis bývá "čistší" a přehlednější v kódu)
Časová složitost:
Paměťová složitost:
// Průběžně si taháme výsledek s sebou v akumulátoru, na konci ho stačí jen vrátit
int faktorial(int n, int akumulator) {
if (n <= 1) return akumulator; // Vrátí rovnou konečný výsledek
return faktorial(n - 1, n * akumulator); // Čisté koncové volání
}
Nastává tehdy, když funkce v rámci jednoho průchodu tělem zavolá sama sebe více než jednou
Obvyklé pro přístup Rozděl a panuj, stromové a grafové průchody
Časová složitost: Typicky exponenciální (např.
Paměťová složitost: Maximální hloubka stromu, typicky tedy
int fibonacci(int n) {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2); // Dvě rekurzivní volání!
}
Opakování instrukcí pomocí smyček (for, while)
Musí existovat ukončovací podmínka, která zastaví cyklus (buď v deklaraci cyklu, nebo např. break;)
Pracuje směrem zdola-nahoru - od jednoduchého problému k celému
Režie na paměť je konstantní
Metoda řešení problému rozložením na nezávislé podproblémy řešené stejným způsobem
Využívá rekurzi
Často klasické operace s binárními stromy (BVS, AVL), binární vyhledávání, MergeSort, QuickSort. QuickSelect, ...
Výhody: Úspornost zápisu kódu, přirozenost, intuitivnost (explicitní pojmenování toho, co se opakuje v menším) a expresivnost (snadné vyjádření složitosti)
Tři fáze algoritmu:
Analýza časové složitosti
Problém:
Řešení:
Průvodce labyrintem algoritmů - sekce 9.3, strana 111
Záznam od Elišky v čase 5:32
(Karacuba, Karatsuba)
Problém:
Řešení
Navazuje tam, kde Rozděl a panuj selhává z důvodu neefektivity
Používá se tehdy, když se problémy překrývají / opakují
Memoizace
Princip dynamického programování
for / whileFibonacciho posloupnost je definována následovně:
Problém:
Řešení:
Problém
vstup[] = [10, 22, 9, 33, 21, 50, 41, 60, 80]
[10, 22, 33, 50] (délka 4)[9, 21, 41, 60, 80] (délka 5)[10, 22, 33, 41, 60, 80] nebo [10, 22, 33, 50, 60, 80] (délka 6)Řešení
cache[] o stejné délce jako původní polecache[] zleva doprava
vstup[i] > vstup[j], zkusíme podposloupnost prodloužit cache[i] = max( cache[i], cache[j]+1 )cache[]int lis(vector<int> const& vstup) {
int n = vstup.size();
vector<int> cache(n, 1); // Stejná velikost jako vstup, naplněno samými jedničkami
for (int i = 0; i < n; i++) {
for (int j = 0; j < i; j++) {
if (vstup[j] < vstup[i])
cache[i] = max(cache[i], cache[j] + 1); // Využití minulých hodnot (DP)
}
}
int vysledek = cache[0];
for (int i = 1; i < n; i++) { // Nalezení maximální hodnoty v poli
vysledek = max(vysledek, cache[i]);
}
return vysledek;
}
Vytvořeno: 27. 5. 2026, 12:00
Poslední aktualizace: 9. 6. 2026, 18:07