Iteracja i rekurencja – przypomnienie

Przypomnijmy sobie podstawowe informacje na temat iteracjiiteracjaiteracjirekurencjirekurencjarekurencji.

Iteracja:

  • polega na wielokrotnym wykonywaniu zapisanych w programie instrukcji,

  • jest realizowana za pomocą pętli – instrukcji iteracyjnych,

  • musi być wprowadzony warunek zakończenia pętli.

Rekurencja:

  • funkcja wywołuje samą siebie w celu osiągnięcia rozwiązania problemu,

  • musi spełniać dwa warunki:

    • warunek początkowy – warunek, który spełniony nie spowoduje wywołania funkcji rekurencyjnej, tylko zwróci konkretną wartość,

    • co najmniej jeden argument w rekurencyjnym wywołaniu funkcji musi mieć inną wartość niż poprzednie.

Którą metodę wybrać?

Dowolny problem możemy rozwiązać dwiema technikami – rekurencyjną i iteracyjną. Problem obliczania wartości elementu ciągu rekurencyjnego możemy także rozwiązać w sposób iteracyjny.

Warto jednak zastanowić się, której metody użyć w algorytmie podczas rozwiązywania danego problemu. Stosowanie techniki rekurencyjnej czyni kod często czytelniejszym, krótszym i zrozumiałym. W przypadku iteracji nasz kod może być dłuższy i trudniejszy do zrozumienia. Trzeba wziąć pod uwagę, że rozwiązując niektóre problemy metodą rekurencyjną, płacimy wysoką cenę. Często funkcja rekurencyjna jest wywoływana dużą liczbę razy, a obliczenia są nieefektywne. W tych przypadkach zdecydowanie wybieramy metodę iteracyjną.

Obliczanie wartości elementu ciągu

Sprawdźmy, jak – na podstawie kilku prostych ćwiczeń – obliczyć wartości elementu ciągu. Przy rozwiązaniu zadań skorzystamy zarówno z techniki rekurencyjnej, jak i z iteracyjnej.

Problem 1

Zdefiniowany jest następujący ciąg:

an = 1gdy n = 04·an - 1 + 2gdy n > 0

Napisz, za pomocą ciągu instrukcji pseudokodu, funkcję której argumentem będzie numer szukanego wyrazu ciągu i która zwróci wartość tego wyrazu.

Przeanalizujmy zapisaną w postaci pseudokodu funkcję realizującą algorytm obliczania wartości n‑tego elementu zdefiniowanego ciągu, przy użyciu techniki rekurencyjnej.

Linia 1. funkcja rekurencyjnie otwórz nawias okrągły n zamknij nawias okrągły. Linia 2. jeżeli n znak równości znak równości 0 wykonaj dwukropek. Linia 3. zwróć 1. Linia 4. w przeciwnym razie wykonaj dwukropek. Linia 5. zwróć 4 asterysk rekurencyjnie otwórz nawias okrągły n minus 1 zamknij nawias okrągły plus 2.

Argumentem funkcji rekurencyjnie(n) jest numer wyrazu ciągu, który chcemy obliczyć. W przypadku zerowego wyrazu ciągu zwracana jest wartość 1, natomiast w innych wypadkach musi zostać obliczona wartość poprzedniego wyrazu ciągu, poprzez wywołanie odpowiedniej funkcji rekurencyjnej z argumentem zmniejszonym o 1.

Problem ten możemy także rozwiązać iteracyjnie. Przeanalizujmy zapisaną za pomocą pseudokodu funkcję, tym razem w wersji iteracyjnej.

Linia 1. funkcja iteracyjnie otwórz nawias okrągły n zamknij nawias okrągły. Linia 2. a znak równości 1. Linia 3. dla i znak równości 1 przecinek 2 przecinek kropka kropka kropka przecinek n wykonuj dwukropek. Linia 4. a znak równości 4 asterysk a plus 2. Linia 5. zwróć a.

Jak widać, powyższa funkcja jest również zrozumiała i krótka. Zmiennej a przypisywana jest wartość 1, to znaczy wartość naszego zerowego elementu ciągu. Następnie dla kolejnych elementów obliczane są wartości w pętli, aż do osiągnięcia naszego poszukiwanego wyrazu o numerze n. Wtedy zwracana jest jego wartość a.

Przejdźmy teraz do trudniejszego przykładu, w którym wartość elementu ciągu będzie zależała od dwóch poprzednich wyrazów ciągu:

Problem 2

Zdefiniowany jest następujący ciąg:

an = 0gdy n = 01gdy n = 1an - 1 · an - 2 + 3gdy n > 1

Napisz, wykorzystując ciąg instrukcji pseudokodu, funkcję, której argumentem będzie numer szukanego wyrazu ciągu i która zwróci wartość tego wyrazu.

Zacznijmy od metody rekurencyjnej:

Linia 1. funkcja rekurencyjnieDrugie otwórz nawias okrągły n zamknij nawias okrągły. Linia 2. jeżeli n znak równości znak równości 0 wykonaj dwukropek. Linia 3. zwróć 0. Linia 4. w przeciwnym razie jeżeli n znak równości znak równości 1 wykonaj dwukropek. Linia 5. zwróć 1. Linia 6. w przeciwnym razie dwukropek. Linia 7. zwróć rekurencyjnieDrugie otwórz nawias okrągły n minus 1 zamknij nawias okrągły asterysk rekurencyjnieDrugie otwórz nawias okrągły n minus 2 zamknij nawias okrągły plus 3.

Funkcje napisane techniką rekurencyjną są czytelne i proste. Podobnie jak w przypadku problemu 1, jeżeli funkcja przyjmie parametr 0 lub 1, od razu zwracana jest konkretna wartość, natomiast dla innych parametrów, następują dwa wywołania rekurencyjne funkcji.

W przypadku techniki iteracyjnej, kod będzie dłuższy i trudniejszy do zrozumienia:

Linia 1. funkcja iteracyjnieDrugie otwórz nawias okrągły n zamknij nawias okrągły. Linia 2. a znak równości 0. Linia 3. b znak równości 1. Linia 4. jeżeli n znak równości znak równości 0 wykonaj dwukropek. Linia 5. zwróć a. Linia 6. dla i znak równości 2 przecinek 3 przecinek kropka kropka kropka przecinek n wykonuj dwukropek. Linia 7. c znak równości a asterysk b plus 3. Linia 8. a znak równości b. Linia 9. b znak równości c. Linia 10. zwróć b.

Ponownie w przypadku zerowego i pierwszego wyrazu ciągu bezpośrednio zwracana jest wartość. Dla kolejnych wyrazów muszą zostać wykonane instrukcje w pętli. W zmiennej c umieszczany jest iloczyn dwóch poprzednich wyrazów ciągu, powiększony o 3, następnie w zmiennej a będzie przechowywana wartość poprzedniego wyrazu ciągu, która dotychczas była w zmiennej b, natomiast do zmiennej b zostaje zapisana wartość aktualnego wyrazu.

Rekurencja czy iteracja?

W przypadku problemu 1 algorytm możemy zapisać zarówno w wersji rekurencyjnej, jak i iteracyjnej. Jeżeli chodzi o problem 2, mimo iż wersja iteracyjna jest mniej czytelna, to właśnie ją lepiej jest zastosować. Technika rekurencyjna rozwiązywania zadania drugiego wymaga wielu wywołań rekurencyjnych, co jest bardzo nieefektywne obliczeniowo. Dla piątego wyrazu ciągu funkcja rekurencyjnieDwa wywoływana jest aż 15 razy!

Słownik

algorytm iteracyjny
algorytm iteracyjny

ciąg operacji, który jest powtarzany tak długo, dopóki nie zostanie spełniony określony warunek

algorytm rekurencyjny
algorytm rekurencyjny

algorytm, w którym funkcja lub procedura wywołuje samą siebie aż do napotkania przypadku podstawowego

iteracja
iteracja

słowo pochodzące od łacińskiego iteratio (powtarzanie); oznacza powtarzanie w pętli tych samych instrukcji, aż do spełnienia pewnego warunku

rekurencja
rekurencja

sytuacja, w której funkcja wywołuje samą siebie aż do napotkania przypadku podstawowego

silnia
silnia

n! – iloczyn liczb naturalnych, mniejszych lub równych n