You are on page 1of 3

Rekurencja

Metodą rekurencyjną nazywamy taką metodę, w której stosujemy rekurencję (zwaną także
rekursją). Być może takie sformułowanie wydaje ci się pozbawione sensu. Tymczasem jest ono
charakterystyczne właśnie dla rekurencji, która oznacza odwoływanie się funkcji (lub definicji) do
samej siebie.
W matematyce funkcją rekurencyjną nazywamy funkcję, która jest zdefiniowana za pomocą samej
siebie. W informatyce zaś funkcją rekurencyjną jest funkcja, która wywołuje samą siebie.
W powyższych definicjach nie wspomnieliśmy jeszcze o najważniejszym elemencie, mianowicie nie
ma w nich określenia warunku zakończenia odwołań rekurencyjnych. Prześledźmy na przykładzie
zastosowanie funkcji rekurencyjnej.

SILNIA LICZBY NATURALNEJ


Silnią dodatniej liczby naturalnej nazywamy iloczyn kolejnych liczb naturalnych, począwszy od
liczby 1 aż do liczby, dla której obliczamy wartość silni. Na przykład dla liczby 5 silnia jest równa
wartości iloczynu 1' 2 • 3 • 4 • 5, czyli 120. Silnia liczby 0 wynosi 1 (z definicji).
Formalny zapis matematyczny funkcji silnia może wyglądać następująco:
!=1 ∈ {0,1}
! = 1 ∗…∗ − {1}

Przykład:
Napiszmy funkcję iteracyjną, która obliczy silnię dowolnej liczby naturalnej.

double fsilnia_iteracyjnie (int n)


{
double silnia = 1;
for (int i=2; i<n+l; i++)
silnia = silnia*i;

return silnia;
}

Powyższa funkcja pobierze naturalną liczbę n, a wynikiem jej działania będzie iloczyn kolejnych
liczb naturalnych (obliczenia wykonają się w pętli for) aż do n włącznie. Jeśli chcemy policzyć silnię
0, program nie wykona pętli, a funkcja przyjmie wartość 1. Ponieważ silnia jest funkcją osiągającą
bardzo duże wartości dla małych n, wybraliśmy dla nich typ double.
Spróbujmy teraz ten sam problem zdefiniować rekurencyjnie. Zacznijmy od tego, że przy znanej
wartość silni liczby 4 łatwo obliczysz silnię dla 5, ponieważ skoro 4! = 24, to 5! = 24 • 5, co daje
120. W ogólnej postaci możemy więc zapisać: n! = (n - 1)! • n
Zwróćmy uwagę na odwołanie rekurencyjne - silnia liczby n jest równa wartości silni liczby (n - 1)
pomnożonej przez liczbę n. Oczywiście, aby zgodnie z naszą definicją rekurencyjną policzyć silnię
dla (n - 1), należy obliczyć silnię (n - 2) i pomnożyć ją przez (n - 1) itd. W celu zakończenia tych
czynności musimy postawić warunek zakończenia odwołań rekurencyjnych.

Aby funkcja rekurencyjną była poprawna, musi mieć ściśle zdefiniowany warunek zakończenia
odwołań rekurencyjnych.

W przypadku funkcji silnia takim warunkiem jest definicja silni dla n = 0, czyli 0! = 1. Pełna definicja
rekurencyjną funkcji silnia ma zatem postać:
!=1 =0
! = ( − 1)! ∗
Pozostaje nam tylko zapisać za pomocą języka programowania definicję matematyczną w postaci
funkcji rekurencyjnej:
double silnia(int n)
{
if (n==0) // warunek początkowy rekurencji (1)
return 1;
else
return silnia(n—1)*n; // rekurencyjne wywołanie funkcji (2)
}

W linii 2 jest zawarte wywołanie rekurencyjne funkcji silnia. We wnętrzu funkcji wywołujemy
funkcję, którą właśnie piszemy. Taki zapis powoduje, że program po dotarciu do linii numer
2 kodu nie jest w stanie dokończyć instrukcji, musi bowiem wywołać funkcję silnia z parametrem
n o 1 mniejszym. Każde wywołanie funkcji jest związane z zapamiętaniem kopii wszystkich
zmiennych funkcji oraz z umieszczeniem na stosie adresu powrotnego, czyli miejsca w programie,
do którego system ma powrócić po zakończeniu funkcji.

Stosem nazywamy obszar pamięci, w którym są przechowywane zmienne wywoływanych funkcji


oraz adresy powrotne. Stos charakteryzuje się tym, że jest strukturą powoływaną dynamicznie, to
znaczy nie ma stałego miejsca w pamięci i jest powiększany w zależności od potrzeb. Zasada
działania stosu przypomina sposób postępowania ze stosem książek ułożonych jedna na drugiej -
aby się dostać do książki z wnętrza stosu, należy zdjąć wszystkie książki położone wyżej. Na
rysunku poniżej przedstawiono graficznie stos z wywołaniami rekurencyjnymi funkcji silnia.
Jeśli obliczamy wartość silni dla liczby większej od zera, wówczas po pewnej ilości odwołań funkcji
do samej siebie, w wyniku kolejnego odejmowania od niej liczby 1, w końcu trafimy na wartość
argumentu równą 0. Funkcja silnia wywołana z argumentem n = 0 wykona się natychmiast
i zgodnie z treścią linii 1 przyjmie wartość 1. Teraz system kolejno może ściągać ze stosu
niedokończone wywołania funkcji i je obliczać. Rysunek powyżej przedstawia graficzną ilustrację
tego procesu dla n równego 4. Największy prostokąt odpowiada pierwszemu umieszczeniu funkcji
silnia na stosie. Ostatnim elementem umieszczonym na stosie Jest wywołanie funkcji
z argumentem 0, potem następuje kolejne ściąganie Wywołań funkcji ze stosu wraz z jej wynikiem
(pamiętaj, że wynik ten jest argumentem w obliczeniach poprzedniego wywołania funkcji).

You might also like