Tartalom 7. Dinamikus Programozás(mátrixok lánc szorzása)... 2 8. A játékelmélet alapjai... 7 12 Haladó rendezések 3 (Quick Sort)... 11 13.



Hasonló dokumentumok
Adatbázis rendszerek Gy: Algoritmusok C-ben

AAO 3. Csink László 2007

Programozási módszertan. Mohó algoritmusok

Keresés és rendezés. A programozás alapjai I. Hálózati Rendszerek és Szolgáltatások Tanszék Farkas Balázs, Fiala Péter, Vitéz András, Zsóka Zoltán

Tartalom Keresés és rendezés. Vektoralgoritmusok. 1. fejezet. Keresés adatvektorban. A programozás alapjai I.

Programozási segédlet

Programozási módszertan. Dinamikus programozás: szerelőszalag ütemezése Mátrixok véges sorozatainak szorzása

Fibonacci számok. Dinamikus programozással

Adatszerkezetek. Nevezetes algoritmusok (Keresések, rendezések)

Műveletek mátrixokkal. Kalkulus. 2018/2019 ősz

Alkalmazott modul: Programozás. Programozási tételek, rendezések. Programozási tételek Algoritmusok és programozási tételek

Dinamikus programozás - Szerelőszalag ütemezése

A félév során előkerülő témakörök

Rendezések. Összehasonlító rendezések

Partíció probléma rekurzíómemorizálással

Kupacrendezés. Az s sorban lévő elemeket rendezzük a k kupac segítségével! k.empty. not s.isempty. e:=s.out k.insert(e) not k.

Haladó rendezések. PPT 2007/2008 tavasz.

BBTE Matek-Infó verseny mintatételsor Informatika írásbeli vizsga

Informatika terméktervezőknek

Programozás alapjai II. (7. ea) C++ Speciális adatszerkezetek. Tömbök. Kiegészítő anyag: speciális adatszerkezetek

Speciális adatszerkezetek. Programozás alapjai II. (8. ea) C++ Tömbök. Tömbök/2. N dimenziós tömb. Nagyméretű ritka tömbök

BME MOGI Gépészeti informatika 5.

Alkalmazott modul: Programozás. Programozási tételek, rendezések Giachetta Roberto

Diszkrét matematika I., 12. előadás Dr. Takách Géza NyME FMK Informatikai Intézet takach november 30.

Felvételi tematika INFORMATIKA

A programozás alapjai előadás. [<struktúra változó azonosítók>] ; Dinamikus adatszerkezetek:

Információs Technológia

// keressük meg a legnagyobb faktoriális értéket, ami kisebb, // mint százmillió

1. Feladat: beolvas két számot úgy, hogy a-ba kerüljön a nagyobb

Bánsághi Anna 2014 Bánsághi Anna 1 of 68

Programozás alapjai 9. előadás. Wagner György Általános Informatikai Tanszék

Programozás alapjai II. (7. ea) C++

Felvételi vizsga mintatételsor Informatika írásbeli vizsga

Rekurzív algoritmusok

Kétszemélyes játékok Gregorics Tibor Mesterséges intelligencia

Programozási módszertan. Dinamikus programozás: A leghosszabb közös részsorozat

Webprogramozás szakkör

Struktúra nélküli adatszerkezetek

Objektumorientált Programozás VI.

Programozás I. 1. előadás: Algoritmusok alapjai. Sergyán Szabolcs

Algoritmusok és adatszerkezetek gyakorlat 07

Programozás I. Matematikai lehetőségek Műveletek tömbökkel Egyszerű programozási tételek & gyakorlás V 1.0 OE-NIK,

Alkalmazott modul: Programozás 4. előadás. Procedurális programozás: iteratív és rekurzív alprogramok. Alprogramok. Alprogramok.

ELEMI PROGRAMOZÁSI TÉTELEK

HORVÁTH ZSÓFIA 1. Beadandó feladat (HOZSAAI.ELTE) ápr 7. 8-as csoport

INFORMATIKAI ALAPISMERETEK

BME MOGI Gépészeti informatika 4.

end function Az A vektorban elõforduló legnagyobb és legkisebb értékek indexeinek különbségét.. (1.5 pont) Ha üres a vektor, akkor 0-t..

Programozás I. Metódusok C#-ban Egyszerű programozási tételek. Sergyán Szabolcs

Rendezések. Sergyán Szabolcs Óbudai Egyetem Neumann János Informatikai Kar október 24.

2. Milyen értéket határoz meg az alábbi algoritmus, ha A egy vektor?. (2 pont)

Programozás I. 3. gyakorlat. Szegedi Tudományegyetem Természettudományi és Informatikai Kar

Optimalizációs stratégiák 1.

Ellenőrző kérdések. 36. Ha t szintű indexet használunk, mennyi a keresési költség blokkműveletek számában mérve? (1 pont) log 2 (B(I (t) )) + t

Algoritmusokfelülnézetből. 1. ELŐADÁS Sapientia-EMTE

Adatbázis és szoftverfejlesztés elmélet. Programozási tételek

C# feladatok gyűjteménye

Vezérlési szerkezetek

15. tétel. Adatszerkezetek és algoritmusok vizsga Frissült: január 30.

3. Előadás. Megyesi László: Lineáris algebra, oldal. 3. előadás Lineáris egyenletrendszerek

Algoritmuselmélet 2. előadás

Tömbök kezelése. Példa: Vonalkód ellenőrzőjegyének kiszámítása

Edényrendezés. Futási idő: Tegyük fel, hogy m = n, ekkor: legjobb eset Θ(n), legrosszabb eset Θ(n 2 ), átlagos eset Θ(n).

14. Mediánok és rendezett minták

Egyszerű programozási tételek

Lineáris algebra (10A103)

BME MOGI Gépészeti informatika 1.

Szoftvertervezés és -fejlesztés I.

6. gyakorlat Egydimenziós numerikus tömbök kezelése, tömbi algoritmusok

Legkönnyebb és legnehezebb Rendezési algoritmusok

INFORMATIKA javítókulcs 2016

B-fa. Felépítés, alapvető műveletek. Programozás II. előadás. Szénási Sándor.

Szoftvertechnolo gia gyakorlat

Változók. Mennyiség, érték (v. objektum) szimbolikus jelölése, jelentése Tulajdonságai (attribútumai):

Algoritmusok bonyolultsága

2015, Diszkrét matematika

1. Jelölje meg az összes igaz állítást a következők közül!

Osztott algoritmusok

Programozás alapjai. 5. előadás

KOVÁCS BÉLA, MATEMATIKA I.

Összetett programozási tételek Rendezések Keresések PT egymásra építése. 10. előadás. Programozás-elmélet. Programozás-elmélet 10.

Java II. I A Java programozási nyelv alapelemei

OOP: Java 1.Gy: Java alapok

Kiegészítő részelőadás 1. Az algoritmusok hatékonyságának mérése

A programozás alapjai 1 Rekurzió

Programozás BMEKOKAA146. Dr. Bécsi Tamás 3. előadás

Hatékonyság 1. előadás

Numerikus integrálás

26. MINIMÁLIS KÖLTSÉGŰ UTAK MINDEN CSÚCSPÁRRA

Algoritmusok és adatszerkezetek gyakorlat 06 Adatszerkezetek

Gauss elimináció, LU felbontás

BABEŞ BOLYAI TUDOMÁNYEGYETEM MATEMATIKA ÉS INFORMATIKA KAR BBTE Matek-Infó verseny 1. tételsor INFORMATIKA írásbeli. A versenyzők figyelmébe:

Nyerni jó évfolyam

Alapok. tisztán funkcionális nyelv, minden függvény (a konstansok is) nincsenek hagyományos változók, az első értékadás után nem módosíthatók

Smalltalk 2. Készítette: Szabó Éva

Branch-and-Bound. 1. Az egészértéketű programozás. a korlátozás és szétválasztás módszere Bevezető Definíció. 11.

Mesterséges intelligencia 3. laborgyakorlat

Algoritmusok vektorokkal keresések 1

Adatszerkezetek I. 7. előadás. (Horváth Gyula anyagai felhasználásával)

Algoritmusok és adatszerkezetek gyakorlat 03 Oszd meg és uralkodj. Nagy

Átírás:

Tartalom 7. Dinamikus Programozás(mátrixok lánc szorzása)... 2 8. A játékelmélet alapjai.... 7 12 Haladó rendezések 3 (Quick Sort)... 11 13. Ritka Mátrix... 14 14. Strassen mátrix szorzás... 18 AAO-s rendezések... 21 AAO-s egyéb kódok... 26 1

7. Dinamikus Programozás(mátrixok lánc szorzása) Dinamikus Programozásról általánosságban A dinamikus programozás hasonlóan, mint az oszd meg és uralkodj módszer, a feladatot részfeladatokra való bontással oldja meg. Az oszd meg és uralkodj módszer felosztja a feladatot független részfeladatokra, melyeket ismételten megold, és a részfeladatok megoldását az eredeti feladat megoldása céljából egyesíti. Ezzel szemben a dinamikus programozás akkor alkalmazható, ha a részproblémák nem függetlenek, azaz közös részproblémáik vannak. Ilyen helyzetben az oszd meg és uralkodj módszer a szükségesnél többet dolgozik, mert ismételten megoldja a részproblémák közös részproblémáit. A dinamikus programozás minden egyes részfeladatot és annak minden részfeladatát pontosan egyszer oldja meg,, az eredményt egy táblázatban tárolja, és ezáltal elkerüli az ismételt számítást, ezt használja fel ha a részfeladattal számítást kellene végezni. Optimalizálási feladatok megoldására használjuk. Ezeknél a feladatoknál a sok részfeladat lokális optimuma helyett egy globális optimum megkeresése a cél. Egy dinamikus programozási algoritmus kifejlesztése négy lépésre bontható fel: 1. Jellemezzük az optimális megoldás szerkezetét 2. Rekurzív módon definiáljuk az optimális megoldás értékét. 3. Kiszámítjuk az optimális megoldás értékét alulról felfelé történő módon. 4. A kiszámított információk alapján megszerkesztünk egy optimális megoldást Mátrix szorzás Két mátrix szorzata akkor definiált, ha a bal oldali mátrix oszlopainak száma megegyezik a jobb oldali mátrix sorainak számával. az eredménymátrixot úgy kapjuk, hogy a sorában lévő elemeket páronként összeszoroztuk az oszlopában lévő elemekkel, majd összeadjuk őket. Mátrixszorzás(A, B) Ha (oszlop(a) sor(b)) akkor Kiír( nem összeillő dimenzió ) Egyébként for i 1 to sorokszama(a) do for j 1 to oszlopokszama(b) do for k 1 to oszlopokszama(a) do C[i,j] C[i,j] + A[i,k] * B[k,j] Elágazás vége Mátrixszorzás C Eljárás vége // A összes során menjen végig. // B összes oszlopán menjen végig // indítok egy ciklust ahol k az A oszlop hossz. // szummázom az összeszorzott tagokat. // visszaadom az eredmény tömböt 2

Adott n darab mátrix (A 1,A 2,,A n ) és ezek szorzatát szeretnénk kiszámítani. A mátrixok szorzása asszociatív, így bármilyen zárójelezés ugyanazt az eredményt adja. Az a mód, ahogy egy szorzatot zárójelezünk, alapvetően befolyásolja a kifejezés kiértékelésének költségét és idejét. Probléma megfogalmazása : A szorzás asszociációja (szabadon zárójelezhetősége) miatt a mátrixok láncszorzásánál felmerül a kérdés, hogyan lehet a műveletvégzésre optimalizálni a feladatot (vagyis a kiszámítás sebességére). Például: 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 mátrix láncszorzás célja, hogy próbáljuk megkeresni az összes zárójelezését mindegyikre számítsuk ki a műveletek számát és ezek közül válasszuk ki a legjobbat A szorzás során felhasználható összes zárójelezhetőség a 4 n exponenciális függvény alakjára hasonlít viszonylag kevés érték esetén is már hatalmas vizsgálandó számítási halmazt eredményez. Ez a fajta megközelítése a problémának viszonylag hamar véges időn belül kiszámíthatatlan nagyságú műveleti halmazt eredményez. Optimális megoldás keresésére más módszert kell keresnünk. Erre a célra két megközelítés terjedt el. Mohó megközelítés: A mohó algoritmus vagy greedy algoritmus az a problémamegoldó algoritmus, amely helyi optimumok megvalósításával próbálja megtalálni a globális optimumot. Brutális módszer Kiszámítja az egyes mátrixok összeszorzása esetén végzendő szorzások számát. A kiszámított szorzás műveletek darabszámának minimalizálásával találja meg az optimális szorzási művelet számot. A futási idő a mátrixok számának növekedésével exponenciálisan növekszik. Viszonylag kevés mátrix esetén is már kiszámíthatatlan időt produkál. Brutális módszer alapjai: Keressük meg a legjobb zárójelezését ennek: AiAi+1 Aj. Legyen N[i,j] = ezen részprobléma műveleti igénye. A teljes probléma optimális megoldása N[0,n-1] képződik. A teljes probléma kört részproblémákra bontjuk. A részproblémák optimális megoldása alapján fogjuk megkapni a globális optimumot. Abból a feltevésből indulunk ki, hogy kell lennie utolsó optimális megoldásnak. Feltesszük, hogy ez a k-ik helyen van így a teljes alap halmazt két kisebb probléma körre bontjuk amelyben a vizsgálatot hasonló képen tovább bontva kapjuk a megoldást. ( optimális lépés N[i,k] N[k+1,j] ahol az i az első elem a j pedig az utolsó) Ezt dolgot az alproblémák átfedése miatt lehet így megközelíteni. Képletben : N i, j = j+ i k< j min Ni, k + Nk+ 1, j + didk+ 1d 1 3

// bemenő paraméterek minden rendezésnél // S rendezendő tömb vagyis így S = 10, 5, 10, 3, 10 // mátrixos formában a lásd: Mátrix1= 10x5, Mátrix2= 5x10, Mátrix3= 10x3, Mátrix4= 3x10 // n az S tömb hossza -1, mert csak 4 mátrix generálható // O a segédmátrix ami majd a zárójelezés kiíratásához kell static double MatrixChain(int[] S, out int[,] O) int n = S.Length - 1; double[,] N = new double[n, n]; O = new int[n, n]; for (int b = 1; b < n; b++) for (int i = 0; i < n - b; i++) int j = i + b; N[i, j] = Double.PositiveInfinity; for (int k = i; k < j; k++) double sum = N[i, k] + N[k + 1, j] + S[i] * S[k + 1] * S[j + 1]; if (sum < N[i, j]) N[i, j] = sum; O[i, j] = k; return N[0, n - 1]; static void Main(string[] args) int[] S = 10, 5, 10, 3, 10 ; int[,] O; Console.WriteLine("Az eredmény= " + MatrixChain(S, out O)); Console.WriteLine("A zárójelezés = " + EXP(0, O.GetLength(1) - 1, O)); Console.ReadLine(); static string EXP(int i, int j, int[,] O) int k; string s1, s2; if (i == j) return "A" + i; else k = O[i, j]; s1 = EXP(i, k, O); s2 = EXP(k + 1, j, O); return "(" + s1 + s2 + ")"; 4

Eljárás Kiiratás(i, j, O) Ha (i=j) akkor return A + i egyébként k O[i, j] s1 Kiiratás(i, k, O) s2 Kiiratás(k+1, j, O) return ( + s1 + s2 + ) Elágazás vége Eljárás vége Megoldásnak a menete vesz egy szumma adattagot amiben eltárolja az adott elem alatti és egyel balra lévő elemek valamint a végzendő szorzások számát összegét. Megvizsgálja, hogy az adott cellában ennél kisebb vagy nagyobb összeg szerepel-e Ha kisebb akkor kicseréli, ha nagyobb akkor nem csinál semmit. Először a főátló feletti elemeket számolja ki majd átlósan haladva tovább a többit a korábbiakból. Az optimális szorzás szám az A[0, n-1]-es mezőbe képződik(jobb felső sarok) Az O[] ben a pirossal karikázott értékek kerülnek tárolásra. Példa : Mohó: Az ötlet szerint legjobb A((BC)D) 109989+9900+108900=228789 szorzás Brutális: Mohónál jobb: (AB)(CD) 9999+89991+89100=189090 szorzás Brutális vs. Mohó A mérete 101 11 B mérete 11 9 C mérete 9 100 D mérete 100 99 5

Irodalom jegyzék http://hu.wikipedia.org/wiki/moh%c3%b3_algoritmus http://nik.bmf.hu/csink/aao/aao_folytat%e1s++.ppt 6

8. A játékelmélet alapjai. Stratégia: Cselekvések egy hosszabb távú terve egy bizonyos cél elérésé érdekében. A stratégia szerinti cselekvést utasítás rendszerként is felfoghatjuk, e rendszer az alkalmazási terület minden lehetséges helyzetére végrehajtandó előírásokat tartalmaz. Stratégia alkotás során a stratégia megalkotójának fel kell mérnie és előre mérlegelnie kell a lehetséges helyzeteket, a lehetséges helyzetekben választható döntési lehetőségeket és a döntések által elérhető nyereségeket. Nyerő stratégia: Olyan stratégia, amelyet alkalmazva az alkalmazó a célját biztosan eléri. Elsősorban játékok esetén szokták használni, segítségével a játék végén a nyerő stratégiát alkalmazó személy nyeri meg a játékot. Vagyis nyerő stratégiát alkalmazva a stratégiát alkalmazó személy biztosan nyer. Amennyiben a játék kimenetelében a döntetlen nem megengedett, akkor az egyik játékosnak biztosan van nyerő stratégiája. Az ilyen játékokat egyszerű játékoknak hívjuk. Játékfa: Célunk az, hogy olyan algoritmust írjunk le, amely egy igen széles körű játékosztályban lévő bármely játékra alkalmazható, és amely minden játékos számára a lehetséges stratégiák közül a "legjobbat" állapítja meg. Az egyszerű játékok szabályai : 1. Minden játékban két játékos vesz részt, akik felváltva lépnek. 2. Minden játszmának csak egy kimenetele lehet: A kezdőjátékos A nyer (+), vagy a B játékos nyer(-). 3. A játékos minden lépésben kiválaszt egy variánst a lehetőségek összességéből úgy, hogy választásában nem jut szerephez a véletlen (pl. nem a dobókockás eredményét használja fel). 4. Minden lépéskor a játékos ismeri a játszma összes eddigi lépésének eredményét. Tizenegy gyufaszál játék 11 gyufaszál van az asztalon. Az első játékos ezekből elvehet tetszés szerint 1, 2 vagy 3 db gyufaszálat, ezután a második játékos vehet fel tetszés szerint 1, 2, vagy 3 gyufaszálat és így tovább. Minden alkalommal a soron levő játékos legfeljebb 3 gyufaszálat (köteles). Az veszít, aki az utolsót veszi el. Megteheti-e a kezdő játékos, A, hogy partnerét B-t arra kényszerítse, hogy ő vegye fel az utolsó szál gyufát? A játék elemzése azt mutatja, hogy az A játékos a következő utasításrendszert követve elérheti, hogy B-nek kelljen az utolsó gyufaszálat elvennie: 1. A felvesz 2 gyufaszálat 2. ha B az előző lépésben k gyufaszálat vett el, és még maradt gyufa, akkor A 4-k gyufaszálat vesz el. Ilyen esetben mindenképp A nyer, ha ő kezdett, stratégiája nyerő stratégia lesz. A B A B A B 2 2 2 1 3 1 A B A B A B 2 3 1 1 3 1 7

Ha A az első lépésben 1 vagy 3 gyufát vesz fel, akkor B képes úgy irányítani a játékot, hogy biztosan ő nyerjen. Páros győz játék 27 gyufaszálból a két játékos felváltva vesz legalább 1 és legfeljebb 4 szálat. Az győz, akinél a végén páros számú gyufaszál gyűlik össze. Itt is csak a kezdőjátékos számára van nyerő stratégia: 1. A vesz két gyufaszálat 2. ha B-nek páros számú gyufája van: az ellenfélnek annyi gyufaszálat kell hagyni, hogy azok száma 6-tal osztva 1 maradékot adjon (19, 13, 7). Ha ez nem lehetséges, akkor 5 megmaradt gyufából 4-et, 3-ból 2-t kell elvenni. 3. ha B-nek páratlan számú gyufája van: az ellenfélnek hagyott gyufák száma 1-gyel kisebb legyen 6 valamelyik többszörösénél (23, 17, 11, 5). Ha ez lehetetlen, akkor 6 többszöröse maradjon. Ha ez is lehetetlen, akkor az 1 vagy 3 megmaradt gyufaszálat mind el kell venni. A B A B A B A B A B A B 2 1 1 3 1 3 4 1 4 2 4 1 11 tárgy játék -> 6 tárgy játékfával 6 gyufaszál van az asztalon, ketten felváltva játszanak, 2 vagy 1 gyufaszálat kell felvenni. Az veszít, aki az utolsó gyufaszálat veszi el. A fa pontjai (csúcsai) azokat a különböző helyzeteket jelentik, amelyek a játékszabályok szerint lefolyt játszmában előfordulhatnak. Az egyes pontokból induló élek a rákövetkező lépésben lehetséges variánsokat szemléltetik. Jelen esetben bármely lépésben (az utolsó kivételével) két variáns lehetséges. A baloldali ág 1, a jobboldali ág a 2 gyufaszál húzásának felel meg. Egy játszmát olyan út szemléltet, amely a fa legalsó alfa pontjából (gyökérpont) indul, és olyan pontban végződik, amelyből már nincs kiinduló él (végpont). Minden lépésben megfelel egy, az adott pontból induló élen valamelyik felette lévő pontba való átmenet. A játszmák végeredményét a bekarikázott + ill - jelenti. A képen a bevonalkázott játszma: A B A B 2 1 2 1 Ebben a játszmában A győz. 8

A fa pontjaihoz (a végpontok kivételével) rangot rendelünk. Ezek közül a legnagyobbat a fa rangjának nevezzük: ez az adott játékban előforduló leghosszabb játszma hosszát adja meg. A páratlan rangú csúcsok szemléltetik azokat a helyzeteket, amelyekben az A kezdőjátékos lép, a párosak pedig B lépéseit jelzik. Nyerő stratégia létezése: Tétel: Minden egyszerű játékban van az egyik játékosnak nyerő stratégiája. Az algoritmus felépítését a játékban előforduló leghosszabb játszma v hosszára vonatkozó indukcióval végezzük (v megegyezik a játék fájának rangjával) A v=1 eset: ekkor minden játszma egy lépésből áll. Áttérés (v-1)-ről v-re: tegyük fel, hogy a tételt minden v-nél kisebb rangra már bebizonyítottuk, igazoljuk most v-re. Ebben az esetben a háromszögek olyan részfákat jelölnek, amelyeknek gyökérpontjai az egész fa alfával jelölt gyökérpontjához csatlakozó v1, v2...vn pontok. Tegyük fel, hogy az alfa azt az esetet ábrázolja, amikor A lép. Ekkor a 1, 2 n részfákkal jellemzett játékokban B lép először, és a leghosszabb játszma mindegyikében legfeljebb v-1 hosszúságú lehet. A végpontokból, azaz a magasabb rangú pontoktól az alacsonyabb rangú pontok felé haladva az egyes pontokhoz a + ill. - jeleket írtuk attól függően, hogy a megfelelő részjátékban A-nak ill. B-nek van e nyerő stratégiája. Ez az alkalmazás olyan játékokra is érvényes, ahol a két játékos A ill B győzelmén kívül döntetlen is előfordulhat, de ekkor az előző algoritmus mindegyik játékosnak egy olyan stratégiát ad, amelynek alapján legalább döntetlent érhet el. 9

Sakk A sakkra a játékfa nehezen alkalmazható, gyakorlatban nem szerkeszthető meg, hiszen a sakkjáték fájának gyökérpontjából 20 él indul ki, amelyek a fehér lehetséges kezdőlépéseit szemléltetik. Innen rengeteg él indul tovább. Mivel a sakk végződhet döntetlenre (pl. csak a két király marad a táblán, és egymás elől menekülnek), ezért a sakkban nincs nyerő stratégia, legfeljebb döntetlen, vagyis ha mindkét játékos tökéletesen játszik, akkor döntetlen lesz az eredmény. 10

12 Haladó rendezések 3 (Quick Sort) QuickSort A QuickSort (gyorsrendezés) összehasonlító rendezési algoritmus, és a partícionáló-cserés rendezések családjába tartozik. Helyben rendező, nem stabil rendezés. (Stabil változata is létezik, aminek Ω(n) extra tárigénye van, nem helyben rendező.) Általában rekurzív módon van megvalósítva, mert úgy gyorsabb, viszont fennáll a veremtúlcsordulás veszélye. Ez ellen általában úgy védekeznek, hogy csak egy bizonyos mélységig megy a rekurzió, és a kisebb listákat már valamilyen más rendezéssel rendezik a végén, például beillesztéses rendezéssel, vagy kupacrendezéssel (ezt nevezik Introsort-nak). A QuickSort könnyen párhuzamosítható, ha az al-listák előfeldolgozásának idejét nem vesszük figyelembe, lineáris sebességnövekedést lehet elérni a processzorok számának függvényében. Futásidő: - Átlagos eset: O(n * log n) - Legjobb eset: O(n * log n) - Legrosszabb eset: O(n 2 ) A gyorsrendezés oszd meg és uralkodj elven működik: a rendezendő számok listáját két részre bontja, majd ezeket a részeket rekurzívan, gyorsrendezéssel rendezi. A felbontáshoz kiválaszt egy támpontnak nevezett elemet (más néven pivot, főelem vagy vezérelem), és partícionálja a listát: a vezérelemnél kisebb elemeket bal oldalára, a nagyobbakat jobb oldalára mozgatja. Ekkor a vezérelem a végső helyére kerül. A vezérelemtől balra, az első elemig lesz egy új partíció, valamint a vezérelemtől jobbra az utolsó elemig is lesz egy új partíció. Ezekre az új partíciókra is meghívjuk a gyorsrendezést (a régi vezérelem nem szerepel már egyik partícióban sem, az már a végső helyén van, helyette új vezérelemet választunk minden új partícióban). Teljes indukcióval könnyen belátható, hogy ez az algoritmus helyesen működik. Az egyik legegyszerűbb megoldás, ha a vezérelemet a legelső elemnek választjuk, ekkor azonban O(n 2 ) lesz a futásidő, ha a lista már eleve rendezett. Megoldás lehet például, ha a vezérelemet véletlenszerűen választjuk ki; vagy a partíció középső elemét választjuk; vagy kiválasztjuk az első, középső és utolsó elemet, ezeket rendezzük, és a középsőt használjuk fel vezérelemnek ( Median-of- Three partitioning ). C# kód: A cserét végző metódus: static void Swap(ref int a, ref int b) int t = a; a = b; b = t; 11

A partícionáló metódus: static int GetPivot(int[] a, int left, int right) int pivotindex = left; int pivotvalue = a[pivotindex]; for (int i = left + 1; i <= right; i++) if (a[i] < pivotvalue) pivotindex++; Swap(ref a[pivotindex], ref a[i]); Swap(ref a[left], ref a[pivotindex]); return pivotindex; QuickSort: static void QuickSort(int[] a, int left, int right) if (left < right) int pivotindex = GetPivot(a, left, right); QuickSort(a, left, pivotindex - 1); QuickSort(a, pivotindex + 1, right); Meghívása: QuickSort(a, 0, a.length - 1); 12

QuickSort nem rekurzív megvalósítása: C# kód static void Lovasz_Gacs(int[] K) int i, n, L, M, KVIZSG, csere; n = K.Length; int[] T = new int[n]; eleje: for (i = 0; (i < n) && (T[i]!= 0); i++) ; // van e 0 a T tömbben? if (i!= n) // van, meghatározzuk az új partíciót L = i; // partíció első eleme (első 0) for (i = L; (i < n) && (T[i] == 0); i++) ; // első 0 utáni első 1-es M = i - 1; // partíció utolsó eleme (egymás utáni 0-k utolsó 0-ja) KVIZSG = K[L]; // KVIZSG a vezérelem, ami a helyére kerül // partícionálás elkezdése: bal_ciklus: if (L == M) T[L] = 1; goto eleje; // a vezérelem a helyére került if (KVIZSG < K[M]) M--; goto bal_ciklus; // ha jó a sorrend előre csere = K[L]; K[L] = K[M]; K[M] = csere; // másik oldalra tevés L++; goto jobb_ciklus; // csere volt, a másik irányban vizsgálunk innentől jobb_ciklus: if (L == M) T[L] = 1; goto eleje; // a vezérelem a helyére került if (KVIZSG > K[L]) L++; goto jobb_ciklus; //ha jó a sorrend előre csere = K[L]; K[L] = K[M]; K[M] = csere; // másik oldalra tevés M--; goto bal_ciklus; // csere volt, a másik irányban vizsgálunk innentől A T tömb az elején csupa 0-ból áll. Ha egy vezérelem a helyére kerül, akkor a vezérelem K-beli indexénél a T-tömbben a 0 1-esre változik. Ez a 0-kat egy bal és egy jobb oldali részre osztja, keletkezik két új partíció. Megvizsgáljuk, van e még olyan elem ami nincs a helyén. Ha van, akkor meghatározunk egy új partíciót a még rendezetlen elemekből. A partíciót partícionáljuk (vezérelemnél kisebbek vezérelemtől balra, nagyobbak jobbra), a vezérelem a helyére kerül. Ezeket a lépéseket addig ismételjük míg minden elem a helyén lesz, T tömb csupa 1-esből fog állni. Ha jó a sorrend előre: azt jelenti, hogy a vizsgált elem a megfelelő oldalán van a vezérelemnek. Ha a vizsgált kisebb, mint a vezérelem, akkor bal oldalt, egyébként jobb oldalt. 13

13. Ritka Mátrix A mátrix egy matematikai objektum. Sorokból és oszlopokból áll, amelyek számokat tartalmaznak. Programozói nyelven a mátrix egy kétdimenziós tömb. (A[1..m, 1..n]). Amikor egy elemre rá akarunk mutatni, azt könnyen megtehetjük, a következő módon: A[m, n], vagyis arra a számra mutatunk, ami az m-edik sor n-edik eleme. Multidimenzionális On Line Analitical Processing (MOLAP) alkalmazások esetében adatainkat speciális multidimenzionális struktúrában tároljuk(kockákban). Amennyiben az adatmátrixunk ritka, tehát az adatok a kockán belül szétszórtan helyezkednek el, a kocka a hasznos adat mennyiségéhez képest nagy területet foglalhat el. Ennek oka, hogy az előre felépített indexstruktúra miatt a háttértáron előre helyet kell foglalni a kocka egészének. Sok dimenzió és nagy kiterjedésű dimenziók esetén ez akár oda is vezethet, hogy az adatbázis használhatatlanul naggyá válik. A ritka mátrix probléma kezelésére egyes multidimenzionális adatbáziskezelők tartalmaznak ún. ritka mátrix algoritmust, amely a kocka szerkezetéből megpróbálja a nem használt részeket kiszűrni, és a nekik fenntartott helyet felszabadítani, így elkerülve a mátrix kezelhetetlen naggyá válását. A probléma ismertetése : Adott egy vagy több dimenziós nagy méretű mátrix amelyben sok a nulla elem hogyan tároljuk tárhely kapacitás hatékonyan? A tapasztalatok szerint 40%-nál kevesebb nem zérus elem esetén érdemes már nem az egész tömböt eltárolni hanem ritka mátrixos formát használni. Ritka mátrixnak nevezzük azt a mátrixot amely három oszlopból és n+1 sorból áll ahol az n az eredeti tömbben lévő nem nulla elemek számát jelöli. A ritka mátrix egyik fontos tulajdonsága, hogy az elemeket sorfolytonosan tároljuk. 14

Az A[0, y] elem a fejléc, tartalmazza, hogy mennyi az eredeti mátrix sorainak, oszlopainak és elemeinek száma. Az A[1, y] és A[2, y] elemek tartalmazzák az eredeti mátrixból átvett nem 0 elemek tulajdonságait. Ezek a sorok az első mező szerint rendezve vannak (egyenlőség esetén a második sor szerint is). Normál mátrix (A) átalakítása ritka formátumúvá (R) 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++; // nem nulla elemek összeszámolása 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; Ritka mátrix (R) visszaalakítása normál formátumúvá (N) static int[,] ritka2normal(int[,] R) int[,] N = new int[r[0, 0], R[0, 1]]; for (int i = 1; i <= R[0, 2]; i++) N[R[i, 0], R[i, 1]] = R[i, 2]; return N; 15

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! Ritka mátrix transzponáltjának előállítása Egy mátrix transzponálása a főátlóra való tükrözést jelenti Nem lehet egyszerűen a sorokat felcserélni az oszlopokkal, mert akkor nem lesz sorfolytonos. (vagyis a transzponáltat még rendezni is kell sorai szerint.) int[,] A = new int[10, 2]; // az eredeti tömb // beleírunk néhány értéket, hogy ne csupa 0 legyen A[3, 0] = 4; A[5, 1] = 9; A[1, 1] = 9; A[8, 1] = 6; int[,] R = normal2ritka(a); // ritka mátrixszá alakítva int n = R.GetLength(0); // A nem nulla elemeinek száma + 1 int m = R.GetLength(1); // m == 3 // transzponálás kezdése 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 (int j = 0; j < R[0, 1]; j++) // j R oszlopain megy végig for (int 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++; 16

Gyorsított 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; // sorok száma int[] s = new int[r[0, 1]]; // oszlopok száma // Ezután a leszámláló rendezést alkalmazzuk, // ez azért jó mert stabil, rendezett marad a mátrix // soronként, és azon belül oszloponként is // 1. lépés // összeszámoljuk, hogy melyik oszlopból mennyi van for (int i = 1; i < darab; i++) s[r[i, 1]]++; // 2. lépés // pozíciók előkészítése for (int i = 1; i < s.length; i++) s[i] += s[i - 1]; // 3. lépés // leszámlálás for (int i = R[0, 2]; i > 0; i--) TR[s[R[i, 1]], 0] = R[i, 1]; TR[s[R[i, 1]], 1] = R[i, 0]; TR[s[R[i, 1]], 2] = R[i, 2]; s[r[i, 1]]--; Felhasznált irodalom: http://www.tankonyvtar.hu/konyvek/numerikus-modszerek-1/numerikus-modszerek-1-1- 081029-24 http://nik.uni-obuda.hu/csink/aao/ritka_matrixok.ppt http://scs.web.elte.hu/work/dw/adattarhazak.htm 17

14. Strassen mátrix szorzás Strassen algoritmusa csökkenti a szorzások számát az összeadások rovására. Mivel a szorzás költségesebb művelet, mint az összeadás, az algoritmus gyorsabb a hagyományos mátrixszorzási algoritmusnál. Csak n*n-es mátrixokra (négyzetes mátrixokra) alkalmazható, ahol az n 2 valamilyen hatványa. Strassen felhasználásával O(n 2.81 ) lépésben szorozhatunk össze. Ez tehát elég nagy n-re gyorsabb, mint az O(n 3 ) igényű mátrixszorzási algoritmus. Egy 2*2-es mátrixon szemléltetve a következő képen kaphatjuk meg: A és B az összeszorzandó mátrixok C pedig az eredmény mátrix Az eredeti mátrix szorzása ezen műveletek végrehajtása során adja a kívánt eredményt. A mátrix szorzás gyorsítása érdekében lecsökkentjük a szorzások számát és növeljük az összeadások számát. A Strassen segédváltozókat vezet be ezek a következők lesznek: 18

A segéd változók felhasználásával elő állítjuk az eredmény halmazt. Minden 2*2-es nél nagyobb méretű mátrix esetén, amelyek megfelelnek a Strassen algoritmus feltételének a szorzást úgy hajtjuk végre, hogy addíg bontjuk fel a mátrixot kettő kisebb hatványaira rekurzív módon amíg 2*2-es mátrixokat nem kapunk. A rekurzió egyes lépéseiben a rész-mátrixokat is a strassen algoritmus segítségével szorozzuk össze, így a lépésszám-csökkenés még jelentősebb lesz. Ha mátrix nem olyan négyzetes mátrix, amelyben sorainak és/vagy oszlopainak száma nem kettő hatványa, akkor a mátrix sorait és/vagy oszlopait kiegészítjük 0 elemekkel úgy, hogy kettő hatványai legyenek.(az eredmény a nulla elemek bevezetésével nem fog változni. Strassen-algoritmus használhatóságát a futási idejének képletében foglalt nagy konstans megkérdőjelezi, hacsak nem nagy méretű (n>=45), vagy sűrű (kevés nem 0 elemet tartalmazó) mátrixról van szó. Kis mátrixok esetén a szokásos algoritmus használata célszerűbb, míg nagyméretű, ritka mátrixokra a speciális technikák alkalmazhatóak előnyösebben. Így Strassen módszere főleg elméleti jellegű. Strassen algoritmusának alkalmazásához nem feltétel, hogy a mátrix elemei valós számok legyenek. 19

A Strassen-algoritmus gyakorlati alkalmazását az alábbi tényezők korlátozzák: 1. Az eljárás futási idejének képletében rejlő állandó nagyobb, mint a hagyományos módszer O(n3) képletében foglalt állandó 2. A ritka mátrixokra kidolgozott speciális algoritmusok gyorsabbak 3. A Strassen-algoritmus numerikusan kevésbé stabil, mint a hagyományos módszer. 4. A rekurziós lépések során a részmátrixok tárolása a memóriában helyet igényel. Felhasznált irodalom: http://en.wikipedia.org/wiki/strassen_algorithm 20

AAO-s rendezések Kerti törpe rendezés Elindul a sorozat elejéről a vége felé, egészen addig, míg egy olyan elemet talál, ami kisebb mint az előző, tehát nincs sorrendben. Ekkor az előtte lévővel megcseréli, így azok már rendezve lesznek. Azonban így az egyel előbbit is újra kell vizsgálni, mert az átmozgatott elem nem került feltétlen a helyére. Lehetséges, hogy egészen a sorozat legelejéig vissza kell menni. Ezután megint elindul előre, és addig folytatja ezt a módszert, amíg a sorozat végére ér. Javítani lehetne az algoritmust, ha megjegyeztetnénk a törpével, hogy hol találta az aktuális problémás elemet. Így nem kellene visszasétálnia egyesével oda ahonnan visszafordult, hanem rögtön visszateleportálhatna, hiszen odáig már csere nélkül visszajutna egyébként is. Ekkor a beillesztéses rendezés egyik változatává válna. C# kód: static void Swap(ref int a, ref int b) int t = a; a = b; b = t; static void GnomeSort(int[] a, int n) int pos = 0; while (pos < n) if (pos == 0 a[pos - 1] <= a[pos]) pos++; else Swap(ref a[pos - 1], ref a[pos]); pos--; 21

Koktélrendezés A buborékrendezés egyik módosított változata, ahol egyszer balról jobbra, aztán jobbról balra megyünk végig a sorozat elemein. Ezáltal a sorozat végén lévő kis elemek hamarabb a helyükre kerülnek. A rendezés stabil marad. Tehát például először balról jobbra vizsgáljuk az elemeket, és közben cserélgetünk, ha szükséges. Ha történt csere azt megjegyezzük, mert ha nem történt, akkor már rendezve van a sorozat, tehát felesleges jobbról balra is megvizsgálni még egyszer (vagy a másik irányba, ezért a főciklusnak két kilépési pontja lesz). Minden végigpásztázás után csökkentjük egyel a vizsgálandó tartomány hosszát, mivel egy elem mindig a helyére kerül: a vizsgált tartomány elejére vagy végére, a pásztázás irányától függően. C# kód: static void CocktailSort(int[] a, int n) int begin = 0; int end = n - 1; bool swapped; do swapped = false; for (int i = begin; i < end; i++) if (a[i] > a[i + 1]) Swap(ref a[i], ref a[i + 1]); swapped = true; end--; if (!swapped) break; swapped = false; for (int i = end; i > begin; i--) if (a[i] < a[i - 1]) Swap(ref a[i], ref a[i - 1]); swapped = true; begin++; while (swapped); 22

Fésűs rendezés A koktélrendezéshez hasonlóan, itt is a lassan helyére kerülő elemek problémájára találunk megoldást. Itt is egy logikai változó jelzi majd, hogy rendezett e már a sorozat. A gap használata hasonló célt szolgál, mint a Shell rendezésnél a lépésköz, csak itt nem a beillesztéses rendezés van továbbfejlesztve, hanem a buborékrendezés. A gap beállításával először a távol levő elemeket rendezzük. Ezután a gap csökken, míg végül 1 lesz. Ez esetben azonos a program a buborékrendezéssel; következésképpen korrekt. Stephen 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ő. A gap legalább 1 kell hogy legyen. A gyakorlatban közel olyan gyors mint a gyorsrendezés, és az eleve rendezett sorozat esetében gyorsabb is. C# kód: static void CombSort(int[] a, int n) int gap = n; bool swapped = false; while (gap > 1 swapped) gap = (int)(gap / 1.3); gap = gap < 1? 1 : gap == 10 gap == 9? 11 : gap; swapped = false; for (int i = 0; i + gap < n; i++) if (a[i] > a[i + gap]) Swap(ref a[i], ref a[i + gap]); swapped = true; 23

Galambdúc rendezés Nem helyben rendező, stabil, nem összehasonlító rendezés. Az átlagos és a legrosszabb futásideje is O(n+2 k ). Memóriaszükséglete O(2 k ). Ahol az elemszámot n jelöli, k pedig a kulcsok méretét. A kulcs méretének elég nagynak kell ahhoz lennie, hogy minden elem egyedi kulccsal rendelkezhessen. Szükségünk lesz egy segéd tömbre, ami a galambdúc. Egy galambdúc az egy nagy szekrény lyukakkal, a lyukakban lehetnek a galambok. Egy lyukba több galamb is kerülhet, vagy akár egy se. Az eredeti tömbünk, amit rendezni akarunk, abban vannak a galambok. Minden galambnak azonosítója (kulcsa) van, ami szerint rendezni szeretnénk. Jelen példában a galambok egész számok lesznek, a számok maguk lesznek a kulcsok is. Ezért a segédtömbünk egy adott indexű elemébe több ugyanolyan értékű szám is kerülhet (ha például 2 darab 5-ös is van az a tömbben), ezért a segédtömb egy rekeszében (indexe alatt) az abban lévő számok (galambok) számát tároljuk. 1. Határozzuk meg a segédtömb méretét. Ez a legnagyobb kulcs és a legkisebb kulcs különbsége plusz egy lesz. 2. Az eredeti tömbön végigmegyünk, és az elemeket átrakjuk a segédtömbbe. Az elem indexe a segédtömbben az elem kulcsa lesz, eltolva a legkisebb kulcs értékével, hogy 0-tól kezdődhessen a segédtömb indexelése. Az átrakás úgy valósul meg, hogy növeljük a rekeszben (a segédtömb egy elemében) lévő szám értékét egyel. Így több azonos kulcsú elem is lehet egy rekeszben. 3. A segédtömbből visszamásoljuk az elemeket az eredeti tömbbe, szép sorban, és ha egy rekeszben több azonos kulcsú elem volt, akkor azok egymást fogják követni (egyenlő számok). Egy rekeszben csak azonos kulcsú elemek lehetnek, a kérdés csak az, hogy mennyi van benne. Visszamásolásnál korrigálni kell az index eltolásból fakadó kulcsérték változást. Így az eredeti tömb rendezve lesz. Az eredeti tömb egy rekeszében természetesen csak egy elem lehet. holes: a galambdúc, a segédtömb room: egy a lyuk (szoba) a galambdúcban, amikben galambok lehetnek. A segédtömb egy rekesze, amiben egy szám van, ami azt jelzi mennyi azonos kulcsú elem van benne. 24

C# kód: static void PigeonHoleSort(int[] a, int n) //.NET 3.0 //int min = a.min(); //int max = a.max(); int min = a[0]; int max = a[0]; foreach (int x in a) min = Math.Min(x, min); max = Math.Max(x, max); int size = max - min + 1; int[] holes = new int[size]; foreach (int x in a) holes[x - min]++; int i = 0; for (int room = 0; room < size; room++) while (holes[room]-- > 0) a[i++] = room + min; 25

AAO-s egyéb kódok Itt a tömbben a sokszög pontjainak a koordinátái vannak megadva. Az első érték az első pont x koordinátája, a második értél az első pont y koordinátája, a harmadik érték a második pont x koordinátája és így tovább Háromszög területe (Heron képlet): double Heron(double x1, double y1, double x2, double y2, double x3, double y3) double s, d1, d2, d3; d1 = Szakasz(x1, y1, x2, y2); d2 = Szakasz(x2, y2, x3, y3); d3 = Szakasz(x1, y1, x3, y3); s = (d1 + d2 + d3) / 2.0; return Math.Sqrt(s * (s - d1) * (s - d2) * (s - d3)); double Szakasz(double x1, double y1, double x2, double y2) return Math.Sqrt(Math.Pow(x1 - x2, 2) + Math.Pow(y1 - y2, 2)); Konvex sokszög területe: double[] tomb = 1.0, 0.0, 0.0, 2.0, -1.0, 0.0, 0.0, -3.0 ; int n = tomb.length; double x, y, x1, y1, x2, y2, terulet = 0; x = tomb[0]; y = tomb[1]; for (int i = 2; i + 3 < n; i += 2) x1 = tomb[i]; y1 = tomb[i + 1]; x2 = tomb[i + 2]; y2 = tomb[i + 3]; terulet += Heron(x, y, x1, y1, x2, y2); Konvex sokszög kerülete: double kerulet = 0; for (int i = 0; i + 3 < n; i += 2) x1 = tomb[i]; y1 = tomb[i + 1]; x2 = tomb[i + 2]; y2 = tomb[i + 3]; kerulet += Szakasz(x1, y1, x2, y2); kerulet += Szakasz(tomb[n - 2], tomb[n - 1], tomb[0], tomb[1]); 26

Fibonacci: A fibonacci számok gyorsan nőnek, a long indokolt lehet. Rekurzívan: // Az i. fibonacci számot keressük static long fibo(long i) if (i == 0) return 0; else if (i == 1) return 1; else return fibo(i - 1) + fibo(i - 2); Iteratívan: // Az n. fibonacci számot keressük static long fib(int n) if (n == 0) return 0; if (n == 1) return 1; long f = 0; long elozoelotti = 0; long elozo = 1; for (int i = 2; i <= n; i++) f = elozo + elozoelotti; elozoelotti = elozo; elozo = f; return f; Iteratívan, tömbbel: // Az első n db. fibonacci számot keressük long[] f = new long[n]; f[0] = 0; f[1] = 1; for (int i = 2; i < n; i++) f[i] = f[i - 1] + f[i - 2]; 27

Iteratívan, listával: // Az első, n-nél nagyobb fib. számot keressük long fi(int n) List<long> fiblist = new List<long>(); fiblist.add(0); fiblist.add(1); long value = 0; for (int i = 2; value <= n; i++) value = fiblist[i - 1] + fiblist[i - 2]; fiblist.add(value); return fiblist[fiblist.count - 1]; Zárt alakban: // Az n. fibonacci számot keressük long fibzart(int n) double gyot = Math.Sqrt(5.0); long f = (long)math.truncate( (1.0 / gyot) * ( Math.Pow(((1.0 + gyot) / 2.0), n) - Math.Pow(((1.0 - gyot) / 2.0), n) ) ); return f; Legnagyobb közös osztó: int Euklidesz(int a, int b) int t; while (a!= b) if (a > b) a = a - b; else t = a; a = b; b = t; return a; 28

int gcd(int a, int b) int t = 0; while (b!= 0) t = b; b = a % b; a = t; return a; int gcd(int a, int b) return (b == 0? a : gcd(b, a % b)); int gcd(int a, int b) if (a == b) return a; else if (a > b) return gcd(a - b, b); else return gcd(a, b - a); Horner elrendezés: P(x)=7x 3 2x 2 + 5x - 8 = (7x 2 2x + 5)x - 8 = ((7x-2) x +5)x - 8 // A szorzások száma 3+2+1, általános esetben: O(n*n) // A szorzások száma 3, általános esetben: O(n) int x = 19; int n = 3; int[] a = new int[n]; //Az együtthatókat jelöljük: a[3] = 7; a[2] = -2; a[1] = 5; a[0] = -8; int POL = a[n]; for (int i = n - 1; i >= 0; i--) POL = POL * x + a[i]; 29

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 // Itt megjegyezném, hogy.net-ben teljesen felesleges kinullázni az int-eket, mivel alapból 0-ák. // Pascalban kellett ezt mindig megtenni, máskülönben alapból valami memóriaszemét lenne az int értéke 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. 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; 30

Másodfokú egyenlet megoldása: double x1 = Double.NegativeInfinity; double x2 = Double.NegativeInfinity; double determinans = 0; int ag = -1; if (a == 0) if (b == 0) if (c == 0) ag = 4; else ag = 5; else ag = 6; x1 = -c / b; else determinans = b * b - 4 * a * c; if (determinans < 0) ag = 1; else determinans = Math.Sqrt(b * b - 4 * a * c); if (determinans == 0) ag = 2; x1 = -b / (2 * a); else ag = 3; x1 = (-b + determinans) / (2 * a); x2 = (-b - determinans) / (2 * a); switch (ag) case 1: return "nincs valós megoldás"; case 2: return "egy megoldás van: x1=" + x1; case 3: return "két megoldás van: x1=" + x1 + ", x2=" + x2; case 4: return "minden valós szám megoldás"; case 5: return "nincs megoldás"; case 6: return "elfajuló egyenlet, egy megoldás: x=" + x1; default: return "Hiba"; 31

Newton gyökvonás: double Newton(double inp) // inp adott szám, melyből gyököt akarunk vonni double gy, ujgy, d, eps; gy = 1; d = 1; eps = 0.00001; while (d > eps) ujgy = (1.0 / 2) * (gy + inp / gy); d = Math.Abs(ujgy - gy); gy = ujgy; return gy; További AAO-s kódok, amik kellhetnek: Megtalálhatóak a PPT-s tételek között a PPT-s.pdf fájlban: programozási tételek o sorozatszámítás o eldöntés o kiválasztás o keresés o megszámlálás o maximumkeresés rendezések o buborékrendezés o minimum kiválasztásos rendezés o beillesztéses rendezés (alias beszúrásos rendezés) halmazműveletek o metszet o unió o unió speciális esetben (ha rendezettek a tömbök) bináris keresés (alias logaritmikus keresés) (ha rendezettek a tömbök) o rekurzív bináris keresés o iteratív bináris keresés 32