WYKŁAD 8 Funkcje i algorytmy rekurencyjne Proste przykłady Programy: c3_1.c..., c3_6.c Tomasz Zieliński
METODY REKURENCYJNE (1) - program c3_1 ====================================================================================================== Funkcja rekurencyjna to funkcja, która wywołuje samą siebie. ====================================================================================================== /* Przyklad 3.1 - wypisz znaki z klawiatury w odwrotnej kolejnosci */ #include <stdio.h> void odwrotnie( void ); void main() printf("\npisz w linii. Zakoncz <Enter>. \n\n"); odwrotnie(); void odwrotnie( void ) char c; // wczytaj znak z klawiatury i podstaw jego if ( (c=getchar() )!= '\n' ) // kod ASCII do c; jeśli nie jest to koniec linii, to: // odwrotnie(); // wywołaj ponownie funkcję odwrotnie() printf( "%c", c); // wyświetl na ekranie znak c
METODY REKURENCYJNE (2) - program c3_1 Wypisz w odwrotnej kolejności znaki z klawiatury ZAŁOŻENIE: z klawiatury: ab [ENTER] void main()... odwrotnie();... c a ; odwrotnie(); c b ; odwrotnie(); c \n ; void odwrotnie( void ) char c; if ( (c=getchar())!= '\n' ) odwrotnie(); printf( "%c", c); wypisz c; wypisz c; c jest lokalną zmienną każdego z wywołań funkcji, która ma różną wartość w każdym z wywołań
METODY REKURENCYJNE (3) - program c3_1 Wypisz w odwrotnej kolejności znaki z klawiatury Program główny ZAŁOŻENIE: z klawiatury: abcd [ENTER] a printf b printf c printf d printf \n
METODY REKURENCYJNE (4) - program c3_2 Zamiana integer na ASCII /* Przyklad 3.2 - wypisz ma ekranie liczbę calkowitą */ /* czyli INTEGER na ASCII */ #include <stdio.h> #include <math.h> void wypisz( int n ); /* program glowny -------------------------------------------------------------------- */ void main() int x; printf(" \n jaka liczba calkowita? "); scanf("%d", &x); printf(" \n podane = %d \n", x); printf(" rekursja = "); wypisz( x ); printf("\n");
/* Funkcja rekurencyjna ----------------------------------------------------------- */ void wypisz( int n ) int i; if ( n < 0 ) putchar('-'); n = -n; if ( (i=n/10)!= 0 ) wypisz( i ); // jeśli liczba ujemna, // to napisz - oraz zaneguj liczbę // jeśli i, czyli część całkowita z n/10, // jest różna od zera, to wywołaj ponownie // ale z argumentem i putchar( 0 +n%10); // to (reszta z dzielenia n przez 10) // putchar( '0' + (unsigned char) (n - 10 * i) ); // lub to (czyli najmniej znacząca cyfra)
METODY REKURENCYJNE (5) - program c3_2 Zamiana integer na ASCII Program główny ZAŁOŻENIE: z klawiatury: 12345 [ENTER] n 12345 putchar 5 putchar = putchar( 0 + (unsigned char) (n % 10) i = n/10 n=1234 putchar 4 = putchar( 0 + (unsigned char) (n 10*i) i = n/10 n=123 putchar 3 wypisz resztę z dzielenia n przez 10, czyli najmniej znaczącą cyfrę n i = n/10 n=12 putchar 2 i = n/10 n=1 putchar 1
METODY REKURENCYJNE (6) - program c3_3 n! czyli n-silnia /* Przyklad 3.3 - METODY REKURENCYJNE - oblicz n! */ /* n! = 1*2*3*...*(n-1)*n np. 5! = 1*2*3*4*5 */ #include <stdio.h> long silnia( long n ); /* program glowny -------------------------------------------------------------- */ void main() long n, x, iloczyn; printf("\n Obliczam funkcje n! Podaj n? [max 12] "); scanf("%ld", &n); /* Metoda iteracyjna */ iloczyn = 1; for( x = n; x > 0; x--) iloczyn = iloczyn * x; printf( "\n Metoda iteracyjna --> n! = %ld \n", iloczyn );
/* Metoda rekurencyjna */ iloczyn = silnia( n ); printf( "\n Metoda rekurencyjna --> n! = %ld \n", iloczyn); /* Funkcja rekurencyjna ----------------------------------------------------------- */ long silnia( long n ) long x, y; if( n == 0L ) return(1); // L znaczy long x = n-1; y = silnia(x); /* rekurencyjne wywolanie */ return(n*y); long silnia( long n ) if( n == 0L ) return(1); return(n* silnia(n-1)); /* rekurencyjne wywolanie */
METODY REKURENCYJNE (7) - program c3_3 n! czyli n-silnia Program główny ZAŁOŻENIE: z klawiatury: 4 [ENTER] n 4 4*(3*2*1*1) 24 n-1 3 3*(2*1*1) 6 n-1 2 2*(1*1) n-1 1 1*(1) n-1 0 1 2 1 1 long silnia( long n ) long x, y; if( n == 0L ) return(1); x = n-1; y = silnia(x); return(n*y); long silnia( long n ) if( n == 0L ) return(1); return( n*silnia(n-1) );
METODY REKURENCYJNE (7) - program c3_5 szukanie elementu metodą podziału zbioru na dwie części indeks i tablica dzielników ZADANIE: znaleźć indeks i tablicy, dla którego: tab[ i ] == x N-1 2.0 15 5 4 3 2 1 0 1.5 0.5 0.4 0.3 0.2 0.1 0.0 x = 1.6 ROZWIĄZANIE 1 (sekwencyjne): i = 0; while( ( x!= tab[i] ) & (i < N-1) ) i++; ROZWIĄZANIE 2 (rekurencyjne): int szukaj( int tab[ ], int x, int dol, int gora ) int srodek; srodek = (dol + gora)/2; if ( x == tab[ srodek ] ) return( srodek); if ( x < tab[ srodek ] ) return( szukaj( tab, x, dol, srodek - 1 ) ); else return( szukaj( tab, x, srodek + 1, gora ) );
METODY REKURENCYJNE (8) - program c3_5 PRZYKŁAD: przetworniki A/C kompensacyjne: równomierny (po lewej) i wagowy (po prawej) U licznika U x K 0/1 U x K 0/1 U C/A C/A 0 0 1 1 Licznik/Generator U REF Stop Start U C/A C/A U REF 0 0 1 1 Stop Układ logiki Start U licznika U zakres U zakres U x 3/4U z 1/2U z U x stan licznika 1/4U z 0000 0001 0010 0011 0100 0 1 2 3 nr bitu C/A
METODY REKURENCYJNE (9) - program c3_5 szukanie metodą podziału na dwie części /* Przyklad 3.5 - METODY REKURENCYJNE - szukanie "dwojkowe" */ /* WEJŚCIE: tab = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ] */ /* x = liczba naturalna z klawiatury */ /* WYJŚCIE: położenie (indeks) elementu x w tablicy tab[] */ #include <stdio.h> int szukaj( int tab[ ], int x, int dol, int gora ); void main()/* program glowny ---------------------------------------------------------------------- */ int tab[ 11 ] = 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10 ; int x, indeks, dol, gora; printf("\n Jaka jest calkowita wartosc poszukiwanego elementu? "); scanf("%d", &x); dol = 0; gora = 10; indeks = szukaj( tab, x, dol, gora ); printf( "\n Indeks = %i \n", indeks);
/* funkcja rekursywna ----------------------------------------------------------------- */ int szukaj( int tab[ ], int x, int dol, int gora ) int srodek; if ( dol > gora ) return(-1); /* -1 oznacza brak elementu w zbiorze */ srodek = (dol + gora)/2; if ( x == tab[ srodek ] ) return( srodek); if ( x < tab[ srodek ] ) return( szukaj( tab, x, dol, srodek - 1 ) ); else return( szukaj( tab, x, srodek + 1, gora ) );