KATEDRASYSTEMÓWOBLICZENIOWYCH ALGORYTMY I STRUKTURY DANYCH 1.Rekurencja Rekurencja inaczej rekursja (ang. recursion) to wywołanie z poziomu metody jej samej. Programowanie z wykorzytaniem rekurencji pozwala na przejrzyste zapisanie algorytmów, w których wynik końcowy jest złożeniem wielu wyników cząstkowych (np. wydajne algorytmy sortujące). Sprawdź co zwraca zapytanie: rekurencja w wyszukiwarce Google. Tworząc metody rekurencyjne musimy pamiętać o odpowiednim zakończeniu wywołań rekurencyjnych (nie mogą one odbywać się w nieskończoność). Zobaczmy poniższy kod źródłowy: static void { System.out.println(""); ; System.out.println(""); ; 1
Algorytmy i Struktury Danych Sposób realizacji programu: main(){ itd. Efekt uruchomienia programu:... Exception in thread "main" java.lang.stackoverflowerror Wywołania rekurencyjne muszą zakończyć się (w metodzie musi zostać zdefiniowany warunek zatrzymania się algorytmu, warunek stopu). Programzwarunkiemstopu Zmodyfikowana wersja programu zawierająca warunek stopu może wyglądać w następujący sposób: static int licz = 0; static void { licz++; System.out.println(""); if (licz <=5 ) ; // warunek stopu System.out.println(""); ; 2
Rekurencja Realizacja programu main(){ licz = 1 licz = 2 licz = 3 licz = 4 licz = 5 licz = 6 Efekt uruchomienia programu: Co się stanie jeśli jeszcze raz uruchomimy naszą metodę? Dlaczego tak się dzieje? Rekurencyjne obliczenie silni Wykorzystajmy naszą wiedzę do napisania prostego programu obliczającego wartość silni dla dowolnego n. static int silnia(int n) { int pomoc; System.out.println("Wywołanie: silnia(" + n + ")"); if ((n == 0) (n == 1)) pomoc = 1; else pomoc = n * silnia(n-1); System.out.println("Zwrócenie wyniku: " + n + "! = " + pomoc); return pomoc; System.out.println("4! = " + silnia(4)); 3
Algorytmy i Struktury Danych Sposób realizacji programu: main() { silnia(4); 24 n = 4; pomoc = 4 * silnia(3); Efekt działania programu: Wywołanie: silnia(4) Wywołanie: silnia(3) Wywołanie: silnia(2) Wywołanie: silnia(1) Zwrócenie wyniku: 1! = 1 Zwrócenie wyniku: 2! = 2 Zwrócenie wyniku: 3! = 6 Zwrócenie wyniku: 4! = 24 4! = 24 6 n = 3; pomoc = 3 * silnia(2); 2 n = 2; pomoc = 2 * silnia(1); 1 n = 1; pomoc = 1; Uproszczona wersja programu (bez zmiennej pomoc, oraz wyświetlania poszczególnych etapów działania aplikacji) może wygladać tak: static int silnia(int n) { if (n == 0) return 1; else return (n * silnia(n-1)); System.out.println("4! = " + silnia(4)); Powyższa wersja jest nieodporna na błędy. Co się stanie jeśli wywołamy metodę silnia() z parametrem ujemnym? 4
Rekurencja CiągFibonacciego Wykorzystanie rekurencji może okazać się bardzo kosztowne. Rozwiązania iteracyjne nieraz bywają bardziej wydajne. Zobaczmy jak wygląda definicja ciągu Fibonacciego. Poniżej diagram przedstawia rekurencyjne obliczenie piątego elementu ciągu. fib(2) fib(3) fib(0) fib(4) fib(5) fib(2) fib(0) fib(2) Zauważ ile razy algorytm oblicza te same dane, a jest to dopiero piąty element ciągu. Zadaniadowykonania fib(3) fib(0) 1. Napisz rekurencyjną metodę obliczającą sumę 1 + 2 +... + n, gdzie wartość n jest parametrem funkcji. 2. Napisz rekurencyjną metodę obliczającą sumę cyfr w liczbie całkowitej podanej jako parametr. 3. Każdego roku pewna populacja królików podwaja się. Jeżeli początkowo było m królików to ile ich będzie po n latach? Napisz odpowiednią metodę rekurencyjną. 4. Napisz rekurencyjną metodę zwracającą podany jako parametr ciąg znaków w odwrotnej kolejności. 5
Algorytmy i Struktury Danych 5. Napisz w postaci rekurencyjnej metodę wyznaczającą, za pomocą algorytmu Euklidesa, największy wspólny dzielnik dwóch liczb całkowitych dodatnich. 6. Napisz z wykorzystaniem rekurencji metodę potęga obliczającą n-tą potęgę liczby m. np.: wywołanie: potega(3, 1) zwróci wynik: 3 wywołanie: potega(3, 2) zwróci wynik: 9 wywołanie: potega(3, 3) zwróci wynik: 27 7. Napisz metodę wyznaczającą rekurencyjnie n-ty element ciągu Fibonacciego. Po wyznaczeniu n-tego elementu wyświetl ile razy metoda została wywołana. Zastanów się i przedstaw również rozwiązanie iteracyjne oraz sprawdź za pomocą klasy Stoper czasy wykonania obu metod. Klasa Stoper jest dostępna w zadaniach z przedmiotu Programowanie Komputerów. 8. Napisz metodę wyznaczającą binarną reprezentację podanej jako parametr liczby całkowitej. Zastosuj rozwiązanie rekurencyjne. Jak wiadomo wartość binarna wyznaczana jest poprzez odczytanie od tyłu reszt z dzielenia przez 2, a właściwy porządek cyfr można osiągnąć poprzez odpowiednie zastosowanie rekurencji. 6