rekurencja

Transkrypt

rekurencja
rekurencja
1
Rekurencja/rekursja
• Alternatywny dla pętli sposób powtarzania pewnych
czynności; kolejny etap – podzadanie poprzedniego
• Rekursja może być zamieniona na iteracje
• Cechy rekurencji
– Rozłożenie problemu na problemy elementarne i na problem mniej
skomplikowany niż wejściowy
– Jasno określony warunek zakończenia (przypadek podstawowy,
zdegenerowany)
• Iluzja istnienia wielu kopii tego samego algorytmu
(aktywacji)
• Tylko jedna aktywacja jest aktywna w danej chwili
2
silnia
silnia(4) →4*silnia(3)
function silnia(x)
if (x=0)
then (silnia:=1; return)
else
( silnia:=x*silnia(x-1))
silnia(3)→3*silnia(2)
procedure silnia(x)
wynik:=1;
i:=1;
repeat
(wynik:=wynik *i;
i:=i+1)
until (i>x)
silnia(2)→2*silnia(1)
silnia(1)→1*silnia(0)
silnia(0)=1
procedure silnia(x)
wynik:=1;
i:=1;
while (i<=x)
do
(wynik:=wynik *i;
i:=i+1)
3
Wyszukiwanie binarne
li i=1,..n
procedure szukaj(l,p,k,wartosc)
if((k-p)<0) then (return – porażka)
else
j:=(p+k)/2;
if (wartość=lj) then (return –sukces - j )
else
if (wartość >lj)
then
szukaj(l,j+1,k,wartosc)
else
szukaj(l,p,j-1, wartosc)
4
Krzywe Hilberta
H1- 4 puste krzywe H0 połączone liniami prostymi
H2- 4 kopie H1 zmniejszone i obrócone połączone liniami prostymi
4 warianty:
A: D ←A ↓ A → B
A
D
B: C ↑ B → B ↓ A
C: B → C ↑ C ← D
D: A ↓ D ← D ↑ C
A
B
5
Krzywe Sierpińskiego
A
D
B
S2
C
S1
S3
A: A
BD A
B: B
C ↓↓ A B
C: C
D <= B C
D: D A ↑↑ C
S1 S2 S3 S4
S: A B C D
D
6
Wieże Hanoi
X
Y
Z
X
Y
Z
3,X,Y,Z
2,X,Z,Y
1,X,Y,Z
procedure move(n,X,Y,Z)
if (n=1) then (X→Y)
else
(move(n-1,X,Z,Y);
X→Y;
move(n-1,Z,Y,X))
X→Z
1,Y,Z,X
X→Y
Y→Z
X→Y
2,Z,Y,X
1,Z,X,Y
Z→Y
1,X,Y,Z
Z→X
X→Y
7
Wieże Hanoi
X
Y
Z
X
procedure move(n,X,Y,Z)
repeat
(przenies najmniejszy krazek na nastepny kolek;
przenies nienajmniejszy krazek (jedyny ruch))
until(OK)
Y
Z
X→Y
X→Z
Y→Z
X→Y
Z→X
Z→Y
X→Y
8
Wieże Hanoi
– Liczba pojedynczych przeniesień
krążka= 2N-1
N – liczba krążków
– Złożoność wykładnicza
– Problem Tybetańczyków – 64 krążki
• Przeniesienie 1 krążka – 10 s
• 5 bilionów (1012) lat
9
Algorytmy z powrotami
• Droga skoczka szachowego
• Problem ośmiu hetmanów
(Gauss 1850; 12 różnych istotnie rozwiązań)
• Problem trwałego małżeństwa
10
Droga skoczka szachowego
procedure proba
repeat
(wybierz ruch;
if (dopuszczalny) then
(zapisz go;)
if (sa puste pola) then
(proba;
if(nieudany) then
(wykresl ostatni zapis)
else udany))
until (ruch udany lub brak ruchu)
11
Niebezpieczeństwa rekurencji
• Powtarzanie części obliczeń (ciąg
Fibonacciego) – programowanie dynamiczne
• Przepełnienie stosu
• Błąd – nieskończona liczba wywołań
• Różne kompilatory –różne wyniki
identycznych programów
12
Ciąg Fibonacciego
fib(0)=0
fib(1)=1
fib(n)=fib(n-1) + fib(n-2) dla n>=2
fib(0)
fib(2)
function fib(x)
if(x=0) then (fib:=0)
else
if(x=1) then (fib:=1)
else
fib:=fib(x-1)+fib(x-2)
fib(1)
fib(4)
fib(1)
fib(3)
fib(0)
fib(2)
fib(1)
13
Przepełnienie stosu
procedure MacCarthy(x)
if (x>100)
then (wynik:=x-10)
else
(wynik:=MacCarthy(MacCarthy(x+11)))
MC(96)---MC(MC(107))----MC(97)----MC(MC(108))----MC(98)----MC(MC(109))----MC(99)----MC(MC(110))----MC(100)--MC(MC(111))----MC(101)----91
14
nieskończona liczba wywołań
• Upraszczanie nie doprowadza do przypadku elementarnego
function fun(n)
if(n=1) then return 1
else
(if (n%2 =0)
then
else
)
(fun:=fun(n-2)*n;
return fun)
(fun:=fun(n-1)*n;
return fun)
15
Nieskończony ciąg wywołań
function fun(n,m)
if (n=0)
then
return 1
else
return fun(n-1,fun(n-m,m)
fun(1,0) → fun(0,fun(1,0)) → fun(0,fun(1,0)) → fun(0,fun(1,0)) ….
Parametry funkcji rekurencyjnej wartościowane jako pierwsze
16
Przykłady funkcji
rekurencyjnych w języku C
17
silnia
double silnia(int x)
{
if(x<=0) return 1;
else
return (x*silnia(x-1));
}
18
Zamiana na liczbę binarną
void zamiana(int liczba)
{
if(liczba>1)
{zamiana(liczba/2);
printf("%d",liczba%2);
}
else
printf("%d\n",liczba);
}
19
Binarne wyszukiwanie
int szukaj(int p, int k, int *tab, int x)
{
int s;
if(k==p)
if(tab[p]==x)
return p;
else
return -1;
else
{
s=(p+k)/2;
if(tab[s]==x)
return s;
else
if(x>tab[s])
return szukaj(s+1,k,tab,x);
else
return szukaj(p,s,tab,x);
}
}
20
Odwracanie posortowanej tablicy
void odw(tab,p,k)
int p,k;
int *tab;
{
int pom;
if(p<k)
{
pom=tab[p];
tab[p]=tab[k];
tab[k]=pom;
odw(tab,p+1,k-1);
}
}
21
Zliczanie ostatnich 0 w reprezentacji binarnej
liczby całkowitej
int licz0(int k)
{
if(k==0)
return 1;
if (k%2)
return 0;
else
return 1+licz0(k/2);
}
22
Zliczanie ostatnich 1 w reprezentacji binarnej
liczby całkowitej
int licz1(int k)
{
if (k%2)
return 1+licz1(k/2);
else
return 0;
}
23
Algorytm Euklidesa
int nwd_euklides(int m, int n)
{
if(n==0 )return m;
return nwd_euklides(n, m%n);
}
1.
2.
3.
Przypisz zmiennym M i N odpowiednio
większą i mniejszą wartość wejściową
Podziel M przez N, resztę z dzielenia
nazwij R
Jeśli R nie jest zerem, to przypisz
zmiennej M wartość N, zmiennej N
wartość R i powróć do kroku 2, w
przeciwnym razie NWD to wartość N
24
Szukanie wartości minimalnej w tablicy
int mint( n, t, i)
int n, t[n],i;
{
int kk;
if(i==n-1)
return t[i];
else
{
kk = mint(n,t,i+1);
if ( t[i] < kk )
return t[i];
else
return kk;
}
}
25
Wyszukiwanie binarne – maksymalny element
tablicy
int max(a,p,k)
int *a,p,k;
{
int s,max1,max2;
if(p==k)
return a[p];
s=(p+k)/2;
max1=max(a,p,s);
max2=max(a,s+1,k);
if (max1>max2) return max1;
else
return max2;
}
26
Wyszukiwanie binarne strategia ”dziel i rządź”
• Dwa wywołania rekurencyjne
• Każde obsługuje połowę zbioru danych
wejściowych
27
Metoda „dziel i zwyciężaj”
– Podział problemu na kilka mniejszych, podobnych do
początkowego
– Rozwiązywanie rekurencyjne podproblemów
– Łączenie rozwiązań
• Etapy każdego poziomu rekursji
– Dziel
– Zwyciężaj – rozwiązanie małych podproblemów rekurencyjnie, dla
małych rozmiarów – metody bezpośrednie
– Połącz
• Przykład – sortowanie przez scalanie
28
Programowanie dynamiczne
•
•
•
Poprawia metodę „dziel i zwyciężaj” w sytuacji wielokrotnego
rozwiązywania tych samych problemów
– Czas wykładniczy  liniowy
Wstępujące
– Obliczenie wartości począwszy od najmniejszych wartości;
– Obliczenie bieżącej wartości korzystając z poprzednio obliczonych
wartości
– Warunek – istnieje możliwość gromadzenia obliczonych wartości
Zstępujące (zapamiętywanie)
– Procedura rekurencyjna sprawdza zapisane wartości i zapisuje
obliczoną przez siebie wartość
29
Liczby Fibonacciego
int F(int i)
{
if(i<1) return 0;
if(i==1) return 1;
return F(i-1)+F(i-2);
}
int main()
{
int k;
cin>>k;
cout<<"F("<<k<<")="<<F(k);
}
const int maxN=100;
int F(int i)
{
static int Fib[maxN];
if(i<0) return 0;
if(Fib[i]!=0) return Fib[i];
int t=i;
if(i>1) t=F(i-1)+F(i-2);
return Fib[i]=t;
}
int main()
{
int k;
cin>>k;
cout<<"F("<<k<<")="<<F(k);
}
30
Liczby Fibonacciego
• Program1 – czas wykładniczy
T (n)  O( n ),   1.618
a
  , złoty podziałodcinka
b
Np. – obliczenie F(n) – 1 s
obliczenie F(n+9) – 1min
obliczenie F(n+18) – 1h
ab a

a
b
 9  60
• Program2 - wykorzystuje tablicę statyczną (na
początku wypełniona 0)
T(n)=O(n)
F(45)=1 836 311 903 - największa 32-bitowa całkowita liczba
Fibonacciego
-potrzebna tablica 46-elementowa
31
Liczby Fibonacciego – F6
6
5
4
4
3
3
3
2
2
2
2
1
1
1
1
6
2
1
1
1
1
1
1
1
1
1
3
3
1
1
1
2
1
3
2
4
3
5
5
6
8
7
15
wypełnienie
tablicy
2
2
0
1
5
4
1
0
8
5
Program1
25 wywołań
0
Program2
6 wywołań
32
Symbol Newtonarekurencja
 n   n  1  n  1 
   
  
 dla m  0, m  n
m
m
m

1
  
 

n
   1 dla m  0  m  n
 m
T (n)  O(a n )
int symbol_newtona(int n, int m)
{
int sn;
if(m==0 ||m==n) return 1;
sn=symbol_newtona(n-1,m)+symbol_newtona(n-1,m-1);
return sn;
}
sn(4,2)=
sn(3,2) + sn(3,1) =
sn(2,2)+sn(2,1)+sn(2,1)+sn(2,0)=
1+sn(1,1)+sn(1,0)+sn(1,1)+sn(1,0) +1=6
33
Symbol Newtona
programowanie dynamiczne
int sn(int n, int m)
{
static int tab[maxN];
int i,j;
if(m==0 ||m==n) return 1;
for(j=0;j<=n;j++) tab[j]=1;
for(i=2;i<=n;i++)
for(j=i-1;j>0;j--)//j>m-1
tab[j]=tab[j-1]+tab[j];
return tab[m];
}
i
 j
w i-tym kroku tab[j] = 
 
T (n)  O(n 2 )
34
Symbol Newtona
programowanie dynamiczne
i
w i-tym kroku tab[j] =  
 j
i=1
tab[0]
1
tab[1]
1
tab[2]
1
tab[3]
1
tab[4]
1
tab[5]
1
m
n=6
i=2 i=3 i=4 i=5 i=6
1
1
2
3
4
5
6
3
6
10
15
4
10
20
5
15
n
1
1
1
1
1
2
3
4
5
1
3
6
10
1
4
10
1
5
1
6
 4
dla i=4 tab[3] =   = 4
 3
6
dla i=6 tab[3] =   = 20
 3
n
 
m
5
 
 2
n>m
n = 0, 1,…
m = 0, 1,….
 4
 
 335