Az előadás letöltése folymat van. Kérjük, várjon

Az előadás letöltése folymat van. Kérjük, várjon

AAO Csink László 2010. ősz. 2 Adminisztráció Előadók: Csink László A tárgy

Hasonló előadás


Az előadások a következő témára: "AAO Csink László 2010. ősz. 2 Adminisztráció Előadók: Csink László A tárgy"— Előadás másolata:

1 AAO Csink László ősz

2 2 Adminisztráció Előadók: Csink László A tárgy Login: aao Jelszó: algorithm Az objektumorientált programozás 5 előadásból áll, melyet Miklós Árpád

3 3 A tárgy célja Ismerkedés az algoritmus fogalmával, egyszerű „klasszikus” algoritmusokkal Ismerkedés az algoritmusok implementálásához (megvalósításához) szükséges legalapvetőbb adatstruktúrákkal Bevezetés az objektumorientált programozási paradigma alapjaiba Algoritmuskészítési készség kialakítása AAO= Algoritmusok, Adatstruktúrák, Objektumok Mindez az OOP tárggyal való szoros együttműködésben valósul meg

4 4 Irodalom Könyvek, amibikből lehet meríteni: Cormen, Leiserson, Rivest: Algoritmusok (újabb kiadás is, valamint Informatikai algoritmusok) Trahtenbrot: Algoritmusok és absztrakt automaták Kotsis et al: Többnyelvű programozástechnika Lovász L., Gács P.: Algoritmusok Referencia linkek: Matematikai háttér Lexikon: Ajánlott feladatgyűjtemény (PPKE) (A Kotsis et al könyv mellett):

5 5 Hogyan készüljenek? Sajnos, igen nagy szokott lenni a bukási arány! A diák csak vázlatot jelentenek, a vetített anyag nem tankönyv! Sokakat megtéveszt, hogy az előadásokon nincs névsor ellenőrzés. Ennek ellenére folyamatosan kell tanulni már a félév elejétől, sok gyakorlatra van szükség, a tudásnak „érlelődnie” is kell Az előadásokon tárgyalt algoritmusokat célszerű C#-ban otthon megírni A Kotsis könyvben található algoritmusokat elolvasni, megérteni, megpróbálni segítség nélkül megírni A feladatgyűjtemény feladataira a programokat megírni Az OOP gyakorlatokon tanultakat hasznosítani

6 6 Algoritmus fogalma Az algoritmus egy eljárás (jóldefiniált utasítások véges halmaza), amelyet valamely feladat megoldására készítünk. A feladat egy adott kezdeti állapotból egy meghatározott végállapotba jut (szakszóval terminál). Az algoritmus kiszámítási bonyolultsága és hatékony implementációja az alkalmazott adatstruktúrától függ.

7 7 Informális és formális definíció Az algoritmus tipikusan kisebb-nagyobb alkotórészekből épül fel. Az egyszerű algoritmus egy ételrecepthez hasonlítható. A formális definíció Alan Turing (Turing gép, 1936) és Alonzo Church (lambda kalkulus) matematikusokhoz köthető. (lásd Haladó algoritmusok tárgy a későbbiekben)

8 8 Informális megközelítés: ételrecept Informálisan – hétköznapi szavakkal – egy egyszerű algoritmus egy receptnek tekinthető. A recept tartalmazza az adott étel nevét; elkészítésének idejét; a szükséges alkotórészek nevét és mennyiségét; az elkészítéshez szükséges eszközöket illetve környezetet (például mikrosütő); az elkészítéshez szükséges eljárásokat meghatározott sorrendben; az elkészült adagok számát; a kalóriatartalmat egy adagra vetítve; az étel eltarthatóságának idejét.

9 9 A másodfokú egyenlet „receptje” 1. Készítsünk algoritmust az ax 2 +bx+c=0 egyenlet megoldására. 1. lépés: az input adatok meghatározása Jelen esetben: a, b, c valós számok 2. lépés: output adat(ok) meghatározása: egy x valós szám (egy megoldás, illetve ha a két gyök egybeesik), x1 és x2 valós számok (két különböző megoldás), illetve a „nincs valós megoldás” szöveg.

10 10 A megoldás menete Úgy fogjuk a megoldás menetét prezentálni, ahogy tervezés közben „eszünkbe jut” Óhatatlan, hogy menet közben lesznek még hibák, mert nem pattan ki a tökéletes megoldás az agyunkból egyszerre Minden lépés után elemezzük, hogy jól működik-e a programunk, és ha nem tökéletes, akkor javítunk rajta

11 11 A feladat „receptje”: a hozzávalók A „recept” adatai: Név:MASODFOKU elkészítésének ideje (és szerző): CsL a feltétlenül szükséges adatok neve és típusa: a,b,c,3 valós szám (INPUT) x valós szám, VAGY x1 és x2 valós számok, VAGY ” nincs valós megoldás” szöveg (OUTPUT) az elkészítéshez szükséges eszközök illetve környezet: Turbo C (természetesen más is lehetne, például C#) Windows XP operációs rendszer alatt (ez is lehetne más) az elkészítéshez szükséges eljárások: gyökvonás, abszolút érték (ezek elkészítettnek tekintett programok) Megjegyzés: Az OOP gyakorlatokon Visual Studio C# környezetben fogunk dolgozni. (A Turbo C++ előnye, hogy ingyenes)

12 12 A feladat pontosítása Hasznos dolog egy konkrét példát megnézni: 4x 2 -12x+8=0 A megoldás x1=2; x2=1 Erre a feladatra ez a két értékadás tulajdonképpen egy program. Ez a program azonban nem ad megoldást a 3x 2 +4x-2.11=0 feladatra. Azt szeretnénk, hogy ugyanaz a a program erre a feladatra is megoldást adjon. Mi a helyzet az 12x+8=0 egyenlettel? Ez már elsőfokú. El kell dönteni, hogy eredetileg a másodfokú, vagy a legfeljebb másodfokú egyenlet megoldását tűztük-e ki célul? Megállapítjuk, ezen példa kapcsán, hogy a feladat pontos mibenléte gyakran a megoldás során tisztázódik. A feladat specifikációja tehát finomodhat a megoldás közben.

13 13 A specifikáció Oldjuk meg az ax 2 +bx+c=0 egyenletet minden a, b, c valós szám esetén. Nevezzük a {ax 2 +bx+c=0 | a, b, c valós számok} problémaosztálynak, melynek a megoldását keressük. Lehetett volna a problémaosztályt {ax 2 +bx+c=0 | a, b, c valós számok és a≠0} halmaznak választani, ekkor a megoldási algoritmus kicsit egyszerűbb, de kevésbé általános.

14 14 Létezik-e megoldás? Tudjuk (például mert érettségiztünk ), hogy van megoldóképlet: Ha komplex megoldást nem engedünk meg – azaz a specifikációt úgy finomítjuk tovább, hogy valós x megoldásokat keresünk – akkor nincs megoldás.

15 15 Tanulságok Hajlamosak vagyunk azt gondolni, hogy mindig létezik valamilyen megoldás, talán azért, mert hozzászoktunk a megoldható feladatokhoz a középiskolában. Vannak azonban algoritmussal nem megoldható problémák. Nem oldható meg például a szögharmadolási probléma: tetszőleges szög harmadának megszerkesztése. Egy probléma algoritmussal való megoldhatóságának kérdése igen mély dolog, lásd incompleteness theorem a wikipedia-ban. (E tételt felállító Kurt Gödelről az az anekdota szól, hogy Einstein csak azért járt be Princetonban az egyetemre, hogy Gödellel sétálhasson haza és beszélgethessenek )

16 16 Első nekifutás VÁLTOZÓK gy, a,b,c VALÓS SZÁM BEOLVAS(a,b,c) gy ← (b*b-4*a*c) HA gy ≥0 AKKOR gy ← GYOKVONAS(b*b-4*a*c) EGYÉBKÉNTKIIR(nincs valós megoldás) Itt folytatódna a megoldás, de csak akkor, ha a gyökvonás lehetséges volt. Mivel a gy<0 esetben a KIIR végrehajtása után nem akarjuk, hogy a program folytatódjon, ezért trükkösen megcseréljük a feltételt a HA mögött. gy mint egész nem jó, pl. b=1.1., a=1, c=0.2 értékadás

17 17 Folytatjuk 1. VÁLTOZÓK gy,a,b,c, x1 VALÓS SZÁM 2. BEOLVAS(a,b,c) 3. gy ← (b*b-4*a*c) 4. HA gy <0 AKKOR KIIR(nincs valós megoldás) 5. EGYÉBKÉNT{ 6. gy ← GYOKVONAS(b*b-4*a*c) 7. HA gy=0 AKKORx1= -b/(2*a) 8. EGYÉBKÉNT folytatni kell a dolgot 9. } Piros színnel jelezzük a változásokat az előzőekhez képest. 6., 7., 8. sorok egybetartozásának jelölése (a zárójelek párban vannak!)

18 18 Tovább folytatjuk (EZ MÉG NEM VÉGLEGES! 1. VÁLTOZÓK gy,a,b,c, x1,x2 VALÓS SZÁM ag EGÉSZ SZÁM 2. BEOLVAS(a,b,c) 3. gy ← (b*b-4*a*c) 4. HA gy <0 AKKOR ag=1 5. EGYÉBKÉNT{ ag=2 6. gy ← GYOKVONAS(b*b-4*a*c) 7. HA gy=0 AKKORx1= -b/(2*a) 8. EGYÉBKÉNT{ag=3 9. x1=-b+gy/(2a) 10. x2=-b-gy/(2a) 11. } 12. } 13. ESETEK ag 14. 1:KIIR(nincs valós megoldás) 15. 2:KIIR(egy megoldás van:, x1) 16. 3:KIIR(két megoldás van:, x1, x2) 17. ESETEK VEGE

19 19 Javítások, megjegyzések Kellenek további zárójelek: 9. x1=(-b+gy)/(2a) 10. x2=(-b-gy)/(2a) Feltételezzük, hogy a KIIR argumentumában ha magyar mondat van, akkor a szöveg íródik ki, ha változónév van, akkor a változó értéke. Azt is feltesszük, hogy a BEOLVAS a megfelelő változókba a billentyűzetről megadott adatokat elhelyezi. A BEOLVAS és a KIIR megvalósításával nem „bíbelődünk”. Mi történik, ha a 7., vagy a 9. vagy a 10. sorban a=0 eset áll elő? Ekkor nullával való osztásra utaló hibaüzenet generálódik. Az ilyen esetek kezelésére a legtöbb nyelvben vannak eszközök (ezzel most nem foglalkozunk), hanem megpróbáljuk „előre látni”, hogy ilyen eset előfordulhat.

20 20 a=0 eset HA a=0 AKKOR Megoldjuk a bx+c=0 egyenletet EGYÉBKÉNT Amit eddig csináltunk (a≠0, b,c tetszőleges) Kész programblokk Megírandó programblokk A lépésenkénti finomítás módszerét alkalmazuk, pszeudokód segítségével.

21 21 A nyilak jelzik a megfelelő színű zárójelpárokat, azaz hogy melyik AKKOR és EGYÉBKÉNT melyik HA-hoz tartozik. Az alapértelmezés pont olyan, hogy ezek a zárójelek elhagyhatók. VÁLTOZÓK gy,a,b,c, x1,x2 VALÓS SZÁM BEOLVAS(a,b,c) HA a=0 AKKOR { HA b=0 AKKOR { HA c=0 AKKOR KIIR(minden valós szám megoldás) EGYÉBKÉNT KIIR(nincs megoldás)} } EGYÉBKÉNT x1=-c/b } EGYÉBKÉNT Amit eddig csináltunk (a≠0, b,c tetszőleges)

22 22 A program (algoritmus) összerakása PROGRAM MASODFOKU VÁLTOZÓK gy,a,b,c, x1,x2 VALÓS SZÁM ag EGÉSZ SZÁM BEOLVAS(a,b,c) HA a=0 AKKOR HA b=0 AKKOR HA c=0 AKKOR ag=4 EGYÉBKÉNT ag=5 EGYÉBKÉNT{ ag=6; x1=-c/b} EGYÉBKÉNT{ gy ← (b*b-4*a*c) HA gy <0 AKKOR ag=1 EGYÉBKÉNT{ag=2 gy ← GYOKVONAS(b*b-4*a*c) HA gy=0 AKKOR x1= -b/(2*a) EGYÉBKÉNT{ ag=3 x1=(-b+gy)/(2a) x2=(-b-gy)/(2a) } ESETEK ag 1 : KIIR(nincs valós megoldás) 2 : KIIR(egy megoldás van:, x1) 3 : KIIR(két megoldás van:, x1, x2)) 4 : KIIR(minden valós szám megoldás) 5 : KIIR(nincs megoldás) 6 : KIIR(elfajulo egyenlet, egy megoldás:, x1) ESETEK VEGE PROGRAM VÉGE

23 23 Közelítő gyökvonás (Newton módszer) Legyen A>0, emelyből gyököt szeretnénk vonni, és gy 1 tetszőleges, például 1. Ekkor elég nagy n-re gy n közel van egy számhoz, amely A négyzetgyöke. Más szóval a gy n sorozat konvergens és határértéke A négyzetgyöke. Ilyenkor elég nagy n-re gy n és gy n+1 egy tetszőlegesen előre megadott számnál is közelebb kerülnek egymáshoz. A következőkben gy n helyett gy-t, gy n+1 helyett ujgy-t írunk és iteratíven számolunk.

24 24 A gyökvonás programja 1. // inp adott szám, melyből gyököt akarunk vonni 2. VÁLTOZÓK inp, ujgy, gy, d, eps DUPLAPONTOS 3. BEOLVAS(inp) 4. gy = d= eps= ISMETELNI HA( d > eps){ 8. ujgy = (1.0/2)*(gy + inp/gy) 9. d = | ujgy – gy | 10. gy = ujgy 11. } 12. KIIR(gy) Abszolút érték A piros rész ismétlődik mindaddig, amíg a sárga rész teljesül. Figyeljük meg, hogy d menetközben változik!

25 25 6 négyzetgyökének közelítő számítása gyujgyd (=|ujgy-gy|) , , e-06

26 26 Vigyázat! A fentiek csak azért működtek jól, mert tudtuk (matematikából), hogy gy n konvergens. Ha most akkor ugyan s n+1 -s n bármilyen kicsi lehet, s n mégsem konvergens! Tanulság: egy program használhatóságához szükséges, hogy az elméleti megalapozás korrekt legyen! Anélkül, hogy a gy n konvergenciáját bebizonyítjuk, vagy legalább hivatkozunk a megfelelő szakirodalomra, a fenti program nem ad megoldást, mert nem tudhatjuk, hogy véget ér-e a program, és ha igen, korrekt eredményt ad-e?

27 27 Példa: Hogyan keresünk algoritmust egy feladatra igazi alkalmazásoknál? A napi gyakorlatban –ahelyett, hogy magunk készítünk algoritmust – sokszor inkább körülnézünk. Pontosabban: mindig körülnézünk, hogy van-e megoldás a feladatunkra, vagy nekünk kell nekifognunk megcsinálni (kivétel persze a zh vagy vizsga ) Nézzünk egy példát: tegyük fel, hogy egy szám prím vagy összetett voltát akarjuk megállapítani. Keresünk egy algoritmus gyűjteményt, például a MathWorld weblapját (ld. referencia linkek): Mivel jól tudunk angolul, könnyedén elnavigálunk az adott területre: Number Theory, Prime Numbers, Primality Testing.

28 28 „An algorithm for making tables of primes. Sequentially write down the integers from 2 to the highest number you wish to include in the table. Cross out all numbers which are divisible by 2 (every second number). Find the smallest remaining number. It is 3. So cross out all numbers which are divisible by 3 (every third number). Find the smallest remaining number. It is 5. So cross out all numbers which are divisible by 5 (every fifth number). Continue until you have crossed out all numbers divisible by. The numbers remaining are prime. „ Forrás: MathWorldalgorithmprimesintegersprime ERATHOSTENESI SZITA

29 29 Akkor miért nem csináljuk mindig így? A feladat pontos megértéséhez gyakran el kell kezdeni megoldani a feladatot. Nem mindig van tehát elegendő információnk a feladatmegoldás kezdetén ahhoz, hogy algoritmus adatbázisokat vagy szakirodalmat használjunk. Ahhoz, hogy a megfelelő megoldási változatot (paraméterek, sebesség, környezet stb.) kiválasszuk, algoritmuselmélet ismeretekre – és implementációs gyakorlatra – van szükségünk, melyet például ez a tárgy is adhat. Lehet, hogy az adott feladatra nem találunk az igényeinket kielégítő megoldást. Lehet, hogy a talált megoldásnál jobb jut eszünkbe (hiszen az irodalomban és a weben publikált megoldásokat is kitalálta valaki valamikor).

30 30 Egyszerű programozási tételek Sorozatszámítás Eldöntés Kiválasztás Keresés Megszámolás Maximumkeresés

31 31 Sorozatszámítás A múlt évben minden hónapban eltettem a gázszámlát. Szeretném kiszámolni, hogy mennyi pénzbe került az éves gázfogyasztás. A megoldás lépései: Lenullázok egy gyűjtőváltozót. A következő két lépést 12-szer ismételem: Megfogom a soron következő számlát. Hozzáadom az előző összeghez. Megvan az összeg.

32 32 Pszeudokód VÁLTOZÓK i, sum EGÉSZ, szamla[i] EGÉSZ) i ← 0; sum ← 0; ISMÉTELNI HA( i kisebb mint 12){ sum ← sum + szamla[i]; i ← i+1; } KIIR(sum) Január a 0.-dik, február az 1., …, december a 11. hónap a jelölés szerint

33 33 Eldöntés Egy tanuló érdemjegyei alapján szeretném eldönteni, hogy kitűnő-e, vagy sem. Kétféle ötlet is lehet: 1. Ha a jegyei közt van olyan, ami nem ötös, akkor nem kitűnő. 2. Ha minden jegye ötös, akkor kitűnő. Vizsgáljuk meg először az első ötletet közelebbről! Nézzük végig a jegyeket, először az elsőt, majd sorra a többit, és ellenőrizzűk, hogy ötös-e. Ha találtunk olyat, ami nem ötös, akkor nem kell megnézni a további jegyeket, mert van nem ötös osztályzat, azaz nem kitűnő.

34 34 Az 1. számú pszeudokód VÁLTOZÓK tantárgy_szám, i, jegyek[i] EGÉSZ, van_nemotos LOGIKAI i ← 1 ISMÉTELD HA(i ≤ tantárgy_szám) és (jegyek[i] egyenlő 5-tel){ i ← i+1 } van_nemotos ←(i ≤ tantárgy_szám) HA (van_nemotos) AKKOR KIIR(nem kitűnő) EGYÉBKÉNT KIIR(kitűnő) Végignézem a jegyeket. Az elsővel kezdem. ellenőrizzük a többit is, hogy ötös-e.

35 35 Második ötlet Nézzük végig a jegyeket, először az elsőt,majd sorra a többit, és ellenőrizzük, hogy ötös-e. Ha a tömb minden elemét megvizsgáltuk, akkor minden érdemjegy ötös, azaz kitűnő. VÁLTOZÓK tantárgy_szám, i, jegyek[i] EGÉSZ, mind_otos LOGIKAI i ← 1 ISMÉTELD HA(i ≤ tantárgy_szám) és (jegyek[i] egyenlő 5) { i ← i+1 } mind_otos ← (i > tantárgy_szám) HA(mind_otos) AKKOR KIIR(kitűnő) EGYÉBKÉNT KIIR(nem kitűnő)

36 36 Kiválasztás Egy tankör zárthelyi dolgozatai közül válasszuk ki az egyik elégséges dolgozatot. Megoldás: nézzük végig a dolgozatokat, először az elsőt, majd sorra a többit, amíg nem találunk elégséges dolgozatot. Amikor megtaláltunk egy elégségest, akkor ő lesz a kiválasztott.

37 37 Pszeudokód VÁLTOZÓK i, sorsz, dolg_szama, dolgozatok[i] EGÉSZ i ← 1 ISMÉTELD HA ( (i ≤ dolg_szama) és (dolgozatok[i] ≠ 2) ) { i ← i + 1 } sorsz ← i // Ha találtunk elégségest, az lesz a megoldás. HA(i <= dolg_szama) AKKOR KIIR(sorsz); EGYÉBKÉNT KIIR ("nincs elégséges") Hasonlít az eldöntéshez, de más a konklúzió!

38 38 Keresés Ismerjük egy üzlet januári napi bevételeit. Adjunk meg egy olyan napot -ha van-, amikor a bevétel több volt, mint 20,000 Ft. Megoldás: Nézzük végig a bevételeket, először az elsőt, majd sorra a többit, amíg nem találunk 20,000 Ft-nál nagyobbat. Ha találtunk ilyet, akkor van megoldás, és a megoldás a megtalált bevétel sorszáma különben nincs megoldás

39 39 Input adatok generálása Töltsük fel véletlen egészekkel a január tömb elemeit. (Ezt most még nem kell megérteni, a félév végére világos lesz.) int[] januar = new int [32]; // 0-tól indul, a 32. lesz jan. 31 ! Random RandomClass = new Random(); for(int i = 1;i <=31; i++) januar[i] = RandomClass.Next(10,30); …. Január 1, 2, 3, 4, 5, …. Bevételei rendre ezer forintban, akkor január 3.-át kell megtalálnunk. Persze az is lehet, hogy a bevétel egyetlen napon sem haladja meg a 20 ezer forintot. A for ciklust fogjuk részletesen taglalni

40 40 A kód (a while ciklust fogjuk részletesen taglalni) int i = 1; while (januar[i] < 20) i++; Console.Write(januar[i] + " "); Ez akkor nem jó, ha nincs megoldás, azaz jan. 31.-én (i=32) Is a bevétel kisebb, mint 20. Mitől állna meg a ciklus? Ha a napokszama == 31, akkor: i = 1; while ( (i<=napokszama) && (januar[i] <= 20)) i++; if (i > napokszama) Console.WriteLine("NINCS megoldas"); else Console.Write(i + "dik nap! ");

41 41 Megszámolás Az előző feladatot kicsit módosítjuk. Számoljuk meg, hány napon (ha egyáltalán) volt az üzlet bevétele 20 ezer forintnál nagyobb?

42 42 Megszámolás kódja int darab = 0; for (i = 1; i <= napokszama; i++) if (januar[i] > 20) darab++; Console.WriteLine("a nagyobb bevételek száma: " +darab);

43 43 Maximum-kiválasztás Tegnap este a térképet nézegettem. Kiírtam magamnak 20 magas hegy tengerszint feletti magasságát. Adjuk meg az egyik legmagasabb csúcsot! Megoldás: Megjegyzem az első hegy magasságát. Ezt tekintem a legmagasabbnak. A többi hegyet sorra végignézem: Ha valamelyik magasabb, mint az eddigi legmagasabb, akkor az eddigi legmagasabbat elfelejtem, és az újat jegyzem meg. A végén pont az első legmagasabb hegyet jegyeztük meg.

44 44 Maximum-kiválasztás pszeudokódja 1 int hegyekszama = 10; int[] magas = new int [hegyekszama+1]; // mert 1-től indexelünk int i; Random RandomClass = new Random(); for (i = 1; i <= hegyekszama; i++){ magas[i] = RandomClass.Next(10, 26); Console.Write(magas[i]+" "); }

45 45 Maximum-kiválasztás pszeudokódja 2 int max = magas[1]; int eddigi = 1; for (i = 1; i <= hegyekszama; i++) if (magas[i] > max) { max = magas[i]; eddigi = i; } Console.WriteLine("az (egyik) legmagasabb sorszáma: "+eddigi+" magassag "+max); // magas[] tartalmát 1-től kezeljük // Ha mondjuk a 2. hegy és a 7. hegy ugyanolyan magas, // és a többi mind kisebb, az eredmény 2 lesz vagy 7? // 2 lesz. Azonban ha > helyett >= kerül be, akkor 7.

46 46 C# típus.Net Framework (System) típus Elő- jeles? Elfoglalt bájtok Lehetséges értékek sbyteSystem.SbyteIgen1-128 to 127 shortSystem.Int16Igen to intSystem.Int32Igen to longSystem.Int64Igen to byteSystem.ByteNem10 to 255 ushortSystem.Uint16Nem20 to uintSystem.UInt32Nem40 to ulongSystem.Uint64Nem80 to floatSystem.SingleIgen4Approximately ±1.5 x to ±3.4 x with 7 significant figures doubleSystem.DoubleIgen8Approximately ±5.0 x to ±1.7 x with 15 or 16 significant figures decimalSystem.DecimalIgen12Approximately ±1.0 x to ±7.9 x with 28 or 29 significant figures charSystem.Char---2Any Unicode character (16 bit) boolSystem.Boolean---1 / 2true or false Egyszerű változók (OOP gyakorlatokon részletezzük)

47 47 Példák int x = 10; // deklarálás kezdeti értékadással int y = x; y = 20; // x értéke 10 és y értéke 20 float v=2.34; double w;

48 48 Adatkonverziók A konverzió C# -ban lehet implicit vagy explicit. Ha az átalakítás automatikus, akkor implicit konverzióról beszélünk, ilyenkor nincs adatvesztés. Az explicit konverzió kikényszerített, ilyenkor előfordulhat adatvesztés. Konverzió leggyakrabban függvényhívás paraméter- átadásakor történik (később látunk majd példákat), vagy kevert típusú adatokkal való numerikus számítások esetén.

49 49 A nyilak mutatják az implicit konverziós lehetőségeket (referencia táblázat)

50 50 Implicit numerikus konverzió long x1; int y1 = 25; x1 = y1; // implicit numerikus konverzió int ->long Console.WriteLine(x1); int x1; long y1 = 25; x1 = y1; // long -> int nyíl nincs, mi lesz ? // HIBAÜZENET: NEM LÉTEZŐ implicit konverzió! // OK: mert esetleges adatvesztés lehetséges!

51 51 Megoldás kasztolással (explicit) int x1, x2; long y1 = , y2 = ; //y1 „belefér” int-be, y2 „nem fér bele” x1 = (int)y1; x2 = (int)y2; // (int) kasztolás Console.WriteLine(x1+" "+x2); // x1 = , x2 = -10 // x2 esetében adatvesztés történt

52 52 Egész-osztás vagy valós osztás? int i = 13, j = 7; // mindkét argumentum eredetileg egész int k = i / j; Console.WriteLine(k); // KIIR: 1 float k1 = i / j; Console.WriteLine(k1); // KIIR: 1 float k2 = (float) i / j; Console.WriteLine(k2); // // (float) i / (float) j vagy i / (float) j is jó! Console.WriteLine( 55 / 7); // 7 Console.WriteLine(55.0 / 7); //

53 53 Osztás folytatása int j = 7; float i2 = 13,0f; f = i2 / j; Console.WriteLine(f); // f == double i1 = 13.15; int j = 7; // i1 duplapontos, nem egészértékű Console.WriteLine(i1/j); // float i2 = 13.15; // double, nem tud floattá alakulni, HIBA! int j = 7; Console.WriteLine((int) i2 / j); float i2 = 13.15F; // 13.15F valós konstans int j = 7; Console.WriteLine((int) i2 / j); // 1-t fog kiírni

54 54 Duplapontos változó konvertálása egészre adatvesztéssel double i2 = 13.83; Console.WriteLine( (int) i2 ); // 13 Példa logikai kifejezésre int a = 7; bool log; log = a % 2 == 0; // log = (a % 2 == 0); if (log) Console.WriteLine(" paros"); else Console.WriteLine("paratlan");

55 55 String -> numerikus (egész) érték string sz = "123"; int sz1 = Int32.Parse(sz); // így is lehet int sz2 = Convert.ToInt32(sz); // vagy akár így is lehet

56 56 String -> numerikus (valós) érték string myDoubleStr = " -12,2 " ; double x = Double.Parse(myDoubleStr) + 5.3; double y = Convert.ToDouble(myDoubleStr) +1.1; Console.WriteLine(x); // -6,9 Console.WriteLine(y); // -11,1 Érdemes a tizedespont illetve a vessző használatára figyelni. A stringek részletes tárgyalása az IMOP gyakorlatokon történik!!

57 57 Elöltesztelő és hátultesztelő ciklus 1. int a = 0; while (a < 3) { Console.WriteLine(a); a++; } // a=0 indulással kiírja a 0, 1, 2 számokat int a = 0; do{ Console.WriteLine(a); a++; } while(a < 3); // a=0 indulással ugyanúgy, mint a zöld kód, kiírja a 0,1,2-t Nem olyan, mint a repeat Delphiben! Vissza

58 58 Elöltesztelő és hátultesztelő ciklus 2. int a = 5; while (a < 3) { Console.WriteLine(a); a++; } // ha a=5 induláskor, akkor egyszer sem hajtódik végre int a = 5; do{ Console.WriteLine(a); a++; } while(a < 3); // ha induláskor a=5; akkor kiírja az 5-t, egyszer végrehajtódik, többször nem Nem olyan, mint a repeat Delphiben!

59 59 For ciklus for (int a = 0; a < 5; a++) // 0, 1, 2, 3, 4 kiírása Console.WriteLine(a); // Nem hajtódik végre a ciklusmag a következő esetben: for (int a = 6; a < 5; a++) Console.WriteLine(a); // 0, 2, 4 íródik ki a következő esetben (ámbár nem ajánlott // ciklusváltozót egyszerre két helyen változtatni!): for (int a = 0; a < 5; a++) Console.WriteLine(a++);

60 60 Függvények használata érték visszaadása nélkül public static void change(int b) // void szerepe !! { b = 5; } static void Main() { int a = 0; change(a); Console.WriteLine(a); // hívás után is a==0 marad }

61 61 Egy érték visszaadása a metódus nevében public static int change(int b) // int szerepe !! { b = 5; return b; } static void Main() { int a = 0; int c; c = change(a); Console.WriteLine(c); // c==5 lesz }

62 62 Paraméterátadás ref segítségével public static void change(ref int b) { b = 5; } static void Main() { int a = 0; // ha hívás előtt ‘a’ nem kapna értéket, az hiba! change(ref a); Console.WriteLine(a); // a==5 }

63 63 Paraméterátadás out segítségével public static void change(out int b) { b = 5; } static void Main() { int a; // = 0; nem muszáj, hogy ‘a’ értéket kapjon! change(out a); // a==5, még akkor is, ha az előző sorban a értéket kapna Console.WriteLine(a); }

64 64 Egydimenziós tömb int[] itomb; // deklarálás itomb = new int[3] { 0, 1, 2 }; // inicializálás for (int i = 0; i < itomb.Length; i++) Console.WriteLine(itomb[i]); int[] itomb = new int[3] { 0, 1, 2 }; // a deklarálás és az inicializálás össze is vonható

65 65 Egydimenziós tömb átlaga public static double atlag(double[] vektor) { double s = 0.0; for (int i = 0; i < vektor.Length; i++) s += vektor[i]; return s/vektor.Length; } public static void Main(){ double[] tomb = new double[] { -4.11, 1.23, 2.14 }; Console.WriteLine(atlag(tomb)); // - 0,246.. Console.ReadKey(); // várakozás }

66 66 Írjunk egy függvényt, amely nullára cseréli egy tömb ama elemeit, melyek abszolút értéke egy paraméternél nagyobb public static double atl_csere (ref double[] vektor, double eps) { double s = 0.0; for (int i = 0; i < vektor.Length; i++) s += vektor[i]; s = s/vektor.Length; // átlagszámítás for (int i = 0; i < vektor.Length; i++) // csere, ha kell if ((vektor[i] >eps) || (vektor[i] < - eps)) vektor[i] = 0; return s; // a „régi átlag” visszaadása }

67 67 …és a főprogram public static void Main() { double[] tomb; double eps = 5.1; tomb = new double[] { -4.11, 1.23, }; Console.WriteLine(atl_csere(ref tomb,5)); for (int i = 0; i < tomb.Length; i++) Console.WriteLine( tomb[i]); // „új” tömb Console.ReadKey(); // várakozás } // a ref ebben az esetben mellőzhető! A tömbök tárgyalására visszatérünk!

68 68 Nem-egydimenziós tömbök A nem-egydimenziós tömbökkel a későbbiekben részletesen fogunk foglalkozni!

69 69 Egy n elemű sorozat csupa 0-ból és 1-ből áll. Rendezzük n-1 összehasonlítással! int i; int[] b = { 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0 }; for (i = 0; i < b.Length; i++) Console.Write(b[i] + " "); Console.WriteLine(); int n = b.Length; int[] b1 = new int[n]; // b1 segédtömb for (i = 0; i < b.Length; i++) b1[i] = 0; // kinullázzuk a segédtömböt for (i = 0; i <= b.Length - 1; i++) if (b[i] == 1) b1[--n] = 1; // fontos, hogy --n és nem n-- for (i = 0; i < b.Length; i++) Console.Write(b1[i] + " "); Console.ReadLine();

70 70 Egy n elemű sorozat csupa 0-ból és 1-ből áll. Rendezzük összehasonlítás nélkül! int szum = 0, i = 0; int[] b = { 0,0,1,0,1,1,0,0,1,0,1,0,0,1,1,0 }; // megszámoljuk, hány 1-es van for (i = 0; i < b.Length; i++) szum += b[i]; // b „elejét” kellő számú nullával feltöltjük for (i = 0; i < b.Length - szum; i++) b[i]=0; // b „végét” feltöltjük annyi 1-essel, amennyivel kell for (int j= i; j < b.Length; j++) b[j] = 1;

71 71 A két megoldás összehasonlítása Az első változatban kellett egy n hosszú ciklus és n-1 összehasonlítás, valamint még egy tömb A második változatban nem kellett összehasonlítás és extra tömb

72 72 Geometriai feladat Legyen adott egy konvex sokszög a síkban, csúcsainak koordinátáival, melyek óramutató járása szerinti bejárási tömbben adottak egy tömbben: x0 y0 x1 y1 x2 y2 ….. Számítsuk ki a sokszög kerületét és területét!

73 73 A kerületszámítás eleje Az egyik pont (x,y), a másik (xx,yy) koordinátájú A távolságot számító függvény: public static double tav(double x, double y, double xx, double yy) { return Math.Sqrt((x - xx) * (x - xx) + (y - yy) * (y - yy)); };

74 74 Közepe (a Main() belseje) // példaadatok double[] tomb = new double[] { 1.0, 0.0, 0.0, 2.0, -1.0, 0.0, 0.0, -3.0 }; double x, y, xx, yy, d = 0.0; int i, n=tomb.Length; // a kód for (i = 0; i+3 < n; i=i+2) { // végig a pontokon x = tomb[i]; y = tomb[i+1]; xx = tomb[i+2]; yy = tomb[i+3]; d += tav(x, y, xx, yy); } d += tav(tomb[0], tomb[1], tomb[n - 2], tomb[n - 1]);

75 75 Háromszög területe Heron képlettel A 3szög pontjai (x1,y1), (x2,y2), (x3,y3) public static double heron(double x1, double y1, double x2, double y2, double x3, double y3){ double s, d1, d2, d3 ; d1 = Math.Sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2)); d2 = Math.Sqrt((x2 - x3) * (x2 - x3) + (y2 - y3) * (y2 - y3)); d3 = Math.Sqrt((x1 - x3) * (x1 - x3) + (y1 - y3) * (y1 - y3)); s = (d1 + d2 + d3) / 2.0; return Math.Sqrt(s * (s - d1) * (s - d2) * (s - d3)); }

76 76 Konvex sokszög területszámítása double[] tomb = new double[] { 1.0, 0.0, 0.0, 2.0, -1.0, 0.0, 0.0, -3.0 }; double x, y, x1, y1, x2,y2, h = 0.0; int n = tomb.Length; x = tomb[0]; y = tomb[1]; for (int i = 2; i +3 < n; i = i+2) { x1 = tomb[i]; y1 = tomb[i+1]; x2 = tomb[i+2]; y2 = tomb[i+3]; h += heron(x, y, x1, y1, x2,y2); } Console.WriteLine("terulet: " + h); Koordinátatömbbeli indexek

77 77 Miért kell a konvexitás? Amit számítunk: T=(sárga+lila+kék)+(lila+kék) +(lila+barna) Helyesen: T=(sárga+lila+kék) - (lila+kék) +(lila+barna)=sárga+lila+barna A konvexitás biztosítja, hogy a területek összeadhatók!

78 78 Legnagyobb közös osztó 1. public static int euklidesz(int a, int b) { int t,a1,b1; a1 = Math.Max(a, b); // kell-e ez a sor ?! b1 = Math.Min(a, b); // kell-e ez a sor ?! while (a1 != b1) { if (a1 > b1) a1 = a1 - b1; else { t = a1; a1 = b1; b1 = t; } } return a1; }

79 79 Legnagyobb közös osztó 2. public static int gcd(int a, int b) { int t=0; while (b != 0) { Console.WriteLine("t= " + t + " a= " + a + " b= " + b); t = b; b = a % b; a = t; } Console.WriteLine("t= " + t + " a= " + a + " b= " + b); return a; } tab Hívás gcd(6,10)

80 80 Legnagyobb közös osztó 3. function gcd(a, b) ha b = 0 return a egyébként return gcd(b, a mod b) public static int gcd(int a, int b) { return ( b == 0 ? a : gcd(b, a % b) ); } Rekurzív C# algoritmus Pszeudokódban

81 81 Horner séma egy polinom adott x helyen vett értékének gyors kiszámítására Példa egy harmadfokú polinomra: P(x)=7x 3 – 2x x - 8 = (7x 2 – 2x + 5) x - 8= ((7x-2) x +5) x - 8 Az együtthatókat jelöljük: a[3] = 7 a[2]= - 2 a[1]= 5 a[0]= - 8 n=3; POL= a[n]; for(i=n-1; i>=0; i--) POL = POL*x + a[i]; A szorzások száma 3+2+1, ált esetben O(n*n) A szorzások száma 3, ált esetben O(n)

82 82 A Fibonacci sorozat A Fibonacci számsorozatban minden szám az első kettő után - az azt megelőző kettő összege. Így tehát a számsorozat: 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233 stb. Minél későbbi tagjait vesszük a sorozatnak, két egymást követő szám aránya annál inkább az aranymetszéshez fog közelíteni (ami megközelítőleg 1:1,618 vagy – ami ezzel közelítőleg egyenlő - 0,618:1)

83 83 Kiszámítás rekurzívan public static int fibo(int i){ if (i == 0) return 0; else if (i == 1) return 1; else return fibo(--i) + fibo(--i); } Beugrató kérdés: Ez ugyanaz-e, mint return 2*fibo(--i) ? return fibo(i-1) + fibo(i-2); A Fibonacci számok gyorsan nőnek, a long indokolt lehet

84 84 Fibonacci tömbbel int i, n; Console.Write("n= "); n = int.Parse(Console.ReadLine()); long[] f = new long[n]; // Fibonacci számok gyorsan nőnek f[0]=0; f[1]=1; for( i=2;i

85 85 Fibonacci ArrayList-tel int i=0, value=0; Console.Write(„Keressük az első Fibonacci számot, amely nagyobb mint: "); int n = int.Parse(Console.ReadLine()); ArrayList fiblist = new ArrayList(); fiblist.Add(0); fiblist.Add(1); for (i = 2; value <= n; i++) { int[] tomb = new int[fiblist.Count]; fiblist.CopyTo(tomb); value = tomb[i - 1] + tomb[i - 2]; fiblist.Add(value); } Console.WriteLine(n+". fibo= " + fiblist[--i]);

86 86 Volt-e szükség menetközben mindegyik Fibonacci számra? Ha a feladat úgy szól, hogy olvassunk be egy n számot, és ha az első n-nél nagyobb Fibonacci szám 5-tel osztható, akkor írjuk ki az eddigi Fibonacci számok számtani közepét, egyéb esetben pedig a mértani közepét, akkor szükség van az összes korábbi Fibonacci számra (avagy mégsem??) De ha csak az aktuális Fibonacci szám kell, akkor van a tömbhasználatnál egyszerűbb megoldás. A rekurzió, vagy…

87 87 Fibonacci segédváltozókkal int i = 0, seged0 = 0, seged1 = 1, f=0; Console.Write("Keressük az n-dikFibonacci számot, ahol n= "); int n = int.Parse(Console.ReadLine()); if (n == 0) Console.WriteLine("A válasz 0"); else if (n==1) Console.WriteLine("A válasz 1"); else{ for (i = 2; i <= n; i++) { f =seged0 + seged1; seged0 = seged1; seged1 = f; } Console.WriteLine("f= "+f); } Gyors és memóriatakarékos! Csak a legutolsó Fibonacci számot adja meg.

88 88 Fibonacci zárt alakban – a képlet Ekkor c 0 =0, c 1 =1, és n >=1 esetén (teljes indukcióval belátható) Fentiekből következik, hogy c n a Fibonacci sorozat!!!

89 89 Fibonacci zárt alakban – a program int fib; Console.Write("Hanyadik Fibonacci számot számítsuk: "); double n = double.Parse(Console.ReadLine()); double gyot =Math.Sqrt(5.0); fib = (int) Math.Truncate( (1.0/gyot)*( Math.Pow(((1.0+gyot)/2.0),n) - Math.Pow(((1.0-gyot)/2.0),n) ) ); Console.WriteLine("Az eredmény:"+fib); Duplapontos szám egész részét számolja (kihagyható)

90 90 Rendezések A rendezési algoritmus olyan algoritmus, amely egy lista vagy egy tömb elemeit egy meghatározott (növekvő vagy csökkenő) sorrendbe helyezi el. A rendezés lehet numerikus és lehet lexikografikus. A rendezés legtöbbször azért szükséges, hogy utána könnyebben lehessen keresni. Ezentúl, szűkebb értelemben vett rendezés alatt egy olyan algoritmust fogunk érteni, melynek inputja egy egészeket tartalmazó számsorozat, outputja a számsorozat növekvő sorrendben. Az output mindig egy permutációja az inputnak.

91 91 A rendezési algoritmusok osztályozása Egy n elemű tömb esetében a szükséges összehasonlítások száma szerint Általános esetben (mi is az általános eset ?!) O(n*log n) összehasonlításnál kevesebb nem elég Számos ismert esetben (példák jönni fognak) O(n*n) összehasonlítás szükséges Néhány igen speciális esetben (legutóbb tárgyalt eset, ahol csak 0 és 1 szerepelt) O(n) is elég Az O (ordó) jelölés magyarázatát ld. az Analízis tárgyban, vagy a következő dián:

92 92 Ordó, ordó Legyen f és g két, természetes számokon értelmezett, nem-negatív, valós értékű függvény. Vezessük be a következő jelöléseket: f=O(g), (f=nagy Ordó g) ha van olyan c>0 konstans, hogy minden elég nagy n-re f(n) ≤ c*g(n) f=o(g), (f=kis ordó g) ha g(n) csak véges sok ehlyen nulla, és f(n)/g(n)→0, ha n →∞ f=Ω(g), ha g=O(f). (ritkán használatos) f=Θ (g), ha f=O(g) és g=O(f), azaz vannak olyan c 1,c 2 konstansok, hogy minden elég nagy n-re c 1 g(n) ≤ f(n) ≤c 2 g(n) Az egyenlőség nem szimmetrikus, pl. O(n)=O(n 2 ), ez ugyanis azt jelenti, hogy f=O(n) esetén f=O(n 2 ) is fennáll, de fordítva ez nem igaz: O(n 2 ) ≠O(n)

93 93 További szempontok Szokás vizsgálni a cserék (swap) számát is. Legyen a és b egészek. Cseréljük ki az értéküket! { int kesztyu = a; a = b; b = kesztyu; } Vizsgálható a memória takarékosság, vannak „helyben” rendező algoritmusok, és vannak olyanok, amelyek segéd tárterületeket igényelnek. Vannak rekurzív és nem rekurzív rendezések.

94 94 Stabilitás Stabil rendezésnél az azonos kulcsú rekordok relatív sorrendje megmarad, nem stabil rendezésnél változhat. Tekintsünk egész koordinátájú pontokat a síkban, és bocsássunk merőlegeseket az x-tengelyre. Legyen az a feladat, hogy az így keletkezett szakaszokat rendezni kell az x-tengelyen vett koordinátájuk szerint. Nevezzük az x-koordinátákat kulcsnak. Eszerint történnek az összehasonlítások, de csere esetén a teljes szakaszt (azaz pontpárt) kell cserélni. Legyen a pontsorozat (4, 2) (3, 7) (3, 1) (5, 6) Két sorrend is létrejöhet, ha vannak azonos x-koordinátájú (x=3) pontok: (3, 7) (3, 1) (4, 2) (5, 6) (eredeti sorrend marad, ez a stabil) (3, 1) (3, 7) (4, 2) (5, 6) (eredeti sorrend változik)

95 95 Buborékrendezés A buborék rendezés a legrosszabb esetben (amikor az elemek csökkenő sorrendben vannak) valamint az átlagos esetben (amikor az elemek véletlenszerűen helyezkednek el) is O(n*n) komplexitású. Mivel sok O(n*log n) komplexitású rendezés van, nagy n esetén a buborék nem előnyös, kivéve, ha az elemek nagyjából eleve növekvően rendezettek.

96 96 Buborék 1. (a legnagyobb elem „felszáll”) public static void bubbleSort(int[] A) { bool csereltunk; int i, kesztyu; do { csereltunk = false; for (i = 0; i < A.Length - 1; i++) { if (A[i] > A[i + 1]) { kesztyu = A[i]; A[i] = A[i + 1]; A[i + 1] = kesztyu; csereltunk = true; } } while (csereltunk); } // nem ad visszajelzést, ha a tömb 0 vagy 1 hosszú

97 97 Buborék 1. főprogram // példának okáért rendezzünk 10 véletlen generált egész számot static void Main() { int[] A = new int[10]; int i; Random RandomClass = new Random(); for (i = 0; i < A.Length; i++) { A[i] = RandomClass.Next(10, 30); Console.Write(A[i] + " "); } Console.WriteLine(); bubbleSort( A ); for (i = 0; i < A.Length; i++) Console.Write(A[i] + " "); Console.ReadLine(); }

98 98 Buborék 2. (a lgkisebb elem „leszáll”) public static void bubbleSort(int[] A) { if (A.Length == 0) Console.WriteLine("A tömb üres!"); else if (A.Length == 1) Console.WriteLine("A tömb 1 elemű!"); else { int i, j, kesztyu; for (i = 0; i < A.Length - 1; i++) for (j = A.Length - 1; j > i; j--) if (A[ j – 1 ] > A[ j ]) { kesztyu = A[j]; A[j] = A[j - 1]; A[j - 1] = kesztyu; } }

99 99 Kétirányú buborék – cocktail sort bottom = 0; top = n-1; bool csere_volt = true; while (csere_volt == true){ csere_volt = false; for (i = bottom; i < top; i++) if (a[i] > a[i + 1]) { csere_volt= true; kesztyu = a[i]; a[i]=a[i+1]; a[i+1]=kesztyu; } top = top - 1; for (i = top; i > bottom; i--) if (a[i] < a[i - 1]) { csere_volt = true; kesztyu = a[i]; a[i] = a[i-1]; a[i-1] = kesztyu; } bottom = bottom + 1; }

100 100 2, 3, 4, 5, 1 sorozatnál „felszálló buborék” 4 menetet csinál, a „leszálló buborék” egyet 5, 1, 2, 3, 4 sorozatnál fordítva A kétirányú buborék mindkét esetben egy menetet csinál, igaz; egy menet két ciklust igényel Nagyságrendileg a cocktail is O(n*n)

101 101 Kerti törpe rendezés (C#) i = 1; while (i < n) { if (a[i - 1] <= a[i]) i++; // ha jó a sorrend, előre! else { int kesztyu = a[i - 1]; a[i - 1] = a[i]; a[i] = kesztyu; i--; if (i == 0) i = 1; } // else vége } // while vége

102 102 Hogyan működik? Az algoritmus megkeresi az első olyan helyet, ahol két egymást követő elem rossz sorrendben van, és megcseréli őket. Ha egy ilyen csere után rossz sorrend keletkezik, az csak közvetlenül a legutolsó csere előtt lehet, így ezt is ellenőrizzük. Talán ez az elképzelhető legegyszerűbb rendezés.

103 103 A buborék lényeges javítása: fésűs rendezés A fésűs rendezést (combsort) eredetileg 1980-ban tervezték, majd újra felfedezték és 1991-ben publikálták a Byte magazinban. A buborék rendezés módosítása, sebességében közelít a híres quicksorthoz. Az alapötlet az, hogy a sorozat végén levő kicsi értékekre találjunk rá minél hamarabb, mert ezek lassítják jelentősen a buborékot. (A sorozat elején levő nagy értékek nem annyira lassítóak, mert ezekre hamar rátalálunk).

104 104 A fésű kódja public static void combSort(int[] A) { int i; if (A.Length == 0) Console.WriteLine("A tömb üres!"); else if (A.Length == 1) Console.WriteLine("A tömb egyelemű!"); else { int gap = A.Length, cserevolt = 0, kesztyu; while ((gap >1) || (cserevolt !=0)) { if (gap > 1) // gap /1.3 lefelé kerekítve gap = (int)Math.Truncate((double)gap / 1.3); if ((gap == 10) || (gap == 9)) gap = 11; i = 0; cserevolt = 0; while (i + gap < A.Length) { if (A[i] > A[i+gap]){ kesztyu = A[i]; A[i]=A[i+gap]; A[i+gap] = kesztyu; cserevolt = 1; } i++; }

105 105 Megjegyzések 10 ezer elemű tömbön végzett kísérletek szerint a fésűs rendezés alig rosszabb a quicksortnál (10 %-kal); a változtatás a buborékhoz képest nem nagy. Ugyanakkor nem kell gondoskodni az eleve rendezett esetről, ami a quicksortot nagyon lelassítja (látni fogjuk). A gap beállításával először a távollevő elemeket rendezzük. Ezután a gap csökken, míg végül egy lesz. Ez esetben azonos a program a buborékkal; következésképpen korrekt. Lacey és Richard Box megmutatták, hogy a gap minden lépésben 1.3-mal osztandó. Továbbá felfedezték, hogy 9 és 10 nem alkalmas gap-nek, és 11-gyel helyettesítendő.

106 106 Combsort versus quicksort Quicksort sec Combsort sec Bubblesort sec 10 ezer egész szám rendezési kísérletének időeredményei Forrás:http://www.yagni.com/combsort/index.php [2008. nov. 16.]http://www.yagni.com/combsort/index.php

107 107 Quicksort -rekurzívan static void csere( ref int x, ref int y) { int t= x; x = y; y = t; } // a baloldali elemet a helyére teszi és visszaadja a hely indexét static int partition (int[] a, int first, int last) { int pivot = a[first], lastS1 = first, firstUnknown = first + 1; while (firstUnknown <= last) { if (a[firstUnknown] < pivot) { lastS1++; csere( ref a[firstUnknown], ref a[lastS1]); } firstUnknown++; } csere( ref a[first], ref a[lastS1]); return lastS1; } static void quicksort (int[] a) { quicksort (a, 0, a.Length - 1); } static void quicksort (int[] a, int first, int last) { if (first < last) { int pivotIndex = partition (a, first, last); quicksort (a, first, pivotIndex - 1); quicksort (a, pivotIndex + 1, last); }

108 108 Minimum kiválasztásos rendezés static void csere (ref int x, ref int y) { int cs =x; x=y; y=cs; } static void Main() { int i,min, n = 10; int[] a = new int[n]; Random RandomClass = new Random(); for (i = 0; i < n; i++) a[i] = RandomClass.Next(10, 26); for (i = 0; i < n; i++) { min = i; for (int j = i + 1; j < n; j++) if (a[j] < a[min]) min = j; csere(ref a[i], ref a[min]); }

109 109 Beszúrásos rendezés static void csere (ref int x, ref int y) { int cs =x; x=y; y=cs; } static void Main() { int i,j, n = 10; int[] a = new int[n]; Random RandomClass = new Random(); for (i = 0; i < n; i++) a[i] = RandomClass.Next(10, 26); for (i = 1; i < n; i++) { j = i - 1; while ((j> -1) && (a[j] > a[j+1])) { csere(ref a[j], ref a[j+1]); j--; }

110 110 Sorting demo -demo.html -demo.html

111 111 Vödörrendezés // a 0 és M intervallumba eső elemek rendezése const int darab = 60; // rendezendő elemek száma const int M = 100; // maximum érték const int vödörszám = 10; int vödör_range = M / vödörszám; // a rendezendő sorozat véletlen generálása és kiíratása int i,j; int[] a = new int[darab]; Random r = new Random(); for (i = 0; i < a.Length; i++) a[i] = r.Next(M); for (i = 0; i < a.Length; i++) Console.Write(" " + a[i]); Console.WriteLine();

112 112 A tömböt szétszedjük vödrökre // listatömb deklarációja ArrayList[] array = new ArrayList[vödörszám]; for (i = 0; i < array.Length; i++) array[i] = new ArrayList(); // a tömböt szétszedjük vödrökre (=listákra) for (i = 0; i < a.Length; i++) { j = a[i] / vödör_range; // a[i] a j-dik vödörbe esik array[j].Add(a[i]); // a[i]-t betesszük a j-dik vödörbe }

113 113 A listák rendezése egyenként for (i = 0; i < array.Length; i++) { Console.WriteLine(i + ". lista= "); // a listákat egyenként rendezzük for (j = 0; j < array[i].Count; j++) array[i].Sort(); // és kiírjuk a demo kedvéért for (j = 0; j < array[i].Count; j++) Console.Write(" " + array[i][j]); Console.WriteLine(); }

114 114 Befejezés // átmásoljuk a vödröket egyetlen listába ArrayList egylista = new ArrayList(); for (i = 0; i < array.Length; i++) for (j = 0; j < array[i].Count; j++) egylista.Add(array[i][j]); // az egyesített listát visszaírjuk a tömbbe egylista.CopyTo(a); // és kiírjuk a rendezett tömböt for (i = 0; i < a.Length; i++) Console.Write(" " + a[i]);

115 115 Halmazműveletek: metszet A feladat most két tömb a[0..n-1] és b [0..m-1] azonos elemeinek kiválogatása c tömbbe. A feladat csak úgy értelmezhető pontosan, ha az egyes tömbökben egy elem nem szerepel kétszer. (Mivel most a matematikai halmazokat tömbként ábrázoljuk.) Az algoritmus lényege: menjünk végig az a tömb elemein, és válogassuk ki azokat (kiválogatás), melyek szerepelnek b-ben (eldöntés). Így a feladat a korábbi tételekre visszavezethetõ. c maximális elemszáma n és m közül a kisebbik. Feltételeztük, hogy egyik halmaz sem üres.

116 116 Deklarációk a metszethez C# int n = 10, m=6, db =Math.Min(n,m); // tömbméretek int i,j,k; // ciklusváltozók int[] a = new int [n]; // a halmaz elemei 0..n-1 int[] b = new int [m]; // b halmaz elemei 0..m-1 int[] c = new int [db]; // a metszet elemei // db csak a maximális lehetséges tömbméret. Ha a metszet // üres, akkor nyilván nincs elem a metszetben.

117 117 Metszet C# kód k = 0; for (i=0; i

118 118 Halmazműveletek: unió A feladat most két tömb a[0..n-1] és b [0..m-1] elemeinek egyesítése c tömbbe. Az egyes tömbökben egy elem nem szerepel kétszer. (mint az előbb) A legkézenfekvőbb megoldás: tegyük be c-be a összes elemét, majd b-ből azokat, melyek nem szerepelnek a-ban. c elemszáma legfeljebb n+m. Feltételeztük, hogy egyik halmaz sem üres.

119 119 Unió C# kód for (i = 0; i < n; i++) c[i] = a[i]; //a-t áttöltjük c-be k = n; for (j = 0; j < m; j++){ // keressük azt a b-belit, ami nincs a-ban for (i = 0; (i< n) && (b[j] != a[i]); i++) ; if (i >= n) c[k++] = b[j]; // ha volt ilyen, c-be teszzük } for (i = 0; i < k; i++) Console.WriteLine(c[i]); // Futásidő n*m nagyságrendű!

120 120 Unió speciális esetben (C#): az a és b (halmazokat reprezentáló) tömbök rendezettek (összefuttatás) i = 0; j = 0; k = 0; while(( i < n) && ( j < m)) if (a[i]

121 121 Rekurzív bináris keresés (rendezett tömbben) public static int binker(int[] tomb, int value, int low, int high) { if (high < low) return -1; int mid = (low + high) / 2; if (tomb[mid] > value) { mid--; return binker(tomb, value, low, mid); } else if (tomb[mid] < value) { mid++; return binker(tomb, value, mid, high); } else return mid; }

122 122 Iteratív bináris keresés (rendezett tömbben) public static int binker(int[] tomb, int value) { int mid, low = 0, high = tomb.Length-1; while (low <= high) { mid = (low + high) / 2; if (tomb[mid] > value) high = --mid; else if (tomb[mid] < value) low = ++mid; else return mid; // megtalálva } return -1; // nincs meg }

123 Dinamikus Programozás

124 124 Mátrixok láncszorzása A dinamikus programozás egy általános eljárás bizonyos problémák megoldására Példa: Mátrixok láncszorzása Hogyan szorzunk mátrixokat. C = AB A is d × e, B is e × f O(d*e*f ) időben AC B dd f e f e i j i,j

125 125 Mátrixok láncszorzása Kiszámítandó A = A 0 A 1 …A n-1 A i mérete d i × d i+1 Probléma: Hogyan zárójelezzünk? Az eredménynek mindegy, mert a szorzás asszociatív, de a műveleti sebesség nagyon eltérhet! Example B mérete 3 × 100 C mérete 100 × 7 D mérete 7 × 5 (BC)D3 × 100 × ×7× 5 = 2305 szorzás B(CD)3 × 100 × × 7 × 5 = 5000 szorzás

126 126 A „brutális” módszer Mátrix láncszorzás: Próbáljuk megkeresni az összes zárójelezését A=A 0 A 1 …A n-1 -nak Mindegyikre számítsuk ki a műveletek számát Válasszuk ki a legjobbat Futásidő: Zárójeléezések száma = n-csúcsú bináris fák száma Exponenciális! Ez az n-dik Catalan szám – nagyságrendileg 4 n. Kiszámíthatatlan  !

127 127 A mohó megközelítés Ötlet #1: mindig azt a szorzatot válasszuk, amelyik a legkevesebb műveletet igényli Ellenpélda arra, hogy a fenti ötlet optimális lehetne: A mérete 101 × 11 B mérete 11 × 9 C mérete 9 × 100 D mérete 100 × 99 Az ötlet szerint legjobb A((BC)D) = szorzás Ennél jobb: (AB)(CD) = szorzás AB 101*11*9=9999 BC 11*9*100=9900 CD 9*100*99=89100 A(BC) 101*11*100= (BC)D 11*100*99=108900

128 128 A “rekurzív” megközelítés Definiálunk alproblémákat: Keressük meg a legjobb zárójelezését ennek: A i A i+1 …A j. Legyen N i,j = ezen részprobléma műveleti igénye. A teljes probléma optimális megoldása N 0,n-1. Részprobléma optimalitás: Az optimális megoldás az optimális részprblémák függvényében lesz definiálva Kell, hogy legyen egy utoljára végrehajtott szorzás az optimális megoldásban (ez a bináris fa gyökere) Mondjuk, hogy ez az i indexnél volt: (A 0 …A i )(A i+1 …A n-1 ). Ekkor az optimális megoldás N 0,n-1 ia két optimális részmegoldás, N 0,i és N i+1,n-1 összege, valamint az utolsó szorzás

129 129 A karakterisztikus egyenlet A globális optimum az optimális részproblémáktól, valamint az utolsó szorzás helyétől függ Vizsgáljunk meg minden lehetséges helyet az utolsó szorzásra: Tudjuk, hogy A i mérete d i × d i+1 Így a karakterisztikus egyenlet N i,j –re a következő alakú: Az alproblémák nem függetlenek, az alproblémák átfedik egymást.

130 130 A dinamikus programozási algoritmus Nem használunk rekurziót, mivel az alproblémák átfedik egymást helyette “bottom-up” módon alproblémákkal foglalkozunk N i,i számítása könnyű, ezért ezzel kezdünk Ezután 2,3,… hosszú alproblémákkal foglalkozunk A futási idő: O(n 3 ) Algorithm matrixChain(S): Input: n db összeszorzandó mátrix Output:a szorzások optimális száma for i  1 to n-1 do N i,i  0 for b  1 to n-1 do for i  0 to n-b-1 do j  i+b N i,j  +  for k  i to j-1 do N i,j  min{N i,j, N i,k +N k+1,j +d i d k+1 d j+1 }

131 131 A válasz N … n-1 … j i Az algoritmus magyarázata A bottom-up konstrukció feltölti az N tömböt az átlók mentén N i,j az i-dik sor és a j-dik oszlop korábban kiszámított értékeiből számítódik A táblázat egy eleme O(n) idő alatt tölthető ki A teljes idő O(n 3 ) A zárójelezéshez az kell, hogy „k” értékére „emlékezzünk” mindegyik esetben

132 132 A láncszorzási algoritmus Algorithm matrixChain(S): Input: n db összeszorzandó mátrix Output:# szorzások optimális száma for i  0 to n-1 do N i,i  0 for b  1 to n-1 do // b is # of ops in S for i  0 to n-b-1 do j  i+b N i,j  +infinity for k  i to j-1 do sum = N i,k +N k+1,j +d i d k+1 d j+1 if (sum < N i,j ) then N i,j  sum O i,j  k return N 0,n-1 Példa: ABCD A mérete 10 × 5 B mérete 5 × 10 C mérete 10 × 5 D mérete 5 × 10 N A B C D AB BC CD A(BC) (BC)D (A(BC))D

133 133 static void Main(string[] args) { int[] d = { 10, 5, 10, 5, 10 }; int i, j, k, b, n = d.Length-1; double sum = 0.0; const double v = 1.0 / 0; // végtelen double[,] N = new double[n, n]; for(i=0;i

134 134 Recovering operations Example: ABCD A is 10 × 5 B is 5 × 10 C is 10 × 5 D is 5 × 10 N A B C D AB BC CD A(BC) (BC)D (A(BC))D // a zárójelezéshez // mátrixlánc A i -től A j -ig exp(i,j) if (i=j) then// alapeset, 1 mátrix return ‘A i ’ else k = O[i,j]// piros értékek S1 = exp(i,k)// 2 rekurzív hívás S2 = exp(k+1,j) return ‘(‘ S1 S2 ‘)’

135 135 static string EXP(int i, int j, int[,] O) { int k; string s1, s2; if (i == j) return "A" + i.ToString(); else { k = O[i, j]; s1 = EXP(i, k, O); s2 = EXP(k+1,j,O); return "("+s1 + s2+")"; static void Main(string[] args) { int[,] O = new int[n, n]; for(i=0;i

136 136 Optimalizálási problémák Egy optimalizálási problémában nemcsak egy megoldást, hanem a legjobb megoldást keressük A mohó algoritmus fázisokban dolgozik. Minden egyes fázisban: Tegyük azt, ami most a legjobb, nem törődve a jövővel. Abban bízik a mohó, hogy a lokális optimumok sorozata globális optimumhoz vezet. (Néha ez a helyzet, lásd Kruskal algoritmus, PPT, jövő félév).

137 137 Mohó algoritmusok Maximalizáljuk életünk örömeit: Első algoritmus: élvezzük az életet naponta Második algoritmus: dolgozz keményen, tanulj, szerezz diplomát, legyen jó fizetésű állásod, keress pénzt, és legyen jó nyugdíjad Melyik algoritmus maximalizál a teljes életre?

138 Ritka mátrixok

139 Jelölje a fenti 10x8 –as mátrixot A. Összesen 7 nem nulla eleme van.

140 Sorok száma az eredeti A mátrixban Oszlopok száma az eredeti A mátrixban Jelölje RA a baloldali mátrixot. Tárigénye 8*3*4=96 byte. Az előző dia A mátrixának tárigénye 10*8*4= 320 byte. A két mátrix ugyanazt az információt hordozza! Figyeljük meg, hogy RA sorai (a fejlécet nem beszámítva) rendezettek a sorok első mezői szerint, és azonos első mező esetén (5) a második mező szerint rendezettek.

141 141 Mi ennek a jelentősége? Ha az A mátrix nagyon nagy (pl. 1000*1000 méretű), akkor tárolása gondot okozhat. Ha azonban a nem nulla elemek száma relatíve kicsi (mondjuk 100), és A-t átírjuk RA ritka mátrixos formába, akkor RA tárigénye 101*3*4 byte, szemben A tárigényével, ami 1000*1000*4 byte. A „spórolást” úgy kaptuk, hogy a nullákat nem tároltuk, azaz megállapodtunk abban, hogy amit nem tárolunk, az nulla.

142 142 normál mátrix (A) átalakítása ritka formátumúvá static int[,] normal2ritka(int[,] A) { int i, j, t=0; int k=1; // a nulladikba a fejléc kerül for (i = 0; i < A.GetLength(0); i++) for (j = 0; j < A.GetLength(1); j++) if (A[i, j] != 0) t++; int[,] R = new int[t + 1, 3]; R[0, 0] = A.GetLength(0); R[0, 1] = A.GetLength(1); R[0, 2] = t; for (i = 0; i < A.GetLength(0); i++) { for (j = 0; j < A.GetLength(1); j++) if (A[i, j] != 0) { R[k, 0] = i; R[k, 1] = j; R[k, 2] = A[i,j]; k++; } return R; } Figyeljük meg, hogy ebben az algoritmusban A elemein sorfolytonosan kell végigmenni, tehát ha A túl nagy és nem fér el a tárban, lehet szekvenciálisan eljárni!

143 143 Transzponálás Egy mátrix transzponálása a főátlóra való tükrözést jelenti (komplex esetben konjugálni is szoktunk, de most vegyük csak a valós esetet). Jelölje B az A transzponáltját. int[,] B = new int [A.GetLength(1),A.GetLength(0)]; for (i = 0; i < A.GetLength(0); i++) { for (j = 0; j < A.GetLength(1); j++) B[j,i] = A[i, j]; } Ha A nagyon nagy méretű, akkor ez az egyszerű algoritmus nem használható, mert például A nem fog elférni a tárban. Itt i és j „messze” lehet egymástól, a szekvenciális feldolgozás nem megy.

144 RA (A ritka mátrixos alakja) Ez leírja A transzponáltját, de sajnos nem ritka mátrixos forma, mert hiányzik a rendezettség!

145 145 R ritka mátrix transzponáltjának (TR) előállítása: első módszer int n = normal2ritka(A).GetLength(0); // A nem nulla elemeinek száma +1 int m = normal2ritka(A).GetLength(1); // m== 3 int[,] R = new int[n, m]; R = normal2ritka(A); int[,] TR = new int[n, m]; TR[0, 0] = R[0,1]; TR[0, 1] = R[0,0]; TR[0, 2] = R[0, 2]; // TR[0,2]==n – 1== A nem nulla elemeinek száma int q = 1; for(j=1; j< R[0,1]; j++) // j A oszlopain megy végig for (i = 1; i <= R[0, 2]; i++) // R sorain megy végig if (R[i,1] == j) { TR[q,0]=R[i,1]; TR[q,1]=R[i,0]; TR[q,2]=R[i,2]; q++; }

146 146 Egy gyorsabb módszer int[,] TR = new int[n, m]; TR[0, 0] = R[0,1]; TR[0, 1] = R[0,0]; TR[0, 2] = R[0, 2]; int darab = R[0,2]+1; int[] s = new int[darab]; int[] t = new int[darab]; for (i = 0; i < darab; i++) s[i] = 0; // összeszámoljuk, hogy melyik oszlopból mennyi van for (j = 1; j

147 147 int sum = 0; t[0] = 1; // pozíciók előkészítése for (j = 1; j < darab; j++) { sum = sum + s[j - 1]; t[j] = sum + 1; } for (j=1;j<= R[0,2]; j++) { TR[t[R[j, 1]], 0] = R[j, 1]; TR[t[R[j, 1]], 1] = R[j, 0]; TR[t[R[j, 1]], 2] = R[j, 2]; t[R[j, 1]]++; }


Letölteni ppt "AAO Csink László 2010. ősz. 2 Adminisztráció Előadók: Csink László A tárgy"

Hasonló előadás


Google Hirdetések