14
Programowanie I Rekurencja

Programowanie I

Embed Size (px)

DESCRIPTION

Programowanie I. Rekurencja. Wstęp - funkcje i dane rekurencyjne. Definicja: Mówimy, że funkcja lub typ danych są rekurencyjne, jeżeli w ich definicji następuje odwołanie do nich samych. - PowerPoint PPT Presentation

Citation preview

Page 1: Programowanie I

Programowanie I

Rekurencja

Page 2: Programowanie I

Wstęp - funkcje i dane rekurencyjne• Definicja: Mówimy, że funkcja lub typ danych są rekurencyjne,

jeżeli w ich definicji następuje odwołanie do nich samych. • Zwykle rekurencja powstaje z powodu definiowania danej wielkości

przez samą siebie, np. znana funkcja silnia może być zdefiniowana matematycznie następująco (najpierw wykonujemy operacje w najbardziej zagnieżdżonych nawiasach):

• n*(n-1)*...*1=n*((n-1)*...*1)• Jej odpowiednia definicja programowa jest następująca:• silnia(n)= 1, gdy n=0• n*silnia(n-1) dla n>0• Natomiast rekurencyjny typ danych możemy określić następująco:

rozważmy zbiór B+ wszystkich niepustych ciągów złożonych z elementów ustalonego alfabetu B. B+ może być określona następująco:– jeśli b B, to <b> B+,– jeśli w B+ i b B, to w<b> B+.

Page 3: Programowanie I

Wstęp• Funkcje rekurencyjne pozwalają wyrazić nam w

sposób jawny szczególny rodzaj złożenia czynności – tzw. złożenie rekurencyjne.

• Z takim rodzajem złożenia spotkaliśmy się już w semantyce instrukcji “while” i “do”.

• Dla instrukcji „while” możemy złożenie rekurencyjne zdefiniować następująco:void dopóki(int B)

{if (B) { S; dopóki(B)}

}

Page 4: Programowanie I

Wstęp• a dla „do”

void powtarzaj(int B)

{S;

if (B)

{powtarzaj(B);

}

}

• Podobnie możemy postąpić dla instrukcji for.

Page 5: Programowanie I

Wstęp• Algorytmy zapisane za pomocą rekurencji są zapisywane

bardzo prosto i zapisanie ich za pomocą czynności określanych iteracyjnie nie musi być łatwe.

• Przykłady zapisu znanych instrukcji za pomocą ich odpowiedników rekurencyjnych pokazują, że iterację można zapisać za pomocą rekurencji, natomiast odwrotna zasada nie jest prawdziwa.

• Przykładem takiej sytuacji mogą być algorytmy, w których realizacja wymaga rozwiązania za pomocą odpowiedniej, zmiennej w zależności od danych, ilości pętli iteracyjnych.

• Należy jednak dodać, że pochopne stosowanie rekurencji może powodować poważne kłopoty z pamięcią i należy szczególnie ostrożnie rozważać problem skończoności obliczeń.

Page 6: Programowanie I

Wstęp - rola stopu• Np. procedura silnia, która może być zdefiniowana

następująco:

int silnia(int n)

{

if (n=0)

silnia=1;

else

silnia=n*silnia(n-1)

}

• Co dla n<0?. Czy można to poprawić?

Page 7: Programowanie I

Wstęp - działanie rekurencji

• Przykład:void p1(int n){if (n>0) p1(n-1);cout <<n;}

int main(){ p1(4); getch(); return 0;}

Wywołujemy p1(4), jaki wynik i dlaczego?

Page 8: Programowanie I

Wstęp - działanie rekurencji

• Przykładvoid p2(int n){cout <<n;if (n>0) p2(n-1);}

int main(){ p2(4); getch(); return 0;}

Wywołujemy p2(4), jaki wynik?

Page 9: Programowanie I

Przykłady rekurencji - wyjściowe wzory

0n,1

0n,)!1n(*n!n

1n

1i

n

1i

xixnxi

0!x,xx

0x,0x

)x,...,xmin(x),x,...,xmin(

)x,...,xmin(x,x1n,x

)x,...,xmin(

1n1n1n1

1n1nn

1

n1

Page 10: Programowanie I

Wstęp - przykłady• Sumujemy do napotkania 0

int suma()

{

int x;

cin>>x;

if (x!=0) return suma()+x;

else return 0;

}

int main(int argc, char **argv)

{

cout<<suma();

getch();

return 0;

}

Page 11: Programowanie I

Przykłady - silniaint silnia(int n)

{

if (n>0) return n*silnia(n-1);

else return 1;

}

int main(int argc, char **argv)

{

cout<<silnia(4);

getch();

return 0;

}

Page 12: Programowanie I

Rekurencja - przykład

Wzór: fibn=fibn-1+fibn-2, fib1=fib2=1Implementacja

int fib (int n) {

if (n < 3 ) return (1);

else {

return( fib(n-2) + fib(n-1)); }

Page 13: Programowanie I

Rekurencja• Przykład algorytmu, którego nie można

zaimplementować za pomocą iteracji:• Problem n-hetmanów:

– ustaw n-hetmanów na szachownicy o wymiarze nxn, tak by się wzajemnie nie szachowały.

• Idea algorytmu (algorytm z nawrotami):– stawiamy hetmana na wybranym polu, – następne hetmany dostawiamy tak, by się nie

szchowały, – jeśli to niemożliwe, to zdejmujemy ostatniego

hetmana i powtarzamy dla innych pól. – Przykład działania na tablicy.

Page 14: Programowanie I

Rekurencja• Bardziej formalne rozwiązanie:

• Stopniowa konstrukcja polega na tym, że znajdujemy reprezentację rozwiązania x postaci [x1,x2,...,xn] konstruując kolejno [x1], [x1,x2], [x1,x2,x3] itd. w ten sposób, że – 1.każde przejście od [x1,...,xj] do [x1,...,xj,xj+1] jest prostsze niż obliczanie

całego próbnego rozwiązania,

– 2.jeśli q jest predykatem charakteryzującym rozwiązanie, to musi zachodzić: j ((1<=j<=n)=>(q(x)=>q([x1,...,xj])

• Warunek 2 oznacza, że aby otrzymać pełne i poprawne rozwiązanie musimy uzupełnić rozwiązanie częściowe tak, by spełniało ono kryterium poprawności. Jeżeli takie uzupełnienie nie jest w danym momencie możliwe, to odwołujemy pewne poprzednie uzupełnienia tego rozwiązania, czyli skracamy je do [x1,...,xi], gdzie i<j i próbujemy inne uzupełnienie. Takie powroty i próbowanie nowego rozwiązania nazywamy nawracaniem.

• Implementacja samodzielnie.