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]); }