Írta: Kurdi Zsombor
ALGORITMUSOK OPTIMÁLIS
MEGVALÓSÍTÁSA PÁRHUZAMOS KÖRNYEZETBEN
Lektorálta: oktatói munkaközösség
COPYRIGHT:
2011-2016, Kurdi Zsombor, Óbudai Egyetem, Neumann János Informatikai Kar
LEKTORÁLTA: oktatói munkaközösség
Creative Commons NonCommercial-NoDerivs 3.0 (CC BY-NC-ND 3.0)
A szerző nevének feltüntetése mellett nem kereskedelmi céllal szabadon másolható, terjeszthető, megjelentethető és előadható, de nem módosítható.
TÁMOGATÁS:
Készült a TÁMOP-4.1.2-08/2/A/KMR-2009-0053 számú, “Proaktív informatikai modulfejlesztés (PRIM1): IT Szolgáltatásmenedzsment modul és Többszálas processzorok és programozásuk modul” című pályázat keretében
KÉSZÜLT: a Typotex Kiadó gondozásában FELELŐS VEZETŐ: Votisky Zsuzsa
ISBN 978-963-279-559-1
2
KULCSSZAVAK:
algoritmus, párhuzamosítás, kölcsönös kizárás, programozási tételek, rendezések, keresések, elosztott adatszerkezetek, Gauss elimináció, Fourier transzformáció, gráfalgoritmusok, tömörítés, titkosítás, mintaillesztés, geometriai algoritmusok
ÖSSZEFOGLALÓ:
A tananyag leggyakoribb algoritmusok párhuzamosításának kérdésével foglalkozik. Az algoritmusok elemzésével és párhuzamosításával foglalkozó elméleti bevezető után a gyakorlatokra tevődik át a hangsúly. Ez az egyszerűbb algoritmusokkal, a programozási tételekkel – mint például a minimum/maximum keresés, számlálás, összegzés – kezdődik, majd a rendezésiek, keresések, gráfalgoritmusok után olyan bonyolultabb algoritmusok párhuzamosításáról is szó esik, mint a titkosítási, tömörítési és a geometriai problémákat megoldó algoritmusok. Minden esetben az algoritmus bemutatás után foglalkozunk a párhuzamosítás lehetőségével, valamint a soros és párhuzamos implementációval C#
nyelven.
Mindezek mellett a tananyagban megtalálható egy rövid fejezet, amely a fontosabb
adatszerkezetek elosztott használatával foglalkozik, amely azért fontos, mert a párhuzamos algoritmusok gyakran használhatnak ilyen adatszerkezeteket, amelyeket ilyenkor speciálisan kell kezelnünk (például a kölcsönös kizárás megvalósításával).
Tartalomjegyzék
• Bevezető
• Programozási tételek
• Keresések
• Mintaillesztések
• Rendezések (1)
• Rendezések (2)
• Mátrixműveletek
• Gráfalgoritmusok (1)
• Gráfalgoritmusok (2)
• Geometria
• Tömörítés
• Titkosítás
www.tankonyvtar.hu
© Kurdi Zsombor, ÓE NIK 4
1. óra Bevezető
Algoritmus fogalma, tulajdonságai Algoritmusok elemzése
Aszimptotikus jelölések Példák
Algoritmusok párhuzamosítása
Módszerek Példák
Programok
Irodalomjegyzék
www.tankonyvtar.hu
© Kurdi Zsombor, ÓE NIK
Hallgatói tájékoztató
A jelen bemutatóban található adatok, tudnivalók és információk a számonkérendő anyag vázlatát képezik. Ismeretük szükséges, de nem elégséges feltétele a sikeres zárthelyinek, illetve vizsgának.
Sikeres zárthelyihez, illetve vizsgához a jelen bemutató tartalmán felül a kötelező irodalomként megjelölt anyag, a gyakorlatokon szóban, illetve a táblán átadott tudnivalók ismerete, valamint a gyakorlatokon megoldott példák és az otthoni feldolgozás céljából kiadott feladatok önálló megoldásának képessége is szükséges.
6
Algoritmus fogalma, tulajdonságai
www.tankonyvtar.hu
© Kurdi Zsombor, ÓE NIK
Algoritmus
• Algoritmuson olyan módszert (utasítások sorozatát) értünk, amely valamely problémára megoldást ad.
• A fogalom a matematikában jelent meg, de az informatika népszerűvé válása ültette át a köznyelvbe.
• Algoritmust lehet adni
– egy bútordarab összeszerelésére, – egy étel elkészítésére,
– otthonunkból az iskolába való eljutásra,
– két szám legnagyobb közös osztójának kiszámítására.
– …
8
Algoritmus definíciója
• Turing: egy probléma megoldására adott utasítássorozat akkor tekinthető algoritmusnak, ha van egy vele ekvivalens Turing-gép, amely minden megoldható bemenetre megáll.
• Alternatív definíciók
– Regisztergép – Lambda-kalkulus – Rekurzív függvények – Chomsky-nyelvtanok – Markov-algoritmusok
• Mindegyik definíció ekvivalens a Turing-féle meghatározással.
www.tankonyvtar.hu
© Kurdi Zsombor, ÓE NIK
Algoritmusok tulajdonságai
• Alaptulajdonságok
– Egy algoritmus egyértelműen leírható véges szöveggel (statikus végesség).
– Egy algoritmus minden lépése ténylegesen kivitelezhető.
– Egy algoritmus minden időpontban véges sok tárat használ (dinamikus végesség).
– Egy algoritmus véges sok lépésből áll (termináltság).
• Ezek alapján az algoritmus fogalma
– Egy algoritmus ugyanarra a bemenetre mindig ugyanazt az eredményt adja (determináltság).
– Minden időpontban egyértelműen adott a következő lépés (determinisztikusság).
10
Algoritmusok elemzése
www.tankonyvtar.hu
© Kurdi Zsombor, ÓE NIK
Algoritmusok elemzése
• Befejeződés
– Kiszámíthatóságelméleti feladat.
• Tár- és időigény
– Bonyolultságelméleti feladat.
– Természetes számokon értelmezett függvények segítségével írható le.
– Aszimptotikus korlátokkal adható meg.
– A továbbiakban csak ezzel foglalkozunk.
12
Algoritmusok elemzése
• Legyen két függvény f, g: N → Z
– Ha ∃ c > 0 és n
0, hogy ha n > n
0, akkor 0 ≤ f(n) ≤ c ⋅ g(n), akkor a g függvényt f aszimptotikusan ÉLES felső korlátjának nevezzük (Jele: f(n) = O(g(n) vagy f = O(g))
– Ha ∃ c > 0 és n
0, hogy ha n > n
0, akkor 0 ≤ f(n) < c ⋅ g(n), akkor a g függvényt f aszimptotikusan NEM ÉLES felső korlátjának nevezzük (Jele: f(n) = o(g(n) vagy f = o(g))
– Ha ∃ c > 0 és n
0, hogy ha n > n
0, akkor 0 ≤ c ⋅ g(n) ≤ f(n), akkor a g függvényt f aszimptotikusan ÉLES alsó korlátjának nevezzük (Jele: f(n) = Ω(g(n) vagy f = Ω(g))
– Ha ∃ c > 0 és n
0, hogy ha n > n
0, akkor 0 ≤ c ⋅ g(n) < f(n), akkor a g függvényt f aszimptotikusan NEM ÉLES alsó korlátjának nevezzük (Jele: f(n) = ω(g(n) vagy f = ω(g))
– Ha ∃ c
1,c
2> 0 és n0, hogy ha n > n0, akkor 0 ≤ c
1⋅ g(n) ≤ f(n) ≤ c
2⋅ g(n), akkor a g
függvényt f aszimptotikusan éles korlátjának nevezzük (Jele: f(n) = Θ(g(n)
www.tankonyvtar.hu
© Kurdi Zsombor, ÓE NIK
Algoritmusok elemzése
14
Algoritmusok elemzése
• A definíciók alapján triviális állítás
– ∀ f,g : N → Z függvényre f(n) = Θ(g(n)) ↔ f(n) = O(g(n)) és f(n) = Ω(g(n))
Azaz egy függvény pontosan akkor aszimptotikusan éles korlátja egy másik függvénynek, ha aszimptotikusan éles alsó és
aszimptotikusan éles felső korlátja a függvénynek.
www.tankonyvtar.hu
© Kurdi Zsombor, ÓE NIK
Algoritmusok elemzése
• Az O, o, Ω, ω és Θ jelölések mint bináris relációk tulajdonságai
– O, o, Ω, ω és Θ tranzitívak (pl.: f = ω(g) ∧ g = ω(h) → f = ω(h)) – O, Ω és Θ reflexívek (pl. f = Θ(f))
– Θ szimmetrikus (f = Θ(g) ↔ g = Θ(f))
– O és Ω, valamint o és ω „felcserélten szimmetrikusak” (pl.: f = O(g) ↔ g = Ω(f))
– Rögzített h függvény mellett O(h), o(h), Ω(h), ω(h) és Θ(h) halmazok zártak az összeadásra és a pozitív számmal való szorzásra (pl.: f = ω(h) ∧ g = ω(h) → f + g = ω(h)) és (pl.: f = ω(h) ∧ c > 0 → c ⋅ f = ω(h))
– Összegben a nagyobb függvény határozza meg az aszimptotikát: f + g =
Θ(max(f, g)) (A max ebben az esetben az aszimptotikusan nagyobb függvényt jelenti.)
16
Algoritmusok elemzése
• Az O, o, Ω, ω és Θ jelölések mint bináris relációk tulajdonságai (folytatás)
– Polinom esetén a legnagyobb fokú tag a meghatározó: a
kn
k+ a
k-1n
k-1+ … + a
1n + a
0= Θ(n
k)
– Bármely két (1-nél nagyobb alapszámú) logaritmikus függvény
aszimptotikusan egyenértékű: log
an = Θ(log
bn). Ezért az alap feltüntetése nem szükséges log
an = Θ(logn)
– Hatványfüggvények esetén különböző kitevők különböző
függvényosztályokat jelölnek ki: a ≥ 0 és ε > 0 esetén n
a= O(n
a+ε) és n
a≠
Θ(n
a+ε), tehát n
a= o(n
a+ε)
www.tankonyvtar.hu
© Kurdi Zsombor, ÓE NIK
Példa (Összegzés)
• Bemenet: n db érték (elemek).
• Kimenet: az input értékek összege.
• Algoritmus:
s = 0
for i = 1 to n
s = s + elemek[i]
• Lépésszám
– Legjobb eset: n
– Legrosszabb eset: n – Átlagos eset: n
– Függvényosztály: Θ(n)
18
Példa (Számlálás)
• Bemenet: n db érték (elemek).
• Kimenet: az input értékek közül adott tulajdonságú elemek darabszáma.
• Algoritmus:
d = 0
for i = 1 to n
if χ(elemek[i]) d = d + 1
• Lépésszám
– Legjobb eset: n
– Legrosszabb eset: n
– Átlagos eset: n
www.tankonyvtar.hu
© Kurdi Zsombor, ÓE NIK
Példa (Maximumkeresés)
• Bemenet: n db érték (elemek).
• Kimenet: az input értékek közül a maximális elem.
• Algoritmus:
max = elemek[1]
for i = 2 to n
if elemek[i] > max max = elemek[i]
• Lépésszám
– Legjobb eset: n
– Legrosszabb eset: n – Átlagos eset: n
– Függvényosztály: Θ(n)
20
Párhuzamos algoritmusok
• A párhuzamos algoritmusok olyan algoritmusok, amelyek a feladatot több részre osztva, egymással párhuzamosan (több processzoron) egyidejűleg futnak.
• Ezeket az algoritmusokat két nagy csoportba sorolhatjuk
– Megosztott algoritmusok
Az algoritmust alkotó folyamatok közös memóriát használnak, és azon keresztül kommunikálnak egymással.
– Elosztott algoritmusok
Az algoritmushoz tartozó folyamatok teljesen szeparált tárterületen
dolgoznak, majd valamilyen módszerrel összegzik az eredményeket.
Algoritmusok párhuzamosítása
www.tankonyvtar.hu
© Kurdi Zsombor, ÓE NIK 22
Algoritmusok párhuzamosítása
• „Oszd meg és uralkodj” elv segítségével
– Az adatok felosztása a processzorok (szálak v. folyamatok) között, majd az eredmények összefésülése
Ebben az esetben valamennyi szál elvégzi a teljes algoritmust és az általuk szolgáltatott eredményeket kell valamelyik szálnak összefésülni (ez történhet új algoritmussal vagy a párhuzamosított algoritmus újbóli végrehajtásával).
Olyan algoritmusok esetén hatékony megoldás, amelyek valamennyi inputadatot megvizsgálnak a futás során. (pl. összegzés).
– A feladatok felosztása a processzorok (szálak v. folyamatok) között
Ebben az esetben a szálak az algoritmusnak csak egy részét végzik el és az általuk számolt részeredményt a következő szálnak adják (futószalagszerű rendszer). Az algoritmus végeredményét az utolsó szál szolgáltatja.
Olyan algoritmusok esetén hatékony megoldás, amelyek felbonthatók elemi lépések sorozatára, amelyeket az inputadatokon kell elvégezni, hogy
megkapjuk az outputot. (Pl. sin számítás.)
www.tankonyvtar.hu
© Kurdi Zsombor, ÓE NIK
Adatmegosztás
24
Feladatmegosztás
www.tankonyvtar.hu
© Kurdi Zsombor, ÓE NIK
Példa (Összegzés)
• Párhuzamosítás adatmegosztással
– Osszuk k részre az n értéket.
– Összegezzük a részeket párhuzamosan.
– Összegezzük az egyes részek eredményeit.
• Lépésszám
– Legjobb eset: n / k + k
– Legrosszabb eset: n / k + k – Átlagos eset: n / k + k
– Függvényosztály: Θ(n / k + k)
26
Példa (Számlálás)
• Párhuzamosítás adatmegosztással
– Osszuk k részre az n értéket.
– Végezzük el a számlálást a részeken párhuzamosan.
– Összegezzük az egyes részek eredményeit.
• Lépésszám
– Legjobb eset: n / k + k
– Legrosszabb eset: n / k + k – Átlagos eset: n / k + k
– Függvényosztály: Θ(n / k + k)
www.tankonyvtar.hu
© Kurdi Zsombor, ÓE NIK
Példa (Maximumkeresés)
• Párhuzamosítás adatmegosztással
– Osszuk k részre az n értéket.
– Keressük meg a részek maximumait párhuzamosan.
– Keressük meg a maximumot a részeredmények között.
• Lépésszám
– Legjobb eset: n / k + k
– Legrosszabb eset: n / k + k – Átlagos eset: n / k + k
– Függvényosztály: Θ(n / k + k)
28
Programok
www.tankonyvtar.hu
© Kurdi Zsombor, ÓE NIK
Példaprogramok
• A tananyag további részében szereplő példaprogramok inputadatait a szamok.txt fájl tartalmazza
– A fájl első sora a benne található inputadatok darabszámát tartalmazza.
– Minden további sor egy-egy inputadatot tartalmaz.
30
Adatbeolvasás
private const string inputFile = "szamok.txt";
private static int[] Beolvas()
{ StreamReader input = new StreamReader(inputFile);
int méret = Convert.ToInt32(input.ReadLine());
int[] számok = new int[méret];
for (int i = 0; i < számok.Length; ++i)
számok[i] = Convert.ToInt32(input.ReadLine());
input.Close();
return számok;
} 1 2 3 4 5 6 7 8 10 9 12 11 13 14 15 16 18 17 19
www.tankonyvtar.hu
© Kurdi Zsombor, ÓE NIK
Példaprogramok
• Minden példaprogram elején az inputfájl tartalmát beolvassuk egy tömbbe.
• Ehhez az input fájl nevét egy konstansban tároljuk.
• A beolvasást a Beolvas() nevű művelet végzi.
• Az algoritmus futási idejét Stopwatch objektum segítségével mérjük.
• A program végén az eredményt és a futási időt megjelenítjük a képernyőn.
32
Program (Soros)
private static Stopwatch stopper = new Stopwatch();
static void Main(string[] args) { int[] számok = Beolvas();
stopper.Start();
// algoritmus
stopper.Stop();
// eredmény és futási idő kiírás }
1 2 3 4 5 6 7 8 10 9 12 11 13 14 15 16 18 17 19
www.tankonyvtar.hu
© Kurdi Zsombor, ÓE NIK
Példa (Összegzés)
// algoritmus int s = 0;
for (int i = 0; i < számok.Length; ++i) s += számok[i];
// eredmény és futási idő kiírás
Console.WriteLine("A számok összege: {0}", s);
Console.WriteLine("Összesen {0} db számot adtam össze.", számok.Length);
Console.WriteLine("Futási idő: {0}", stopper.Elapsed);
Program.cs
1 2 3 4 5 6 7 8 10 9 12 11 13 14 15 16 18 17 19 20 22 21 23
34
Példa (Számlálás)
// algoritmus int d = 0;
for (int i = 0; i < számok.Length; ++i) if (Feltétel(számok[i])
++d;
// eredmény és futási idő kiírás
Console.WriteLine("A feltételt teljesítő elemek darabszáma: {0}", d);
Console.WriteLine("Összesen {0} db elemet vizsgáltam.", számok.Length);
Console.WriteLine("Futási idő: {0}", stopper.Elapsed);
// a Feltétel tetszőleges logikai értékű függvény lehet // most a páros számokat számláljuk
private bool Feltétel(int n) { return n % 2 == 0;
} 1 2 3 4 5 6 7 8 10 9 12 11 13 14 15 16 18 17 19
www.tankonyvtar.hu
© Kurdi Zsombor, ÓE NIK
Példa (Maximumkeresés)
// algoritmus
int max = számok[0];
for (int i = 1; i < számok.Length; ++i) if (számok[i] > max)
max = számok[i];
// eredmény és futási idő kiírás
Console.WriteLine("A legnagyobb szám: {0}", max);
Console.WriteLine("Összesen {0} db számot vizsgáltam.", számok.Length);
Console.WriteLine("Futási idő: {0}", stopper.Elapsed);
Program.cs
1 2 3 4 5 6 7 8 10 9 12 11 13 14 15 16 18 17 19 20 22 21 23
36
Program (Párhuzamos)
private struct SzálParaméter { public int SzálIndex;
public int[] Számok;
public int StartIndex;
public int Hossz;
}
private static Stopwatch stopper = new Stopwatch();
private static object sync = new object();
private static int[] eredmények = new int[]();
private static int lefutottSzálak = 0;
static void Main(string[] args) { int[] számok = Beolvas();
stopper.Start();
1 2 3 4 5 6 7 8 10 9 12 11 13 14 15 16 18 17 19
www.tankonyvtar.hu
© Kurdi Zsombor, ÓE NIK
Program (Párhuzamos)
paraméter.SzálIndex = i;
paraméter.Számok = számok;
paraméter.Hossz = számok.Length / szálakSzáma;
paraméter.StartIndex = paraméter.Hossz * i;
ThreadPool.QueueUserWorkItem(new WaitCallback(Szálfüggvény), paraméter);
}
while (lefutottSzálak < szálakSzáma) Thread.Sleep(1);
// összefésülés stopper.Stop();
// eredmény és futási idő kiírás }
private static void Szálfüggvény(object obj) { SzálParaméter param = (SzálParaméter)obj;
// soros algoritmus
Program.cs
1 2 3 4 5 6 7 8 10 9 12 11 13 14 15 16 18 17 19 20 22 21 23
38
Program (Párhuzamos)
eredmények[param.SzálIndex] = /* az algoritmus eredménye */
lock (sync)
{ ++lefutottSzálak;
} } 1 2
3 4 5 6 7 8 10 9 12 11 13 14 15 16 18 17 19
www.tankonyvtar.hu
© Kurdi Zsombor, ÓE NIK
Példa (Összegzés)
// összefésülés int s = 0;
for (int i = 0; i < eredmények.Length; ++i) s += eredmények[i];
// eredmény és futási idő kiírás
Console.WriteLine("A számok összege: {0}", s);
Console.WriteLine("Összesen {0} db számot adtam össze.", számok.Length);
Console.WriteLine("Futási idő: {0}", stopper.Elapsed);
Program.cs
1 2 3 4 5 6 7 8 10 9 12 11 13 14 15 16 18 17 19 20 22 21 23
40
Példa (Számlálás)
// összefésülés int d = 0;
for (int i = 0; i < eredmények.Length; ++i) d += eredmények[i];
// eredmény és futási idő kiírás
Console.WriteLine("A feltételt teljesítő elemek darabszáma: {0}", d);
Console.WriteLine("Összesen {0} db elemet vizsgáltam.", számok.Length);
Console.WriteLine("Futási idő: {0}", stopper.Elapsed);
// a Feltétel tetszőleges logikai értékű függvény lehet // most a páros számokat számláljuk
private bool Feltétel(int n) { return n % 2 == 0;
} 1 2 3 4 5 6 7 8 10 9 12 11 13 14 15 16 18 17 19
www.tankonyvtar.hu
© Kurdi Zsombor, ÓE NIK
Példa (Maximumkeresés)
// összefésülés
int max = eredmények[0];
for (int i = 1; i < eredmények.Length; ++i) if (eredmények[i] > max)
max = eredmények [i];
// eredmény és futási idő kiírás
Console.WriteLine("A legnagyobb szám: {0}", max);
Console.WriteLine("Összesen {0} db számot vizsgáltam.", számok.Length);
Console.WriteLine("Futási idő: {0}", stopper.Elapsed);
Program.cs
1 2 3 4 5 6 7 8 10 9 12 11 13 14 15 16 18 17 19 20 22 21 23
42
Házi feladat
Próbálja ki a példaprogramokat! Kíséreljen meg javítani a párhuzamos változatok hatékonyságán!
Megjegyzés
– Lehetőség szerint a programokat futtassa egy-, illetve többprocesszoros
gépeken!
www.tankonyvtar.hu
© Kurdi Zsombor, ÓE NIK
Irodalomjegyzék
• Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, Clifford Stein: Új algoritmusok, Scolar Kiadó, 2003.
44
2. óra
Programozási tételek
Programozási tételek
Összegzés Számlálás
Maximumkeresés Másolás
Kiválogatás Szétválogatás Metszet
Unió
www.tankonyvtar.hu
Programozási tételek
© Kurdi Zsombor, ÓE NIK 46
Programozási tételek
• Egy adott feladatosztályba tartozó összes feladatra általános megoldást adnak.
• Csoportosításuk
– Egy sorozathoz egy értéket rendelő feladatok.
• Pl.: számítsuk ki n db szám összegét.
– Egy sorozathoz egy sorozatot rendelő feladatok.
• Pl.: másoljuk egy sorozat elemeit fordított sorrendben egy másik sorozatba.
– Sorozathoz több sorozatot rendelő feladatok.
• Pl.: válogassuk szét egy sorozat páros és páratlan elemeit.
– Több sorozathoz egy sorozatot rendelő feladatok.
• Pl.: számítsuk ki két sorozat közös elemeit (metszetét).
www.tankonyvtar.hu
Összegzés
© Kurdi Zsombor, ÓE NIK 48
Összegzés
• Feladat
– Számítsuk ki n db szám összegét.
• Sorozathoz értéket rendel.
• Lásd: előző óra.
www.tankonyvtar.hu
Számlálás
© Kurdi Zsombor, ÓE NIK 50
Számlálás
• Feladat
– Számláljuk meg n db számból hány telesíti F feltételt.
• Sorozathoz értéket rendel.
• F feltétel tetszőleges logikai értékű függvény lehet.
• Lásd: előző óra.
www.tankonyvtar.hu
Maximumkeresés
© Kurdi Zsombor, ÓE NIK 52
Maximumkeresés
• Feladat
– Keressük meg n db szám közül a legnagyobbat.
• Sorozathoz értéket rendel.
• A minimumkeresés is hasonlóan végezhető el.
• Megkereshető a sorozat első, illetve utolsó maximuma (ha több maximum is van).
• Feltétellel bővíthető, hogy a sorozat bizonyos (feltételt teljesítő) elemei közül keressük a maximumot = feltételes maximum
keresés.
• Lásd: előző óra.
www.tankonyvtar.hu
Másolás
© Kurdi Zsombor, ÓE NIK 54
Másolás
• Feladat
– Másoljuk át egy sorozat (s) elemeit egy másik sorozatba (t).
• Sorozathoz sorozatot rendel.
• Algoritmus:
for i = 1 to n
t[i] = s[i]
www.tankonyvtar.hu
© Kurdi Zsombor, ÓE NIK
Másolás
• A másolás közben műveletet is végezhetünk az elemeken.
– Egyszerű művelet (pl. gyökvonás).
– Összetett művelet (pl. s[i]-edik Fibonacci-szám kiszámítása).
• Lépésszám
– Legjobb eset: n
– Legrosszabb eset: n – Átlagos eset: n
– Függvényosztály: Θ(n)
56
Feladat
Adott egy n számot tartalmazó tömb. Számolja ki a számok
négyzetét egy új tömbbe/listába! Oldja meg a feladatot soros és
párhuzamos algoritmussal is!
www.tankonyvtar.hu
© Kurdi Zsombor, ÓE NIK
Megoldás (Soros)
// a másolat
int másolat = new int[számok.Length];
// másolás
for (int i = 0; i < számok.Length; ++i) másolat[i] = számok[i] * számok[i];
// eredmény és futási idő kiírás for (int i = 0; i < számok.Length; ++i)
Console.WriteLine("{0}^2 = {1}", számok[i], másolat[i]);
Console.WriteLine("Összesen {0} db szám négyzetét számoltam ki.", számok.Length);
Console.WriteLine("Futási idő: {0}", stopper.Elapsed);
Program.cs
1 2 3 4 5 6 7 8 10 9 12 11 13 14 15 16 18 17 19 20 22 21 23
58
Megoldás (Párhuzamos)
// a szál-paraméterek szerkezete struct SzálParaméter
{ public int[] Számok; // a beolvasott számok public int SzálIndex; // most nincs jelentősége
public int StartIndex; // ahonnan elkezdi a szál olvasni a Számok tömböt public int Hossz; // ahány elemet a szálnak fel kell dolgozni }
// szálfüggvény
private static void Szálfüggvény(object obj) { SzálParaméter param = (SzálParaméter )obj;
for (int i = param.StartIndex; i < param.StartIndex + param.Hossz; ++i)
Eredmény[i] = param.Számok[i] * param.Számok[i]; // a másolás az Eredmény tömbbe // szinkronizációra nincs szükség, mert a szálak a tömb diszjunkt részeit módosítják
lock (sync) // a terminálás jelzésére a lefutottSzálak változót használjuk 1 2
3 4 5 6 7 8 10 9 12 11 13 14 15 16 18 17 19
www.tankonyvtar.hu
Kiválogatás
© Kurdi Zsombor, ÓE NIK 60
Kiválogatás
• Feladat
– Válogassuk ki egy sorozat elemeit, amelyek teljesítik az F feltételt.
• Sorozathoz sorozatot rendel.
• Algoritmus:
j = 0
for i = 1 to n if F(s[i]) t[j] = s[i]
j = j + 1
www.tankonyvtar.hu
© Kurdi Zsombor, ÓE NIK
Kiválogatás
• F feltétel tetszőleges logikai értékű függvény lehet.
• Lépésszám
– Legjobb eset: n
– Legrosszabb eset: n – Átlagos eset: n
– Függvényosztály: Θ(n)
62
Feladat
Adott egy n számot tartalmazó tömb. Számolja ki a számok
négyzetét egy új tömbbe/listába! Oldja meg a feladatot soros és
párhuzamos algoritmussal is!
www.tankonyvtar.hu
© Kurdi Zsombor, ÓE NIK
Megoldás (Soros)
// az eredmény
List<int> négyzetszámok = new List<int>();
// kiválogatás
for (int i = 0; i < számok.Length; ++i) if (Feltétel(számok[i])
négyzetszámok.Add(számok[i]);
// eredmény és futási idő kiírás
Console.WriteLine("Négyzetszámok:");
for (int i = 0; i < négyzetszámok.Length; ++i) Console.WriteLine(négyzetszámok[i]);
Console.WriteLine("Összesen {0} db számot vizsgáltam.", számok.Length);
Console.WriteLine("Futási idő: {0}", stopper.Elapsed);
// a feltétel
private static bool Feltétel(int n)
{ return Math.Round(Math.Sqrt(n)) * Math.Round(Math.Sqrt(n)) == n;
} Program.cs
1 2 3 4 5 6 7 8 10 9 12 11 13 14 15 16 18 17 19 20 22 21 23
64
Megoldás (Párhuzamos)
// a szál-paraméterek szerkezete struct SzálParaméter
{ public int[] Számok; // a beolvasott számok public int SzálIndex; // most nincs jelentősége
public int StartIndex; // ahonnan elkezdi a szál olvasni a Számok tömböt public int Hossz; // ahány elemet a szálnak fel kell dolgozni }
// szálfüggvény
private static void Szálfüggvény(object obj) { SzálParaméter param = (SzálParaméter )obj;
for (int i = param.StartIndex; i < param.StartIndex + param.Hossz; ++i)
if (Feltétel(param.Számok[i])) // most szükséges a szinkronizáció, mert az Eredmény
lock (Eredmény) // lista kezelése nem diszjunkt részekben
történik
Eredmény.Add(param.Számok[i]);
1 2 3 4 5 6 7 8 10 9 12 11 13 14 15 16 18 17 19
www.tankonyvtar.hu
Szétválogatás
© Kurdi Zsombor, ÓE NIK 66
Szétválogatás
• Feladat
– Válogassuk szét egy sorozat F feltételt teljesítő és nem teljesítő elemeit egy- egy sorozatba.
• Sorozathoz több sorozatot rendel.
• Algoritmus:
j1 = 0, j2 = 0 for i = 1 to n if F(s[i])
t1[j1] = s[i]
j1 = j1 + 1
else
www.tankonyvtar.hu
© Kurdi Zsombor, ÓE NIK
Szétválogatás
• F feltétel tetszőleges logikai értékű függvény lehet.
• Lépésszám
– Legjobb eset: n
– Legrosszabb eset: n – Átlagos eset: n
– Függvényosztály: Θ(n)
68
Feladat
Adott egy n számot tartalmazó tömb. Válogassuk szét a páros és
páratlan elemeket két új tömbbe/listába! Oldja meg a feladatot
soros és párhuzamos algoritmussal is!
www.tankonyvtar.hu
© Kurdi Zsombor, ÓE NIK
Megoldás (Soros)
// az eredmény
List<int> páros = new List<int>();
List<int> páratlan = new List<int>();
// szétválogatás
for (int i = 0; i < számok.Length; ++i) if (Feltétel(számok[i])
páros.Add(számok[i]);
else
páratlan.Add(számok[i]);
// eredmény és futási idő kiírás Console.WriteLine("Páros számok:");
for (int i = 0; i < páros.Length; ++i) Console.WriteLine(páros[i]);
Console.WriteLine("Páratlan számok:");
for (int i = 0; i < páratlan.Length; ++i) Console.WriteLine(páratlan[i]);
Console.WriteLine("Összesen {0} db számot vizsgáltam.", számok.Length);
Console.WriteLine("Futási idő: {0}", stopper.Elapsed);
// a feltétel
private static bool Feltétel(int n) { return n % 2 == 0;
} Program.cs
1 2 3 4 5 6 7 8 10 9 12 11 13 14 15 16 18 17 20 19 22 21 23 24
25 26
70
Megoldás (Párhuzamos)
// a szál-paraméterek szerkezete struct SzálParaméter
{ public int[] Számok; // a beolvasott számok public int SzálIndex; // most nincs jelentősége
public int StartIndex; // ahonnan elkezdi a szál olvasni a Számok tömböt public int Hossz; // ahány elemet a szálnak fel kell dolgozni }
// szálfüggvény
private static void Szálfüggvény(object obj) { SzálParaméter param = (SzálParaméter)obj;
for (int i = param.StartIndex; i < param.StartIndex + param.Hossz; ++i)
if (Feltétel(param.Számok[i])) // most szükséges a szinkronizáció, mert az Eredmény lock (Páros) // lista kezelése nem diszjunkt részekben történik Páros.Add(param.Számok[i]);
else
lock (Páratlan)
Páratlan.Add(param.Számok[i]);
1 2 3 4 5 6 7 8 10 9 12 11 13 14 15 16 18 17 20 19 22 21
www.tankonyvtar.hu
Metszet
© Kurdi Zsombor, ÓE NIK 72
Metszet
• Feladat
– Másoljuk át két (vagy több) sorozat közös elemeit egy új sorozatba.
• Több sorozathoz egy sorozatot rendel.
• Algoritmus
for s in H
1if s not in H
2M = M U {s}
www.tankonyvtar.hu
© Kurdi Zsombor, ÓE NIK
Metszet
• A másolás közben tetszőleges műveletet elvégezhetünk az elemeken.
• Lépésszám
– Legjobb eset: min{n,m}
– Legrosszabb eset: n*m – Átlagos eset: ~n*m
– Függvényosztály: Θ(n*m)
74
Feladat
Adott egy n és egy m számot tartalmazó tömb. Másolja át a két
tömb közös elemeit egy új tömbbe/listába! Oldja meg a feladatot
soros és párhuzamos algoritmussal is!
www.tankonyvtar.hu
© Kurdi Zsombor, ÓE NIK
Megoldás (Soros)
// az eredmény
List<int> metszet = new List<int>();
// metszet
for (int i = 0; i < számok1.Length; ++i) { bool tartalmaz = false;
for (int j = 0; j < számok2.Length && !tartalmaz; ++j) tartalmaz = számok1[i] == számok2[j];
if (tartalmaz)
metszet.Add(számok1[i]);
}
// eredmény és futási idő kiírás Console.WriteLine("Metszet:");
for (int i = 0; i < metszet.Length; ++i) Console.WriteLine(metszet[i]);
Console.WriteLine("Az 1. sorozat elemszáma: {0}", számok1.Length);
Console.WriteLine("A 2. sorozat elemszáma: {0}", számok2.Length);
Console.WriteLine("Futási idő: {0}", stopper.Elapsed);
Program.cs
1 2 3 4 5 6 7 8 10 9 12 11 13 14 15 16 18 17 19 20 22 21 23
76
Megoldás (Párhuzamos)
// a szál-paraméterek szerkezete struct SzálParaméter
{ public int[] Számok1; // az egyik számsorozat public int[] Számok2; // a másik számsorozat public int SzálIndex; // most nincs jelentősége
public int StartIndex; // ahonnan elkezdi a szál olvasni a Számok tömböt public int Hossz; // ahány elemet a szálnak fel kell dolgozni
}
// szálfüggvény
private static void Szálfüggvény(object obj) { SzálParaméter param = (SzálParaméter)obj;
for (int i = param.StartIndex; i < param.StartIndex + param.Hossz; ++i) {
bool tartalmaz = false;
for (int j = 0; j < param.Számok2.Length && !tartalmaz; ++j) tartalmaz = param.Számok1[i] == param.Számok2[j];
if (tartalmaz) // most szükséges a szinkronizáció, mert az Eredmény
lock (Eredmény) // lista kezelése nem diszjunkt részekben történik Eredmény.Add(param.Számok1[i]);
} 1 2
3 4 5 6 7 8 10 9 12 11 13 14 15 16 18 17 20 19 22 21 23 24 25
www.tankonyvtar.hu
Unió
© Kurdi Zsombor, ÓE NIK 78
Unió
• Feladat
– Másoljuk át két (vagy több) sorozat elemeit egy új sorozatba úgy, hogy a közös elemek csak egyszer szerepeljenek.
• Több sorozathoz egy sorozatot rendel.
• Algoritmus
E = H
1for s in H
2if s not in E
E = E U {s}
www.tankonyvtar.hu
© Kurdi Zsombor, ÓE NIK
Unió
• A másolás közben tetszőleges műveletet elvégezhetünk az elemeken.
• Lépésszám
– Legjobb eset: ~n+m – Legrosszabb eset: n*m – Átlagos eset: n*m
– Függvényosztály: Θ(n*m)
80
Feladat
Adott egy n és egy m számot tartalmazó tömb. Másolja át a két tömb elemeit egy új tömbbe/listába úgy, hogy a közös elemek csak egyszer szerepeljenek! Oldja meg a feladatot soros és
párhuzamos algoritmussal is!
www.tankonyvtar.hu
© Kurdi Zsombor, ÓE NIK
Megoldás (Soros)
// az eredmény
List<int> unió = new List<int>();
// unió
for (int i = 0; i < számok1.Length; ++i) unió.Add(számok1[i]);
for (int i = 0; i < számok2.Length; ++i) {
bool tartalmaz = false;
for (int j = 0; j < számok1.Length && !tartalmaz; ++j) tartalmaz = számok2[i] == számok1[j];
if (!tartalmaz)
unió.Add(számok2[i]);
}
// eredmény és futási idő kiírás Console.WriteLine("Unió:");
for (int i = 0; i < metszet.Length; ++i) Console.WriteLine(metszet[i]);
Console.WriteLine("Az 1. sorozat elemszáma: {0}", számok1.Length);
Console.WriteLine("A 2. sorozat elemszáma: {0}", számok2.Length);
Console.WriteLine("Futási idő: {0}", stopper.Elapsed);
Program.cs
1 2 3 4 5 6 7 8 10 9 12 11 13 14 15 16 18 17 20 19 22 21 23 24 25 26
82
Megoldás (Párhuzamos)
// a szál-paraméterek szerkezete struct SzálParaméter
{ public int[] Számok1; // az egyik számsorozat public int[] Számok2; // a másik számsorozat public int SzálIndex; // most nincs jelentősége
public int StartIndex; // ahonnan elkezdi a szál olvasni a Számok tömböt public int Hossz; // ahány elemet a szálnak fel kell dolgozni
}
// szálfüggvény (a Számok2 tömb elemeit a fő szálban másoljuk az Eredménybe) private static void Szálfüggvény(object obj)
{ SzálParaméter param = (SzálParaméter)obj;
for (int i = param.StartIndex; i < param.StartIndex + param.Hossz; ++i) {
bool tartalmaz = false;
for (int j = 0; j < param.Számok1.Length && !tartalmaz; ++j) tartalmaz = param.Számok2[i] == param.Számok1[j];
if (!tartalmaz) // most szükséges a szinkronizáció, mert az Eredmény lock (Eredmény) // lista kezelése nem diszjunkt részekben történik Eredmény.Add(param.Számok1[i]);
} 1 2
3 4 5 6 7 8 10 9 12 11 13 14 15 16 18 17 20 19 22 21 23 24 25
www.tankonyvtar.hu
© Kurdi Zsombor, ÓE NIK
Házi feladat
Próbálja ki a példaprogramokat! Kíséreljen meg javítani a párhuzamos változatok hatékonyságán!
Megjegyzés
– Lehetőség szerint a programokat futtassa egy-, illetve többprocesszoros gépeken!
84
Irodalomjegyzék
• Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, Clifford Stein: Új algoritmusok, Scolar Kiadó, 2003.
www.tankonyvtar.hu
3. óra
Keresések
Keresések
Lineáris keresés Bináris keresés
Visszalépéses keresés Irodalomjegyzék
© Kurdi Zsombor, ÓE NIK 86
Keresések
www.tankonyvtar.hu
Lineáris keresés
© Kurdi Zsombor, ÓE NIK 88
Lineáris keresés
• Feladat
– Keressük meg egy sorozat első F feltételt teljesítő elemét (vagy annak indexét).
• Sorozathoz értéket rendel.
• Algoritmus
for i = 1 to n
if (F(s[i]))
break
www.tankonyvtar.hu
© Kurdi Zsombor, ÓE NIK
Lineáris keresés
• F feltétel tetszőleges logikai értékű függvény lehet.
• Lépésszám
– Legjobb eset: 1
– Legrosszabb eset: n – Átlagos eset: n/2
– Függvényosztály: Θ(n)
90
Feladat
Adott egy n számot tartalmazó tömb. Keresse meg az első 2-vel, 3-
mal, 5-tel és 7-tel is osztható számot! Oldja meg a feladatot soros
és párhuzamos algoritmussal is!
www.tankonyvtar.hu
© Kurdi Zsombor, ÓE NIK
Megoldás (Soros)
// keresés
bool találat = false;
int szám = 0;
for (int i = 0; i < számok.Length && !találat; ++i) { if (Feltétel(számok[i]))
{ találat = true;
szám = számok[i];
} }
// eredmény és futási idő kiírás if (találat)
Console.WriteLine("A feltételnek megfelelő szám: {0}", szám);
else
Console.WriteLine("Nincs a feltételnek megfelelő szám.");
Console.WriteLine("Összesen {0} db számot vizsgáltam.", számok.Length);
Console.WriteLine("Futási idő: {0}", stopper.Elapsed);
// feltétel
private static bool Feltétel(int n)
{ return n % 2 == 0 && n % 3 == 0 && n % 5 == 0 && n % 7 == 0;
}
Program.cs
1 2 3 4 5 6 7 8 10 9 12 11 13 14 15 16 18 17 20 19 22 21 23 24 25 26
92
Lineáris keresés párhuzamosítása
• Az eredmények tömbben a szálak futási állapotát is tároljuk. Ha egy érték.
– –2 : még fut a szál.
– – 1 : a szál lefutott, de nem talált a feltételnek megfelelő elemet.
– Más érték: a szál lefutott és az érték a feltételnek megfelelő elem.
• A program akkor ér véget, amint a legkisebb indexű szál talált
eredményt (vagy egyik szál sem talált megfelelő elemet).
www.tankonyvtar.hu
© Kurdi Zsombor, ÓE NIK
Megoldás (Párhuzamos)
// inicializálás
for (int i = 0; i < szálakSzáma; ++i) eredmények[i] = -2;
…
// lefutás ellenőrzés int index = 0;
while (index < szálakSzáma && eredmények[index] < 0) {
if (eredmények[index] == -1) ++index;
Thread.Sleep(1);
}
Program.cs
1 2 3 4 5 6 7 8 10 9 12 11 13 14 15 16 18 17 20 19 22 21 23
94
Megoldás (Párhuzamos)
// a szál-paraméterek szerkezete struct SzálParaméter
{ public int[] Számok; // a beolvasott számok
public int SzálIndex; // az eredmény tömbben erre az indexre írja a szál a futás eredményét public int StartIndex; // ahonnan elkezdi a szál olvasni a Számok tömböt
public int Hossz; // ahány elemet a szálnak fel kell dolgozni }
// szálfüggvény
private static void Szálfüggvény(object obj) { SzálParaméter param = (SzálParaméter)obj;
bool találat = false;
int szám = 0;
for (int i = param.StartIndex; i < param.StartIndex + param.Hossz; ++i) {
if (Feltétel(param.Számok[i])) {
találat = true;
szám = param.Számok[i];
} } 1 2
3 4 5 6 7 8 10 9 12 11 13 14 15 16 18 17 20 19 22 21 23 24 25
www.tankonyvtar.hu
Bináris keresés
© Kurdi Zsombor, ÓE NIK 96
Bináris keresés
• Feladat
– Döntsük el, hogy egy rendezett sorozat tartalmazza-e az E elemet.
• Sorozathoz értéket rendel.
• Algoritmus
a = 1, f = n, találat = false while a <= f
k = (a + f) / 2 if (s[k] = E) találat = true break
else if (s[k] > E)
www.tankonyvtar.hu
© Kurdi Zsombor, ÓE NIK
Bináris keresés
• Lépésszám
– Legjobb eset: 1
– Legrosszabb eset: log
2n – Átlagos eset: ~log
2n
– Függvényosztály: Θ(log
2n)
98
Feladat
Adott egy n számot tartalmazó rendezett tömb. Döntse el, hogy
tartalmazza-e a tömb a 384-es számot! Oldja meg a feladatot
soros és párhuzamos algoritmussal is!
www.tankonyvtar.hu
© Kurdi Zsombor, ÓE NIK
Megoldás (Soros)
// keresés int eleje = 0;
int vége = számok.Length;
while (eleje < vége)
{ int közepe = (eleje + vége) / 2;
if (számok[közepe] > keresettSzám) vége = közepe - 1;
else if (számok[közepe] == keresettSzám) eleje = vége = közepe;
else
eleje = közepe + 1;
}
// eredmény és futási idő kiírás if (eleje == vége)
Console.WriteLine("A tömb a(z) {0}. indexen tartalmazza a(z) {1} számot.", eleje, keresettSzám);
else
Console.WriteLine("A tömb nem tartalmazza a(z) {0} számot.", keresettSzám);
Console.WriteLine("Összesen {0} db számot vizsgáltam.", számok.Length);
Console.WriteLine("Futási idő: {0}", stopper.Elapsed);
Program.cs
1 2 3 4 5 6 7 8 10 9 12 11 13 14 15 16 18 17 19 20 22 21 23
100
Bináris keresés párhuzamosítása
• Az eredmények tömb helyett eleje és vége nevű tömbök
tartalmazzák az egyes részeken végzett bináris keresések indexeit.
• A korábbi adatfelosztás helyett új módszert alkalmazunk.
• A program akkor ér véget, amint egy szál megtalálta a keresett elemet, vagy minden szál lefutott.
• Emiatt a keresés eredménye nemdeterminisztikus (de az
eldöntéshez nem szükséges determinisztikus eredmény).
www.tankonyvtar.hu
© Kurdi Zsombor, ÓE NIK
Adatbelovasás
// az adatfelosztási módszernek megfelelő beolvasás private static int[,] Beolvas()
{ StreamReader input = new StreamReader(inputFile);
int méret = Convert.ToInt32(input.ReadLine());
int[,] számok = new int[szálakSzáma, méret / szálakSzáma];
for (int i = 0; i < méret; ++i)
számok[i % szálakSzáma, i /szálakSzáma] = Convert.ToInt32(input.ReadLine());
input.Close();
return számok;
}
Program.cs
1 2 3 4 5 6 7 8 10 9 12 11 13 14 15 16 18 17 20 19 22 21 23
102
Megoldás (Párhuzamos)
// inicializálás
for (int i = 0; i < szálakSzáma; ++i) { eleje[i] = 0;
vége[i] = számok.GetLength(1) – 1;
} …
// lefutás ellenőrzés int index = -1;
bool vanFutóSzál = true;
while (vanFutóSzál && index < 0) {
vanFutóSzál = false;
for (int i = 0; i < szálakSzáma; ++i) {
if (eleje[i] == vége[i])
index = eleje[i] * szálakSzáma + i;
else
vanFutóSzál = true;
} 1 2
3 4 5 6 7 8 10 9 12 11 13 14 15 16 18 17 20 19 22 21
www.tankonyvtar.hu
© Kurdi Zsombor, ÓE NIK
Megoldás (Párhuzamos)
// a szál-paraméterek szerkezete struct SzálParaméter
{ public int[] Számok; // a beolvasott számok
public int SzálIndex; // az eredmény tömbben erre az indexre írja a szál a futás eredményét
public int Keresett Szám; // a keresett szám }
// szálfüggvény
private static void Szálfüggvény(object obj) { SzálParaméter param = (SzálParaméter )obj;
while (eleje[param.SzálIndex] < vége[param.SzálIndex]) {
int közepe = (eleje[param.SzálIndex] + vége[param.SzálIndex]) / 2;
if (param.Számok[param.SzálIndex, közepe] > param.KeresettSzám) vége[param.SzálIndex] = közepe - 1;
else if (param.Számok[param.SzálIndex, közepe] == param.KeresettSzám) eleje[param.SzálIndex] = vége[param.SzálIndex] = közepe;
else
eleje[param.SzálIndex] = közepe + 1;
}
} Program.cs
1 2 3 4 5 6 7 8 10 9 12 11 13 14 15 16 18 17 20 19 22 21 23 24 25 26
104
Visszalépéses keresés
www.tankonyvtar.hu
© Kurdi Zsombor, ÓE NIK
Visszalépéses keresés
• Feladat
– Egy rendezett N-est (E
1, E
2, ... E
N) keresünk, amely eleget tesz F feltételnek.
• A rendezett N-es minden komponense rögzített értékkészletből származhat (pl. E1 Є {R
11, R
12, ... R
1k}).
• Az E
ikomponenseket részeredményeknek nevezzük.
• Az egyes értékkészletek számosságát M
i-vel jelöljük.
• Az F feltétel olyan logikai értékű függvény, amely esetében tetszőleges részeredmény esetében megállapítható, hogy az lehet-e (vagy sem) egy jó eredmény része.
106