Rekurze. Jan Faigl. Katedra počítačů Fakulta elektrotechnická České vysoké učení technické v Praze. Přednáška 6 A0B36PR1 Programování 1

Podobné dokumenty
Rekurze. Jan Faigl. Katedra počítačů Fakulta elektrotechnická České vysoké učení technické v Praze. Přednáška 6 A0B36PR1 Programování 1

8. Rekurze. doc. Ing. Jiří Vokřínek, Ph.D. Katedra počítačů Fakulta elektrotechnická České vysoké učení technické v Praze

Část I. Rekurze. Část 1 Rekurze. Rekurze. Část 2 Příklady. Katedra počítačů Fakulta elektrotechnická České vysoké učení technické v Praze

Rozklad problému na podproblémy

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

Rozklad problému na podproblémy, rekurze

Rozklad problému na podproblémy, rekurze

Standardní knihovny C. Rekurze.

Náplň. v Jednoduché příklady na práci s poli v C - Vlastnosti třídění - Způsoby (algoritmy) třídění

A4B33ALG 2010/05 ALG 07. Selection sort (Select sort) Insertion sort (Insert sort) Bubble sort deprecated. Quicksort.

int t1, t2, t3, t4, t5, t6, t7, prumer; t1=sys.readint();... t7=sys.readint(); prume pru r = r = ( 1+t 1+t t3+ t3+ t4 t5+ t5+ +t7 +t7 )/ ;

Funkce a procedury. Jan Faigl. Katedra počítačů Fakulta elektrotechnická České vysoké učení technické v Praze. Přednáška 5 A0B36PR1 Programování 1

Standardní knihovny C. Rekurze.

Část 1 Funkce, lokální proměnné a přidělování paměti. Funkce a procedury. Část 2 Cykly a řízení jejich průchodu. Část 3 Příklady

Část I. Část 1 Standardní knihovny, čtení/zápis ze souboru. Přehled témat. Standardní knihovny C. Rekurze. Standardní knihovny

Část 1 Standardní knihovny, čtení/zápis ze/do souboru

DobSort. Úvod do programování. DobSort Implementace 1/3. DobSort Implementace 2/3. DobSort - Příklad. DobSort Implementace 3/3

Hledání k-tého nejmenšího prvku

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

IB111 Úvod do programování skrze Python

Dynamické datové struktury III.

IAJCE Přednáška č. 9. int[] pole = new int[pocet] int max = pole[0]; int id; for(int i =1; i< pole.length; i++) { // nikoli 0 if (Pole[i] > max) {

Algoritmizace řazení Bubble Sort

Stromy. Karel Richta a kol. Katedra počítačů Fakulta elektrotechnická České vysoké učení technické v Praze Karel Richta a kol.

Algoritmy I, složitost

Algoritmizace a programování

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

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

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

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

Michal Krátký. Úvod do programovacích jazyků (Java), 2006/2007

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

součet cvičení celkem. známka. Úloha č.: max. bodů: skut. bodů:

V případě jazyka Java bychom abstraktní datový typ Time reprezentující čas mohli definovat pomocí třídy takto:

5. Vyhledávání a řazení 1

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

10. Složitost a výkon

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

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

Dekompozice problému, rekurze

Časová složitost algoritmů

Základy řazení. Karel Richta a kol.

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

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

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

Databáze, sítě a techniky programování X33DSP

Rekurze. 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.

Slepé prohledávání do šířky Algoritmus prohledávání do šířky Při tomto způsobu prohledávání máme jistotu, že vždy nalezneme koncový stav, musíme ale p

Michal Krátký. Úvod do programovacích jazyků (Java), 2006/2007

Algoritmizace prostorových úloh

Zadání k 2. programovacímu testu

Algoritmy a datové struktury

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

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

3. přednáška. Obsah: Řídící struktury sekvence, if-else, switch, for, while, do-while. Zpracování posloupnosti

IB111 Úvod do programování skrze Python

Úvod do programovacích jazyků (Java)

Prioritní fronta, halda

Rekurzivní algoritmy

BI-EP1 Efektivní programování 1

Algoritmy a datové struktury

Úvod do programovacích jazyků (Java)

11. Přehled prog. jazyků

Datové struktury. alg12 1

Řetězce a řídicí struktury

Seznamy a iterátory. Kolekce obecně. Rozhraní kolekce. Procházení kolekcí

Test prvočíselnosti. Úkol: otestovat dané číslo N, zda je prvočíslem

Bubble sort. příklad. Shaker sort

Třídění a vyhledávání Searching and sorting

Časová složitost / Time complexity

Časová složitost algoritmů, řazení a vyhledávání

NPRG030 Programování I, 2018/19 1 / :03:07

Pole a kolekce. v C#, Javě a C++

Implementace LL(1) překladů

ALG 09. Radix sort (přihrádkové řazení) Counting sort. Přehled asymptotických rychlostí jednotlivých řazení. Ilustrační experiment řazení

Paměť počítače. alg2 1

Dynamické programování

Paralelní a distribuované výpočty (B4B36PDV)

přirozený algoritmus seřadí prvky 1,3,2,8,9,7 a prvky 4,5,6 nechává Metody řazení se dělí:

5. Dynamické programování

2 Strukturované datové typy Pole Záznam Množina... 4

Úvod do programování 10. hodina

Základní pojmy. Úvod do programování. Základní pojmy. Zápis algoritmu. Výraz. Základní pojmy

2.1 Podmínka typu case Cykly Cyklus s podmínkou na začátku Cyklus s podmínkou na konci... 5

Algoritmizace prostorových úloh

Základy algoritmizace a programování

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

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

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

Maturitní téma: Programovací jazyk JAVA

Filtrace snímků ve frekvenční oblasti. Rychlá fourierova transformace

Fronta (Queue) Úvod do programování. Fronta implementace. Fronta implementace pomocí pole 1/4. Fronta implementace pomocí pole 3/4

Část I Spojové struktury

Obsah přednášky. programovacího jazyka. Motivace. Princip denotační sémantiky Sémantické funkce Výrazy Příkazy Vstup a výstup Kontinuace Program

Algoritmy vyhledávání a řazení. Zatím nad lineární datovou strukturou (polem)

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

Universita Pardubice Fakulta elektrotechniky a informatiky. Mikroprocesorová technika. Semestrální práce

Příklad aplikace Klient/Server s Boss/Worker modelem (informativní)

Transkript:

Rekurze Jan Faigl Katedra počítačů Fakulta elektrotechnická České vysoké učení technické v Praze Přednáška 6 A0B36PR1 Programování 1 Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 1 / 90

Část 1 Rekurze Faktoriál Obrácený výpis Karel Hanojské věže Rekurze Fibonacciho posloupnost Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 2 / 90

Část 2 Příklady Eratosthenovo síto Řazení Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 3 / 90

Část I Rekurze Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 4 / 90

Výpočet faktoriálu Iterace n! = n(n 1)(n 2)... 2 1 int factoriali(int n) { int f = 1; for(; n > 1; --n) { f *= n; } return f; } Rekurze n! = 1 pro n 1 n! = n(n 1)! pro n > 1 int factorialr(int n) { int f = 1; if (n > 1) { f = n * factorialr(n-1); } return f; } lec05/demofactorial.java Připomínka Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 6 / 90

Příklad výpis posloupnosti 1/3 Vytvořte program, který přečte posloupnost čísel a vypíše ji v opačném pořadí Rozklad problému: Zavedeme abstraktní příkaz: obrať posloupnost Příkaz rozložíme do tří kroků: 1. Přečti číslo číslo uložíme pro pozdější obrácený výpis 2. Pokud není detekován konec posloupnost obrať posloupnost pokračujeme ve čtení čísel 3. Vypiš číslo vypíšeme uložené číslo Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 8 / 90

Příklad výpis posloupnosti 2/3 1 void reverse() { 2 int v = scan.nextint(); 3 if (scan.hasnext()) { 4 reverse(); 5 } 6 System.out.printf("%3d ", v); 7 } 8 9 public void start() { 10 System.err.println("Enter a sequence of numbers ( use ctr+d for the end of the the sequence"); 11 reverse(); 12 System.out.println(""); //end of line 13 } lec06/demorevertsequence.java Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 9 / 90

Příklad výpis posloupnosti 3/3 lec06/demorevertsequence.java Vytvoření posloupností./generate_numbers.sh tr \n cat > numbers.txt javac DemoRevertSequence.java java DemoRevertSequence < numbers.txt 2>/dev/null > numbers-r. txt java DemoRevertSequence <numbers-r.txt 2>/dev/null > numbers-rr.txt Příkaz pro výpis obsahu souborů for i in numbers.txt numbers-r.txt numbers-rr.txt; do echo "$i"; cat $i; echo ""; done Výpis obsahu souborů numbers.txt 10 4 20 8 8 5 18 6 7 7 numbers-r.txt 7 7 6 18 5 8 8 20 4 10 numbers-rr.txt 10 4 20 8 8 5 18 6 7 7 Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 10 / 90

Robot Karel hledání beeperu Robot Karel má za úkol najít beeper v bludišti a vrátit se s ním zpět na výchozí pozici Karel se pohybuje v mřížkovém ortogonálním světě Karel umí: jít rovně o jeden krok otočit se doleva o 90 vzít / položit beeper vypnout se Karel umí zjistit, zdali: je před ním zeď na políčku, na kterém stojí, je beeper Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 12 / 90

Robot Karel Iterační řešení 1/3 Návrh řešení 1. Jdi podél zdi (po pravé straně) dokud není na políčku beeper a počítej počet kroků; 2. Seber beeper ; 3. Otoč se a jdi podél zdi (po levé straně) a udělej stejný počet kroků jako při hledání beeperu ; 4. Polož beeper a vypni se. Abstraktní příkazy pro nalezení beeperu sledování zdi na pravé straně: Otoč se doprava: turnright Zjisti, zda-li je na pravé straně zeď: iswallonright Jdi podél pravé zdi: gobyrightwall Analogické abstraktní příkazy pro pohyb podél zdi na levé straně: iswallonleft a gobyleftwall Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 13 / 90

Robot Karel Iterační řešení 2/3 1 void turnright() { 2 for (int i = 0; i < 3; i++) { 3 turnleft(); 4 } 5 } 6 7 boolean iswallonright() { 8 turnright(); 9 boolean out = isinfrontofwall(); 10 11 turnleft(); return out; 12 } 13 14 void gobyrightwall() { 15 while (!isonbeeper()) { 16 if (!wallonright()) { 17 turnright(); 18 } 19 while (isinfrontofwall()) { 20 turnleft(); 21 } 22 step(); 23 } 24 } Analogicky pro zeď po levé straně Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 14 / 90

Robot Karel Iterační řešení 3/3 Počet kroků je inkrementován v proceduře step Při návratu podél levé zdi Karel ujde stejný počet kroků 1 public void execute() { 2 gobyright(); 3 pickbeeper(); 4 turnaround(); 5 6 if (stepstaken > 0) { 7 gobyleft(stepstaken); 8 } 9 10 putbeeper(); 11 turnoff(); 12 } Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 15 / 90

Robot Karel Rekurzivní řešení 1/3 Řešení rekurzí založíme na opakovaném volání funkce, která posune robot pouze o jeden krok vpřed a následně jej vrátí zpět ve funkci go: 1. Pokud jsi na beeperu seber jej a otoč o 180 a ukonči hledání 2. Zapamatuj si svou orientaci a udělej jeden krok podél pravé zdi 3. go (opakuj hledání o jeden krok) 4. Udělej jeden krok zpět (vrať se o jeden krok zpět a natoč se do původního směru) Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 16 / 90

Robot Karel Rekurzivní řešení 2/3 1 void go() { 2 if (isonbeeper()) { 3 pickbeeper(); 4 5 turnaround(); //turn back return; 6 7 } int numberturnright = 0; 8 if (!iswallonright()) { 9 10 turnright(); numberturnright++; 11 } 12 13 while (isinfrontofwall()) { 14 15 turnleft(); numberturnright--; 16 } 17 move(); //move forward 18 go(); 19 move(); //move backward 20 21 numberturnright = (numberturnright + 4) % 4; 22 for (int i = 0; i < numberturnright; ++i) { 23 turnleft(); //revert the turns 24 } 25 } Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 17 / 90

Robot Karel Rekurzivní řešení 3/3 Hlavní procedura obsahuje pouze volání funkce go, která vrací robot na výchozí políčko 1 void execute() { 2 go(); 3 putbeeper(); 4 turnoff(); 5 } Pro spuštění využijeme knihovnu KarelJRobot.jar a modifikovaný svět maze.klwd javac -cp lib/kareljrobot.jar DemoKarel.java java -cp lib/kareljrobot.jar:. DemoKarel Robot se při zpáteční cestě vrací rychleji, protože již explicitně nekontroluje, zda-li je zeď na levé straně. lec06/demokarel.java Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 18 / 90

Příklad Hanojské věže 1 2 3 Přemístit disky na druhou jehlu s použitím třetí (pomocné) jehly za dodržení pravidel: 1. V každém kroku můžeme přemístit pouze jeden disk a to vždy z jehly na jehlu Disky nelze odkládat mimo jehly 2. Položit větší disk na menší není dovoleno Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 20 / 90

Hanojské věže 1 disk 1 Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 21 / 90

Hanojské věže 1 disk 1 Přesunutý disk z jehly 1 na jehlu 2. Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 22 / 90

Hanojské věže 1 disk Hotovo 1 Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 23 / 90

Hanojské věže 2 disky 1 2 Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 24 / 90

Hanojské věže 2 disky 2 1 Přesunutý disk z jehly 1 na jehlu 3. Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 25 / 90

Hanojské věže 2 disky 2 1 Přesunutý disk z jehly 1 na jehlu 2. Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 26 / 90

Hanojské věže 2 disky 1 2 Přesunutý disk z jehly 3 na jehlu 2. Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 27 / 90

Hanojské věže 2 disky Hotovo 1 2 Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 28 / 90

Hanojské věže 3 disky 1 2 3 Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 29 / 90

Hanojské věže 3 disky 2 3 1 Přesunutý disk z jehly 1 na jehlu 2. Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 30 / 90

Hanojské věže 3 disky 3 1 2 Přesunutý disk z jehly 1 na jehlu 3. Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 31 / 90

Hanojské věže 3 disky 1 3 2 Přesunutý disk z jehly 2 na jehlu 3. Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 32 / 90

Hanojské věže 3 disky 1 3 2 Přesunutý disk z jehly 1 na jehlu 2. Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 33 / 90

Hanojské věže 3 disky 1 3 2 Přesunutý disk z jehly 3 na jehlu 1. Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 34 / 90

Hanojské věže 3 disky 2 1 3 Přesunutý disk z jehly 3 na jehlu 2. Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 35 / 90

Hanojské věže 3 disky 1 2 3 Přesunutý disk z jehly 1 na jehlu 2. Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 36 / 90

Hanojské věže 3 disky Hotovo 1 2 3 Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 37 / 90

Hanojské věže 4 disky 1 2 3 4 Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 38 / 90

Hanojské věže 4 disky 2 3 4 1 Přesunutý disk z jehly 1 na jehlu 3. Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 39 / 90

Hanojské věže 4 disky 3 4 2 1 Přesunutý disk z jehly 1 na jehlu 2. Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 40 / 90

Hanojské věže 4 disky 3 4 1 2 Přesunutý disk z jehly 3 na jehlu 2. Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 41 / 90

Hanojské věže 4 disky 1 4 2 3 Přesunutý disk z jehly 1 na jehlu 3. Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 42 / 90

Hanojské věže 4 disky 1 4 2 3 Přesunutý disk z jehly 2 na jehlu 1. Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 43 / 90

Hanojské věže 4 disky 1 4 2 3 Přesunutý disk z jehly 2 na jehlu 3. Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 44 / 90

Hanojské věže 4 disky 1 2 4 3 Přesunutý disk z jehly 1 na jehlu 3. Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 45 / 90

Hanojské věže 4 disky 1 2 4 3 Přesunutý disk z jehly 1 na jehlu 2. Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 46 / 90

Hanojské věže 4 disky 1 4 2 3 Přesunutý disk z jehly 3 na jehlu 2. Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 47 / 90

Hanojské věže 4 disky 1 2 4 3 Přesunutý disk z jehly 3 na jehlu 1. Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 48 / 90

Hanojské věže 4 disky 1 2 4 3 Přesunutý disk z jehly 2 na jehlu 1. Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 49 / 90

Hanojské věže 4 disky 1 2 3 4 Přesunutý disk z jehly 3 na jehlu 2. Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 50 / 90

Hanojské věže 4 disky 3 2 4 1 Přesunutý disk z jehly 1 na jehlu 3. Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 51 / 90

Hanojské věže 4 disky 2 3 4 1 Přesunutý disk z jehly 1 na jehlu 2. Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 52 / 90

Hanojské věže 4 disky 1 2 3 4 Přesunutý disk z jehly 3 na jehlu 2. Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 53 / 90

Hanojské věže 4 disky Hotovo 1 2 3 4 Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 54 / 90

Hanojské věže 5 disků 1 2 3 4 5? Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 55 / 90

Návrh řešení 1 2 3 4 5 Zavedeme abstraktní příkaz movetower(n, 1, 2, 3) realizující přesun n disků z jehly 1 na jehlu 2 s použitím jehly 3. Pro n > 0 můžeme příkaz rozložit na tři jednodušší příkazy 1. movetower(n-1, 1, 3, 2) přesun n 1 disků z jehly 1 na jehlu 3 2. přenes disk z jehly na jehlu 2 přesun největšího disku na cílovou pozici abstraktní příkaz 3. movetower(n-1, 3, 2, 1) přesun n 1 disků na cílovou pozici Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 56 / 90

Příklad řešení 1 void movetower(int n, int from, int to, int tmp) { 2 if (n > 0) { 3 movetower(n - 1, from, tmp, to); //move to tmp 4 System.out.println("Move disc from " + from + " to " + to); 5 movetower(n - 1, tmp, to, from); //move from tmp 6 } 7 } 8 9 void start() { 10 int numberofdiscs = 5; 11 movetower(numberofdiscs, 1, 2, 3); 12 } lec06/demotowersofhanoi.java Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 57 / 90

Příklad výpisu lec06/demotowersofhanoi.java java DemoTowersOfHanoi 3 Move disc from 1 to 2 Move disc from 1 to 3 Move disc from 2 to 3 Move disc from 1 to 2 Move disc from 3 to 1 Move disc from 3 to 2 Move disc from 1 to 2 java DemoTowersOfHanoi 4 Move disc from 1 to 3 Move disc from 1 to 2 Move disc from 3 to 2 Move disc from 1 to 3 Move disc from 2 to 1 Move disc from 2 to 3 Move disc from 1 to 3 Move disc from 1 to 2 Move disc from 3 to 2 Move disc from 3 to 1 Move disc from 2 to 1 Move disc from 3 to 2 Move disc from 1 to 3 Move disc from 1 to 2 Move disc from 3 to 2 Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 58 / 90

Rekurzivní algoritmy Rekurzivní funkce jsou přímou realizací rekurzivních algoritmů Rekurzivní algoritmus předepisuje výpočet shora dolů v závislosti na velikosti vstupních dat Pro nejmenší (nejjednodušší) vstup je výpočet předepsán přímo Pro obecný vstup je výpočet předepsán s využitím téhož algoritmu pro menší vstup Výhodou rekurzivních funkcí je jednoduchost a přehlednost Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 60 / 90

Rekurzivní vs iteračními algoritmy Nevýhodou rekurzivních algoritmů může být časová náročnost způsobená např. zbytečným opakováním výpočtu Řadu rekurzivních algoritmů lze nahradit iteračními, které počítají výsledek zdola nahoru, tj. od menších (jednodušších) vstupních dat k větším (složitějším). Pokud algoritmus výpočtu zdola nahoru nenajdeme, např. při řešení problému Hanojských věží, lze rekurzivitu odstranit pomocí zásobníku. Např. zásobník využijeme pro uložení stavu řešení problému. Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 61 / 90

Rekurze To iterate is human, to recurse divine. L. Peter Deutsch http://www.devtopics.com/101-great-computer-programming-quotes Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 62 / 90

Elegance vs obtížnost rekurze I ve often heard people describe understanding recursion as one of those got it moments, when the universe opened its secret stores of knowledge and gifted the mind of a burgeoning developer with a very powerful tool. For me, recursion has always been hard. Each time I m able to peer more into its murky depths, I am humbled to see how little I feel like I really appreciate and understand its power and elegance. Rick Winfrey, 2012 to-iterate-is-human-to-recurse-divine http://selfless-singleton.rickwinfrey.com/2012/11/27/ Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 63 / 90

Fibonacciho posloupnost 1, 1, 2, 3, 5, 8, 13, 21, 34, 55,... F n = F n 1 + F n 2 pro F 1 = 1, F 2 = 1 Nebo 0, 1, 1, 2, 3, 5,... Nebo F 1 = 0, F 2 = 1 2 3 1 1 5 8 Nekonečná posloupnost přirozených čísel, kde každé číslo je součtem dvou předchozích. Limita poměru dvou následujících čísel Fibonacciho posloupnosti je rovna zlatému řezu. Sectio aurea ideální poměr mezi různými délkami Rozdělení úsečky na dvě části tak, že poměr větší části ku menší je stejný jako poměr celé úsečky k větší části ϕ = 1+ 5 2 1,618 033 988 749 894 848... Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 65 / 90

Fibonacciho posloupnost historie Indičtí matematici (450 nebo 200 BC) Leonardo Pisano (1175 1250) popis růstu populace králíků italský matematik známý také jako Fibonacci F n velikost populace po n měsících za předpokladu První měsíc se narodí jediný pár. Narozené páry jsou produktivní od 2. měsíce svého života. Každý měsíc zplodí každý produktivní pár jeden další pár. Králíci nikdy neumírají, nejsou nemocní atd. Henry E. Dudeney (1857 1930) popis populace krav Jestliže každá kráva vyprodukuje své první tele (jalovici) za rok a poté každý rok jednu další jalovici, kolik budete mít krav za 12 let, jestliže žádná nezemře a na počátku budete mít jednu krávu? Po 12 let je k dispozici jeden či více býků Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 66 / 90

Fibonacciho posloupnost rekurzivně Platí: f 0 = 1 f 1 = 1 f n = f n 1 + f n 2, pro n > 1 1 int fibonacci(int n) { 2 return n < 2 3? 1 4 : fibonacci(n - 1) + fibonacci(n - 2); 5 } Zápis je elegantní, jak je však takový výpočet efektivní? Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 67 / 90

Fibonacciho posloupnost příklad 1/2 Počet operací při výpočtu Fibonacciho čísla n 1 long counter; 2 3 long fibonnacirecursive(int n) { 4 counter++; 5 return n < 2 6? 1 7 : fibonnacirecursive(n-1) + fibonnacirecursive(n-2); 8 } 9 10 long fibonnaciiterative(int n) { 11 long fibm2 = 1l; 12 long fibm1 = 1l; 13 long fib = 1l; 14 for (int i = 2; i <= n; ++i) { 15 fibm2 = fibm1; 16 fibm1 = fib; 17 fib = fibm1 + fibm2; 18 counter += 3; 19 } 20 return fib; 21 } lec06/demofibonacci.java Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 68 / 90

Fibonacciho posloupnost rekurzivně 2/2 1 public void start(string[] args) { 2 3 int n = args.length > 0? Integer.parseInt(args[0]) : 25; counter = 0; 4 5 long fibr = fibonnacir(n); long counter = counter; 6 7 counter = 0; 8 9 long fibi = fibonnacii(n); long countei = counter; 10 11 System.out.println("Fibonacci number recursive: " + fibr); 12 System.out.println("Fibonacci number iteration: " + fibi); 13 System.out.println("Counter recursive: " + counter); 14 System.out.println("Counter recursive: " + countei); 15 } javac DemoFibonacci.java java DemoFibonacci 30 Fibonacci number recursive: 1346269 Fibonacci number iteration: 1346269 Counter recursive: 2692537 Counter iteration: 8 lec06/demofibonacci.java Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 69 / 90

Fibonacciho posloupnost rekurzivně vs iteračně Rekurzivní výpočet Složitost roste exponenciálně s n 2 n Iterační algoritmus Počet operací je proporcionální n 3n lec06/demofibonaccistats.java, lec06/fibonacci.sh Skutečný počet operací závisí na konkrétní implementaci, programovacím jazyku, překladači a hardware Složitost algoritmů proto vyjadřujeme asymptoticky jako funkci velikosti vstupu Například v tzv. Big O notaci rekurzivní algoritmus výpočtu má složitost O(2 n ) iterační algoritmus výpočtu má složitost O(n) Efektivní algoritmy mají polynomiální složitost Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 70 / 90

Eratosthenovo síto Řazení Část II Příklady Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 71 / 90

Eratosthenovo síto Řazení Pole reprezentující množinu prvočísel Vypsat všechna prvočísla menší nebo rovna zadané hodnotě max Algoritmus: 1. Vytvoříme množinu obsahující všechna přirozená čísla od 2 do max 2. Z množiny vypustíme násobky čísla 2 3. Najdeme nejbližší číslo k tomu, jehož násobky jsme v předchozím kroku vypustili, a vypustíme všechny násobky tohoto čísla 4. Opakujeme krok 3, dokud číslo, jehož násobky jsme vypustili, není větší než odmocnina z max 5. Čísla, která v množině zůstanou, jsou hledaná prvočísla Pro reprezentaci množiny čísel použijeme pole prvků typu boolean, kde prvek pole sieve[i] udává, zda-li je celé číslo i v množině (true) nebo není (false), tj. zda-li je nebo není prvočíslem Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 73 / 90

Eratosthenovo síto Řazení Eratosthenovo síto 1/2 1 boolean[] createsieve(int max) { 2 boolean[] sieve = new boolean[max + 1]; 3 for (int i = 2; i <= max; ++i) { 4 sieve[i] = true; 5 } 6 int p = 2; 7 int pmax = (int)math.sqrt(max); 8 do { 9 for(int i = p + p; i <= max; i += p) { 10 sieve[i] = false; 11 } 12 do { 13 p++; 14 } while (!sieve[p]); 15 } while (p <= pmax); 16 return sieve; 17 } lec06/demosieveoferatosthenes.java Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 74 / 90

Eratosthenovo síto Řazení Eratosthenovo síto 2/2 1 void print(boolean[] sieve) { 2 for(int i = 2; i < sieve.length; ++i) { 3 if (sieve[i]) { 4 System.out.print(i + " "); 5 } 6 } 7 } 8 9 void start(int max) { 10 boolean[] sieve = createsieve(max); 11 System.out.print("Prime numbers from 2 to " + max + ": "); 12 print(sieve); 13 System.out.println(""); 14 } javac DemoSieveOfEratosthenes.java java DemoSieveOfEratosthenes Prime numbers from 2 to 100: 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 java DemoSieveOfEratosthenes 30 Prime numbers from 2 to 30: 2 3 5 7 11 13 17 19 23 29 lec06/demosieveoferatosthenes.java Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 75 / 90

Eratosthenovo síto Řazení Řazení pole Problém seřadit množinu prvků podle klíče (celého čísla) Posloupnost prvků q = a 1,..., a n Délka posloupnosti q je q = n Posloupnost q je seřazená, právě tehdy když q < 2 q 2 klíč(a 1 ) klíč(a 2 ) a posloupnost a 2,... je seřazená a neobsahuje prvek a 1. Řazení polí je řazením na místě Pro jednoduchost v příkladech řadíme jen celá čísla, prakticky však zpravidla řadíme dle klíče datových položek. Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 77 / 90

Eratosthenovo síto Řazení Řazení přímým vkládáním Insert Sort 1/2 Příklad - Řazení přímým vkládáním 1 2 3 4 5 6 44 55 12 42 94 18 1 2 3 4 5 6 44 44 55 12 44 55 12 42 44 55 12 42 44 55 94 12 18 42 44 55 94 Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 78 / 90

Eratosthenovo síto Řazení Řazení přímým vkládáním Insert Sort 2/2 for i 2, n vlož a i na patřičné místo mezi a 1,..., a i Příklad - Algoritmus 1 void insertsort(int[] array) { 2 int x; 3 int j; 4 for (int i = 1; i < array.length; i++) { 5 6 x = array[i]; j = i - 1; 7 while (j >= 0 && x < array[j]) { 8 9 array[j + 1] = array[j]; j--; 10 11 } array[j + 1] = x; 12 13 } } Řazení binárním vkládáním - vkládání provádíme do již uspořádaného pole a 1,..., a i 1. Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 79 / 90

Eratosthenovo síto Řazení Řazení přímým výběr Select Sort 1/3 for i 1, n { najdi index k nejmenšího prvku v a i,..., a n, a k = min a i,... a n, zaměň prvky a i, a k } Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 80 / 90

Eratosthenovo síto Řazení Řazení přímým výběr Select Sort 2/3 Příklad - Řazení přímým výběrem Select Sort 1 2 3 4 5 6 44 55 12 42 94 18 1 12 55 44 42 94 18 2 12 18 44 42 94 55 3 12 18 42 44 94 55 4 12 18 42 44 94 55 5 12 18 42 44 55 94 6 12 18 42 44 55 94 Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 81 / 90

Eratosthenovo síto Řazení Řazení přímým výběr Select Sort 3/3 Příklad implementace 1 void selectsort(int[] array) { 2 for (int i = 0; i < array.length-1; ++i) { 3 int minidx = i; 4 for (int j = i + 1; j < array.length; ++j) { 5 if (array[minidx] > array[j]) { 6 minidx = j; 7 } 8 } 9 swap(minidx, i, array); 10 } 11 } Zde pro jednoduchost řadíme jen celá čísla, prakticky však zpravidla řadíme dle klíče datových položek. Složitost O(n 2 ), kde n je počet položek Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 82 / 90

Eratosthenovo síto Řazení Řazení rozdělováním Quick Sort Nejvýznamnější výměny jsou ty na velké vzdálenosti. Pole rozdělíme nějakým prvkem x (pivot). Nalevo od prvku x umístíme všechny prvky menší než x. Napravo od prvku x umístíme všechny prvky větší než x. Rozdělení opakujeme pro pole tvořené prvky nalevo od x a pro pole napravo od x. Postup opakujeme dokud nerozdělujeme jednoprvkové úseky. Strategie rozděl a panuj. Tuto strategii můžeme implementovat rekurzí Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 83 / 90

Eratosthenovo síto Řazení Rozdělení pole Příklad - rozdělení 5 32 12 28 55 18 42 94 5 32 12 28 55 18 42 94 5 18 12 28 55 32 42 94 Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 84 / 90

Eratosthenovo síto Řazení Řazení rozdělením Quick Sort 1/2 1 void qsortpart(int l, int h, int[] array) { 2 3 int i = l; //lower index int j = h; //higher index 4 int pivot = array[l + (h - l) / 2]; 5 while (i <= j) { 6 while(array[i] < pivot) { 7 i++; 8 } 9 while(array[j] > pivot) { 10 j--; 11 12 } if (i <= j) { 13 swap(i++, j--, array); 14 } 15 } 16 if (l < j) { 17 qsortpart(l, j, array); 18 } 19 if (i < h) { 20 qsortpart(i, h, array); 21 22 } } Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 85 / 90

Eratosthenovo síto Řazení Řazení rozdělením Quick Sort 2/2 1 void quicksort(int[] array) { 2 qsortpart(0, array.length-1, array); 3 } Složitost pro nejnepříznivější případ je O(n 2 ) Vhodně zvolený pivot výrazně snižuje časovou náročnost Randomizovaná varianta (vstupní pole permutováno a pivot je volen náhodně) O(nlog 2 n) Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 86 / 90

Eratosthenovo síto Řazení Řazení Select Sort vs Quick Sort Příklad spuštění Select Sort vs Quick Sort javac DemoSort.java && java DemoSort 10 Values: 10 24 41 17 20 31 42 5 24 46 Values Select Sort: 5 10 17 20 24 24 31 41 42 46 Values Quick Sort: 5 10 17 20 24 24 31 41 42 46 java DemoSort 40000 Select Sort required time 3415 ms Quick Sort required time 10 ms lec06/demosort.java Jednoduchý test výpočetní náročnosti můžeme udělat porovnáním výpočetních časů Např. využitím System.currentTimeMillis Skutečné výpočetní nároky se mohou lišit podle vstupních dat Zkuste zjistit počet operací pro vstupní pole uspořádané sestupně Asymptotická složitost udává očekávané výpočetní nároky pro velké vstupy Reálné testování v tzv. mikro benchmarks může být zvláště v Javě zavádějící (HotSpot) Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 87 / 90

Eratosthenovo síto Řazení Zápis algoritmu Quick Sort Implementace Quick Sort v programovacím jazyku Haskell 1 qsort [] = [] 2 qsort (x:xs) = qsort (filter (< x) xs) ++ [x] ++ qsort (filter (>= x) xs) Pro zajímavost Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 88 / 90

Diskutovaná témata Shrnutí přednášky Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 89 / 90

Diskutovaná témata Diskutovaná témata Rekurze a rekurzivní algoritmy Příklady rekurzivních algoritmů: Výpočet faktoriálu Výpis posloupnosti čísel Hanojské věže Fibonacciho posloupnost Reprezentace množiny polem Příklad implementace v algoritmu Eratosthenovo síto Rozklad na prvočinitele Příklad rekurze v řazení Příště: Objektově orientované programování v Javě Jan Faigl, 2015 A0B36PR1 Přednáška 6: Rekurze 90 / 90