Rekurencja 1 Podprogram lub strukturę danych nazywamy rekurencyjną, (recursive subprogram, recursive data structure) jeżeli częściowo składa się z samej siebie lub jej definicja odwołuje się do niej samej. Przykłady definicji rekurencyjnych stosowanych w matematyce 1. Definicja liczb naturalnych 2. Funkcja silnia 3. Ciąg liczb Fibonacci 4. Potęga naturalna liczby rzeczywistej 5. Wielomiany Legendre’a Rekurencja 2 Rekurencja jest użyteczna, bo umożliwia definiowanie nieskończonych zbiorów obiektów przy pomocy skończonych wyrażeń. Program rekurencyjny P można zapisać jako złożenie F instrukcji podstawowych Si nie zawierajęcych P i samego programu P. P = F(Si;P) Definicja Jeżeli podprogram P zawiera bezpośrednio odwołanie do samego siebie, to P nazywamy podprogramem bezpośrednio rekurencyjnym (direct recursive subprogram). Rekurencja 3 Definicja Jeżeli podprogram P zawiera odwołanie do podprogramu Q, który zawiera bezpośrednie odwołanie do P, to P nazywamy podprogramem pośrednio rekurencyjnym (direct recursive subprogram). Definicja Wywołaniem rekurencyjnym podprogramu (recursive call of the subprogram) nazywamy wywołanie podprogramu, który zawiera wywołanie samego siebie (pośrednie, lub bezpośrednie) Podprogramy rekurencyjne umożliwiają wykonywanie nieskończonego procesu obliczeniowego i dlatego powstaje: Rekurencja 4 Problem Zakończenie nieskończonego procesu obliczeniowego w skończonym czasie. Rozwiązanie. Wywołanie podprogramu P uzależnione jest od warunku W, który w pewnym momencie przestaje być prawdziwy, co kończy proces obliczeniowy. Zapisujemy to następująco: P = if W then F(Si;P), albo równoważnie: P = F(Si; if W then P). Rekurencja 5 Prostą i skuteczną metodą zatrzymania procesu rekurencyjnego jest zastosowanie w podprogramie P parametru wejściowego n i wywołanie podprogramu z wartością n-1. Jeżeli W = n > 1, to następujące schematy gwarantują wykonanie podprogramu w skończonej liczbie kroków: P(n) = if n > 1 then F(Si;P(n-1)), P(n) = F(Si; if n > 1 then P(n-1)). Algorytmy rekurencyjne, a co za tym idzie podprogramy rekurencyjne stosuje się wtedy, gdy rozwiązywany problem, lub przetwarzane dane definiujemy rekurencyjnie. Nie zawsze algorytm rekurencyjny jest najefektywniejszym rozwiązaniem problemu. Przykład PP_028_Potega Rekurencja 6 Wartoœæ obliczona = 8.0 Potega_Rek (2.0, 3) Potega_Rek X = 2.0, N = 3 Potega_Rek (2.0, 2) Wartoœæ obliczona = 4.0 Potega_Rek X = 2.0, N = 2 Potega_Rek (2.0, 1) Wartoœæ obliczona = 2.0 Potega_Rek X = 2.0, N = 1 Rekurencja 7 Definicja Wariantem podstawowym, albo bazowym (base case) algorytmu nazywamy wariant, którego rozwiązanie może być wyznaczone bez rekurencji. Definicja Wariantem ogólnym (general case) algorytmu nazywamy wariant, którego rozwiązanie jest wyrażone w postaci prostszej wersji tego samego wariantu. Definicja Algorytmem rekurencyjnym (recursive algorithm) nazywamy algorytm wyznaczający rozwiązanie problemu obliczeniowego wg wariantu ogólnego i wariantu podstawowego (bazowego) Rekurencja 8 Pisanie programów rekurencyjnych wymaga: • Zrozumienia istoty rozwiązywanego problemu • Zdefiniowania wariantów bazowych • Zdefiniowania wariantów ogólnych Przykład PP_029_Permutacje_Rekurencyjnie Rekurencja 9 Przykład PP_030_Wieze_Hanoi 1 2 3 Rekurencja 10 Wyszukiwanie. Wyszukiwanie liniowe. Dane wejściowe: Lista - tablica A(1..n) elementów i element v. Dane wyjściowe: Indeks i taki, że v = A(i), lub informacja, że v nie jest elementem listy. Przykład PP_031_Iterative_Version_Of_Sequential_Search Przykład PP_032_Recursive_Version_Of_Sequential_Search Rekurencja 11 Możliwe jest przypadkowe wprowadzenie rekurencji w sytuacji, gdy nazwa podprogramu jest użyta jako identyfikator zmiennej w podprogramie. Zmienna := Nazwa_Podprogramu; Jeżeli podprogram ma parametry, to kompilator wykryje błąd. Jeżeli podprogram nie ma parametrów, to może powstać nieskończona rekurencja (infinite recursion) odpowiadająca pętli nieskończonej. W takim przypadku wystąpi STORAGE_ERROR.