Rekurzivne metode Rekurzivan metod je onaj metod koji u nekoj svojoj instrukciji sadrži poziv samog sebe. Svakako prilikom kreiranja rekurzivnog metoda moramo voditi računa da ne dodje do beskonačne rekurzije (System.StackOverflow).Uvek moramo imati proveru da li je ispunjen uslov za napuštanje rekurzije (ili da li je ispunjen uslov za dalji ulazak u rekurziju). Posmatrajmo rekurzivan metod kojim u objektu listbox1 klase ListBox upisujemo sve prirodne brojeve od 1 do datog n. void pisi(int n) if (n > 1) pisi(n - 1); pisi(3) if (n > 1) pisi(n - 1); pisiid(2) pisi(2) if > 1) pisi(n - 1); if > 1) pisiid(n - 1); pisiid(1) pisi(1) n=1 if > 1) pisi(n - 1); if > 1) pisiid(n - 1); Analizirajmo izvršavanje ovog metoza kada ga pozovemo za, pisi(3). Prvo se proverava uslov 3>1 kako je uslov ispunjen realizuje se poziv metode pisi(2). To prouzrokuje kreiranje drugog primera metode pisiid sa lokalnom promenljivom n čija je vrednost 2. U drugom primerku ponovo se izvrši prva naredba, proverava uslov i poziva se metod pisi sada sa parametrom 1, pisi(1). To prouzrokuje kreiranje trećeg primerka metode u kojem lokalna promenljiva n
ima vrednost 1. U trećem primerku prvo se proverava uslov 1>1, kako on nije ispunjen ne vrši se poziv metode pisi, veće se izvršava treća naredba, a to je prikaz u objektu listbox1 vrednosti promenljive n koja iznosi 1. Na taj način sve naredbe trećeg primerka metode su izvršene, time je treći primerak metode završen, aplikacija se nastavlja od mesta poziva, to znači da se vraćamo u drugom primerku metode i izvršava se poslednja naredba u drugom primerku prikaz broja n u objektu listbox1, vrednost promenljive n je u drugom primerku 2. Po završetku drugog primerka vraćamo se na mesto poziva u prvom primerku što prouzrokuje prikaz vrednosti promenljive n (3) u objektu listbox1. Tako da je sadržaj objekta listbox1 redom 3 2 1 1 2 3 Lokalne promenljive svakog primerka metode čuvaju se na steku (stack). Stek je memorijski segment za privremeno čuvanje podataka, radi po LIFO principu (LastInFirstOut ) poslednji stavljen podatak prvi će se uzimati sa steka. Kada se pozove metod njeni parametri i lokane promenljive smeštaju se na stek, a kad se metod završi uzimaju se sa steka. n=1 Prilikom rešavanja nekog problema rekurzijom, uočimo potproblem istog tipa (ali manje dimenzije) rešimo taj potproblem pozivom rekurzivne metode i onda njegovo rešenje iskoristimo da dobijemo rešenje polaznog problema. Pri tome kada je polazni problem jednostavan (ne sadrži potproblem istog tipa) rešim ga bez poziva rekurzivne metode. U prethodnom primeru prilikom ispisa brojeva od 1 do n, rešimo podproblem za ispis brojeva od 1 do n-1 (ako je n manje ili jednako sa 1 potproblem ne postiji i ne pozivamo njegove rešavanje) pa upišemo broj n n=1
Važno je napomenuti da prethodni primer može da se reši značajno efikasnije iterativno: for (int i = 0; i < n; i++) listbox1.items.add(i); Zadatke koji slede rešabamo rekurzijom da bi naučili takav način razmišljanja i rešavanja, bez obzira što se većina tih zadataka može rešiti iterativno. 1. Napisati rekurzivnu metodu kojom se za dati prirodan broj n ispisuju brojevi 1, 2, 3,..., n a) prvo u inverznom poretku a zatim u direktnom b) prvo u direktnom a zatim u inverznom poretku void rekurzija1( int i,int n) listbox1.items.add(i); if (i < n) rekurzija1(i + 1, n); listbox1.items.add(i); void rekurzija2(int n) if (n > 1) rekurzija2(n - 1); private void numericupdown1_valuechanged(object sender, EventArgs e) int n = (int)numericupdown1.value; listbox1.items.clear(); if (radiobutton1.checked) rekurzija1(1, n); rekurzija2(n);
2. Napisati rekurzivni metod koja za dati prirodan broj n određuje a) broj cifra broja n b) sumu cifara broja n Prvi način int brojcifara(int n) return 1 + brojcifara(n / 10); int sumacifara(int n) return n % 10 + sumacifara(n / 10); private void button2_click(object sender, EventArgs e) label1.text = "Suma cifara je " + sumacifara(convert.toint32(textbox1.text)); label2.text = "Broj cifara je " + brojcifara(convert.toint32(textbox1.text)); Drugi način void brojcifara(int n, out int b) if (n < 10) b = 1; brojcifara(n / 10, out b); b++; void sumacifara(int n, out int s) if (n == 0) s = 0; sumacifara(n / 10, out s); s += n % 10; private void button1_click(object sender, EventArgs e) int s,b;
sumacifara(convert.toint32(textbox1.text),out s); label1.text = "Suma cifara je "+s; brojcifara(convert.toint32(textbox1.text), out b); label2.text = "Broj cifara je " + b; 3. Napisati rekurzivni metod koja za dati prirodan broj n određuje suma parnih cifara int sumap(int n) if ((n % 10) % 2 == 0) return sumap(n / 10) + n % 10; return sumap(n / 10); private void button3_click(object sender, EventArgs e) int n = Convert.ToInt32(textBox1.Text); int s; s = sumap(n); label1.text = "suma parnih je " + s; 4. Napisati rekurzivni metod koja za dati prirodan broj n određuje a) odredjivanje k-te cifre gledano s desna u levo u broju n int KCifra(int n, int k) if (k == 1) return n % 10; return KCifra(n / 10, k - 1); b) odredjivanje k-te cifre gledano s leva na desno u broju n // s leva na desno int cifrak2(int n, int k) if (n<math.pow(10,k)) return n % 10; return cifrak2(n / 10, k); // s leva na desno int cifrak22(int n, int stk) if (n < stk) return n % 10; return cifrak2(n / 10, stk); Poziv: cifrak22(n,math.pow(10,k))
5. Napisati rekurzivni metod koja za dati prirodan broj n određuje a) broj dobijem tako što se svaka parna cifra podeli sa 2 void podeliparnec(int n, ref int st, ref int x) if (n!= 0) if(n%10%2==0) x = x + n % 10/2 * st; x = x + n % 10 * st; st *= 10; podeliparnec(n / 10, ref st, ref x); int podeliparnec(int n) if (n % 10 % 2 == 0) return podeliparnec(n/10)*10+ n % 10 / 2; return podeliparnec(n/10)*10+ n % 10; b) broj dobijem tako izbacivanjem svake neparne cifre u broju n int izbacineparne(int n) if (n % 10 % 2 == 0) return izbacineparne(n / 10) * 10 + n % 10 ; return izbacineparne(n / 10);