Rekurencja Rekurencja jest techniką programowania

Transkrypt

Rekurencja Rekurencja jest techniką programowania
Rekurencja
Rekurencja jest techniką programowania wykorzystującą funkcje, które wywołują same siebie. Jest to
alternatywny dla pętli sposób powtarzania pewnych czynności, gdzie kolejny etap jest podzadaniem
poprzedniego. Rekurencja może być zamieniona na iteracje. Przy redukcji problemu wymagany jest
wyraźnie określony warunek zakończenia (przypadek podstawowy). Rekurencja daje wrażenie
istnienia wielu kopii tego samego algorytmu (aktywacji), jednak tylko jedna aktywacja jest aktywna
w danej chwili.
Typowym przykładem rekurencji jest definicja silnia:
Wartość silni dla 0 jest przypadkiem elementarnym.
Sposób obliczania wartości 4! można przedstawić następująco:
4! → 4 * 3!
3! → 3 * 2!
2! → 2 * 1!
1! → 1 * 0!
0! = 1
Przykład1:
Oto przykład programu w języku C, który wczytuje liczby i oblicza wartość silni dla każdej z nich.
Warunkiem stopu jest podanie liczby 0. Program kończy się po obliczeniu i wyświetleniu wartości silni
dla 0.
#include <stdio.h>
#include <stdlib.h>
double silnia(int n)
{
if(n<=0) return 1;
else
return (n*silnia(n-1));
}
int main(int argc, char *argv[])
{
int liczba;
do
{
scanf("%d",&liczba);
printf("%d ! = %e\n",liczba,silnia(liczba));
}
while(liczba!=0);
}
Funkcji jest typu double, gdyż daje to możliwość obliczenia wartości silni dla większego zakresu
danych, niż w przypadku użycia typu int lub float.
Przykład 2: Zamiana liczby dziesiątkowej na dwójkową
Ciekawym przykładem wykorzystania rekurencji jest program zamieniający całkowitą liczbę zapisaną
w systemie dziesiętnym na system dwójkowy. W programie iteracyjnym realizującym to zadanie
wynik otrzymuje się wyświetlając cyfry uzyskane podczas dzielenia w kolejności odwrotnej do ich
uzyskania, co wymaga zapamiętywania ich wartości w tablicy. Funkcja rekurencyjna wyświetla je we
właściwej kolejności z uwagi na zagnieżdżanie się kolejnych wywołań. Wypisanie reszty z dzielenia
występuje w funkcji po wywołaniu rekurencyjnym, dlatego wyniki wypisywane są niejako od końca –
od ostatniego „0” lub „1”, będącego rezultatem ciągu dzieleń.
Kod programu:
#include <stdio.h>
#include <stdlib.h>
void zamiana(int liczba)
{
if(liczba>1)
{zamiana(liczba/2);
printf("%d",liczba%2);
}
else
printf("%d\n",liczba);
}
int main(int argc, char *argv[])
{
int liczba;
do
{
scanf("%d",&liczba);
zamiana(liczba);
printf("\n");
}
while(liczba!=0);
}
Przykład3. Wyszukiwanie binarne, odwracanie posortowanego wektora
W kolejnym przykładzie zostały zdefiniowane dwie funkcje rekurencyjne. Pierwsza z nich - szukaj
odnajduje w posortowanej rosnąco tablicy jednowymiarowej tab zadanej wartości x i zwraca indeks
takiego elementu. Rekurencyjny algorytm polega na tym, że sprawdzany jest środkowy element
tablicy, jeśli jest to szukana wartość, funkcja zwraca indeks tego elementu, jeśli środkowy element
jest mniejszy od szukanej wartości, wywoływana jest funkcja szukająca dla lewej połowy tablicy, w
przeciwnym wypadku szukanie kontynuowane jest dla prawej połowy tablicy. Algorytm kończy się,
gdy przeszukiwana część tablicy ma dwa elementy – jest to przypadek elementarny.
Druga funkcja odwroc rekurencyjnie odwraca posortowaną tablicę, zamieniając skrajne elementy –
najpierw element pierwszy zamieniany jest z ostatnim, następnie element drugi z przedostatnim itd.
Algorytm kończy się, gdy dojdzie do środka tablicy. Oto program:
#include <stdio.h>
#include <stdlib.h>
int szukaj(int poczatek, int koniec, int *tab, int x)
{
if( koniec == poczatek )
if( tab[poczatek]==x ) return poczatek;
else
return -1;
else
{
srodek=(poczatek+koniec)/2;
if(tab[srodek]==x)
return srodek;
else
if(x>tab[srodek])
return szukaj(srodek+1,koniec,tab,x);
else
return szukaj(poczatek,srodek,tab,x);
}
}
void odwroc(tab,poczatek,koniec)
int poczatek,koniec;
int *tab;
{
int pom;
if(poczatek<koniec)
{
pom=tab[poczatek];
tab[poczatek]=tab[koniec];
tab[koniec]=pom;
odwroc(tab,poczatek+1,koniec-1);
}
}
int main(int argc, char *argv[])
{
int i,n,x;
scanf("%d",&n);
int tab[n];
for(i=0;i<n;i++)
scanf("%d",&tab[i]);
scanf("%d",&x);
n--;
szukaj(0,n,tab,x);
odw(tab,0,n);
for(i=0;i<=n;i++)
printf("%d ",tab[i]);
}