Rekurze. Jan Hnilica Počítačové modelování 12

Podobné dokumenty
Rekurze. Pavel Töpfer, 2017 Programování 1-8 1

Funkce pokročilé možnosti. Úvod do programování 2 Tomáš Kühr

4. Rekurze. BI-EP1 Efektivní programování Martin Kačer

Rekurze. doc. Mgr. Jiří Dvorský, Ph.D. Katedra informatiky Fakulta elektrotechniky a informatiky VŠB TU Ostrava. Prezentace ke dni 12.

Lineární spojový seznam (úvod do dynamických datových struktur)

Rekurzivní algoritmy

Prohledávání do šířky = algoritmus vlny

Struktura programu v době běhu

Funkce, intuitivní chápání složitosti

Implementace LL(1) překladů

Začínáme vážně programovat. Řídící struktury Přetypování Vstupně výstupní operace Vlastní tvorba programů

Pointery II. Jan Hnilica Počítačové modelování 17

Je n O(n 2 )? Je n 2 O(n)? Je 3n 5 +2n Θ(n 5 )? Je n 1000 O(2 n )? Je 2 n O(n 2000 )? Cvičení s kartami aneb jak rychle roste exponenciála.

Rozklad problému na podproblémy

Programování: základní konstrukce, příklady, aplikace. IB111 Programování a algoritmizace

Binární soubory (datové, typované)

Stromy. Jan Hnilica Počítačové modelování 14

8. lekce Úvod do jazyka C 3. část Základní příkazy jazyka C Miroslav Jílek

Úvod do programování 10. hodina

Čtvrtek 8. prosince. Pascal - opakování základů. Struktura programu:

3. úloha - problém batohu metodami branch & bound, dynamické programování, heuristika s testem

5 Rekurze a zásobník. Rekurzivní volání metody

Úvod do programování. Lekce 5

Algoritmizace Dynamické programování. Jiří Vyskočil, Marko Genyg-Berezovskyj 2010

Dynamické programování

for (i = 0, j = 5; i < 10; i++) { // tělo cyklu }

KOMBINATORIKA (4.ročník I.pololetí DE, 2.ročník I.pololetí NS)

1. Implementace funkce počet vrcholů. Předmět: Algoritmizace praktické aplikace (3ALGA)

2 Datové typy v jazyce C

Pole a Funkce. Úvod do programování 1 Tomáš Kühr

Stromy. Strom: souvislý graf bez kružnic využití: počítačová grafika seznam objektů efektivní vyhledávání výpočetní stromy rozhodovací stromy

Funkce, podmíněný příkaz if-else, příkaz cyklu for

6 Příkazy řízení toku

Definice funkcí a procedur. Mnoho operací provozujeme opakovaně, proto je hloupé programovat je při každém použití znovu.

Řešení: PŘENESVĚŽ (N, A, B, C) = přenes N disků z A na B pomocí C

int ii char [16] double dd název adresa / proměnná N = nevyužito xxx xxx xxx N xxx xxx N xxx N

6. Příkazy a řídící struktury v Javě

Řídicí struktury. alg3 1

Logo2 operace, rekurze, větvení výpočtu

Základní způsoby: -Statické (přidělění paměti v čase překladu) -Dynamické (přiděleno v run time) v zásobníku na haldě

Pro kontrolu správného formátu hodnoty N použijeme metodu try-catch.

IAJCE Přednáška č. 8. double tprumer = (t1 + t2 + t3 + t4 + t5 + t6 + t7) / 7; Console.Write("\nPrumerna teplota je {0}", tprumer);

Obecná informatika. Matematicko-fyzikální fakulta Univerzity Karlovy v Praze. Podzim 2012

Úvod do programování - Java. Cvičení č.4

Vyhledávání. doc. Mgr. Jiří Dvorský, Ph.D. Katedra informatiky Fakulta elektrotechniky a informatiky VŠB TU Ostrava. Prezentace ke dni 21.

2. úkol MI-PAA. Jan Jůna (junajan)

Prohledávání do šířky a do hloubky. Jan Hnilica Počítačové modelování 15

Úvod do informatiky. Miroslav Kolařík

DSA, První krok: máme dokázat, že pro left = right vrátí volání f(array, elem, left, right)

Programování v jazyce C pro chemiky (C2160) 3. Příkaz switch, příkaz cyklu for, operátory ++ a --, pole

5. přednáška - Rozklad problému na podproblémy

ZPRO v "C" Ing. Vít Hanousek. verze 0.3

Základní způsoby: -Statické (přidělění paměti v čase překladu) -Dynamické (přiděleno v run time) v zásobníku na haldě

Lekce 01 Úvod do algoritmizace

Poslední nenulová číslice faktoriálu

- jak udělat konstantu long int: L long velka = 78L;

1. lekce. do souboru main.c uložíme následující kód a pomocí F9 ho zkompilujeme a spustíme:

Vyučovací hodina. 1vyučovací hodina: 2vyučovací hodiny: Opakování z minulé hodiny. Procvičení nové látky

9. lekce Úvod do jazyka C 4. část Funkce, rekurze Editace, kompilace, spuštění Miroslav Jílek

III/2 Inovace a zkvalitnění výuky prostřednictvím ICT

PODOBÁ SE JAZYKU C S NĚKTERÝMI OMEZENÍMI GLOBÁLNÍ PROMĚNNÉ. NSWI162: Sémantika programů 2

Základy programování (IZP)

1. lekce. do souboru main.c uložíme následující kód a pomocí F9 ho zkompilujeme a spustíme:

Základy programování (IZP)

Pokročilé programování v jazyce C pro chemiky (C3220) Třídy v C++

Algoritmus pro generování normálních magických čtverců

Programování v C++ 1, 1. cvičení

Standardní algoritmy vyhledávací.

Algoritmus pro hledání nejkratší cesty orientovaným grafem

Programování v jazyce C a C++

V každém kroku se a + b zmenší o min(a, b), tedy vždy alespoň o 1. Jestliže jsme na začátku dostali 2

8 Třídy, objekty, metody, předávání argumentů metod

Da D to t v o é v ty t py IB111: Datové typy

Programy a algoritmy pracující s čísly. IB111 Úvod do programování skrze Python

Obsah přednášky 7. Základy programování (IZAPR) Přednáška 7. Parametry metod. Parametry, argumenty. Parametry metod.

Koncepce (větších) programů. Základy programování 2 Tomáš Kühr

Implementace seznamů do prostředí DELPHI pomocí lineárního seznamu

Více o konstruktorech a destruktorech

Časová a prostorová složitost algoritmů

Syntaktická analýza. Implementace LL(1) překladů. Šárka Vavrečková. Ústav informatiky, FPF SU Opava

VÝUKOVÝ MATERIÁL. Bratislavská 2166, Varnsdorf, IČO: tel Číslo projektu

Základy programování. Úloha: Eratosthenovo síto. Autor: Josef Hrabal Číslo: HRA0031 Datum: Předmět: ZAP

M - Kvadratické rovnice a kvadratické nerovnice

Programování v C++, 2. cvičení

Základní datové struktury

Datové struktury 2: Rozptylovací tabulky

BI-EP1 Efektivní programování 1

for (int i = 0; i < sizeof(hodnoty) / sizeof(int); i++) { cout<<hodonoty[i]<< endl; } cin.get(); return 0; }

Základy programování (IZP)

ALGORITMIZACE 2010/03 STROMY, BINÁRNÍ STROMY VZTAH STROMŮ A REKURZE ZÁSOBNÍK IMPLEMENTUJE REKURZI PROHLEDÁVÁNÍ S NÁVRATEM (BACKTRACK)

Rozklad problému na podproblémy, rekurze

Rozklad problému na podproblémy, rekurze

Logické programování I

DSL manuál. Ing. Jan Hranáč. 27. října V této kapitole je stručný průvodce k tvorbě v systému DrdSim a (v

17. Projekt Trojúhelníky

ALGORITMIZACE A PROGRAMOVÁNÍ

Algoritmy a datové struktury

Operační systémy. Cvičení 4: Programování v C pod Unixem

C# konzole Podíl dvou čísel, podmínka IF

Základy programování (IZP)

Transkript:

Rekurze Jan Hnilica Počítačové modelování 12 1

Rekurzivní charakter úlohy Výpočet faktoriálu faktoriál : n! = n (n - 1) (n - 2)... 2 1 (0! je definován jako 1) můžeme si všimnout, že výpočet n! obsahuje vnořené výpočty dalších faktoriálů: 6! = 6 5 4 3 2 1 5! = 5 4 3 2 1 4! =... pro n 1 můžeme napsat: n! = n (n - 1)! Rekurzivní úloha řešení úlohy obsahuje řešení dílčích podúloh stejného charakteru podobný rekurzivní chrakter bychom nalezli v řadě úloh - ciferný součet: CS(n) = n % 10 + CS(n / 10) // dokud n 0 - celočíselná mocnina Mocnina(n, exp) = n Mocnina(n, exp - 1) // dokud exp > 0 - průchod lineárním seznamem atd... Jan Hnilica Počítačové modelování 12 2

Rekurzivní funkce jazyk C (a řada dalších jazyků) umožňuje vytvářet tzv. rekurzivní funkce rekurzivní funkce = funkce, která ve svém těle volá sebe samu Rekurzivní funkce pro výpočet faktoriálu: vyjdeme z rekurzivní definice: n! = 1 // pro n == 0 = n (n - 1)! // pro n > 0 kterou ve funkci opíšeme : int Faktorial(int n) if (n < 2) return 1; return n * Faktorial(n - 1); Důležité: funkce má definovanou ukončovací podmínku, při jejímž splnění se další rekurzivní volání už neprovede při rekurzivním volání se mění parametry volané funkce, vždy dochází ke zjednodušení (zmenšení) úlohy Jan Hnilica Počítačové modelování 12 3

Co se děje při rekurzivním volání funkce totéž co u normálního volání funkcí, tzn. při volání funkce je na systémovém zásobníku vytvořen záznam, obsahující lokální proměnné volané funkce, návratovou adresu výsledku atd... volající funkce zastaví provádění kódu a čeká, až volaná funkce dokončí svou činnost poté co volaná funkce skončí, pokračuje volající funkce ve svém kódu při rekurzivním volání volající funkce zavolá svou rekurzivní odnož a čeká, až ta dokončí svoji práci volaná rekurzivní odnož postupuje úplně stejně, také volá další odnož a čeká, takto se postupuje dál, dokud čerstvě volaná funkce nenarazí na ukončovací podmínku najednou je rozpracováno více úloh, které všechny postupují podle téhož kódu při návratu nejdříve skončí funkce, volaná jako poslední, ta vrací řízení předposledně volané funkci... nejpozději skončí ta funkce, která byla volána jako první každá funkce má na zásobníku vlastní záznam (vlastní lokální proměnné atd.) jednotlivé funkce nemají přístup k lokálním proměnným jiných funkcí, můžou ale sdílet proměnné předávané odkazem (nebo globální proměnné) Jan Hnilica Počítačové modelování 12 4

F (4) čeká F (3) čeká F (2) čeká Co se děje při rekurzivním volání funkce Faktorial(4) čas = 4 Faktorial(3) = 3 Faktorial(2) = 2 Faktorial(1) 1 24 F(3) končí 6 F(2) končí 2 F(1) končí F(4) končí Poznámka: Nákres ilustruje fakt, že funkce, která byla volána jako první, dokončí svou práci jako poslední a naopak! (systém zásobníku) Jan Hnilica Počítačové modelování 12 5

Ilustrace rekurzivních volání void Pozpatku() char znak = getchar(); if (znak!= '\n') Pozpatku(); putchar(znak); 1. funkce načte znak na vstupu 2. načtený znak je - konec řádku => funkce končí - něco jiného => funkce volá sebe samu a až poté, co je vráceno řízení, vypíše načtený znak (později volané funkce mezitím načetly a vypsaly vstupní znaky až do konce řádku) výsledkem je otočení řetězce zadaného na vstupu: vstup: abcd výstup: bcda Jan Hnilica Počítačové modelování 12 6

Příklady jednoduchých rekurzivních funkcí Euklidův algoritmus pro výpočet největšího společného dělitele (NSD) jsou zadána dvě celá čísla A a B, úkolem je nalézt jejich NSD - největší číslo, které beze zbytku dělí jak A, tak B pro výpočet NSD se nabízí několik postupů 1. postupné zkoušení všech možných dělitelů 2. vypočítat prvočíselné rozklady A a B, NSD je jejich největší společná část např. 126 = 2 3 3 7 78 = 2 3 13 NSD (126, 78) = 6 3. Euklidův algoritmus: pokud A == B NSD(A, B) = A pokud A > B NSD(A, B) = NSD(A - B, B) pokud B > A NSD(A, B) = NSD(A, B - A) NSD(126, 78) = NSD(48, 78) = NSD(48, 30) = NSD(18, 30) = NSD(18, 12) = = NSD(6, 12) = NSD (6, 6) = 6 Jan Hnilica Počítačové modelování 12 7

Příklady jednoduchých rekurzivních funkcí Euklidův algoritmus pro výpočet největšího společného dělitele (NSD) rekurzivní předpis algoritmu: pokud A == B NSD(A, B) = A pokud A > B NSD(A, B) = NSD(A - B, B) pokud B > A NSD(A, B) = NSD(A, B - A) snadno přepíšeme na rekurzivní funkci: int NSD(int a, int b) if (a == b) return a; if (a > b) return NSD(a - b, b); else return NSD(a, b - a); Jan Hnilica Počítačové modelování 12 8

Příklady jednoduchých rekurzivních funkcí Průchod lineárním seznamem uvažujme jednoduchý LS sestavený z prvků: typedef struct prvek char znak; struct prvek * dalsi; Prvek; průchod seznamem (spojený např. s výpisem prvků) lze napsat takto: void VypisSeznam(Prvek * S) if (S!= NULL) printf("%c ", S->znak); VypisSeznam(S->dalsi); Jan Hnilica Počítačové modelování 12 9

Použití rekurze rekurze se obvykle nepoužívá k řešení úloh, které jdou snadno vyřešit cyklem všechny dosud uvedené funkce jdou snadno napsat i bez rekurze Euklidův NSD: int NSD(int a, int b) while (a!= b) if (a > b) a = a - b; else b = b - a; return a; Faktoriál: int Faktorial(int n) int f = 1; for (int i = n; i > 1; i--) f = f * i; return f; Jan Hnilica Počítačové modelování 12 10

Použití rekurze je nutné si uvědomit, že volání rekurzivních funkcí sebou nese určité náklady na čas a paměť (vytvoření proměnných na zásobníku, návratová adresa, skok do funkce, návrat z funkce...) lze-li úlohu jednoduše řešit bez použití rekurze, je takové řešení efektivnější v ne-rekurzivních algoritmech se většinou také snáze hledají chyby rekurze se obvykle používá v těchto případech: úlohy typu "vygeneruj všechny možnosti" prohledávání do hloubky (backtracking) algoritmy "rozděl a panuj" Jan Hnilica Počítačové modelování 12 11

Kombinatorické úlohy (generování všech možností) pro nácvik rekurze se dobře hodí úlohy na generování základních kombinatorických struktur, zároveň jde také o úlohy, kde je rekurze přirozeným a jednoduchým řešením problému, který by šel iterací řešit jen velmi těžko nejprve připomenutí základních pojmů: - máme n-prvkovou množinu, v našem případě čísla 1, 2,.., n - z této množiny budeme provádět k-prvkové výběry (k n), přičemž rozlišujeme: variace - ve výběru záleží na pořadí prvků, tzn. (1, 2, 3) je jiná variace než (1, 3, 2) kombinace - ve výběru na pořadí prvků nezáleží, tzn. (1, 2, 3) a (1, 3, 2) jsou tytéž kombinace u variací i kombinací dále rozlišujeme varianty a) s opakováním - prvky ve výběru se mohou opakovat (např. 1, 1, 2, 3) b) bez opakování - prvky se opakovat nemohou permutace - jsou variace bez opakování pro n = = k - jinak řečeno jde o záměny pořadí původní množiny prvků Jan Hnilica Počítačové modelování 12 12

Kombinatorické úlohy (generování všech možností) Příklad: n = 4, k = 2, provádíme tedy 2-prvkové výběry z množiny 1, 2, 3, 4 variace s opakováním (1,1) (1,2) (1,3) (1,4) (2,1) (2,2) (2,3) (2,4) (3,1) (3,2) (3,3) (3,4) (4,1) (4,2) (4,3) (4,4) variace bez opakování (1,2) (1,3) (1,4) (2,1) (2,3) (2,4) (3,1) (3,2) (3,4) (4,1) (4,2) (4,3) kombinace s opakováním (1,1) (1,2) (1,3) (1,4) (2,2) (2,3) (2,4) (3,3) (3,4) (4,4) kombinace bez opakování (1,2) (1,3) (1,4) (2,3) (2,4) (3, 4) Jan Hnilica Počítačové modelování 12 13

Kombinatorické úlohy (generování všech možností) Variace s opakováním úloha: vygenerovat všechny k-prvkové variace z množiny čísel 1, 2,..., n postup: na každou z k pozic postupně umístíme všechny hodnoty 1... n úloha řešitelná pomocí vnoření k cyklů, ale pouze za předpokladu, že k a n jsou předem pevně zadány: for (int c1 = 1; c1 <= n; c1++) for (int c2 = 1; c2 <= n; c2++) for (int c3 = 1; c3 <= n; c3++)... for (int ck = 1; ck <= n; ck++) printf("%i %i %i...%i", c1, c2, c3,..., ck); pokud jsou k a n vstupními parametry programu, nelze vnořené cykly použít (není předem známo, kolik jich do kódu napsat a do jaké meze mají probíhat) Jan Hnilica Počítačové modelování 12 14

Kombinatorické úlohy (generování všech možností) Variace s opakováním rekurzivní funkce řeší problém jednoduše parametry funkce: n, k... parametry variace variace...pole délky k, do kterého ukládáme výsledek index... pozice v poli variace, na kterou právě zapisujeme void VariaceSO(int n, int k, int variace[], int index) if (index == k) // hotová variace výpis a konec VypisPole(variace, k); else for (int i = 1; i <= n; i++) // postupně použijeme všechna čísla variace[index] = i; // umístíme číslo na danou pozici VariaceSO(n, k, variace, index + 1); // necháme vygenerovat zbytek rekurzivně volaná funkce stejným způsobem zpracuje další políčko variace analýza funkce je na další straně Jan Hnilica Počítačové modelování 12 15

Kombinatorické úlohy (generování všech možností) Variace s opakováním analýza funkce funkce obhospodařuje vždy jedno políčko vytvářené variace (s indexem index) o o o o v cyklu od 1 do n (tedy přes všechny přípustné hodnoty) do tohoto políčka zapíše aktuální hodnotu a zavolá rekurzivní funkci (svou vlastní kopii) kopie tak dostane ke zpracování pole, kde je políčko index už vyplněné a sama bude stejným způsobem vyplňovat další políčko (proto ji voláme s parametrem index + 1) a sama bude také volat své rekurzivní kopie rekurzivní volání končí ve chvíli, kdy volaná kopie dostane ke zpracování vyplněnou variaci (index == k), kterou jenom vypíše a vrátí řízení řízení se tak vrací k čekajícím funkcím, které pokračují ve svých cyklech a do příslušných polí vyplňují další čísla v pořadí funkci v programu voláme s parametrem index = 0 (začínáme s prázdnou variací) VariaceSO(n, k, variace, 0); Technická poznámka: pole variace je do funkcí předáváno odkazem (jako vždy v jazyce C, u polí si funkce nevyrábí lokální kopii, ale pracují přímo s předaným polem, změny v poli se tak projeví i mimo funkci) všechny rekurzivní exempláře tedy pracují nad tím samým polem v paměti. Jan Hnilica Počítačové modelování 12 16

Kombinatorické úlohy (generování všech možností) Variace s opakováním analýza funkce průběh volání pro n = 3, k = 2, tvoříme tedy 2-prvkové variace z množiny 1, 2, 3 v závorkách funkce je uveden pouze parametr index (červeně), zelené číslo v kroužku udává pořadí, v jakém byla funkce volána, zároveň je znázorněn stav pole variace 1 VO(0) 1 3 2 VO(1) 1 1 1 3 1 2 3 4 5 VO(2) VO(2) VO(2) výpis výpis výpis 2 6 VO(1) 11 3 1 VO(2) výpis 10 12 3 2 VO(1) VO(2) výpis 13 3 3 VO(2) výpis 2 1 2 2 2 3 7 VO(2) 8 VO(2) 9 výpis výpis VO(2) výpis Jan Hnilica Počítačové modelování 12 17

Kombinatorické úlohy (generování všech možností) Variace bez opakování řešíme obdobně jako variace s opakováním, ale před zapsáním čísla i na j-tou pozici je potřeba zjistit, jestli číslo i už není zapsáno na jedné z předchozích pozic [0]..[j - 1] to lze provést několika způsoby a) před zapsáním čísla prohledat doposud vygenerovanou část (od 0 do index - 1) b) jako parametr funkce přidat pomocné pole příznaků (0/1) signalizujících, jestli dané číslo ve variaci je či není, zápis čísla do variace pak může vypadat takto: // zápis čísel do variace for (int i = 1; i <= n; i++) if (!pouzite[i]) // pokud číslo ve variaci zatím není variace[index] = i; // zapíšeme ho pouzite[i] = 1; // oznacime ho jako použité VariaceBO(n, k, index + 1, pouzite, variace); // vygenerujeme zbytek pouzite[i] = 0; // číslo před návratem nahoru uvolníme pro další variace Jan Hnilica Počítačové modelování 12 18

Kombinatorické úlohy (generování všech možností) Kombinace s opakováním řešíme podobně jako variace, ale aby nedošlo k vygenerování stejných kombinací (lišících se pouze pořadím prvků), generujeme pouze neklesající (či nerostoucí) posloupnosti při zápisu čísla do kombinace tedy musíme zjistit minimální (či maximální) hodnotu, kterou na danou pozici můžeme zapsat (prohledat dosud zapsanou část kombinace, předávat minimum jako parametr funkce...) Kombinace bez opakování stejné jako kombinace s opakováním, ale generujeme pouze ostře rostoucí (či klesající) posloupnosti Jan Hnilica Počítačové modelování 12 19

Generování všech možností Palindromy palindrom = slovo, které se čte z obou stran stejně (např. madam) úloha: máme zadaný řetězec, cílem je vygenerovat všechny palindromy, které lze získat vyškrtáním některých znaků řetězce telepatie => epe telepatie => tat telepatie => telet... Řešení rekurzivní generování všech pod-řetězců, testování na palindromicitu, výpis palindromů pro řetězec délky n je 2 n možných pod-řetězců (každý ze znaků v pod-řetězci buďto je a nebo není) generování pod-řetězců: - použijeme pole příznaků, udávajících jestli je znak v aktuálním pod-řetězci obsažen - každý znak postupně použijeme (příznak = 1) nebo nepoužijeme (příznak = 0) a zavoláme tutéž funkci, která takto ošetří další znak v pořadí - vždy po nastavení celé n-tice příznaků pod-řetězec otestujeme Jan Hnilica Počítačové modelování 12 20

Kdy rekurzi nepoužívat Fibonacciho posloupnost je nekonečná posloupnost přirozených čísel F i (pro i = 0, 1, ), kde platí F i = i pro i = 0, 1 F i = F i 1 + F i 2 pro i > 1 prvními dvěma členy jsou 0 a 1, každý další člen pak získáme jako součet dvou předchozích: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144... Úloha: napišme funkci, která spočítá n-tý člen Fibonacciho posloupnosti rekurzivní definice F i = F i 1 + F i 2 přímo svádí k napsání rekurzivní funkce, která by mohla vypadat takto: int Fibonacci(int n) if (n <= 1) return n; return Fibonacci(n - 1) + Fibonacci(n - 2); Jan Hnilica Počítačové modelování 12 21

Kdy rekurzi nepoužívat Fibonacciho posloupnost funkce z předchozí strany počítá správně, ale pomalu, zkuste n > 40 (pozor, do 4-bytového int se vejde maximálně F 46, do unsigned int pak F 47 ) důvodem je opakované počítání stejných funkčních hodnot F 5 F 4 F 3 F 3 F 2 F 2 F 1 F 2 F 1 F 1 F 0 F 1 F 0 Obrázek ukazuje větvení rekurzivních volání při výpočtu F 5. Funkce F 2 je během výpočtu volána 3-krát, funkce F 1 dokonce 5-krát. Při výpočtu vyšších členů posloupnosti bude počet opakovaných volání stejných funkcí dramaticky narůstat. F 1 F 0 Jan Hnilica Počítačové modelování 12 22

Kdy rekurzi nepoužívat Fibonacciho posloupnost časová složitost rekurzivního algoritmu je O(2 n ) - při volání F i (i > 1) se výpočet vždy rozdělí na dvě větve - větvení skončí když jsou volány funkce F0 a F1, což při výpočtu F n nastane v n-tém zanoření řešení 1: použít pomocné pole a zaznamenávat si do něj již spočtené hodnoty, při výpočtu F i se nejprve podívat, jestli už hodnota nebyla spočtena => O(n) rešení 2: počítat od spoda a úlohu tak vyřešit prostým cyklem => O(n) int Fibonacci(int n) if (n <= 1) return n; int f0 = 0, f1 = 1, fn; for (int i = 2; i <= n; i++) fn = f0 + f1; f0 = f1; f1 = fn; return fn; (a ušetříme rekurzivní volání) Jan Hnilica Počítačové modelování 12 23

Poznámky Kdy rekurzi používat? pokud nevede k extrémním časovým nárokům algoritmu pokud rekurzivní funkce významně zjednoduší zápis algoritmu pokud ne-rekurzivní řešení úlohy neznáme Rekurzivní algoritmus bez rekurzivní funkce rekurzivní algoritmy využívají systémového zásobníku, ale datovou strukturu zásobník si můžeme naprogramovat sami program pracuje pomocí běžného cyklu, ze zásobníku vždy odebere ke zpracování dílčí úlohu a uloží do něj nové úlohy zniklé rekurzivním dělením odebrané úlohy, algoritmus končí vyprázdněním zásobníku (pracnější na naprogramování, ale efektivnější vyhneme se volání funkcí) Nepřímá rekurze rekurzivní volání může být skryto - funkce A volá ve svém těle funkci B, která zase volá funkci A Jan Hnilica Počítačové modelování 12 24