640 likes | 842 Views
Rekurze. Rekurze. volání podprogramu opětovně v jeho těle v době, kdy předchozí volání ještě nebylo ukončeno Druhy rekurze přímá rekurze nepřímá rekurze. Přímá rekurze. podprogram volá sám sebe void A(…) { A(); }. Nepřímá rekurze. aktivují se vzájemně dva podprogramy void A(…)
E N D
Rekurze • volání podprogramu opětovně v jeho těle • v době, kdy předchozí volání ještě nebylo ukončeno Druhy rekurze • přímá rekurze • nepřímá rekurze
Přímá rekurze • podprogram volá sám sebe void A(…) { A(); }
Nepřímá rekurze • aktivují se vzájemně dva podprogramy void A(…) { B(); } void B(…) { A(); }
pravidla tvorby rekurzivní funkce • musí být definována podmínka pro ukončení rekurze • v algoritmu se musí ověřit, zda nenastala koncová situace • v každém kroku musí dojít ke zjednodušení problému
Příklad 1 Napište rekurzivní funkci pro výpočet faktoriálu long fakt(int n) { if (n<=1) return 1; else returnn*fakt(n-1); }
Jak se rekurze volá? int main() { fakt(2); } fakt(2) 2 return 2*fakt(1) 1 return 1
V registru procesoru AX se předává návratová hodnota long fakt(int n) {long x; 1:if (n<=1) 2: return 1; 3:else { 4:x=fakt(n-1); 5:x = n*x; 6: return x; } } int main() {long a; 10: a = fakt(3); 11: cout << a; } AX: 2584 a 4589 Zásobník n 3
V registru procesoru AX se předává návratová hodnota long fakt(int n) {long x; 1:if (n<=1) 2: return 1; 3:else { 4:x=fakt(n-1); 5:x = n*x; 6: return x; } } int main() {long a; 10: a = fakt(3); 11: cout << a; } AX: 2584 a 4589 Zásobník x 12346786 11 n 3
V registru procesoru AX se předává návratová hodnota long fakt(int n) {long x; 1:if (n<=1) 2: return 1; 3:else { 4:x=fakt(n-1); 5:x = n*x; 6: return x; } } int main() {long a; 10: a = fakt(3); 11: cout << a; } AX: 2584 a 4589 Zásobník x 12346786 11 n 3
V registru procesoru AX se předává návratová hodnota long fakt(int n) {long x; 1:if (n<=1) 2: return 1; 3:else { 4:x=fakt(n-1); 5:x = n*x; 6: return x; } } int main() {long a; 10: a = fakt(3); 11: cout << a; } AX: 2584 a 4589 Zásobník n 2 x 12346786 11 n 3
V registru procesoru AX se předává návratová hodnota long fakt(int n) {long x; 1:if (n<=1) 2: return 1; 3:else { 4:x=fakt(n-1); 5:x = n*x; 6: return x; } } int main() {long a; 10: a = fakt(3); 11: cout << a; } AX: 2584 a 4589 Zásobník 5 n 2 x 12346786 11 n 3
V registru procesoru AX se předává návratová hodnota long fakt(int n) {long x; 1:if (n<=1) 2: return 1; 3:else { 4:x=fakt(n-1); 5:x = n*x; 6: return x; } } int main() {long a; 10: a = fakt(3); 11: cout << a; } AX: 2584 a 4589 Zásobník x 123464545 5 n 2 x 12346786 11 n 3
V registru procesoru AX se předává návratová hodnota long fakt(int n) {long x; 1:if (n<=1) 2: return 1; 3:else { 4:x=fakt(n-1); 5:x = n*x; 6: return x; } } int main() {long a; 10: a = fakt(3); 11: cout << a; } AX: 2584 a 4589 Zásobník x 123464545 5 n 2 x 12346786 11 n 3
V registru procesoru AX se předává návratová hodnota long fakt(int n) {long x; 1:if (n<=1) 2: return 1; 3:else { 4:x=fakt(n-1); 5:x = n*x; 6: return x; } } int main() {long a; 10: a = fakt(3); 11: cout << a; } AX: 2584 a 4589 Zásobník n 1 x 123464545 5 n 2 x 12346786 11 n 3
V registru procesoru AX se předává návratová hodnota long fakt(int n) {long x; 1:if (n<=1) 2: return 1; 3:else { 4:x=fakt(n-1); 5:x = n*x; 6: return x; } } int main() {long a; 10: a = fakt(3); 11: cout << a; } AX: 2584 a 4589 Zásobník x 123664545 5 n 1 x 123464545 5 n 2 x 12346786 11 n 3
V registru procesoru AX se předává návratová hodnota long fakt(int n) {long x; 1:if (n<=1) 2: return 1; 3:else { 4:x=fakt(n-1); 5:x = n*x; 6: return x; } } int main() {long a; 10: a = fakt(3); 11: cout << a; } AX: 2584 a 4589 Zásobník x 123664545 5 n 1 x 123464545 5 n 2 x 12346786 11 n 3
V registru procesoru AX se předává návratová hodnota long fakt(int n) {long x; 1:if (n<=1) 2: return 1; 3:else { 4:x=fakt(n-1); 5:x = n*x; 6: return x; } } int main() {long a; 10: a = fakt(3); 11: cout << a; } AX: 1 a 4589 Zásobník 5 n 1 x 123464545 5 n 2 x 12346786 11 n 3
V registru procesoru AX se předává návratová hodnota long fakt(int n) {long x; 1:if (n<=1) 2: return 1; 3:else { 4:x=fakt(n-1); 5:x = n*x; 6: return x; } } int main() {long a; 10: a = fakt(3); 11: cout << a; } AX: 1 a 4589 Zásobník n 1 x 1 5 n 2 x 12346786 11 n 3
V registru procesoru AX se předává návratová hodnota long fakt(int n) {long x; 1:if (n<=1) 2: return 1; 3:else { 4:x=fakt(n-1); 5:x = n*x; 6: return x; } } int main() {long a; 10: a = fakt(3); 11: cout << a; } AX: 1 a 4589 Zásobník x 1 5 n 2 x 12346786 11 n 3
V registru procesoru AX se předává návratová hodnota long fakt(int n) {long x; 1:if (n<=1) 2: return 1; 3:else { 4:x=fakt(n-1); 5:x = n*x; 6: return x; } } int main() {long a; 10: a = fakt(3); 11: cout << a; } AX: 2584 a 4589 Zásobník x 2 5 n 2 x 12346786 11 n 3
V registru procesoru AX se předává návratová hodnota long fakt(int n) {long x; 1:if (n<=1) 2: return 1; 3:else { 4:x=fakt(n-1); 5:x = n*x; 6: return x; } } int main() {long a; 10: a = fakt(3); 11: cout << a; } AX: 2 a 4589 Zásobník 5 n 2 x 12346786 11 n 3
V registru procesoru AX se předává návratová hodnota long fakt(int n) {long x; 1:if (n<=1) 2: return 1; 3:else { 4:x=fakt(n-1); 5:x = n*x; 6: return x; } } int main() {long a; 10: a = fakt(3); 11: cout << a; } AX: 2 a 4589 Zásobník n 2 x 2 11 n 3
V registru procesoru AX se předává návratová hodnota long fakt(int n) {long x; 1:if (n<=1) 2: return 1; 3:else { 4:x=fakt(n-1); 5:x = n*x; 6: return x; } } int main() {long a; 10: a = fakt(3); 11: cout << a; } AX: 2 a 4589 Zásobník x 2 11 n 3
V registru procesoru AX se předává návratová hodnota long fakt(int n) {long x; 1:if (n<=1) 2: return 1; 3:else { 4:x=fakt(n-1); 5:x = n*x; 6: return x; } } int main() {long a; 10: a = fakt(3); 11: cout << a; } AX: 2 a 4589 Zásobník x 6 11 n 3
V registru procesoru AX se předává návratová hodnota long fakt(int n) {long x; 1:if (n<=1) 2: return 1; 3:else { 4:x=fakt(n-1); 5:x = n*x; 6: return x; } } int main() {long a; 10: a = fakt(3); 11: cout << a; } AX: 6 a 4589 Zásobník 11 n 3
V registru procesoru AX se předává návratová hodnota long fakt(int n) {long x; 1:if (n<=1) 2: return 1; 3:else { 4:x=fakt(n-1); 5:x = n*x; 6: return x; } } int main() {long a; 10: a = fakt(3); 11: cout << a; } AX: 6 a 6 Zásobník n 3
V registru procesoru AX se předává návratová hodnota long fakt(int n) {long x; 1:if (n<=1) 2: return 1; 3:else { 4:x=fakt(n-1); 5:x = n*x; 6: return x; } } int main() {long a; 10: a = fakt(3); 11: cout << a; } AX: 6 a 6 Zásobník
Úloha 1 Napište rekurzivní funkci pro výpočet Fibbonaciho posloupnosti F(0) = 0 F(1) = 1 F(n) = F(n-1) + F(n-2)
rekurze, je-li příliš „hluboká“, způsobí růst velikosti zásobníku • v některých případech je možné ji nahradit pouhým cyklem • jindy se musí simulovat zásobník long fakt(int n) { long faktorial = 1; for(i=2;i<=n;i=i+1) faktorial = faktorial*i; return faktorial; }
Úloha 2 • Je dána celá částka v Kč. Máme k dispozici mince v hodnotách 20 Kč, 10 Kč, 5 Kč, 2Kč, 1 Kč. Napište rekurzivní proceduru, která vytiskne na obrazovku složení částky z co nejmenšího počtu mincí (vytiskne seznam mincí). • Domácí úloha: Odstraňte rekurzi (přepište proceduru pomocí cyklu).
Hanojské věže • máme 3 tyče (1, 2, 3) • na první tyči je věž z n disků naskládaných na sebe, spodní disk má největší průměr • úkol: • přemístit věž z tyče 1 na tyč 2 pomocí třetí tyče 3 přesouváním disků za podmínek: • v jediném kroku lze přenést jeden disk z tyče na tyč • disk lze odložit pouze na tyč • nelze položit disk o větším průměru na disk s menším průměrem.
triviální úloha • přenesení věže o výšce 1, tj. přenesení disku, z tyče na tyč • je reprezentována procedurou void Prenes_disk(int odkud, int kam), která v našem programu vypíše informaci o přesunu disku, např.: 1 -> 2 • úvaha • chci-li přesunout věž např. o výšce 3 disky z tyče 1 na tyč 2 pomocí tyče 3, musím nejprve přesunout věž o výšce 2 (počítáno od shora) na tyč 3 pomocí 2, pak přesunout spodní největší disk z tyče 1 na tyč 2 a nakonec přesunout věž o výšce 2 z tyče 3 na tyč 2 pomocí tyče 1
odkud = tyč 1 kam = tyč 2 pomocí = tyč 3
void prenes_vez(int vyska, int odkud, int kam, int pomoci) { if (vyska == 1) prenes_disk(odkud,kam); else { prenes_vez(vyska-1, odkud, pomoci, kam); prenes_disk(odkud,kam); prenes_vez(vyska-1,pomoci,kam,odkud); } }
Jaká je složitost algoritmu? • přesunutí věže o n discích se skládá z přesunutí věže o (n-1) discích, přesunutí disku a přesunutí věže zpět o (n-1) discích • počet kroků algoritmu (počet přesunutí disků) je dán rekurentním vztahem: F(n) = F(n-1) + 1 + F(n-1) = 2F(n-1)+1, přičemž F(1) = 1
řešením rovnice je vztah F(n) = 2n - 1 tj. počet přesunů disku u věže výšky n je roven 2n - 1 • složitost algoritmu je tedy O(2n) exponenciální
Aplikace rekurze Prohledávání s návratem (Backtracking) • používá se pro hledání všech řešení daného problému • princip: • řešení hledám po krocích, pokud je řešení nalezeno nebo nelze úlohu dále řešit, vrátím se o krok zpět • úlohy: • hledání všech cest v bludišti • problém rozmístění 8 dam na šachovnici
Problém 8 dam na šachovnici • úkol: • umístit 8 dam na šachovnici 8x8 polí, aby se vzájemně neohrožovaly • princip: • umístím dámu na první řádek na první sloupec, další dámu na druhý řádek na třetí sloupec atd., pokud nemohu další dámu umístit, provedu návrat na předchozí řádek a dámu posunu
Problém 8 dam • demonstrace na 4 dámách na šachovnici 4x4
Problém 8 dam další dámu nemohu umístit, provedu návrat
Problém 8 dam další dámu nemohu umístit, provedu návrat