Szczegóły
Transkrypt
Szczegóły
Temat: Rekurencja jako technika kodowania algorytmów. Anatomia wywołania rekurencyjnego. Rodzaje rekurencji. Wady i zalety kodowania rekurencyjnego. Obiekt zwany jest rekurencyjnym (ang. recursive), je eli cz ciowo składa si z siebie samego lub jego definicja odwołuje si do jego samego. Rekurencja (inaczej rekursja) jest silnym narz dziem w definicjach matematycznych. Przykład 1 Funkcja silnia n!= 1 dla n = 0 n ⋅ (n − 1)! dla n > 0 silnia(n) { if (n==0 || n==1) return 1; else return n*silnia(n-1); } 1. Anatomia wywołania rekurencyjnego Przykład 2 Funkcja obliczaj ca pot g naturaln liczby rzeczywistej power(x, n) { if (n==0) then return 1; else return x*power(x, n-1); } …. x=power(5.6, 2); call stack – stos wywoła funkcji, w którym zapami tywane s tzw. rekordy aktywacji (inaczej rekordy wywołania funkcji) 1 Rekord wywołania (aktywacji) zawiera: • warto ci wszystkich parametrów funkcji, • zmienne lokalne funkcji, • adres powrotu (adres miejsca w kodzie programu, do którego wraca procesor po zako czeniu wywołania funkcji, • dynamiczne dowi zanie (wska nik na poprzedni rekord aktywacji) • warto funkcji (o ile funkcja zwraca warto ) warto funkcji warto ci parametry funkcji zmienne lokalne adres powrotu dynamiczne dowi zanie x=5.6; (1) (2) power(x, n) { if (n==0) return 1; else return x*power(x, n-1); } …. (3) x=power(5.6, 2); Analiza wywołania power(5.6, 2) – stos wywołania 1 x=5.6, n=0 (2) 5.6 x=5.6, n=1 (2) 31.36 x=5.6, n=2 (3) NULL 2 2. Rodzaje rekurencji Rekursja ko cowa nierozgał ziona - zawiera tylko jedno wywołanie rekurencyjne na ko cu kodu funkcji. Taki rodzaj rekursji jest po prostu innym zapisem p tli i mo e by łatwo zast piony wła nie p tl . Rekursja ko cowa jest zazwyczaj nieefektywna ze wzgl du na wy szy koszt czasowy i pami ciowy w porównaniu z wersj iteracyjn . Przykład 3 Funkcja, która wypisuje liczby od i do 1 pisz(i) { if (i>0) { “drukuj i”; pisz(i-1); } } iter_pisz(i) { for (j=i; j>=1; j--) „drukuj j”; } Rekursja nieko cowa nierozgał ziona- zawiera jedno wywołanie rekurencyjne, które nie jest ostatnim rozkazem funkcji. Iteracyjna wersja takiej funkcji wymaga u ycia struktury pomocniczej. Przykład 4 Funkcja, która wypisuje znaki wprowadzone z klawiatury w rewersie reverse() { char ch; „pobierz ch”; if (ch!=ENTER) reverse(); “drukuj ch”; } iter_reverse() { char ch[1000]; int i=0; do{ „pobierz ch”; i++; } while (ch[i-1]!=ENTER); for (int j=i-1;j>=0;j--) “drukuj ch[j]”; } 3 Rekursja rozgał ziona ko cowa – zawiera wi cej ni jedno wywołanie rekurencyjne na ko cu kodu funkcji Przykład 5 Funkcja, która wyszukuje liczb w ci gu uporz dkowanym A={a1, a2, …, an}. Zakładamy, e liczby w ci gu si nie powtarzaj . search(l, r) { int m; if (l>r) return -1; else { m=(l+r)/2; if (x==am) return m; else if (x< am) return search(l, m-1); else return search(m+1, r); } } ... wynik=search(0, n-1); search_iter(A, x, l, r) { int m; while (l<=r) { m=(l+r)/2; if (x== am) return m; else if (x< am) r=m-1; else return l=m+1; } return -1; } ... wynik=search_iter(A, 5, 0, n-1); Rekursja rozgał ziona nieko cowa – zawiera wi cej ni jedno wywołanie rekurencyjne, po niektórych z wywoła albo po ka dym z nich znajduje si instrukcje. 4 Przykład 6 Problem wie Hanoi Załó my, e mamy trzy wie e (kołki) A, B, C. Na pierwszym kołku A znajduje si n kr ków nanizanych w porz dku malej cych wielko ci, podczas, gdy pozostałe kołki s puste. Nale y przenie kr ki z kołka A na B, by mo e u ywaj c kołka C. Reguły przenoszenia kr ków s nast puj ce: • Kr ki mo emy przenosi po jednym na raz. • Kr ek wi kszy nie mo e by umieszczony na wierzchu mniejszego. Rozwi zanie dla n = 3 A A→B; A→C; B B →C; A→B; C C→A; C→B; A→B Algorytm rozwi zuj cy problem wie Hanoi n – liczba kr ków, X ,Y, Z - stojaki Hanoi(n, X, Y, Z) { if (n = =1) “drukuj X →Y”; else { Hanoi(n-1, X, Z, Y); “drukuj X →Y”; Hanoi(n-1, Z, Y, X); } } Przykładowe wywołanie Hanoi(3, A, B, C); 5 Zalety rekurencji: • upraszcza kodowanie • zwi ksza czytelno kodu Wady rekurencji: • spowolnienie wykonania funkcji • wi ksza zaj to pami ciowa i czasowa – przechowywanie na stosie dodatkowej informacji (rekord aktywacji). Je li rekursja jest zbyt gł boka, to mo e si zdarzy sytuacja okre lana jako przepełnienie stosu. 3. Przykład nieuzasadnionego u ycia rekurencji Przykład 7 Funkcja obliczaj ca warto ci elementów ci gu Fibonacciego Ci g Fibonacciego: F(0)=0 F(1)=1 F(n)=F(n-1)+F(n-2) dla n>1 Algorytm I (rozwi zanie rekurencyjne) F(n) { if (n==0) return 0; else if (n==1) return 1; else return F(n-1)+F(n-2); } Zło ono czasowa: (2n) 6 F(6) F(4) F(5) F(2) F(0) 0 F(3) F(1) F(1) 1 1 F(3) F(2) F(1) F(0) F(1) 0 1 1 F(4) F(2) F(2) F(3) F(0) F(1) F(0) F(1) F(1) F(2) 0 1 0 1 1 F(0) F(1) 0 1 Liczba operacji dodawania i liczba wywoła rekurencyjnych przy obliczaniu liczby Fibonacciego n 6 10 15 20 25 30 Liczba dodawa 12 88 986 10945 121392 1346268 Liczba wywoła 25 177 1973 21891 242785 2692537 Algorytm II (wersja z tablic ) F(n, T) { T[0]=0; T[1]=1; for (i=2;i<=n;i++) T[i]=T[i-1]+T[i-2]; return T[n]; } Koszt czasowy: (n) Koszt pami ciowy: (n) 7 Algorytm III (wersja bez tablicy) F(n) { int a=0,b=1,c; for (i=2;i<=n;i++) { c=a+b; a=b; b=c; } return c; } Koszt czasowy: (n) Koszt pami ciowy: (1) Rekurencj stosujemy tylko wtedy, gdy nie wpływa ona znacz co na podniesienie kosztów czasowych i pami ciowych algorytmu, a jest prostsza do zastosownia i czytelniejsza. 8