Rekurencja

Transkrypt

Rekurencja
Rekurencja
Przygotowała:
Agnieszka Reiter
Definicja
• Charakterystyczną cechą funkcji (procedury)
rekurencyjnej jest to, że wywołuje ona samą
siebie. Drugą cechą rekursji jest jej dziedzina,
którą mogą być tylko liczby naturalne.
• Rekurencja jest sposobem programowania, w
którym stosuje się procedury wywołujące same
siebie. Ilość tych wywołań nie ma znaczenia,
fakt wywołania jest podstawą do określenia
algorytmu jako rekurencyjnego.
Po co nam jest rekurencja?
Przede wszystkim dzięki niej łatwo jest wykonać
wiele zadań, w których potrzeba jest wyników
cząstkowych do obliczenia całości.
Sztandarowym przykładem w zagadnieniu
rekurencji jest liczenie silni (n!), lub nieco
bardziej zaawansowany przykład liczenia n-tej
wartości w ciągu Fibonacciego.
Dla przypomnienia, ciąg Fibonacciego jest
ciągiem, w którym każda następna wartość jest
równa sumie dwóch poprzednich.
Algorytm silnia
ALGORYTM SILNI W J. PASCAL
Function silnia(n:byte):word;
Begin
If n<1 then silnia:=1
else silnia:=silnia(n-1)*n;
End;
Algorytm silni
Często przytaczanym przykładem jest
definicja funkcji obliczającej wartość silni
long int SILNIA(int n)
{
if(n<1) return 1;
else return n * SILNIA(n-1);
}
Analiza
Odwołanie się do funkcji wewnątrz tej samej
funkcji następuje z parametrem o 1 mniejszym,
niż oryginalnie podano.
Dlatego kolejna wersja funkcji będzie liczyła
wartość silni już tylko dla np. 5, podczas gdy
początkowe wywołanie było dla 6.
Kolejne poziomy wywołań funkcji SILNIA będą
liczyły silnię dla coraz mniejszych wartości, aż
do 0, a wtedy zwrócone zostanie 1.
Potem, zwracane są kolejne wartości podczas
wychodzenia z kolejnych poziomów wywołań,
i wtedy właśnie będzie obliczana rzeczywista
wartość (będą mnożone przez siebie kolejne
liczby).
Przykład - silnia(6)
Uwaga
Cechą charakterystyczną jest to, że
funkcja wchodzi w kolejny poziom,
aby obliczyć iloczyn podanego jej
parametru oraz wartość (parametr-1).
Dopiero w momencie powrotu
z wywołań obliczane są rzeczywiste
iloczyny, i wtedy też przeliczana jest
wartość silni.
Ciąg fibonacciego
• Liczby naturalne tworzące ciąg o takiej
własności, że kolejny wyraz (z wyjątkiem dwóch
pierwszych) jest sumą dwóch poprzednich
nazywa się liczbami Fibonacciego i pojawiają się
w tak wielu sytuacjach, że wydaje się to
niemożliwe.
• Podstawowy ciąg liczb Fibonacciego to: 1, 1, 2,
3, 5, 8, ... Każda liczba w ciągu jest sumą dwóch
poprzednich (poza pierwszą i drugą). Mamy
więc do czynienia z ciągiem rekurencyjnym.
Występowanie
• Ciąg Fibonacciego można odnaleźć
w wielu aspektach przyrody, ciąg taki opisuje
np. liczbę pędów rośliny jednostajnie
przyrastającej w latach.
• W słoneczniku możemy zaobserwować dwa
układy linii spiralnych, wychodzących ze środka.
• Takie same spirale można zaobserwować na
wielu innych roślinach ( np. kalafior, ananas).
• Liczby spiral występujących w tych roślinach
są kolejnymi liczbami Fibonacciego.
Ciąg fibonacciego w j. Pascal
Function fibonacci(n:byte):word;
Begin
If ((n=1) or (n=2)) then fibonacci:=1
Else
fibonacci := fibonacci(n-1)+fibonacci(n-2);
End;
Ciąg Fibonacciego C++
#include <iostream>
using namespace std;
int Fibonacci(int n)
{
if (n==1 || n==2)
return 1;
else
return Fibonacci(n-1) + Fibonacci(n-2);
}
int main()
{
int n;
cout << "Podaj n= ";
cin >> n;
cout << n << " wyraz ciagu Fibonacciego to: " << Fibonacci(n)
<<endl;
system("pause>null");
return 0;
}
Wieże HANOI
Wieże Hanoi – problem polegający na odbudowaniu,
z zachowaniem kształtu, wieży z krążków o różnych
średnicach (popularna dziecięca zabawka), przy czym
podczas przekładania wolno się posługiwać buforem
(reprezentowanym w tym przypadku przez dodatkowy
słupek), jednak przy ogólnym założeniu, że nie wolno
kłaść krążka o większej średnicy na mniejszy ani
przekładać kilku krążków jednocześnie. Jest to przykład
zadania, którego złożoność obliczeniowa wzrasta
niezwykle szybko w miarę zwiększania parametru
wejściowego, tj. liczby elementów wieży.
Rozwiązania
Dla 2 krążków:
Dla 3 krążków:
rozwiązanie dla 3 krążków składa się z 7 ruchów:
kolejne etapy to:
• przenieś krążek o najmniejszej średnicy na palik docelowy,
• krążek o średnicy większej przenieś na palik pomocniczy,
• krążek najmniejszy przenieś na palik pomocniczy,
• następnie krążek największy przenieś na palik docelowy a najmniejszy
na źródłowy,
• na największym połóż średni i potem najmniejszy,
• koniec
Wieża Hanoi
• Ułóż stos na trzecim patyku przestrzegając następujących
reguł:
- przesuwaj jeden krążek z wierzchu stosu,
- nie kładź większego krążka na mniejszym.
bufora
Od lewej: słupek A
z całą wieżą,
pusty słupek B
pełniący rolę
i pusty słupek
docelowy C
Wieża Hanoi
Wynik końcowy
Ruchy pośrednie
Algorytm
Rozwiązanie rekurencyjne:
1. Zidentyfikuj największy krążek na nie swoim
miejscu (=krążek N)
2. If daje się go przenieść na docelowy słupek
Then przenieś
Else
3. Podzadanie: ustaw (N−1)-krążkową
wieżę na nie-docelowym słupku.
4. Skocz do punktu 1. ...
Rozwiązanie rekurencyjne
Algorytm rekurencyjny składa się z następujących
kroków:
• przenieś (rekurencyjnie) n-1 krążków ze słupka
A na słupek B posługując się słupkiem C,
• przenieś jeden krążek ze słupka A na słupek C,
• przenieś (rekurencyjnie) n-1 krążków ze słupka
B na słupek C posługując się słupkiem A
Implementacja w C++
#include <iostream>
using namespace std;
void hanoi(int n, char A, char B, char C)
{ // przekłada n krążków z A korzystając z B na C
if (n > 0) {
hanoi(n-1, A, C, B);
cout << A << " -> " << C << endl;
hanoi(n-1, B, A, C); } }
int main(int argc, char *argv[])
{
hanoi(3, 'A', 'B', 'C');
return 0;
}

Podobne dokumenty