Rekurencja vs iteracja - porównanie

1. Wprowadzenie

Rekurencja i iteracja to dwa podstawowe podejścia do rozwiązywania problemów powtarzalnych.

Definicje:

Technika Definicja
Rekurencja Funkcja wywołuje samą siebie
Iteracja Używamy pętli (for, while)

Kluczowa prawda:

Każdy problem, który można rozwiązać rekurencyjnie, można też rozwiązać iteracyjnie i vice versa.


2. Proste porównanie – odliczanie

2.1. Wersja rekurencyjna

Cechy: - Wywołuje samą siebie - Warunek stop: n <= 0 - Każde wywołanie dodaje ramkę na stos

2.2. Wersja iteracyjna

Cechy: - Używa pętli while - Warunek stop: n > 0 - Jedna ramka stosu


3. Porównanie wydajności

3.1. Suma liczb od 1 do n

Rekurencja

Złożoność: - Czasowa: O(n) - Pamięciowa: O(n) – stos wywołań

Iteracja

Złożoność: - Czasowa: O(n) - Pamięciowa: O(1) – tylko zmienna suma

3.2. Benchmark – mierzenie czasu


4. Silnia – szczegółowe porównanie

4.1. Rekurencja

Stos wywołań dla factorial_rek(4):

factorial(4)
│ return 4 * factorial(3)
│   └─ factorial(3)
│      │ return 3 * factorial(2)
│      │   └─ factorial(2)
│      │      │ return 2 * factorial(1)
│      │      │   └─ factorial(1)
│      │      │      │ return 1 * factorial(0)
│      │      │      │   └─ factorial(0)
│      │      │      │      │ return 1

Pamięć: 5 ramek na stosie (O(n))

4.2. Iteracja

Wykonanie dla factorial_iter(4):

i = 1: wynik = 1 * 1 = 1
i = 2: wynik = 1 * 2 = 2
i = 3: wynik = 2 * 3 = 6
i = 4: wynik = 6 * 4 = 24
return 24

Pamięć: Tylko zmienne wynik i i (O(1))

4.3. Porównanie

Aspekt Rekurencja Iteracja
Złożoność czasowa O(n) O(n)
Złożoność pamięciowa O(n) O(1)
Czytelność ⭐⭐⭐ ⭐⭐
Wydajność ⭐⭐ ⭐⭐⭐
Prostota ⭐⭐⭐ ⭐⭐

5. Fibonacci – gdzie rekurencja zawodzi

5.1. Rekurencja naiwna

Problem: Wykładnicza złożoność czasowa!

Drzewo wywołań dla fib_rek(5):

                    fib(5)
                   /      \
              fib(4)      fib(3)
             /     \       /    \
        fib(3)   fib(2) fib(2) fib(1)
        /   \     /  \   /  \
    fib(2) fib(1) ...  ...
    /  \
fib(1) fib(0)

Liczba wywołań: 15 dla fib(5), 177 dla fib(10), 2,692,537 dla fib(20)!

Złożoność: O(2^n) – KATASTROFA!

5.2. Iteracja

Złożoność: O(n) – ZNACZNIE lepiej!

5.3. Benchmark


6. Konwersja rekurencja → iteracja

6.1. Wzorzec ogólny

Większość funkcji rekurencyjnych można przekształcić używając stosu:

↓ Konwersja ↓

6.2. Przykład: Suma rekurencyjna → iteracyjna

Rekurencja:

Iteracja ze stosem:

Iteracja prosta:


7. Konwersja iteracja → rekurencja

7.1. Pętla while → rekurencja

Iteracja:

Rekurencja:

7.2. Pętla for → rekurencja

Iteracja:

Rekurencja:


8. Kiedy używać rekurencji?

8.1. Dobre przypadki dla rekurencji

✅ Struktury drzewiastе

Wersja iteracyjna byłaby znacznie bardziej skomplikowana.

✅ Dziel i zwyciężaj (Merge Sort)

✅ Backtracking (permutacje)

8.2. Złe przypadki dla rekurencji

❌ Proste pętle

❌ Duża głębokość


9. Limit rekurencji w Pythonie

Python ma domyślny limit głębokości rekurencji:

9.1. Przekroczenie limitu

9.2. Zwiększenie limitu (OSTROŻNIE!)


10. Złożoność pamięciowa – szczegóły

10.1. Rekurencja – stos wywołań

10.2. Iteracja – stałe zmienne

10.3. Benchmark pamięci


11. Hybrydy – łączenie obu podejść

11.1. Fibonacci z memoizacją (rekurencja + cache)

11.2. Iteracja z rekurencją (Quick Sort)


12. Decyzje projektowe – rekurencja vs iteracja

Kryterium Rekurencja Iteracja
Czytelność ⭐⭐⭐ ⭐⭐
Wydajność ⭐⭐ ⭐⭐⭐
Pamięć ⭐⭐⭐
Prostota (drzewa) ⭐⭐⭐
Prostota (pętle) ⭐⭐⭐
Debugowanie ⭐⭐ ⭐⭐⭐
Stack overflow Ryzyko Brak

Zasada kciuka:

Wybieraj rekurencję dla czytelności, iterację dla wydajności.


13. Podsumowanie

Rekurencja vs Iteracja:

Aspekt Rekurencja Iteracja
Mechanizm Wywołuje siebie Pętla (for/while)
Pamięć O(n) – stos O(1) – zmienne
Wydajność Wolniejsza (overhead) Szybsza
Czytelność Często lepsza Czasem gorsza
Stack overflow Ryzyko dla dużych n Brak ryzyka
Naturalna dla Drzew, grafów, backtrackingu Prostych pętli

Kluczowe wnioski:

  • Każdy problem rekurencyjny można rozwiązać iteracyjnie
  • Rekurencja często czytelniejsza, iteracja szybsza
  • Fibonacci naiwny: rekurencja O(2^n), iteracja O(n)
  • Python ma limit rekurencji (domyślnie 1000)
  • Dla drzew i grafów – rekurencja naturalna
  • Dla prostych pętli – iteracja lepsza

Co dalej warto poznać:

  • Stos wywołań (jak działa pod maską)
  • Rekurencja ogonowa (optymalizacja)
  • Memoizacja (cache dla rekurencji)
  • Programowanie dynamiczne