R6JcAWVXWnPKM
Fotografia przedstawia wysoki słup z wieloma kładkami.

I_R_W13_M10_Java Rekurencja w Javie

Źródło: schrupp, domena publiczna.

Poznaliśmy już algorytm służący do znajdowania największego wspólnego dzielnika dwóch liczb naturalnych. Wersję iteracyjną Algorytmu Euklidesa w języku Python omówiliśmy w e‑materiale Algorytm Euklidesa w języku Java – tym razem zbadamy podejście rekurencyjne.

Algorytm Euklidesa z odejmowaniem – implementacja algorytmu w języku Java

Zaimplementujmy z użyciem rekurencji algorytm Euklidesa w języku Java.

Nasza funkcja wygląda następująco:

Linia 1. public int NWD otwórz nawias okrągły int a przecinek int b zamknij nawias okrągły otwórz nawias klamrowy. Linia 2. if otwórz nawias okrągły a wykrzyknik znak równości b zamknij nawias okrągły otwórz nawias klamrowy. Linia 3. if otwórz nawias okrągły a zamknij nawias ostrokątny b zamknij nawias okrągły otwórz nawias klamrowy. Linia 4. return NWD otwórz nawias okrągły a minus b przecinek b zamknij nawias okrągły średnik. Linia 5. zamknij nawias klamrowy. Linia 6. return NWD otwórz nawias okrągły a przecinek b minus a zamknij nawias okrągły średnik. Linia 7. zamknij nawias klamrowy. Linia 8. otwórz nawias ostrokątny code style znak równości cudzysłów white minus space dwukropek pre średnik cudzysłów data minus inline zamknij nawias ostrokątny return a średnik otwórz nawias ostrokątny prawy ukośnik code zamknij nawias ostrokątny. Linia 10. zamknij nawias klamrowy.

W funkcji NWD(), która przyjmuje dwie zmienne typu int, użylibyśmy instrukcji warunkowej if, w której warunek będzie taki sam, jak w przypadku pętli while w wykonaniu iteracyjnym, czyli a != b.

Jeżeli warunek jest spełniony, to znaczy a != b, funkcja będzie wywoływana rekurencyjnie. W przypadku gdy wartość a będzie większa od wartości b, funkcja zwróci NWD(a - b, b), a w przeciwnym przypadku NWD(a, b - a). W algorytmie korzystamy z równości NWD(a, b) = NWD(a - b, b) dla a > b lub NWD(a, b) = NWD(a, b - a) dla b > a, które pokazaliśmy w e‑materiale Algorytm EuklidesaP7OAFYVSiAlgorytm Euklidesa.

Jeżeli warunek nie jest spełniony, funkcja zwróci a. Oczywiście mogłaby też zwrócić b – jeżeli warunek nie zostanie spełniony, będzie to oznaczać, że wartość obu zmiennych jest identyczna.

Funkcja kończy swoje działanie po zwróceniu wartości, więc nie musimy stosować instrukcji else.

Algorytm Euklidesa z dzieleniem – implementacja algorytmu w języku Java

Kod wygląda następująco:

Linia 1. public int NWD otwórz nawias okrągły int a przecinek int b zamknij nawias okrągły otwórz nawias klamrowy. Linia 2. if otwórz nawias okrągły b wykrzyknik znak równości 0 zamknij nawias okrągły otwórz nawias klamrowy. Linia 3. return NWD otwórz nawias okrągły b przecinek a procent b zamknij nawias okrągły średnik. Linia 4. zamknij nawias klamrowy. Linia 5. return a średnik. Linia 6. zamknij nawias klamrowy.

Zadeklarujemy funkcję NWD() zwracającą typ int. Przyjmie ona parametry ab – obydwa typu int. W ciele funkcji umieścimy instrukcję warunkową if, której testem logicznym będzie b != 0. Jeżeli zależność zachodzi, funkcja zwróci samą siebie z argumentami ba % b. W przeciwnym razie funkcja zwróci zmienną a.

Istotne jest, żeby funkcja zwróciła przypadek podstawowy w momencie, gdy b przyjmie wartość 0. W innym przypadku w następnym wywołaniu funkcji pojawiłby się argument, który doprowadziłby do wykonania operacji niedozwolonej, czyli szukania reszty z dzielenia przez 0.

Ciekawostka

Co mają zatem wspólnego matrioszka i algorytmy rekurencyjne? Rosyjska lalka to w zasadzie zestaw kilku lalek – największa lalka ma w sobie trochę mniejszą, mniejsza – jeszcze mniejszą i tak dalej, aż do najmniejszej lalki, która jest tak mała, że nie da się w niej zmieścić kolejnej. Podobnie z rekurencją – algorytm rozwiązuje problem, dzieląc go na podproblemy. Robi to do momentu, w którym natrafia na przypadek podstawowy.

Słownik

NWD
NWD

skrót pojęcia największy wspólny dzielnik dwóch liczb całkowitych – największa liczba naturalna, która dzieli dwie rozpatrywane liczby bez reszty

przypadek podstawowy
przypadek podstawowy

przypadek, w którym funkcja rekurencyjna zwraca konkretną wartość, a nie wywołanie samej siebie

rekurencja
rekurencja

technika programowania polegająca na odwoływaniu się procedur lub funkcji do samych siebie, aż do momentu spełnienia warunku podstawowego