Przeczytaj
Silnia
Zacznijmy od algorytmu wyznaczania silnisilni z liczby naturalnej. Zastosujemy w pseudokodzie rekurencję – funkcja będzie wywoływała samą siebie aż do momentu dojścia do przypadku podstawowegoprzypadku podstawowego. Przy pisaniu pseudokodu pomocna okaże się definicja rekurencyjna silni.
Zgodnie z tą definicją funkcja będzie wywoływała samą siebie z parametrem zmniejszonym o 1, aż do momentu, gdy n będzie równe 0 – wtedy zostanie zwrócona wartość 1. Pseudokod funkcji rekurencyjnej realizującej algorytm wyznaczania silni liczby naturalnej n wygląda następująco:
Zastanówmy się, jaki będzie schemat kolejnych wywołań rekurencyjnych w przypadku wyznaczenia silni liczby 6.
Najpierw będą rekurencyjnie wywoływane funkcje z coraz mniejszymi wartościami, czyli 5, 4, 3, 2, 1, aż dojdziemy do 0. Wtedy nastąpi zwrócenie wartości 1 i zaczniemy po kolei wychodzić z zagnieżdżenia wywołań funkcji, za każdym razem zwracając wynik danej silni. Na koniec osiągniemy szukaną wartość 6!:
Wyraz ciągu rekurencyjnego
Napiszmy funkcję funkcja(n)
przyjmującą parametr naturalny n
, która w przypadku n
parzystego zwróci funkcja(n‑2) --- 3
, natomiast w przypadku n
nieparzystego zwróci funkcja(n‑1) mod 9
. Dodatkowo dla n
< 2 zawsze powinna zostać zwrócona wartość 122.
Rozpocznijmy od warunku, który mówi o tym, że dla n
mniejszego od 2 zwracana jest wartość 122.
Natomiast jeżeli n
NIE JEST mniejsze od 2, musimy sprawdzić, czy n
jest liczbą parzystą, i umieścić odpowiednie instrukcje w przypadku spełnienia tego warunku.
Jeżeli n
nie jest liczbą parzystą, musimy zwrócić funkcja(n‑1) mod 9
.
Zapisaliśmy za pomocą pseudokodu funkcję zwracającą n‑ty wyraz ciągu rekurencyjnego.
Dla powyższego pseudokodu obliczmy zwracane wartości dla n
z zakresu od 0 do 7.
Funkcja wywołuje samą siebie we wszystkich przypadkach poza tymi, kiedy n = 0
lub n = 1
. Na przykład funkcja(5)
wywołuje funkcję funkcja(4)
. Nie musimy jednak ponownie wyznaczać wartości tej funkcji, ponieważ obliczyliśmy ją w poprzednim kroku.
Ciąg rekurencyjny
Przeanalizujmy przedstawioną za pomocą pseudokodu funkcję ciąg(x, y)
przyjmującą parametry x
i y
typu całkowitego, której wywołanie spowoduje wypisanie ciągu liczb całkowitych:
Wypiszmy wszystkie wywołania rekurencyjne funkcji ciąg(2, 4)
.
Do wykonania tego zadania pomocne okaże się drzewo wywołań rekurencyjnych, w którym umieścimy wszystkie wywołania funkcji ciąg(2, 4)
.
W drzewie zostały przedstawione wywołania tylko tych funkcji, których wartość drugiego przyjmowanego argumentu, czyli y
, jest większa od 0. Z tego względu wykonania niektórych funkcji powodują wywołanie tylko jednej rekurencyjnej funkcji. Lewa strzałka każdej z funkcji prowadzi do wywołania funkcji ciąg(2*x, y‑1)
, natomiast prawa prowadzi do ciąg(3*x, y‑2)
.
Podajmy teraz wynik działania funkcji ciąg(2, 4)
i uzupełnijmy wygenerowany ciąg rekurencyjny:
Ponownie skorzystamy z drzewa wywołań rekurencyjnych. Wiemy, że nasz ciąg to uzyskane wartości działań x - y.
Jednak w jakiej kolejności wypisywane są te wartości? Spójrzmy ponownie na zapisaną za pomocą pseudokodu funkcję ciąg(x, y)
. Najpierw zostanie wywołana rekurencyjnie funkcja ciąg(2*x, y‑1)
, czyli lewa skierowana krawędź, następnie ciąg(3*x, y‑2)
, czyli prawa krawędź, a na końcu wypisana zostanie wartość x - y
.
A zatem początek wygenerowanego ciągu rekurencyjnego zgadza się z naszymi wnioskami. W pierwszej kolejności wykonywane jest najniżej położone, lewe poddrzewo, zatem wywołana zostanie funkcja ciąg(16, 1).
Następnie miałoby zostać wykonane prawe poddrzewo, jednak takie nie istnieje, przechodzimy więc do wyższego poziomu, czyli ciąg(8, 2)
. Stosując powyższe obserwacje, uzyskamy następujący ciąg:
Słownik
przypadek, dla którego funkcja rekurencyjna nie wywołuje samej siebie (warunek zakończenia), zwraca za to konkretną, wyliczoną wartość; jest to pewien założony stan początkowy
– iloczyn kolejnych liczb naturalnych, mniejszych lub równych n