Část Rekurze Rekurze Jan Faigl Katedra počítačů Fakulta elektrotechnická České vysoké učení technické v Praze Přednáška 6 A0B6PR Programování Faktoriál Obrácený výpis Karel Hanojské věže Rekurze Fibonacciho posloupnost Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze / 9 Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze / 9 Část Příklady Eratosthenovo síto Rozklad na prvočinitele Část I Rekurze Řazení Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze / 9 Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze / 9
Výpočet faktoriálu Příklad výpis posloupnosti / Iterace n! = n(n )(n )... int factoriali(int n) { int f = ; for(; n > ; --n) { f *= n; return f; Rekurze n! = pro n n! = n(n )! pro n > int factorialr(int n) { int f = ; if (n > ) { f = n * factorialr(n-); return f; lec05/demofactorial.java Připomínka 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ů:. Přečti číslo číslo uložíme pro pozdější obrácený výpis. Pokud není detekován konec posloupnost obrať posloupnost pokračujeme ve čtení čísel. Vypiš číslo vypíšeme uložené číslo Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 6 / 9 Příklad výpis posloupnosti / void reverse() { int v = scan.nextint(); if (scan.hasnext()) { reverse(); 5 6 System.out.printf("%d ", v); 7 8 9 public void start() { 0 System.err.println("Enter a sequence of numbers ( use ctr+d for the end of the the sequence"); reverse(); System.out.println(""); //end of line lec06/demorevertsequence.java Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 9 / 9 Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 8 / 9 Příklad výpis posloupnosti / lec06/demorevertsequence.java Vytvoření posloupností./generate_numbers.sh tr \n cat > numbers.txt javac DemoRevertSequence.java java DemoRevertSequence < numbers.txt >/dev/null > numbersr.txt java DemoRevertSequence <numbers-r.txt >/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 0 0 8 8 5 8 6 7 7 numbers-r.txt 7 7 6 8 5 8 8 0 0 numbers-rr.txt 0 0 8 8 5 8 6 7 7 Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 0 / 9
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, zda-li: je před ním zeď je na políčku, na kterém stojí, beeper Robot Karel Iterační řešení / Návrh řešení. Jdi podél zdi (po pravé straně) dokud není na políčku beeper a počítej počet kroků;. Seber beeper ;. Otoč se a jdi podél zdi (po levé straně) a udělej stejný počet kroků jako při hledání beeperu ;. 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, 0 A0B6PR Přednáška 6: Rekurze / 9 Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze / 9 Robot Karel Iterační řešení / void turnright() { for (int i = 0; i < ; i++) { turnleft(); 5 6 7 boolean iswallonright() { 8 turnright(); 9 boolean out = isinfrontofwall(); 0 turnleft(); return out; void gobyrightwall() { 5 while (!isonbeeper()) { 6 if (!wallonright()) { 7 turnright(); 8 9 while (isinfrontofwall()) { 0 turnleft(); step(); Analogicky pro zeď po levé straně Robot Karel Iterační řešení / Počet kroků je inkrementován v proceduře step Při návratu podél levé zdi Karel ujde stejný počet kroků public void execute() { gobyright(); pickbeeper(); turnaround(); 5 6 if (stepstaken > 0) { 7 gobyleft(stepstaken); 8 9 0 putbeeper(); turnoff(); Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze / 9 Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 5 / 9
Robot Karel Rekurzivní řešení / Ř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:. Pokud jsi na beeperu seber jej a otoč o 80 a ukonči hledání. Zapamatuj si svou orientaci a udělej jeden krok podél pravé zdi. go (opakuj hledání o jeden krok). Udělej jeden krok zpět (vrať se o jeden krok zpět a natoč se do původního směru) Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 6 / 9 Robot Karel Rekurzivní řešení / Hlavní procedura obsahuje pouze volání funkce go, která vrací robot na výchozí políčko void execute() { go(); putbeeper(); 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ě. Uvedený demonstrační program není plným řešení úlohy ze. cvičení lec06/demokarel.java Robot Karel Rekurzivní řešení / void go() { if (isonbeeper()) { pickbeeper(); 5 turnaround(); //turn back return; 6 7 int numberturnright = 0; 8 if (!iswallonright()) { 9 0 turnright(); numberturnright++; while (isinfrontofwall()) { 5 turnleft(); numberturnright--; 6 7 move(); //move forward 8 go(); 9 move(); //move backward 0 numberturnright = (numberturnright + ) % ; for (int i = 0; i < numberturnright; ++i) { turnleft(); //revert the turns 5 Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 7 / 9 Příklad Hanojské věže Přemístit disky na druhou jehlu s použitím třetí (pomocné) jehly za dodržení pravidel:. 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. Položit větší disk na menší není dovoleno Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 8 / 9 Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 0 / 9
Hanojské věže disk Hanojské věže disk Přesunutý disk z jehly na jehlu. Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze / 9 Hanojské věže disk Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze / 9 Hanojské věže disky Hotovo Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze / 9 Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze / 9
Hanojské věže disky Hanojské věže disky Přesunutý disk z jehly na jehlu. Přesunutý disk z jehly na jehlu. Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 5 / 9 Hanojské věže disky Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 6 / 9 Hanojské věže disky Hotovo Přesunutý disk z jehly na jehlu. Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 7 / 9 Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 8 / 9
Hanojské věže disky Hanojské věže disky Přesunutý disk z jehly na jehlu. Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 9 / 9 Hanojské věže disky Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 0 / 9 Hanojské věže disky Přesunutý disk z jehly na jehlu. Přesunutý disk z jehly na jehlu. Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze / 9 Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze / 9
Hanojské věže disky Hanojské věže disky Přesunutý disk z jehly na jehlu. Přesunutý disk z jehly na jehlu. Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze / 9 Hanojské věže disky Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze / 9 Hanojské věže disky Přesunutý disk z jehly na jehlu. Přesunutý disk z jehly na jehlu. Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 5 / 9 Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 6 / 9
Hanojské věže disky Hanojské věže disky Hotovo Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 7 / 9 Hanojské věže disky Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 8 / 9 Hanojské věže disky Přesunutý disk z jehly na jehlu. Přesunutý disk z jehly na jehlu. Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 9 / 9 Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 0 / 9
Hanojské věže disky Hanojské věže disky Přesunutý disk z jehly na jehlu. Přesunutý disk z jehly na jehlu. Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze / 9 Hanojské věže disky Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze / 9 Hanojské věže disky Přesunutý disk z jehly na jehlu. Přesunutý disk z jehly na jehlu. Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze / 9 Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze / 9
Hanojské věže disky Hanojské věže disky Přesunutý disk z jehly na jehlu. Přesunutý disk z jehly na jehlu. Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 5 / 9 Hanojské věže disky Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 6 / 9 Hanojské věže disky Přesunutý disk z jehly na jehlu. Přesunutý disk z jehly na jehlu. Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 7 / 9 Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 8 / 9
Hanojské věže disky Hanojské věže disky Přesunutý disk z jehly na jehlu. Přesunutý disk z jehly na jehlu. Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 9 / 9 Hanojské věže disky Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 50 / 9 Hanojské věže disky Přesunutý disk z jehly na jehlu. Přesunutý disk z jehly na jehlu. Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 5 / 9 Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 5 / 9
Hanojské věže disky Hanojské věže disky Hotovo Přesunutý disk z jehly na jehlu. Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 5 / 9 Hanojské věže 5 disků Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 5 / 9 Návrh řešení 5? 5 Zavedeme abstraktní příkaz movetower(n,,, ) realizující přesun n disků z jehly na jehlu s použitím jehly. Pro n > 0 můžeme příkaz rozložit na tři jednodušší příkazy. movetower(n-,,, ) přesun n disků z jehly na jehlu. přenes disk z jehly na jehlu přesun největšího disku na cílovou pozici abstraktní příkaz. movetower(n-,,, ) přesun n disků na cílovou pozici Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 55 / 9 Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 56 / 9
Příklad řešení void movetower(int n, int from, int to, int tmp) { if (n > 0) { movetower(n -, from, tmp, to); //move to tmp System.out.println("Move disc from " + from + " to " + to); 5 movetower(n -, tmp, to, from); //move from tmp 6 7 8 9 void start() { 0 int numberofdiscs = 5; movetower(numberofdiscs,,, ); lec06/demotowersofhanoi.java Příklad výpisu lec06/demotowersofhanoi.java java DemoTowersOfHanoi Move disc from to Move disc from to Move disc from to Move disc from to Move disc from to Move disc from to Move disc from to java DemoTowersOfHanoi Move disc from to Move disc from to Move disc from to Move disc from to Move disc from to Move disc from to Move disc from to Move disc from to Move disc from to Move disc from to Move disc from to Move disc from to Move disc from to Move disc from to Move disc from to Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 57 / 9 Rekurzivní algoritmy Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 58 / 9 Rekurzivní vs iteračními 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 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, 0 A0B6PR Přednáška 6: Rekurze 60 / 9 Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 6 / 9
Rekurze Elegance vs obtížnost rekurze To iterate is human, to recurse divine. L. Peter Deutsch http://www.devtopics.com/0-great-computer-programming-quotes 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, 0 to-iterate-is-human-to-recurse-divine http://selfless-singleton.rickwinfrey.com/0//7/ Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 6 / 9 Fibonacciho posloupnost,,,, 5, 8,,,, 55,... F n = F n + F n pro F =, F = Nebo 0,,,,, 5,... Nebo F = 0, F = 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 ϕ = + 5,68 0 988 79 89 88... 5 8 Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 6 / 9 Fibonacciho posloupnost historie Indičtí matematici (50 nebo 00 BC) Leonardo Pisano (75 50) 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. 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 (857 90) 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 let, jestliže žádná nezemře a na počátku budete mít jednu krávu? Po let je k dispozici jeden či více býků Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 65 / 9 Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 66 / 9
Fibonacciho posloupnost rekurzivně Platí: f 0 = f = f n = f n + f n, pro n > int fibonacci(int n) { return n <? : fibonacci(n - ) + fibonacci(n - ); 5 Zápis je elegantní, jak je však takový výpočet efektivní? Fibonacciho posloupnost příklad / Počet operací při výpočtu Fibonacciho čísla n long counter; long fibonnacir(int n) { counter++; 5 return n <? : fibonnacir(n-) + fibonnacir(n-); 6 7 8 long fibonnacii(int n) { 9 long fibm = l; 0 long fibm = l; long fib = l; for (int i = ; i <= n; ++i) { fibm = fibm; fibm = fib; 5 fib = fibm + fibm; 6 counter += ; 7 8 return fib; 9 lec06/demofibonacci.java Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 67 / 9 Fibonacciho posloupnost rekurzivně / public void start(string[] args) { int n = args.length > 0? Integer.parseInt(args[0]) : 5; counter = 0; 5 long fibr = fibonnacir(n); long counter = counter; 6 7 counter = 0; 8 9 long fibi = fibonnacii(n); long countei = counter; 0 System.out.println("Fibonacci number recursive: " + fibr); System.out.println("Fibonacci number iteration: " + fibi); System.out.println("Counter recursive: " + counter); System.out.println("Counter recursive: " + countei); 5 javac DemoFibonacci.java java DemoFibonacci 0 Fibonacci number recursive: 669 Fibonacci number iteration: 669 Counter recursive: 6957 Counter iteration: 8 lec06/demofibonacci.java Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 69 / 9 Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 68 / 9 Fibonacciho posloupnost rekurzivně vs iteračně Rekurzivní výpočet Složitost roste exponenciálně s n n Iterační algoritmus Počet operací je proporcionální n n 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( n ) iterační algoritmus výpočtu má složitost O(n) Efektivní algoritmy mají polynomiální složitost Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 70 / 9
Část II Příklady Pole reprezentující množinu prvočísel Vypsat všechna prvočísla menší nebo rovna zadané hodnotě max Algoritmus:. Vytvoříme množinu obsahující všechna přirozená čísla od do max. Z množiny vypustíme násobky čísla. Najdeme nejbližší číslo k tomu, jehož násobky jsme v předchozím kroku vypustili, a vypustíme všechny násobky tohoto čísla. Opakujeme krok, 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, 0 A0B6PR Přednáška 6: Rekurze 7 / 9 Eratosthenovo síto / boolean[] createsieve(int max) { boolean[] sieve = new boolean[max + ]; for (int i = ; i <= max; ++i) { sieve[i] = true; 5 6 int p = ; 7 int pmax = (int)math.sqrt(max); 8 do { 9 for(int i = p + p; i <= max; i += p) { 0 sieve[i] = false; do { p++; while (!sieve[p]); 5 while (p <= pmax); 6 return sieve; 7 lec06/demosieveoferatosthenes.java Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 7 / 9 Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 7 / 9 Eratosthenovo síto / void print(boolean[] sieve) { for(int i = ; i < sieve.length; ++i) { if (sieve[i]) { System.out.print(i + " "); 5 6 7 8 9 void start(int max) { 0 boolean[] sieve = createsieve(max); System.out.print("Prime numbers from to " + max + ": "); print(sieve); System.out.println(""); javac DemoSieveOfEratosthenes.java java DemoSieveOfEratosthenes Prime numbers from to 00: 5 7 7 9 9 7 7 5 59 6 67 7 7 79 8 89 97 java DemoSieveOfEratosthenes 0 Prime numbers from to 0: 5 7 7 9 9 lec06/demosieveoferatosthenes.java Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 75 / 9
Rozklad na prvočinitele / Rozklad přirozeného čísla n na součin prvočísel Řešení: Dělit, pak, pak 5 a dalšími prvočísly, až n Každé dělení beze zbytku dodá jednoho prvočinitele Příklad: 60 / 0 / 5 / 5 / 5 60 má prvočinitele,,, 5 Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 77 / 9 Řazení pole Problém seřadit množinu prvků podle klíče (celého čísla) Posloupnost prvků q = a,..., a n Délka posloupnosti q je q = n Posloupnost q je seřazená, právě tehdy když q < q klíč(a ) klíč(a ) a posloupnost a,... neobsahuje prvek a. Řazení polí je řazením na místě Pro jednoduchost v příkladech třídíme jen celá čísla, prakticky však zpravidla třídíme klíče datových položek. Rozklad na prvočinitele / Iterační algoritmus void getprimesi(int x) { int d = ; while (d < x) { while (d < x && x % d!= 0) { d++; System.out.print(d + " "); x = x / d; void start(int n) { Rekurzivní algoritmus System.out.println("Decomposition of " System.out.print("Iterative algorithm: "); getprimesi(n); System.out.println(""); System.out.print("Recursive algorithm: "); getprimesr(n, ); System.out.println(""); void getprimesr(int x, int d) { if (d < x) { while (d < x && x % d!= 0) { d++; System.out.print(d + " "); getprimesr(x / d, d); + n + " to primies"); lec06/demoprimes.java Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 78 / 9 Třídění přímým vkládáním Insert Sort / Příklad - Třídění přímým vkládáním 5 6 5 6 55 9 8 55 55 55 55 9 8 55 9 Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 80 / 9 Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 8 / 9
Třídění přímým vkládáním Insert Sort / for i, n vlož a i na patřičné místo mezi a,..., a i Příklad - Algoritmus void insertsort(int[] array) { int x; int j; for (int i = ; i < array.length; i++) { 5 6 x = array[i]; j = i - ; 7 while (j >= 0 && x < array[j]) { 8 9 array[j + ] = array[j]; j--; 0 array[j + ] = x; Řazení přímým výběr Select Sort / for i, 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 Třídění binárním vkládáním - vkládání provádíme do již zatříděného pole a,..., a i. Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 8 / 9 Řazení přímým výběr Select Sort / Příklad - Řazení přímým výběrem Select Sort 5 5 6 55 9 8 55 9 8 8 9 55 8 9 55 8 9 55 8 55 9 Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 8 / 9 Řazení přímým výběr Select Sort / Příklad implementace void selectsort(int[] array) { for (int i = 0; i < array.length-; ++i) { int minidx = i; for (int j = i + ; j < array.length; ++j) { 5 if (array[minidx] > array[j]) { 6 minidx = j; 7 8 9 swap(minidx, i, array); 0 Zde pro jednoduchost třídíme jen celá čísla, prakticky však zpravidla třídíme klíče datových položek. Složitost O(n ), kde n je počet položek 6 8 55 9 Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 8 / 9 Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 85 / 9
Ř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í Rozdělení pole Příklad - rozdělení 5 8 55 8 9 5 8 55 8 9 5 8 8 55 9 Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 86 / 9 Řazení rozdělením Quick Sort / void qsortpart(int l, int h, int[] array) { int i = l; //lower index int j = h; //higher index int pivot = array[l + (h - l) / ]; 5 while (i <= j) { 6 while(array[i] < pivot) { 7 i++; 8 9 while(array[j] > pivot) { 0 j--; if (i <= j) { swap(i++, j--, array); 5 6 if (l < j) { 7 qsortpart(l, j, array); 8 9 if (i < h) { 0 qsortpart(i, h, array); Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 88 / 9 Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 87 / 9 Řazení rozdělením Quick Sort / void quicksort(int[] array) { qsortpart(0, array.length-, array); Složitost pro nejnepříznivější případ je O(n ) 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 n) Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 89 / 9
Řazení Select Sort vs Quick Sort Příklad spuštění Select Sort vs Quick Sort javac DemoSort.java && java DemoSort 0 Values: 0 7 0 5 6 Values Select Sort: 5 0 7 0 6 Values Quick Sort: 5 0 7 0 6 java DemoSort 0000 Select Sort required time 5 ms Quick Sort required time 0 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 setříděné 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, 0 A0B6PR Přednáška 6: Rekurze 90 / 9 Diskutovaná témata Zápis algoritmu Quick Sort Implementace Quick Sort v programovacím jazyku Haskell qsort [] = [] qsort (x:xs) = qsort (filter (< x) xs) ++ [x] ++ qsort (filter (>= x) xs) Pro zajímavost Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 9 / 9 Diskutovaná témata Diskutovaná témata Shrnutí přednášky 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, 0 A0B6PR Přednáška 6: Rekurze 9 / 9 Jan Faigl, 0 A0B6PR Přednáška 6: Rekurze 9 / 9