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