HIKGHB Németh Gábor LUF9NV Simon Attila
A programozás alapjai előadás Híradástechnikai Tanszék
Rekurzió
Bináris fa bejárása - preorder (gyökér – bal gyerek – jobb gyerek) mentés - visszaállítás
Bináris fa bejárása - inorder (bal gyerek – gyökér – jobb gyerek) rendezés
Bináris fa bejárása - posztorder (bal gyerek – jobb gyerek – gyökér) képlet kiértékelése
Bináris fa bejárása typedef … adat; typedef stuct fa { adat a; struct fa *b,*j; } faelem; void feldolgoz (adat d) { … }
Bináris fa bejárása - preorder void bejar(faelem *p) void bejar(faelem *p) { { if (p) feldolgoz(p->a); { if (p->b) bejar(p->b); feldolgoz(p->a); if (p->j) bejar(p->j); bejar(p->b); } bejar(p->j); } }
Bináris fa bejárása - inorder void bejar(faelem *p) void bejar(faelem *p) { { if (p) if (p->b) bejar(p->b); { feldolgoz(p->a); bejar(p->b); if (p->j) bejar(p->j); feldolgoz(p->a); } bejar(p->j); } }
Bináris fa bejárása - posztorder void bejar(faelem *p) void bejar(faelem *p) { { if (p) if (p->b) bejar(p->b); { if (p->j) bejar(p->j); bejar(p->b); feldolgoz(p->a); bejar(p->j); } feldolgoz(p->a); } }
Közvetlen rekurzió: egy szegmens hivatkozik önmagára
Közvetett rekurzió: szegmensek egymásra hivatkozásaiban kör van
A rekurzió célja:
A feladat méretének, vagy bonyolultságának csökkentése egy kezelhető szintig.
A rekurzió kritikus pontja:
A leállás feltételének teljesülését minden esetben biztosítani kell.
A rekurzió nagy előnye
A rekurzió nagy előnye az elegancia
Néhány sorban, könnyen érthető kódot írhatunk.
A rekurzió nagy hátránya
A rekurzió nagy hátránya a csábítás
Akkor is használjuk, ha kevéssé hatékony, sőt pazarló.
Mikor ne használjunk rekurziót?
Ha az eredmény zárt alakban is előállítható.
Mikor ne használjunk rekurziót? Ha az eredmény zárt alakban is előállítható. Pl.: számtani sorozat n-edik eleme
Mikor ne használjunk rekurziót? Ha az eredmény zárt alakban is előállítható. Pl.: számtani sorozat n-edik eleme Ha a feladat ciklusszervezéssel is könnyen megoldható.
Mikor ne használjunk rekurziót? Ha az eredmény zárt alakban is előállítható. Pl.: számtani sorozat n-edik eleme Ha a feladat ciklusszervezéssel is könnyen megoldható. Pl.: faktoriális számítás
A rekurzió és a ciklus kapcsolata
A rekurzió és a ciklus kapcsolata Minden ciklus megvalósítható rekurzióval.
A rekurzió és a ciklus kapcsolata Minden ciklus megvalósítható rekurzióval. Minden rekurzió megvalósítható ciklussal és segédváltozókkal.
Minden ciklus megvalósítható rekurzióval. A C B Vége A B C A
Minden rekurzió megvalósítható ciklussal és segédváltozókkal.
A megoldásra rátalálni néha nem könnyű feladat!
Minden rekurzió megvalósítható ciklussal és segédváltozókkal. A megoldásra rátalálni néha nem könnyű feladat! Lássunk példát erre is, arra is!
Egy könnyű probléma:
A Fibonacci számsorozat
Egy könnyű probléma: A Fibonacci számsorozat …
Egy könnyű probléma: A Fibonacci számsorozat … A sorozat harmadik elemétől kezdve minden elem az előző kettő összege.
A Fibonacci számsorozat Rekurzív megvalósítás fib(unsigned n) { if (n<2) return n; return fib(n-2) + fib(n-1); }
A Fibonacci számsorozat Megvalósítás ciklussal fib(unsigned n) { int regi=0,uj=1; for(n--;n;n--) { uj+=regi; regi=uj-regi;} return uj; }
Egy nehéz probléma:
Hanoi tornyai
Egy nehéz probléma: Hanoi tornyai A MESE
Hanoi tornyai Rekurzív megvalósítás void hanoi(unsigned hanyat, char honnan,char hova) { char seged=3*′B′-honnan-hova; if (--hanyat) hanoi(hanyat,honnan,seged); printf(″%c %c\n″,honnan,hova); if (hanyat) hanoi(hanyat,seged,hova); }
4 A B3 A C2 A B1 A C 1 A B 1 C B 1 A C 2 B C1 B A 1 B C 1 A C 1 A B 3 C B2 C A1 C B 1 C A 1 B A 1 C B 2 A B1 A C 1 A B 1 C B
Hanoi tornyai Megvalósítás ciklussal ?
4 A B3 A C2 A B1 A C 1 A B 1 C B 1 A C 2 B C1 B A 1 B C 1 A C 1 A B 3 C B2 C A1 C B 1 C A 1 B A 1 C B 2 A B1 A C 1 A B 1 C B
4 A B3 A C2 A B1 A C 1 A B 1 C B 1 A C 2 B C1 B A 1 B C 1 A C 1 A B 3 C B2 C A1 C B 1 C A 1 B A 1 C B 2 A B1 A C 1 A B 1 C B
A C A B C B A C B A B C A C A B C B C A B A C B A C A B C B
1A C 2A B 3C B 4A C 5B A 6B C 7A C 8A B 9C B 10C A 11B A 12C B 13A C 14A B 15C B
0001A C 0010A B 0011C B 0100A C 0101B A 0110B C 0111A C 1000A B 1001C B 1010C A 1011B A 1100C B 1101A C 1110A B 1111C B
0001A C0 0010A B1 0011C B0 0100A C2 0101B A0 0110B C1 0111A C0 1000A B3 1001C B0 1010C A1 1011B A0 1100C B2 1101A C0 1110A B1 1111C B0
0001A C0 0010A B1 0011C B0 0100A C2 0101B A0 0110B C1 0111A C0 1000A B3 1001C B0 1010C A1 1011B A0 1100C B2 1101A C0 1110A B1 1111C B0
0001A C0 0010A B1 0011C B0 0100A C2 0101B A0 0110B C1 0111A C0 1000A B3 1001C B0 1010C A1 1011B A0 1100C B2 1101A C0 1110A B1 1111C B0
0001A C0 0010A B1 0011C B0 0100A C2 0101B A0 0110B C1 0111A C0 1000A B3 1001C B0 1010C A1 1011B A0 1100C B2 1101A C0 1110A B1 1111C B0
0001A C0 0010A B1 0011C B0 0100A C2 0101B A0 0110B C1 0111A C0 1000A B3 1001C B0 1010C A1 1011B A0 1100C B2 1101A C0 1110A B1 1111C B0
0001A C0 0010A B1 0011C B0 0100A C2 0101B A0 0110B C1 0111A C0 1000A B3 1001C B0 1010C A1 1011B A0 1100C B2 1101A C0 1110A B1 1111C B0
A páratlan lépéseket a legkisebb koronggal tesszük meg, mindig ugyanarra. A párosadik lépések is egyértelműen meghatározottak: - Tudjuk, hogy merre kell lépni. - Amivel léptünk, azzal nem léphetünk. - A legkisebb korongra nem rakodhatunk.
Hanoi tornyai Megvalósítás ciklussal - Ha n korong van, 2 n -1 lépés kell. - Minden páratlanadik lépést a legkisebb koronggal kell megtenni. - Ha n páratlan, A-B-C-A sorrendben lép, ha n páros, A-C-B-A sorrendben lép. - Ha a következő lépést ugyanarra kell megtenni, oda kell lépni, ahonnan léptünk. - Ha a következő lépést ellenkező irányban kell megtenni, onnan kell lépni, ahonnan léptünk.
Hogyan lehet megvalósítani a rekurziót?
Hogyan lehet megvalósítani, hogy a függvénynek egyszerre több példánya éljen?
Ezt már tudjuk!
A nagy ÖTLET: CSAK EGY VEREM KELL! Kalkulátor verem = ahol a kifejezések kiértékelése történik Hívás verem = ahol a visszatérési címet tároljuk Paraméter verem = ahol a paramétereket adjuk át Ha már lúd, legyen kövér! Tároljuk itt a szegmensek belső változóit is!
Mit kell tudnia a függvényről a fordítóprogramnak, hogy meg tudja hívni?
azonosítóját a megvalósító szubrutin címét
paraméterezését az átadandó paraméterek típusát
Ez képezi a függvény deklarációját
Mit nem szükséges tudnia a függvényről a fordítóprogramnak, hogy meg tudja hívni?
megvalósítását az végrehajtandó utasításokat
Ez képezi a függvény definícióját
Hogyan definiálunk függvényt?
Ezt is tudjuk!
Függvény definíciója ( )
A közvetlen rekurzióhoz ez több mint elég!
Közvetlen rekurzió: egy szegmens hivatkozik önmagára
De mi a helyzet a közvetett rekurzióval?
Közvetett rekurzió: szegmensek egymásra hivatkozásaiban kör van
Ez a „ tyúk vagy a tojás” esete!
Megoldás: Válasszuk szét a függvény deklarációját és definícióját!
Függvény definíciója ( )
Függvény deklarációja ( ) ;
Függvény deklarációja ( ) ; A blokk helyén ; áll.
Függvény deklarációja ( ) ; A paraméterek nevét a fordítóprogram nem veszi figyelembe, ezért elhagyható, vagy tetszőleges nevet használhatunk.
A függvény deklarációja minden a híváshoz szükséges információt tartalmaz. A függvény prototípusának is nevezzük. Másként a függvény fejléce.
A függvények tetszőleges sorrendben hívhatják egymást, ha a fejléceket kigyűjtjük, és a kód elejére írjuk. Jó szokás egy fájlba írni, és #include direktívával hivatkozni rá.