Jednym z tematów, który wydaje się regularnie pojawiać się na listach mailingowych i w dyskusjach online, są zalety (lub ich brak) zdobycia tytułu informatyka. Argumentem, który wydaje się pojawiać raz po raz dla strony negatywnej, jest to, że kodowała ona od kilku lat i nigdy nie używała rekurencji.
Więc pytanie brzmi:
- Co to jest rekurencja?
- Kiedy używać rekursji?
- Dlaczego ludzie nie używają rekurencji?
recursion
computer-science
Mike Minutillo
źródło
źródło
Odpowiedzi:
Istnieje wiele dobrych wyjaśnień rekurencji w tym wątku, ta odpowiedź dotyczy tego, dlaczego nie powinieneś jej używać w większości języków. * W większości głównych implementacji języków imperatywnych (tj. Każda większa implementacja C, C ++, Basic, Python Iteracja w Rubim, Javie i C #) jest zdecydowanie lepsza niż rekurencja.
Aby zobaczyć, dlaczego, wykonaj czynności, których używają powyższe języki do wywołania funkcji:
Wykonanie wszystkich tych kroków zajmuje trochę czasu, zazwyczaj trochę więcej niż przejście przez pętlę. Jednak prawdziwy problem tkwi w kroku 1. Kiedy uruchamia się wiele programów, alokują one pojedynczy fragment pamięci dla swojego stosu, a gdy zabraknie im tej pamięci (często, ale nie zawsze z powodu rekurencji), program ulega awarii z powodu przepełnienia stosu .
Zatem w tych językach rekurencja jest wolniejsza i naraża Cię na awarie. Nadal istnieją argumenty przemawiające za jego użyciem. Ogólnie rzecz biorąc, kod napisany rekurencyjnie jest krótszy i nieco bardziej elegancki, gdy wiesz, jak go czytać.
Istnieje technika, której mogą używać implementatorzy języka, nazywanej optymalizacją wywołań ogonowych, która może wyeliminować niektóre klasy przepełnienia stosu. Mówiąc zwięźle: jeśli wyrażenie zwracane przez funkcję jest po prostu wynikiem wywołania funkcji, nie musisz dodawać nowego poziomu do stosu, możesz ponownie użyć bieżącego poziomu dla wywoływanej funkcji. Niestety, kilka imperatywnych implementacji języka ma wbudowaną optymalizację wywołań ogonowych.
* Uwielbiam rekurencję. Mój ulubiony język statyczny w ogóle nie używa pętli, rekurencja to jedyny sposób, aby coś powtarzać. Po prostu nie sądzę, aby rekurencja była ogólnie dobrym pomysłem w językach, które nie są do niej dostrojone.
** Swoją drogą Mario, typowa nazwa Twojej funkcji ArrangeString to „join” i byłbym zdziwiony, gdyby Twój wybrany język nie posiadał jeszcze jej implementacji.
źródło
Prosty angielski przykład rekurencji.
źródło
W najbardziej podstawowym sensie informatycznym rekurencja jest funkcją, która wywołuje samą siebie. Załóżmy, że masz połączoną strukturę listy:
I chcesz dowiedzieć się, jak długa jest połączona lista, możesz to zrobić z rekurencją:
(Można to oczywiście zrobić również za pomocą pętli for, ale jest to przydatne jako ilustracja koncepcji)
źródło
length(list->next)
nadal musi wrócić do,length(list)
aby ten ostatni mógł dodać 1 do wyniku. Gdyby było napisane tak, aby przekroczyć dotychczasową długość, tylko wtedy moglibyśmy zapomnieć, że dzwoniący istnieje. Lubięint length(const Node* list, int count=0) { return (!list) ? count : length(list->next, count + 1); }
.Za każdym razem, gdy funkcja wywołuje samą siebie, tworząc pętlę, jest to rekursja. Jak ze wszystkim, rekurencja ma dobre i złe zastosowania.
Najprostszym przykładem jest rekurencja ogona, gdzie ostatnia linia funkcji jest wywołaniem samej siebie:
Jest to jednak kiepski, prawie bezsensowny przykład, ponieważ można go łatwo zastąpić bardziej wydajną iteracją. W końcu rekursja cierpi z powodu narzutu wywołania funkcji, który w powyższym przykładzie może być znaczny w porównaniu z operacją wewnątrz samej funkcji.
Tak więc cały powód, aby wykonywać rekursję zamiast iteracji, powinien polegać na wykorzystaniu stosu wywołań do wykonania sprytnych rzeczy. Na przykład, jeśli wywołujesz funkcję wiele razy z różnymi parametrami wewnątrz tej samej pętli, jest to sposób na wykonanie rozgałęzienia . Klasycznym przykładem jest trójkąt Sierpińskiego .
Możesz narysować jedną z nich w bardzo prosty sposób za pomocą rekurencji, w której stos wywołań rozgałęzia się w 3 kierunkach:
Jeśli spróbujesz zrobić to samo z iteracją, myślę, że okaże się, że wykonanie znacznie więcej kodu zajmie dużo więcej.
Inne typowe przypadki użycia mogą obejmować hierarchie przechodzenia, np. Przeszukiwacze witryn, porównania katalogów itp.
Wniosek
W praktyce rekurencja ma największy sens, gdy potrzebujesz iteracyjnego rozgałęziania.
źródło
Rekurencja to metoda rozwiązywania problemów oparta na mentalności dziel i zwyciężaj. Podstawową ideą jest to, aby wziąć pierwotny problem i podzielić go na mniejsze (łatwiejsze do rozwiązania) wystąpienia samego siebie, rozwiązać te mniejsze wystąpienia (zwykle używając ponownie tego samego algorytmu), a następnie złożyć je ponownie w ostateczne rozwiązanie.
Przykładem kanonicznym jest procedura generowania silni n. Silnię n oblicza się, mnożąc wszystkie liczby od 1 do n. Iteracyjne rozwiązanie w C # wygląda następująco:
Nie ma nic zaskakującego w rozwiązaniu iteracyjnym i powinno mieć sens dla każdego, kto zna C #.
Rozwiązanie rekurencyjne znajdujemy, uznając, że n-ta silnia to n * Fakt (n-1). Innymi słowy, jeśli wiesz, jaka jest konkretna liczba silnia, możesz obliczyć następną. Oto rozwiązanie rekurencyjne w C #:
Pierwsza część tej funkcji jest znana jako przypadek bazowy (lub czasami klauzula ochronna) i to ona uniemożliwia działanie algorytmu w nieskończoność. Zwraca po prostu wartość 1 za każdym razem, gdy wywoływana jest funkcja z wartością 1 lub mniejszą. Druga część jest bardziej interesująca i jest znana jako krok rekurencyjny . Tutaj nazywamy tę samą metodę z nieznacznie zmodyfikowanym parametrem (zmniejszamy ją o 1), a następnie mnożymy wynik przez naszą kopię n.
Przy pierwszym napotkaniu może to być trochę zagmatwane, więc pouczające jest zbadanie, jak to działa po uruchomieniu. Wyobraź sobie, że nazywamy FactRec (5). Wchodzimy w rutynę, nie jesteśmy wychwytywani przez przypadek podstawowy, więc kończymy tak:
Jeśli ponownie wprowadzimy metodę z parametrem 4, ponownie nie zostaniemy zatrzymani przez klauzulę guard, a więc otrzymamy:
Jeśli podstawimy tę wartość zwracaną do wartości zwracanej powyżej, otrzymamy
To powinno dać ci wskazówkę, jak doszło do ostatecznego rozwiązania, więc szybko prześlemy i pokażemy każdy krok na drodze w dół:
Ta ostatnia zamiana ma miejsce, gdy zostanie uruchomiony przypadek podstawowy. W tym miejscu mamy do rozwiązania prosty algorytm algrebraiczny, który w pierwszej kolejności równa się bezpośrednio definicji silni.
Warto zauważyć, że każde wywołanie metody powoduje wyzwolenie przypadku podstawowego lub wywołanie tej samej metody, w której parametry są bliżej przypadku podstawowego (często nazywane wywołaniem rekurencyjnym). Jeśli tak nie jest, metoda będzie działać wiecznie.
źródło
FactRec()
należy pomnożyć przezn
przed zwróceniem.Rekursja to rozwiązywanie problemu za pomocą funkcji, która wywołuje samą siebie. Dobrym tego przykładem jest funkcja silnia. Silnia to problem matematyczny, w którym na przykład silnia 5 wynosi 5 * 4 * 3 * 2 * 1. Ta funkcja rozwiązuje ten problem w języku C # dla dodatnich liczb całkowitych (nie testowano - może występować błąd).
źródło
Rekursja odnosi się do metody, która rozwiązuje problem poprzez rozwiązanie mniejszej wersji problemu, a następnie wykorzystanie tego wyniku oraz innych obliczeń do sformułowania odpowiedzi na pierwotny problem. Często w trakcie rozwiązywania mniejszej wersji metoda rozwiązuje jeszcze mniejszą wersję problemu i tak dalej, aż osiągnie „podstawowy przypadek”, który jest trywialny do rozwiązania.
Na przykład, aby obliczyć silnię liczby
X
, można ją przedstawić jakoX times the factorial of X-1
. Tak więc metoda „powtarza się”, aby znaleźć silnięX-1
, a następnie mnoży to, co otrzymała,X
aby dać ostateczną odpowiedź. Oczywiście, aby znaleźć silnię zX-1
, najpierw obliczy silnięX-2
, i tak dalej. Podstawowy przypadek byłby równyX
0 lub 1, w którym to przypadku wie, że ma powrócić1
od tego czasu0! = 1! = 1
.źródło
Rozważ stary, dobrze znany problem :
Definicja gcd jest zaskakująco prosta:
gdzie mod jest operatorem modulo (czyli resztą po dzieleniu liczb całkowitych).
W języku angielskim ta definicja mówi, że największym wspólnym dzielnikiem dowolnej liczby i zerem jest ta liczba, a największy wspólny dzielnik dwóch liczb m i n to największy wspólny dzielnik liczby n, a reszta po podzieleniu m przez n .
Jeśli chcesz wiedzieć, dlaczego to działa, zobacz artykuł w Wikipedii na temat algorytmu Euklidesa .
Obliczmy jako przykład gcd (10, 8). Każdy krok jest równy temu tuż przed nim:
W pierwszym kroku 8 nie jest równe zeru, więc obowiązuje druga część definicji. 10 mod 8 = 2, ponieważ 8 przechodzi do 10 raz z resztą 2. W kroku 3 druga część ma zastosowanie ponownie, ale tym razem 8 mod 2 = 0, ponieważ 2 dzieli 8 bez reszty. W kroku 5 drugi argument to 0, więc odpowiedź to 2.
Czy zauważyłeś, że gcd pojawia się po lewej i prawej stronie znaku równości? Matematyk powiedziałby, że ta definicja jest rekurencyjna, ponieważ wyrażenie, które definiujesz, powtarza się w swojej definicji.
Definicje rekurencyjne wydają się być eleganckie. Na przykład rekurencyjna definicja sumy listy to
gdzie
head
jest pierwszym elementem listy itail
pozostałą częścią listy. Zauważ, żesum
na końcu powtarza się w definicji.Może wolisz zamiast tego maksymalną wartość na liście:
Możesz zdefiniować mnożenie nieujemnych liczb całkowitych rekurencyjnie, aby przekształcić je w serię dodawania:
Jeśli ten fragment dotyczący przekształcania mnożenia w serię dodatków nie ma sensu, spróbuj rozwinąć kilka prostych przykładów, aby zobaczyć, jak to działa.
Sortowanie przez scalanie ma piękną rekurencyjną definicję:
Definicje rekurencyjne są wszędzie, jeśli wiesz, czego szukać. Zauważ, że wszystkie te definicje mają bardzo proste przypadki podstawowe, np. Gcd (m, 0) = m. Przypadki rekurencyjne zmniejszają problem, aby przejść do łatwych odpowiedzi.
Dzięki temu zrozumieniu możesz teraz docenić inne algorytmy w artykule Wikipedii na temat rekurencji !
źródło
Przykładem kanonicznym jest silnia, która wygląda następująco:
Ogólnie rekurencja niekoniecznie musi być szybka (narzut wywołań funkcji jest zwykle wysoki, ponieważ funkcje rekurencyjne są zwykle małe, patrz wyżej) i może powodować pewne problemy (ktoś przepełnia stos?). Niektórzy twierdzą, że trudno jest je „dobrze” znaleźć w nietrywialnych przypadkach, ale ja tak naprawdę nie wierzę w to. W niektórych sytuacjach rekurencja ma największy sens i jest najbardziej eleganckim i przejrzystym sposobem zapisu określonej funkcji. Należy zauważyć, że niektóre języki preferują rozwiązania rekurencyjne i znacznie bardziej je optymalizują (przychodzi na myśl LISP).
źródło
Funkcja rekurencyjna to taka, która sama siebie wywołuje. Najczęstszym powodem, dla którego go używam, jest przechodzenie przez strukturę drzewa. Na przykład, jeśli mam TreeView z polami wyboru (pomyśl o instalacji nowego programu, strona „wybierz funkcje do zainstalowania”), mogę potrzebować przycisku „zaznacz wszystko”, który wyglądałby mniej więcej tak (pseudokod):
Możesz więc zobaczyć, że checkRecursively najpierw sprawdza węzeł, do którego jest przekazywany, a następnie wywołuje siebie dla każdego z dzieci tego węzła.
Musisz być trochę ostrożny z rekurencją. Jeśli dostaniesz się do nieskończonej pętli rekurencyjnej, otrzymasz wyjątek przepełnienia stosu :)
Nie mogę wymyślić powodu, dla którego ludzie nie powinni go używać, kiedy jest to stosowne. Jest to przydatne w pewnych okolicznościach, a w innych nie.
Myślę, że ponieważ jest to interesująca technika, być może niektórzy programiści używają jej częściej niż powinni, bez prawdziwego uzasadnienia. To spowodowało, że rekurencja miała złą opinię w niektórych kręgach.
źródło
Rekurencja to wyrażenie bezpośrednio lub pośrednio odwołujące się do siebie.
Rozważmy rekurencyjne akronimy jako prosty przykład:
Więcej przykładów na Wikipedii
źródło
Rekurencja działa najlepiej z czymś, co lubię nazywać „problemami fraktali”, gdzie mamy do czynienia z wielką rzeczą, która składa się z mniejszych wersji tej dużej rzeczy, z których każda jest jeszcze mniejszą wersją dużej rzeczy, i tak dalej. Jeśli kiedykolwiek będziesz musiał przechodzić lub przeszukiwać coś takiego jak drzewo lub zagnieżdżone identyczne struktury, masz problem, który może być dobrym kandydatem do rekursji.
Ludzie unikają rekurencji z wielu powodów:
Większość ludzi (łącznie ze mną) wycina swoje umiejętności programowania w programowaniu proceduralnym lub obiektowym w przeciwieństwie do programowania funkcjonalnego. Dla takich osób podejście iteracyjne (zazwyczaj przy użyciu pętli) wydaje się bardziej naturalne.
Tym z nas, którzy wycinają swoje umiejętności programowania w programowaniu proceduralnym lub obiektowym, często mówiono, aby unikali rekursji, ponieważ jest ona podatna na błędy.
Często słyszymy, że rekurencja jest powolna. Wielokrotne wywoływanie i powracanie z rutyny wiąże się z częstym wpychaniem i wyskakiwaniem stosu, co jest wolniejsze niż zapętlanie. Myślę, że niektóre języki radzą sobie z tym lepiej niż inne, a te języki najprawdopodobniej nie są tymi, w których dominujący paradygmat jest proceduralny lub zorientowany obiektowo.
Przynajmniej dla kilku języków programowania, których używałem, pamiętam zalecenia, aby nie używać rekursji, jeśli przekroczy ona określoną głębokość, ponieważ jej stos nie jest tak głęboki.
źródło
Instrukcja rekurencyjna to taka, w której definiujesz proces tego, co należy zrobić, jako kombinację danych wejściowych i tego, co już zrobiłeś.
Na przykład, weź silnię:
Ale łatwo zauważyć, że silnia (6) to również:
Więc ogólnie:
Oczywiście, najtrudniejsze w rekurencji jest to, że jeśli chcesz zdefiniować rzeczy w kategoriach tego, co już zrobiłeś, musisz mieć od czego zacząć.
W tym przykładzie po prostu tworzymy specjalny przypadek, definiując silnię (1) = 1.
Teraz widzimy to od dołu do góry:
Ponieważ zdefiniowaliśmy silnię (1) = 1, osiągamy „dno”.
Ogólnie rzecz biorąc, procedury rekurencyjne składają się z dwóch części:
1) Część rekurencyjna, która definiuje jakąś procedurę pod względem nowych danych wejściowych połączonych z tym, co „już zrobiłeś” za pomocą tej samej procedury. (tj.
factorial(n) = n*factorial(n-1)
)2) Część podstawowa, która zapewnia, że proces nie będzie się powtarzał w nieskończoność, dając mu miejsce do rozpoczęcia (tj.
factorial(1) = 1
)Na początku może być trochę zagmatwane, ale spójrz tylko na kilka przykładów i wszystko powinno się połączyć. Jeśli chcesz głębiej zrozumieć tę koncepcję, przestudiuj indukcję matematyczną. Należy również pamiętać, że niektóre języki są optymalizowane pod kątem wywołań rekurencyjnych, a inne nie. Tworzenie szalenie wolnych funkcji rekurencyjnych jest dość łatwe, jeśli nie jesteś ostrożny, ale istnieją również techniki, dzięki którym w większości przypadków są one wydajne.
Mam nadzieję że to pomoże...
źródło
Podoba mi się ta definicja: w
rekurencji procedura sama rozwiązuje niewielką część problemu, dzieli go na mniejsze części, a następnie wzywa siebie do rozwiązania każdego z mniejszych elementów.
Podoba mi się również dyskusja Steve'a McConnell'a na temat rekursji w Code Complete, gdzie krytykuje przykłady użyte w książkach informatycznych na temat rekursji.
Pomyślałem, że to bardzo interesująca kwestia do podniesienia i może być powodem, dla którego rekurencja jest często źle rozumiana.
EDYCJA: To nie była kopalnia odpowiedzi Dava - nie widziałem tej odpowiedzi, kiedy to opublikowałem
źródło
1.) Metoda jest rekurencyjna, jeśli może wywołać samą siebie; albo bezpośrednio:
lub pośrednio:
2.) Kiedy używać rekursji
3.) Ludzie używają rekurencji tylko wtedy, gdy napisanie kodu iteracyjnego jest bardzo skomplikowane. Na przykład techniki przechodzenia po drzewie, takie jak preorder, postorder, mogą być zarówno iteracyjne, jak i rekurencyjne. Ale zwykle używamy rekurencji ze względu na jej prostotę.
źródło
Oto prosty przykład: ile elementów w zestawie. (są lepsze sposoby liczenia rzeczy, ale to jest ładny, prosty przykład rekurencyjny).
Po pierwsze, potrzebujemy dwóch zasad:
Załóżmy, że masz taki zestaw: [xxx]. policzmy, ile jest przedmiotów.
Możemy to przedstawić jako:
Stosując rozwiązanie rekurencyjne, zazwyczaj masz co najmniej 2 reguły:
Jeśli przetłumaczymy powyższe na pseudokod, otrzymamy:
Jest o wiele więcej przydatnych przykładów (na przykład przechodzenie po drzewie), które z pewnością będą omawiać inne osoby.
źródło
Cóż, masz całkiem przyzwoitą definicję. Wikipedia też ma dobrą definicję. Więc dodam dla ciebie kolejną (prawdopodobnie gorszą) definicję.
Kiedy ludzie odnoszą się do „rekurencji”, zwykle mówią o napisanej przez siebie funkcji, która wywołuje samą siebie wielokrotnie, dopóki nie zostanie zakończona. Rekursja może być pomocna podczas przechodzenia przez hierarchie w strukturach danych.
źródło
Przykład: rekurencyjna definicja klatki schodowej to: Klatka schodowa składa się z: - pojedynczego stopnia i klatki schodowej (rekurencja) - lub tylko jednego stopnia (zakończenie)
źródło
Aby powtórzyć się w rozwiązanym problemie: nic nie rób, gotowe.
Aby powtórzyć się w przypadku otwartego problemu: wykonaj następny krok, a następnie powtórz resztę.
źródło
Mówiąc prostym językiem: załóżmy, że możesz zrobić 3 rzeczy:
Masz przed sobą dużo jabłek na stole i chcesz wiedzieć, ile jest jabłek.
Proces powtarzania tej samej rzeczy, dopóki nie skończysz, nazywa się rekurencją.
Mam nadzieję, że jest to odpowiedź „zwykłym angielskim”, której szukasz!
źródło
Funkcja rekurencyjna to funkcja, która zawiera wywołanie samej siebie. Struktura rekurencyjna to struktura zawierająca wystąpienie samej siebie. Możesz połączyć te dwie klasy w klasę rekurencyjną. Kluczową częścią elementu rekurencyjnego jest to, że zawiera on własną instancję / wywołanie.
Rozważ dwa lustra zwrócone do siebie. Widzieliśmy zgrabny efekt nieskończoności, jaki wywołują. Każde odbicie jest instancją zwierciadła, które jest zawarte w innej instancji lustra, itd. Lustro zawierające odbicie samego siebie jest rekurencją.
Wyszukiwania binarne drzewo jest dobrym przykładem programowanie rekursji. Struktura jest rekurencyjna, a każdy węzeł zawiera 2 wystąpienia węzła. Funkcje do pracy na drzewie wyszukiwania binarnego są również rekurencyjne.
źródło
To jest stare pytanie, ale chcę dodać odpowiedź z logistycznego punktu widzenia (tj. Nie z punktu widzenia poprawności algorytmu lub punktu widzenia wydajności).
Używam Javy do pracy, a Java nie obsługuje funkcji zagnieżdżonych. W związku z tym, jeśli chcę wykonywać rekursję, być może będę musiał zdefiniować funkcję zewnętrzną (która istnieje tylko dlatego, że mój kod zderza się z biurokratyczną regułą Javy) lub być może będę musiał całkowicie refaktoryzować kod (czego naprawdę nienawidzę robić).
Dlatego często unikam rekursji i zamiast tego używam operacji na stosie, ponieważ sama rekursja jest zasadniczo operacją na stosie.
źródło
Chcesz go używać zawsze, gdy masz strukturę drzewa. Jest to bardzo przydatne w czytaniu XML.
źródło
Rekurencja w przypadku programowania polega w zasadzie na wywołaniu funkcji z jej własnej definicji (wewnątrz samej siebie), z różnymi parametrami w celu wykonania zadania.
źródło
„Jeśli mam młotek, spraw, by wszystko wyglądało jak gwóźdź”.
Rekurencja to strategia rozwiązywania dużych problemów, w której na każdym kroku „zamień dwie małe rzeczy w jedną większą rzecz” za każdym razem tym samym młotkiem.
Przykład
Załóżmy, że twoje biurko jest pokryte chaotycznym bałaganem złożonym z 1024 kartek. Jak zrobić jeden schludny, czysty stos papierów z bałaganu, używając rekurencji?
Zauważ, że jest to dość intuicyjne, poza liczeniem wszystkiego (co nie jest absolutnie konieczne). W rzeczywistości możesz nie zejść do stosów z 1 arkuszem, ale możesz i nadal będzie działać. Ważną częścią jest młotek: za pomocą rąk zawsze możesz umieścić jeden stos na drugim, aby uzyskać większy stos, i nie ma znaczenia (w granicach rozsądku), jak duży jest każdy stos.
źródło
Rekurencja to proces, w którym wywołanie metody polega na tym, aby móc wykonać określone zadanie. Zmniejsza nadmiarowość kodu. Większość funkcji lub metod rekurencyjnych musi mieć warunek, aby przerwać wywołanie rekusyjne, tj. Zatrzymać wywoływanie samego siebie, jeśli warunek zostanie spełniony - zapobiega to tworzeniu nieskończonej pętli. Nie wszystkie funkcje nadają się do użytku rekurencyjnego.
źródło
hej, przepraszam, jeśli moja opinia się z kimś zgadza, po prostu próbuję wyjaśnić rekurencję prostym angielskim.
załóżmy, że masz trzech menedżerów - Jacka, Johna i Morgana. Jack zarządza 2 programistami, Johnem - 3 i Morganem - 5. Masz zamiar dać każdemu menedżerowi 300 $ i chcesz wiedzieć, ile by to kosztowało. Odpowiedź jest oczywista - ale co, jeśli 2 pracowników Morgan-s jest również menedżerami?
TUTAJ nadchodzi rekurencja. zaczynasz od góry w hierarchii. koszt letni to 0 $. zaczynasz od Jacka, potem sprawdź, czy ma jakichś menedżerów jako pracowników. jeśli zauważysz, że któryś z nich jest, sprawdź, czy mają jakichś menedżerów jako pracowników i tak dalej. Dodaj 300 $ do letniego kosztu za każdym razem, gdy znajdziesz menedżera. kiedy skończysz z Jackiem, udaj się do Johna, jego pracowników, a następnie do Morgana.
Nigdy nie dowiesz się, ile cykli przejdziesz, zanim uzyskasz odpowiedź, chociaż wiesz, ilu masz menedżerów i ile budżetu możesz wydać.
Rekurencja to drzewo z gałęziami i liśćmi, zwane odpowiednio rodzicami i dziećmi. Kiedy używasz algorytmu rekurencyjnego, mniej lub bardziej świadomie budujesz drzewo na podstawie danych.
źródło
Mówiąc prostym językiem, rekurencja oznacza ciągłe powtarzanie czegoś.
W programowaniu jednym z przykładów jest wywołanie funkcji w samej sobie.
Spójrz na następujący przykład obliczania silni liczby:
źródło
Każdy algorytm wykazuje strukturalną rekursję na typie danych, jeśli zasadniczo składa się z instrukcji przełączającej z przypadkiem dla każdego przypadku typu danych.
na przykład, gdy pracujesz nad czcionką
strukturalny algorytm rekurencyjny miałby postać
jest to naprawdę najbardziej oczywisty sposób na napisanie dowolnego algorytmu, który działa na strukturze danych.
teraz, gdy spojrzymy na liczby całkowite (no cóż, liczby naturalne) zdefiniowane za pomocą aksjomatów Peano
widzisz, że strukturalny algorytm rekurencyjny na liczbach całkowitych wygląda tak
zbyt dobrze znana funkcja silnia jest najbardziej trywialnym przykładem tej postaci.
źródło
funkcja wywołuje samą siebie lub używa własnej definicji.
źródło