AAO Csink László 2010. ősz.

Slides:



Advertisements
Hasonló előadás
Készítette: Kosztyán Zsolt Tibor
Advertisements

C# nyelvi áttekintő A „Programozás C# nyelven (Illés Zoltán)”
Programozási tételek, és „négyzetes” rendezések
1 Hernyák Zoltán Programozási Nyelvek II. Eszterházy Károly Főiskola Számítástudományi tsz.
C++ programozási nyelv Gyakorlat hét
Tömbök C#-ban.
Matematika és Tánc Felkészítő tanár: Komáromi Annamária
1 Hernyák Zoltán Programozási Nyelvek II. Eszterházy Károly Főiskola Számítástudományi tsz.
HIKGHB Németh Gábor LUF9NV Simon Attila. A programozás alapjai előadás Híradástechnikai Tanszék.
Rekurzió (Horváth Gyula és Szlávi Péter előadásai felhasználásával)
Euklidészi gyűrűk Definíció.
Egy f  R[x] polinom cS -beli helyettesítési értéke
Programozási alapismeretek 8. előadás. ELTE 2/  További programozási tételek További programozási tételek 
Csala Péter ANDN #4. 2 Tartalom  C# - ban előre definiált típusok  Változók  Változókkal műveletek  Elágazás  Ciklus.
Bevezetés a Java programozásba
4. előadás (2005. március 8.) Pointerek Pointer aritmetika
C A C nyelv utasításai.
Készítette: Pető László
Algoritmizálás Göncziné Kapros Katalin humaninformatika.ektf.hu.
Másodfokú egyenletek.
Java programozási nyelv 2. rész – Vezérlő szerkezetek
A C++ programozási nyelvSoós Sándor 1/12 C++ programozási nyelv Gyakorlat - 8. hét Nyugat-Magyarországi Egyetem Faipari Mérnöki Kar Informatikai Intézet.
1 Miskolci Egyetem Informatikai Intézet Általános Informatikai Tanszé k Pance Miklós Adatstruktúrák, algoritmusok előadásvázlat 1. Bevezetés Miskolc, 2004.
Miskolci Egyetem Informatikai Intézet Általános Informatikai Tanszé k Pance Miklós Adatstruktúrák, algoritmusok előadásvázlat Miskolc, 2004 Technikai közreműködő:
A TERMÉSZETTUDOMÁNYOK ALAPJAI 1. Matematika
C++ Alapok, első óra Elemi típusok Vezérlési szerkezetek
A számfogalom bővítése
Operációs rendszerek gyakorlat sed, awk parancsok.
Programozás I. Ciklusok
Programozás I Függvények általános jellemzői
A Fibonacci-féle sorozat
Matematika a természetben és a művészetben
ISZAM III.évf. részére Bunkóczi László
Miskolci Egyetem Informatikai Intézet Általános Informatikai Tanszé k Pance Miklós Adatstruktúrák, algoritmusok előadásvázlat Miskolc, 2004 Technikai közreműködő:
PHP I. Alapok. Mi a PHP? PHP Hypertext Preprocessor Szkriptnyelv –Egyszerű, gyors fejlesztés –Nincs fordítás (csak értelmező) Alkalmazási lehetőségek:
1 Bevezetés a funkcionális programozásba 2009.
P ROGRAMOZÁS C# - BAN Kivételkezelés. P ÉLDA I. Nullával való osztás miatt kapjuk a hibaüzenetet.
P ROGRAMOZÁS I/O műveletek. S YSTEM.C ONSOLE A programjainknak fontos része a felhasználóval való kommunikáció. Adatokat kell kérni tőle, vagy közölnünk.
Beolvasó utasítás Console.Read();  Int típusú adatot kapunk. Console.ReadLine();  String típusú adatot kapunk. Console.ReadKey();  Tetszőleges billentyű.
Tömbök és programozási tételek
Ciklusok (iterációk).
Programozási nyelvek.
1 Hernyák Zoltán Programozási Nyelvek II. Eszterházy Károly Főiskola Számítástudományi tsz.
Hernyák Zoltán Programozási Nyelvek II.
1 Hernyák Zoltán Web: Magasszintű Programozási Nyelvek I. Eszterházy.
1 Hernyák Zoltán Web: Magasszintű Programozási Nyelvek I. Eszterházy.
AAO Csink László november.
1 AAO folytatás ++ Csink László. 2 Rekurzív bináris keresés (rendezett tömbben) public static int binker(int[] tomb, int value, int low, int high) public.
V 1.0 Szabó Zsolt, Óbudai Egyetem, Programozási Paradigmák és Technikák Programozási eszközök Interfészek Generikus.
A Dijkstra algoritmus.
Java programozási nyelv Metódusok
Java programozási nyelv Adatbekérés konzolról
Algoritmusok.
Egyenesvonalú (lineáris) adatszerkezetek
Objektum orientált programozás
Programozás I. Matematikai lehetőségek Műveletek tömbökkel
ProgramozásProgramozás célja hosszabb számítások elvégzése ill. kiíratása akkor érdemes programot írni, ha sok számolni való van illetve ha ugyanazt az.
Feladatok (értékadás)
Függvények a C nyelvben 1 Függvényeket a következő esetekben szokás írni: Ha ugyanazt a tevékenységet többször is el kell végeznünk ugyanolyan típusú,
Programozási alapismeretek 8. előadás. ELTE Szlávi-Zsakó: Programozási alapismeretek 8.2/  További programozási.
1. feladat  Készíts olyan függvényt, mely paraméterül kapja két egész típusú változó címét, s hívása után a két változó értéke helyet cserél.
Grafikus programozás Készítette: Csernok László
Hibaszámítás Gräff József 2014 MechatrSzim.
C++2. Ciklusok elöltesztelő (for, while) A ciklusmag feldolgozása előtt történik a vizsgálat  lehet, hogy egyszer sem fut le. A soronkövetkező iteráció.
TÁMOP /1-2F Informatikai gyakorlatok 11. évfolyam Alapvető programozási tételek megvalósítása Czigléczky Gábor 2009.
Programozás alapjai Készítette: Csiszár Nóra Anita
Gépészeti informatika (BMEGEMIBXGI)
Bevezetés a programozásba Algoritmikus gondolkodás
Informatikai gyakorlatok 11. évfolyam
Algoritmus készítés.
Előadás másolata:

AAO Csink László 2010. ősz

Adminisztráció Előadók: Csink László csink.laszlo@nik.bmf.hu A tárgy weblapja: http://nik.bmf.hu/csink/aao Login: aao Jelszó: algorithm Az objektumorientált programozás 5 előadásból áll, melyet Miklós Árpád (miklos.arpad@nik.bmf.hu) tart

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

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 http://mathworld.wolfram.com/ Lexikon: http://wikipedia.org/ Ajánlott feladatgyűjtemény (PPKE) (A Kotsis et al könyv mellett): http://digitus.itk.ppke.hu/~lovei/2007-2/feladatok.html

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

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.

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)

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.

A másodfokú egyenlet „receptje” 1. Készítsünk algoritmust az ax2+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.

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

A feladat „receptje”: a hozzávalók A „recept” adatai: Név: MASODFOKU elkészítésének ideje (és szerző): 2006-07-11. 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++ 3.0 (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)

A feladat pontosítása Hasznos dolog egy konkrét példát megnézni: 4x2-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 3x2+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.

A specifikáció Oldjuk meg az ax2+bx+c=0 egyenletet minden a, b, c valós szám esetén. Nevezzük a {ax2+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 {ax2+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.

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.

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 )

Első nekifutás VÁLTOZÓK gy, a,b,c VALÓS SZÁM BEOLVAS(a,b,c) gy mint egész nem jó, pl. b=1.1., a=1, c=0.2 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ÉNT KIIR(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. értékadás

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

Tovább folytatjuk (EZ MÉG NEM VÉGLEGES! VÁLTOZÓK gy,a,b,c, x1,x2 VALÓS SZÁM ag EGÉSZ SZÁM BEOLVAS(a,b,c) 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) ESETEK VEGE

Javítások, megjegyzések Kellenek további zárójelek: x1=(-b+gy)/(2a) 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.

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.

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)

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

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

A gyökvonás programja // inp adott szám, melyből gyököt akarunk vonni VÁLTOZÓK inp, ujgy, gy, d, eps DUPLAPONTOS BEOLVAS(inp) gy = 1.0 d=1.0 eps=0.00001 ISMETELNI HA( d > eps){ ujgy = (1.0/2)*(gy + inp/gy) d = | ujgy – gy | gy = ujgy } 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!

6 négyzetgyökének közelítő számítása ujgy d (=|ujgy-gy|) 1 3.5 2.5 2.607143 0.892857 2.454256 0.152886 2,454256 2,449494 0.004762 2.449494 2.44949 4.628819e-06

Vigyázat! A fentiek csak azért működtek jól, mert tudtuk (matematikából), hogy gyn konvergens. Ha most akkor ugyan sn+1-sn bármilyen kicsi lehet, sn 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 gyn 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?

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): http://mathworld.wolfram.com/ Mivel jól tudunk angolul , könnyedén elnavigálunk az adott területre: Number Theory, Prime Numbers, Primality Testing.

ERATHOSTENESI SZITA „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: MathWorld

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).

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

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.

Pszeudokód sum ← sum + szamla[i]; i ← i+1; } KIIR(sum) 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

Eldöntés Egy tanuló érdemjegyei alapján szeretném eldönteni, hogy kitűnő-e, vagy sem. Kétféle ötlet is lehet: Ha a jegyei közt van olyan, ami nem ötös, akkor nem kitűnő. 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ő.

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.

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ő)

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.

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ó!

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

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); 18 26 28 12 …. 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

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! ");

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?

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);

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.

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]+" "); }

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.

Egyszerű változók (OOP gyakorlatokon részletezzük) C# típus .Net Framework (System) típus Elő-jeles? Elfoglalt bájtok Lehetséges értékek sbyte System.Sbyte Igen 1 -128 to 127 short System.Int16 2 -32768 to 32767 int System.Int32 4 -2147483648 to 2147483647 long System.Int64 8 -9223372036854775808 to 9223372036854775807 byte System.Byte Nem 0 to 255 ushort System.Uint16 0 to 65535 uint System.UInt32 0 to 4294967295 ulong System.Uint64 0 to 18446744073709551615 float System.Single Approximately ±1.5 x 10-45 to ±3.4 x 1038 with 7 significant figures double System.Double Approximately ±5.0 x 10-324 to ±1.7 x 10308 with 15 or 16 significant figures decimal System.Decimal 12 Approximately ±1.0 x 10-28 to ±7.9 x 1028 with 28 or 29 significant figures char System.Char --- Any Unicode character (16 bit) bool System.Boolean 1 / 2 true or false

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;

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.

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

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!

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

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); // 1.857143 // (float) i / (float) j vagy i / (float) j is jó! Console.WriteLine( 55 / 7); // 7 Console.WriteLine(55.0 / 7); // 7.8571...

Osztás folytatása int j = 7; float i2 = 13,0f; f = i2 / j; Console.WriteLine(f); // f == 1.85.. double i1 = 13.15; int j = 7; // i1 duplapontos, nem egészértékű Console.WriteLine(i1/j); // 1.87... float i2 = 13.15; // 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

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");

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

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!!

Elöltesztelő és hátultesztelő ciklus 1. Vissza 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!

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!

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++) // 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++);

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

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

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

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);

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ó

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

Í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 }

…és a főprogram public static void Main() { double[] tomb; double eps = 5.1; tomb = new double[] { -4.11, 1.23, 20.14 }; 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!

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

Egy n elemű sorozat csupa 0-ból és 1-ből áll 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();

Egy n elemű sorozat csupa 0-ból és 1-ből áll 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;

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

Geometriai feladat Számítsuk ki a sokszög kerületét és területét! 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!

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)); };

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]);

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)); }

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

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!

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;

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; Hívás gcd(6,10) t a b 6 10 4 2

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

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)=7x3 – 2x2 + 5 x - 8 = (7x2 – 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)

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)

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

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<n; i++) f[i]= f[i-1]+f[i-2];

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]);

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…

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.

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

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ó)

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.

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:

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 c1,c2 konstansok, hogy minden elég nagy n-re c1g(n) ≤ f(n) ≤c2g(n) Az egyenlőség nem szimmetrikus, pl. O(n)=O(n2), ez ugyanis azt jelenti, hogy f=O(n) esetén f=O(n2) is fennáll, de fordítva ez nem igaz: O(n2) ≠O(n)

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.

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)

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.

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ú

Buborék 1. főprogram static void Main() { // 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();

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; } }

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; }

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)

Kerti törpe rendezés (C#) 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

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.

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).

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++;

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ő.

Combsort versus quicksort 0.0038 sec Combsort 0.0042 sec Bubblesort 1.36 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.]

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);

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]); }

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--; }

Sorting demo http://www.cs.ubc.ca/~harrison/Java/sorting-demo.html

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();

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 }

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(); }

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]);

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.

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.

Metszet C# kód k = 0; for (i=0; i<n;i++) { Az if NINCS a ciklusban, mert a for törzse üres! k = 0; for (i=0; i<n;i++) { for(j=0; (j<m) && (b[j] != a[i]); j++); // amíg j<m és b[j]<>a[i] if (j<m) c[k++]=a[i]; // ha j=m, akkor a[i] nem szerepelt b-ben // ha j<m, akkor a[i] előfordult b-ben } for (i = 0; i < k; i++) Console.WriteLine(c[i]); // kiíratás

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.

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ű!

Unió speciális esetben (C#): az a és b (halmazokat reprezentáló) tömbök rendezettek (összefuttatás) Csak az egyik fut! i = 0; j = 0; k = 0; while(( i < n) && ( j < m)) if (a[i]<b[j]) c[k++] = a[i++]; else if (a[i]==b[j]) {c[k++]= a[i++]; j++;} else c[k++] = b[j++]; for (x=i; x<n; x++) c[k++] =a[x]; for (x=j; x<m; x++) c[k++] =b[x]; for (i = 0; i < k; i++) Console.WriteLine(c[i]); // Futásidő n+m nagyságrendű, n*m helyett (előző)!

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;

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

Dinamikus Programozás

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 A C B d f e i j i,j

Mátrixok láncszorzása Kiszámítandó A = A0A1…An-1 Ai mérete di × di+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)D 3×100×7 + 3×7×5 = 2305 szorzás B(CD) 3×100×5 + 100×7×5 = 5000 szorzás

A „brutális” módszer Mátrix láncszorzás: Futásidő: Próbáljuk megkeresni az összes zárójelezését A=A0A1…An-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 4n. Kiszámíthatatlan !

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) 109989+9900+108900=228789 szorzás Ennél jobb: (AB)(CD) 9999+89991+89100=189090 szorzás AB 101*11*9=9999 BC 11*9*100=9900 CD 9*100*99=89100 A(BC) 101*11*100=111100 (BC)D 11*100*99=108900

A “rekurzív” megközelítés Definiálunk alproblémákat: Keressük meg a legjobb zárójelezését ennek: AiAi+1…Aj. Legyen Ni,j = ezen részprobléma műveleti igénye. A teljes probléma optimális megoldása N0,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: (A0…Ai)(Ai+1…An-1). Ekkor az optimális megoldás N0,n-1 ia két optimális részmegoldás, N0,i és Ni+1,n-1 összege, valamint az utolsó szorzás

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 Ai mérete di × di+1 Így a karakterisztikus egyenlet Ni,j –re a következő alakú: Az alproblémák nem függetlenek, az alproblémák átfedik egymást.

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 Ni,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(n3) Algorithm matrixChain(S): Input: n db összeszorzandó mátrix Output: a szorzások optimális száma for i  1 to n-1 do Ni,i  0 for b  1 to n-1 do for i  0 to n-b-1 do j  i+b Ni,j  + for k  i to j-1 do Ni,j  min{Ni,j , Ni,k +Nk+1,j +di dk+1 dj+1}

Az algoritmus magyarázata A bottom-up konstrukció feltölti az N tömböt az átlók mentén Ni,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(n3) A zárójelezéshez az kell, hogy „k” értékére „emlékezzünk” mindegyik esetben A válasz N n-1 1 2 j … 1 … i n-1

A láncszorzási algoritmus Példa: ABCD A mérete 10 × 5 B mérete 5 × 10 C mérete 10 × 5 D mérete 5 × 10 Algorithm matrixChain(S): Input: n db összeszorzandó mátrix Output: # szorzások optimális száma for i  0 to n-1 do Ni,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 Ni,j  +infinity for k  i to j-1 do sum = Ni,k +Nk+1,j +di dk+1 dj+1 if (sum < Ni,j) then Ni,j  sum Oi,j  k return N0,n-1 N 0 1 2 3 500 500 1000 2 A AB A(BC) (A(BC))D 1 250 500 1 B BC (BC)D 2 500 C CD 3 D

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<n;i++) N[i,i] = 0; for(b=1;b<n;b++) for (i = 0; i < n - b ; i++) { j = i + b; N[i,j] = v; // végtelen for (k = i; k < j ; k++) { sum = N[i, k] + N[k + 1, j] + d[i] * d[k + 1] * d[j + 1]; if (sum < N[i, j]) N[i, j] = sum; } for (i = 0; i < n; i++) { for (j = 0; j < n; j++) Console.Write(N[i, j].ToString().PadLeft(6) ); Console.WriteLine(); Console.WriteLine("Az eredmény= " + N[0, n - 1]); Console.ReadLine(); } // Main vége

Recovering operations Example: ABCD A is 10 × 5 B is 5 × 10 C is 10 × 5 D is 5 × 10 // a zárójelezéshez // mátrixlánc Ai -től Aj -ig exp(i,j) if (i=j) then // alapeset, 1 mátrix return ‘Ai’ 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 ‘)’ N 0 1 2 3 500 500 1000 2 A AB A(BC) (A(BC))D 1 250 500 1 B BC (BC)D 2 500 C CD 3 D

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<n;i++) N[i,i] = 0; for(b=1;b<n;b++) for (i = 0; i < n - b ; i++) { j = i + b; N[i,j] = v; for (k = i; k < j ; k++) { sum = N[i, k] + N[k + 1, j] + d[i] * d[k + 1] * d[j + 1]; if (sum < N[i, j]) { N[i, j] = sum; O[i, j] = k; } } Console.WriteLine("Az eredmény= " + N[0, n - 1]); Console.WriteLine("A zárójelezés = " + EXP(0,n-1,O)); Console.ReadLine(); } // Main vége

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).

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?

Ritka mátrixok

4 11 16 2 -1 3 -7 Jelölje a fenti 10x8 –as mátrixot A. Összesen 7 nem nulla eleme van.

10 8 7 1 2 4 3 11 5 16 -1 9 -7 Sorok száma az eredeti A mátrixban Oszlopok száma az eredeti A mátrixban 10 8 7 1 2 4 3 11 5 16 -1 9 -7 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.

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.

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!

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.

RA (A ritka mátrixos alakja) 8 10 7 2 1 4 3 11 5 16 -1 9 -7 10 8 7 1 2 4 3 11 5 16 -1 9 -7 Ez leírja A transzponáltját, de sajnos nem ritka mátrixos forma, mert hiányzik a rendezettség!

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++; }

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 <darab; j++) s[R[j, 1]]++;

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]]++;