Információs Technológia Rekurzió, Fa adatszerkezet Fodor Attila Pannon Egyetem Műszaki Informatika Kar Villamosmérnöki és Információs Rendszerek Tanszék foa@almos.vein.hu 2010. november 18.
Rekurzió Rekurzió Rekurzió "Ismételni emberi dolog. Rekurziót írni isteni..." (L. Peter Deutsch) Fodor A. (Pannon Egyetem) Információs technológia 2010. november 18. 2 / 41
Rekurzió Rekurzió Rekurzió A feladat algoritmusa eleve rekurzív formában adott Például: n! 4! = 1 * 2 * 3 * 4 3! = 1 * 2 * 3 2! = 1 * 2 1! = 1 A valójában nem rekurzív de egyszerűbb a rekurzió használata Például: sorrend fordítás Megoldás menete: Megkeressük azt a legegyszerűbb esetet amiben a megoldás triviális Megkeressük, hogy hogyan vezethető vissza ismételt egyszerűsítésekkel a legegyszerűbb esetre a probléma Fodor A. (Pannon Egyetem) Információs technológia 2010. november 18. 3 / 41
Rekurzió Rekurzió fajtái, osztályozása Rekurzió Meghívás módja alapján közvetlen (a függvény hívja a függvényt) közvetett (a függvény hívja b függvényt és b függvény hívja a függvényt) Meghívás módja és helye alapján (Hányszor, hány helyen hívja meg önmagát) Egyszerű Többszörös Fodor A. (Pannon Egyetem) Információs technológia 2010. november 18. 4 / 41
Faktoriális (n!) Rekurzió Faktoriális Rekurzívan adott az algoritmus. Kiszámítás menete (példa): n! = 1 * 2 * 3 * 4 *... * n. 4! = 1 * 2 * 3 * 4 3! = 1 * 2 * 3 2! = 1 * 2 1! = 1 Kiszámítása: n! = n * (n-1)! ha n>1 1! = 1 long fakt(int n) if (n > 1) return n*fakt(n-1); return 1; Fodor A. (Pannon Egyetem) Információs technológia 2010. november 18. 5 / 41
Faktoriális (n!) Rekurzió Faktoriális long fakt(int n) if (n > 1) return n*fakt(n-1); return 1; Kiszámítás lépései: fakt(4) return 4 * fakt(3) return 3 * fakt(2) return 2 * fakt(1) return 1 return 2 * fakt(1) 2*1 2 return 3 * fakt(2) 3*2 6 return 4 * fakt(3) 4*6 24 Fodor A. (Pannon Egyetem) Információs technológia 2010. november 18. 6 / 41
Szám bináris kiírása Rekurzió Szám bináris kiírása Kiszámítás módja: Elosztjuk 2-vel a számot, akkor a maradék az utolsó számjegy Probléma: Ezt a bitet kellene utoljára kiírni!!! Probléma megoldása: A biteket egy tömbben kell eltárolni... Megoldás: A rekurzív hívás után írunk ki (a rekurzív hívások során tárolódnak a már kiszámított számjegyek) void binkiir(int n) int e, m; m = n % 2; if (e = n / 2) binkiir(e); printf("%d", m); Fodor A. (Pannon Egyetem) Információs technológia 2010. november 18. 7 / 41
Szám bináris kiírása Rekurzió Szám bináris kiírása void binkiir(int n) int e, m; m = n % 2; if (e = n / 2) binkiir(e); printf("%d", m); Kiszámítás lépései: (5 = 2 2 + 2 0 Binárisan: 101) binkiir(5) m:1 e:2 binkiir(2) m:0 e:1 binkiir(1) m:1 e:0 printf("%d", 1); 1 printf("%d", 0); 0 printf("%d", 1); 1 Fodor A. (Pannon Egyetem) Információs technológia 2010. november 18. 8 / 41
Hanoi tornyai legendája Rekurzió Hanoi tornyai A legenda: Sok ezer évvel ezelőtt Indiában, Fo Hi uralkodása alatt, a benaresi Siva-templom közepén volt egy márványtábla, amelyből három gyémánttű állt ki. Az első tűn 64 vékony aranykorong helyezkedett el, alul a legnagyobb átmérőjű, majd rajta egyre kisebbek. Egyszer Siva isten megparancsolta a templom papjainak, hogy rakják át a korongokat az első tűről a másodikra. Két fontos szabályt azonban be kellett tartaniuk: A korongok igen sérülékenyek, ezért egyszerre csak egyet lehet mozgatni, nem kerülhet a szent korongokból magasabb értékű alacsonyabb értékű fölé A szerzetesek természetesen használhatták a harmadik tűt is a rakodás közben. Amikor az utolsó korong a helyére kerül, a templom porrá omlik össze, és a világ véget ér. Fodor A. (Pannon Egyetem) Információs technológia 2010. november 18. 9 / 41
Hanoi tornyai Rekurzió Hanoi tornyai Megoldás lépései 3 korong esetén Hét áthelyezést adja a leggyorsabb megoldást 3 korong esetén Demo: http://www.irt.org/games/js/hanoi/index.htm?d=5 Fodor A. (Pannon Egyetem) Információs technológia 2010. november 18. 10 / 41
Hanoi tornyai Rekurzió Hanoi tornyai Felírható a következő képlet: L=L +1+L, ahol L a lépések száma K-1 korong esetén. Az összeadás három tagja a megoldás három lépését jelöli: (1) K-1 korong az első tűről a harmadikra (L lépés) (2) Legnagyobb korong a helyére rekása (1 lépés) (3) a K-1 korong vissza a másodikra (L lépés) Lépések száma: L = 2 K 1 (K: korongok száma) A szerzeteseknek tehát 2 64 1 áthelyezést kell végrehajtaniuk. Ha feltesszük, hogy egy korongot átlagosan egy másodperc alatt tesznek át akkor több mint 590 000 000 000 évig tartana! Fodor A. (Pannon Egyetem) Információs technológia 2010. november 18. 11 / 41
Rekurzió Hanoi tornyai Hanoi tornyai lépéseit kiszámoló függvény Függvény kódja: void Hanoi_tornyai(int korong, char honnan, char hova, char seged) if (korong > 0) Hanoi_tornyai(korong-1, honnan, seged, hova); printf("%d. korong %c --> %c\n", korong, honnan, hova); Hanoi_tornyai(korong-1, seged, hova, honnan); Meghívása:... Hanoi_tornyai(3, A, B, T ); Hanoi_tornyai(4, A, B, T );... Fodor A. (Pannon Egyetem) Információs technológia 2010. november 18. 12 / 41
Rekurzió Hanoi tornyai Hanoi tornyai lépései 3 korong esetén 1. korong A --> B 2. korong A --> T 1. korong B --> T 3. korong A --> B 1. korong T --> A 2. korong T --> B 1. korong A --> B Fodor A. (Pannon Egyetem) Információs technológia 2010. november 18. 13 / 41
Rekurzió Hanoi tornyai Hanoi tornyai lépései 6 korong esetén 1. korong A --> T 1. korong T --> B 2. korong A --> B 2. korong T --> A 1. korong T --> B 1. korong B --> A 3. korong A --> T 3. korong T --> B 1. korong B --> A 1. korong A --> T 2. korong B --> T 2. korong A --> B 1. korong A --> T 1. korong T --> B 4. korong A --> B 4. korong T --> A 1. korong T --> B 1. korong B --> A 2. korong T --> A 2. korong B --> T 1. korong B --> A 1. korong A --> T 3. korong T --> B 3. korong B --> A 1. korong A --> T 1. korong T --> B 2. korong A --> B 2. korong T --> A 1. korong T --> B 1. korong B --> A 5. korong A --> T 5. korong T --> B 1. korong B --> A 1. korong A --> T 2. korong B --> T 2. korong A --> B 1. korong A --> T 1. korong T --> B 3. korong B --> A 3. korong A --> T 1. korong T --> B 1. korong B --> A 2. korong T --> A 2. korong B --> T 1. korong B --> A 1. korong A --> T 4. korong B --> T 4. korong A --> B 1. korong A --> T 1. korong T --> B 2. korong A --> B 2. korong T --> A 1. korong T --> B 1. korong B --> A 3. korong A --> T 3. korong T --> B 1. korong B --> A 1. korong A --> T 2. korong B --> T 2. korong A --> B 1. korong A --> T 1. korong T --> B 6. korong A --> B Fodor A. (Pannon Egyetem) Információs technológia 2010. november 18. 14 / 41
Rekurzió Rekurzió A rekurzió átalakítása A rekurzív algoritmusok sokszor egyszerűbbnek tűnnek, de nem biztos, hogy a rekurzív megoldás a legoptimálisabb Rekurzív algoritmus bizonyos esetekben egyszerűbb felépítéssű (könyebben megérthető) A rekurzió ciklussá alakítható A ciklus rekurzív algorítmussá is alakítható Rekurzív adatszerkezetek Rekurzív görbék (fraktálok) (Koch görbe, Mandelbrot halmaz) Fodor A. (Pannon Egyetem) Információs technológia 2010. november 18. 15 / 41
Rekurzió-ciklus átalakítás Rekurzió A rekurzió átalakítása Minden rekurzió megvalósítható ciklussal és segédváltozókkal A megoldás bizonyos esetekben nem egyszerű! Fodor A. (Pannon Egyetem) Információs technológia 2010. november 18. 16 / 41
Fibonacci sorozat Rekurzió A rekurzió átalakítása, Fibonacci Megadása: 0, ha n=0 1, ha n=1 fib(n-1)+fib(n-2), ha n>1 A sorozat rekurzív alakban adott Sorozat elemei: 0-0 1-1 2 - fib(0)+fib(1) = 0+1 = 1 3 - fib(1)+fib(2) = fib(1)+[fib(0)+fib(1)] = 1+[0+1] = 2 4 - fib(2)+fib(3) = [fib(0)+fib(1)]+[fib(1)+fib(2)] = [fib(0)+fib(1)]+[fib(1)+[fib(0)+fib(1)]] = [0+1]+[1+[0+1]] = 3 Fodor A. (Pannon Egyetem) Információs technológia 2010. november 18. 17 / 41
Rekurzió A rekurzió átalakítása, Fibonacci Fibonacci sorozatot kiszámoló rekurzív függvény Függvény kódja: long fib(int n) if (n < 0) return -1; if (n <= 1) return n; else return fib(n-1) + fib(n-2); Meghívása:... for(i=0; i<20; i++) printf("fib( %d ) = %d \n", i, fib(i));... Fodor A. (Pannon Egyetem) Információs technológia 2010. november 18. 18 / 41
Rekurzió A rekurzió átalakítása, Fibonacci Fibonacci sorozatot kiszámoló NEM rekurzív függvény (1.) Hátulról számolva (n értékét folyamatosan csökkenti) Függvény kódja: long fib_cikl_hatul(long n) long x,y,z; if (n < 0) return -1; if (n == 0) return 0; x=0; y=1; z=1; while (n > 1) z=x+y; x=y; y=z; n=n-1; return z; Meghívása: for(i=0; i<20; i++) printf("fib_cikl_hatul( %d ) = %d \n", i, fib_cikl_hatul(i));... Fodor A. (Pannon Egyetem) Információs technológia 2010. november 18. 19 / 41
Rekurzió A rekurzió átalakítása, Fibonacci Fibonacci sorozatot kiszámoló NEM rekurzív függvény (1.)(tömörebben) Hátulról számolva (n értékét folyamatosan csökkenti) Függvény kódja: long fib_cikl_hatul_for(long n) long x,y,z; if (n < 0) return -1; if (n == 0) return 0; for(x=0, y=1, z=1; n > 1; n=n-1) z=x+y; x=y; y=z; return z; Meghívása:... for(i=0; i<20; i++) printf("fib_cikl_hatul_for( %d ) = %d \n", i, fib_cikl_hatul_for(i));... Fodor A. (Pannon Egyetem) Információs technológia 2010. november 18. 20 / 41
Rekurzió A rekurzió átalakítása, Fibonacci Fibonacci sorozatot kiszámoló NEM rekurzív függvény (2.) Elölről számolva (n értékét folyamatosan növeli) Függvény kódja: long fib_cikl_elol(long n) long x,y,z,i; if (n < 0) return -1; if (n == 0) return 0; x=0; y=1; z=n; for(i=1; i < n; i++) z=x+y; x=y; y=z; return z; Meghívása:... for(i=0; i<20; i++) printf("fib_cikl_elol( %d ) = %d \n", i, fib_cikl_elol(i));... Fodor A. (Pannon Egyetem) Információs technológia 2010. november 18. 21 / 41
Fibonacci sorozat tagjai Rekurzió A rekurzió átalakítása, Fibonacci fib( 0 ) = 0 fib_cikl_hatul( 0 ) = 0 fib( 1 ) = 1 fib_cikl_hatul( 1 ) = 1 fib( 2 ) = 1 fib_cikl_hatul( 2 ) = 1 fib( 3 ) = 2 fib_cikl_hatul( 3 ) = 2 fib( 4 ) = 3 fib_cikl_hatul( 4 ) = 3 fib( 5 ) = 5 fib_cikl_hatul( 5 ) = 5 fib( 6 ) = 8 fib_cikl_hatul( 6 ) = 8 fib( 7 ) = 13 fib_cikl_hatul( 7 ) = 13 fib( 8 ) = 21 fib_cikl_hatul( 8 ) = 21 fib( 9 ) = 34 fib_cikl_hatul( 9 ) = 34 fib( 10 ) = 55 fib( 11 ) = 89 -------------------- fib( 12 ) = 144 fib_cikl_elol( 0 ) = 0 fib( 13 ) = 233 fib_cikl_elol( 1 ) = 1 fib( 14 ) = 377 fib_cikl_elol( 2 ) = 1 fib( 15 ) = 610 fib_cikl_elol( 3 ) = 2 fib( 16 ) = 987 fib_cikl_elol( 4 ) = 3 fib( 17 ) = 1597 fib_cikl_elol( 5 ) = 5 fib( 18 ) = 2584 fib_cikl_elol( 6 ) = 8 fib( 19 ) = 4181 fib_cikl_elol( 7 ) = 13 fib( 20 ) = 6765 fib_cikl_elol( 8 ) = 21 fib( 21 ) = 10946 fib_cikl_elol( 9 ) = 34 fib( 22 ) = 17711 fib( 23 ) = 28657 fib( 24 ) = 46368 fib( 25 ) = 75025 fib( 26 ) = 121393 fib( 27 ) = 196418 fib( 28 ) = 317811 fib( 29 ) = 514229 fib( 30 ) = 832040 fib( 31 ) = 1346269 fib( Fodor 32 ) A. = (Pannon 2178309 Egyetem) Információs technológia 2010. november 18. 22 / 41
Fa adatszerkezet Fa adatszerkezet Fa adatszerkezet A keresés gyorsítása érdekében a láncolt adatszerkezetet fába rendeztük Fa: az adatszerkezet az egyes elemeknél elágazhat Kétfelé ágazó fákat bináris fának nevezzük A bináris fa és annak minden részfája vagy üres, vagy a gyökérelemből és annak bal és jobboldali részfájából áll Levél: Egy elemnek nincs utódja Kiegyensúlyozott fa: az összes levél azonos szinten van Rekurzív adatszerkezet rekurzív algoritmusokkal egyszerűbb kezelni A keresés az elemek 2-es alapú logaritmusával arányos műveletet igényel Fodor A. (Pannon Egyetem) Információs technológia 2010. november 18. 23 / 41
Fa adatszerkezet Fa adatszerkezet Fa adatszerkezet Adatszerkezetnek tartalmaznia kell: adat jobb oldali fa címe bal oldali fa címe struct faelem int adat; struct faelem *bal, *jobb; ; Fodor A. (Pannon Egyetem) Információs technológia 2010. november 18. 24 / 41
Fa felépítése Fa adatszerkezet Fa felépítése 2. adat elhelyezése 3. adat elhelyezése Fodor A. (Pannon Egyetem) Információs technológia 2010. november 18. 25 / 41
Fa felépítése Fa adatszerkezet Fa felépítése 4. adat elhelyezése 5. adat elhelyezése Fodor A. (Pannon Egyetem) Információs technológia 2010. november 18. 26 / 41
Fa felépítése Fa adatszerkezet Fa felépítése 6. adat elhelyezése Fodor A. (Pannon Egyetem) Információs technológia 2010. november 18. 27 / 41
Fa felépítése Fa adatszerkezet Fa felépítése Fa adatszerkezetbe való rendezett beszúrást végző függvény kódja: void beszur(faelem **ppfa, int ertek) if(!*ppfa ) *ppfa = (faelem*) malloc(sizeof(faelem)); (*ppfa)->adat = ertek; (*ppfa)->bal = (*ppfa)->jobb = NULL; else if ( (*ppfa)->adat!= ertek ) if ((*ppfa)->adat > ertek) beszur( &(*ppfa)->bal, ertek); else beszur( &(*ppfa)->jobb, ertek); Fodor A. (Pannon Egyetem) Információs technológia 2010. november 18. 28 / 41
Fa felépítése Fa adatszerkezet Fa felépítése Fa adatszerkezetbe való beszúrást végző függvény meghívása: void main(void) faelem *fa; fa = NULL; beszur(&fa, 4); beszur(&fa, 1); beszur(&fa, 3); beszur(&fa, 6); beszur(&fa, 2); beszur(&fa, 5); Fodor A. (Pannon Egyetem) Információs technológia 2010. november 18. 29 / 41
Fa adatszerkezet Fa felépítése A függvényhívások után felépített fa Beszúrt adatok: 4, 1, 3, 6, 2, 5 Fodor A. (Pannon Egyetem) Információs technológia 2010. november 18. 30 / 41
Fa bejárása Fa adatszerkezet Fa felépítése Több startégia van Stratégiak közötti kölönbség, hogy mikor dolgozzuk fel az adatot. Preorder Először feldogozom az adatot, bejárom a bal faágat, bejárom a jobb oldali faágat Inorder Bejárom a bal faágat, feldolgozom az adatot, bejárom a jobb oldali faágat Postorder Bejárom a bal faágat, bejárom a jobb oldali faágat, feldolgozom az adatot Fodor A. (Pannon Egyetem) Információs technológia 2010. november 18. 31 / 41
Preorder bejárás Fa adatszerkezet Fa bejárása Először feldogozom az adatot, bejárom a bal faágat, bejárom a jobb oldali faágat void preorder(faelem *fa) if (fa) printf("%d\n", fa->adat); preorder(fa->bal); preorder(fa->jobb); Fodor A. (Pannon Egyetem) Információs technológia 2010. november 18. 32 / 41
Fa adatszerkezet Preorder bejárás eredménye Fa bejárása Először feldogozom az adatot, bejárom a bal faágat, bejárom a jobb oldali faágat Eredmény: 4 1 3 2 6 5 void preorder(faelem *fa) if (fa) printf("%d\n", fa->adat); preorder(fa->bal); preorder(fa->jobb); Fodor A. (Pannon Egyetem) Információs technológia 2010. november 18. 33 / 41
Inorder bejárás Fa adatszerkezet Fa bejárása Bejárom a bal faágat, feldolgozom az adatot, bejárom a jobb oldali faágat void inorder(faelem *fa) if (fa) inorder(fa->bal); printf("%d\n", fa->adat); inorder(fa->jobb); Fodor A. (Pannon Egyetem) Információs technológia 2010. november 18. 34 / 41
Fa adatszerkezet Inorder bejárás eredménye Fa bejárása Bejárom a bal faágat, feldolgozom az adatot, bejárom a jobb oldali faágat Eredmény: 1 2 3 4 5 6 Rendezetten adja vissza az adatokat void inorder(faelem *fa) if (fa) inorder(fa->bal); printf("%d\n", fa->adat); inorder(fa->jobb); Fodor A. (Pannon Egyetem) Információs technológia 2010. november 18. 35 / 41
Postorder bejárás Fa adatszerkezet Fa bejárása Bejárom a bal faágat, bejárom a jobb oldali faágat, feldolgozom az adatot void postorder(faelem *fa) if (fa) postorder(fa->bal); postorder(fa->jobb); printf("%d\n", fa->adat); Fodor A. (Pannon Egyetem) Információs technológia 2010. november 18. 36 / 41
Fa adatszerkezet Postorder bejárás eredménye Fa bejárása Bejárom a bal faágat, bejárom a jobb oldali faágat, feldolgozom az adatot Eredmény: 2 3 1 5 6 4 void postorder(faelem *fa) if (fa) postorder(fa->bal); postorder(fa->jobb); printf("%d\n", fa->adat); Fodor A. (Pannon Egyetem) Információs technológia 2010. november 18. 37 / 41
Fa adatszerkezet Műveletek a fa adatszerkezettel A fa adatszerkezet egyéb tulajdonságai Beszúrás Törlése Bejárás Keresés Fa diagnosztizálása Mélység Kiegyensúlyozottság Van-e jobb/bal ága Fodor A. (Pannon Egyetem) Információs technológia 2010. november 18. 38 / 41
Bináris fa Fa adatszerkezet A fa adatszerkezet egyéb tulajdonságai Adattagjai: adat 2 ág (jobb-bal) Megvalósítás: struct binfaelem int adat; struct binfaelem *bal, *jobb; ; Fodor A. (Pannon Egyetem) Információs technológia 2010. november 18. 39 / 41
Nem bináris fa Fa adatszerkezet A fa adatszerkezet egyéb tulajdonságai Adattagjai: adat 2...n ág Megvalósítás: #define N 6 struct nembinfaelem int adat; struct nembinfaelem *faagak[ N ]; ; Fodor A. (Pannon Egyetem) Információs technológia 2010. november 18. 40 / 41
Elfajult fa Fa adatszerkezet A fa adatszerkezet egyéb tulajdonságai A fa valamely ága sokkal nagyobb mélységű, mint a többi Az építés során keletkezhetnek a gondok Például: (1 6 20 24 30) Fodor A. (Pannon Egyetem) Információs technológia 2010. november 18. 41 / 41