Trudno precyzyjnie określić kompromisy związane z rekurencją.
Na poziomie matematycznie abstrakcyjnym rekursja daje potężne ramy do opisu jawnego zachowania funkcji. Na przykład, możemy matematycznie definiować silni jak
x! = 1 if x == 0
x! = x * (x - 1)! else
Albo możemy określić bardziej złożoną funkcję rekurencyjnie, jak w jaki sposób możemy obliczyć „N wybrać K”:
C(n, k) = 1 if k == 0
C(n, k) = 0 if k < 0 or if n > k
C(n, k) = C(n - 1, k) + C(n - 1, k - 1) else
Przy użyciu rekursji jako techniki implementacji, nie ma gwarancji, że skończy się używanie większej ilości pamięci lub tworzenie kodu, który działa bardziej wydajnie. Często rekurencja wykorzystuje więcej miejsca ze względu na pamięć wymaganą do przechowywania ramek stosu, ale w niektórych językach nie stanowi to problemu, ponieważ kompilator może próbować zoptymalizować wywołania funkcji (patrz na przykład eliminacja wywołań końcowych). W innych przypadkach rekurencja może zużyć ogromne zasoby do punktu, w którym kod rekursywny może przestać kończyć się prostymi problemami.
Co do problemów związanych z wydajnością, często kod rekurencyjny jest znacznie mniej wydajny niż kod iteracyjny. Wywołania funkcji są drogie, a naiwne tłumaczenie rekursji na kod prowadzi do niepotrzebnego powielania pracy. Na przykład, naiwna implementacja Fibonacciego
int Fibonacci(int n) {
if (n <= 1) return n;
return Fibonacci(n - 1) + Fibonacci(n - 2);
}
Czy horrendalnie nieefektywne i jest tak powolny, że nigdy nie jest stosowany w praktyce. Chociaż kod jest czystszy, nieefektywność zżera wszelkie potencjalne korzyści rekurencji.
W innych przypadkach rekursja może być niesamowitą oszczędnością czasu.Jako przykład mergesort jest bardzo szybki algorytm sortowania zdefiniowane przez piękną rekursji:
Mergesort(array, low, high) {
if (low >= high - 1) return;
Mergesort(array, low, low + (high - low)/2);
Mergesort(array, low + (high - low)/2, high);
Merge(array, low, low + (high - low)/2, high);
}
Kod ten jest bardzo szybki i odpowiedni kod iteracyjny będzie prawdopodobnie wolniejsze, trudniejsze do odczytania, i trudniejsze do zrozumienia.
Krótko mówiąc, rekursja nie jest ani magicznym lekarstwem, ani siłą, której należy unikać. Pomaga oświetlić strukturę wielu problemów, które w przeciwnym razie mogą wydawać się trudne lub prawie niemożliwe. Chociaż często prowadzi to do wyraźniejszego kodu, często dzieje się tak kosztem czasu i pamięci (choć niekoniecznie jest to automatycznie mniej wydajne, w wielu przypadkach może być wydajniejsze). Zdecydowanie warto studiować, aby poprawić ogólne myślenie algorytmiczne i umiejętności rozwiązywania problemów, nawet jeśli nigdy nie napiszesz innej funkcji rekursywnej w swoim życiu.
Mam nadzieję, że to pomoże!
+1 Życzę więcej odpowiedzi na SO były równie dobrze przemyślane jak ten. Gdybym mógł, zrobiłbym +2. – Josh