310 likes | 408 Views
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ő: Imre Mihály, műszaki informatikus hallgató. Prioritási várakozó sorok (Priority Queues).
E N D
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ő: Imre Mihály, műszaki informatikus hallgató
Prioritási várakozó sorok (Priority Queues) • Nyomtató jobok queue-ba: 1 lapos, sok lapos, különösen fontos anyag • Több felhasználós környezetben: • Az ütemező mely processzeket futtassa, queue-ba, rögzített időszeletet kap, befejeződik vagy az időkorlát érvényesül, a sor végére kerül. • A rövid jobok fussanak le mielőbb, és vannak nagyon fontos jobok • Ezekhez az alkalmazásokhoz Prioritási várakozósorok kellenek. A PQ ADT hatékony implementációja, a PQ-k felhasználása, a PQ-k korszerű implementációi. Ezek az adatszerkezetek a számítástudomány legelegánsabbjai. 2
DeleteMin(H) Insert(H) Priority Queue: H PQ ADT Olyan adatmodell, ami legalább a következő két műveletet lehetővé teszi: Insert és DeleteMin, keresi, visszaadja és eltárolja a PQ minimális elemét vagy Enqueue, Dequeue. A DeleteMin az inputját is megváltoztatja, jelenleg a szoftver engineeringben ezt nem tartják jó gondolatnak. De mi történeti okokból ezt a működési módot használjuk. Más műveleteket is hozzárendelhetünk, de ezek nem az alapmodell részei. Korábban láttuk alkalmazását a rendezéseknél (heapsort). Fontosak a greedy algoritmusok megvalósításában. Diszkrét esemény szimuláció. Külső rendezés. 3
PQ Egyszerű megvalósítások Egyszerű láncolt lista: Beszúrás: O(1), a lista bejárása a törléshez O(N) Rendezett láncolt lista: Beszúrás O(N), DeleteMin O(1) Az első kedvezőbb lehet, mivel biztosan nincs több törlés, mint beszúrás. Bináris halom: (Binary heap) A PQ-nál annyira általánosan használt, hogy a heap alatt bináris heapet értünk. 4
PQ • Két tulajdonsága van: • szerkezeti tulajdonság • heap order tulajdonság (rendezettségi). • Egy heap művelet sértheti, akkor helyreállítás. • Szerkezeti tulajdonság: • A heap bináris fa, ami teljesen kitöltött a legalsó szint kivételével és ami balról-jobbra van kitöltve. Ez a fa a teljes bináris fa. (Nem a tökéletes.) 5
C G J A B D E F H I 8 9 10 7 2 0 1 3 4 5 6 D B C A F I H J G E PQ A h magasságú 2h , 2h+1 –1 közötti csúcspontú, a magasság [log N], ami O(log N). Mivel ennyire szabályos, tömbbel is megvalósítható, pointerek nélkül. 6
PQ Type PQ = record Elem[0..Maxelem] of elemtipus; Meret : integer; End; Bármely i. elem bal gyereke a 2i. elem, jobbja a 2i+1, a szülője pedig [i/2]. Tehát nem kell pointer. De meg kell adni a max heap méretet. A továbbiakban a heapeket faként ábrázoljuk és tömbbel valósítjuk meg. 7
PQ A heap order tulajdonság: A műveletek gyors végrehajtására kell a heap order tulajdonság. Mivel a minimumot akarjuk gyorsan megkereseni, ezért a gyökérbe tesszük a minimumot. Ha figyelembe vesszük, hogy az alfáknak szintén heapeknek kell lenniük, akkor minden csúcsnak kisebbnek kell lennie az összes leszármazottjánál, azaz a gyökér kivételével minden X csúcs kulcsa nem kisebb a szülője kulcsánál. Így a FindMin (extra) művelet O(1) igényű. (analóg a FindMax-xal, de ezt előre el kell dönteni.) 8
D B A C 68 34 19 E 13 16 21 31 24 65 26 PQ Pl. Alap Heap műveletek A két szükséges művelet végrehajtása egyszerű, mindegyiknél ügyelni kell a heap order tulajdonság fenntartására. 9
13 13 16 14 16 21 21 24 24 65 26 65 26 19 31 68 34 19 68 31 19 32 68 32 13 16 21 31 24 65 26 PQ InsertA következő rendelkezésre álló helyen egy lyukat hozzunk létre. Ha ide az X behelyezhető, akkor kész. Ha nem akkor a szülőjét lecsúsztatjuk, azaz a lyukat felbugyborékoltatjuk, míg az X-et el nem tudjuk helyezni. -> 14 10
PQ Az Insert rutinban nem cserélgetünk (3d értékadás művelet volna, d a szintek száma), awhile ciklust a 0 pozícióba tett kis értékű határolóelemmel (sentinel) állítjuk le,így d+1 értékadás. 11
PQ {H.elem[0] a sentinel} Procedure Insert(X: elemtipus; var H: PQ); Var i: integer; Begin If Telt(H) then Error(’ PQ tele van’) Else Begin H.meret := H.meret + 1;i := H.meret; while H.elem[i div 2] > X do {bit shifttel} Begin H.elem[i] := H.elem[ i div 2 ]; i := i div 2; End; H.elem[i] := X; End; End; Maximum O(log N) művelet, ha az elem az új minimum, átlagban 2,607 összehasonlítás; így az új elem 1,607 szintet emelkedik átlagosan. 12
PQ DeleteMinA minimum elem a gyökérben van, kilyukad, a heap eggyel kisebb lesz. Az utolsó X elemet a heap-ben valahol el kell helyezni. Ha betehető a gyökérbe akkor OK. A lyuk kisebbik gyerekét feltoljuk, a lyuk lefelé megy, míg az X el nem helyezhető. 13
13 16 16 14 14 21 21 19 19 65 65 26 26 14 16 19 21 26 19 68 19 32 68 31 19 31 68 32 32 65 31 PQ Mindig figyeljünk arra, hogy nem biztos a két gyerek megléte, gyakori hibaforrás! 14
PQ Function DeleteMin(var H: PQ) : elemtípus; Var i, gyerek : integer; utelem : elemtipus; stop : boolean; {goto nélkül} begin if Ures(H) then Error(’a PQ üres’) else begin DeleteMin := H.elem[1]; utelem := H.elem[H.meret]; H.meret := H.meret – 1; i := 1; stop := false; while (i*2 <= H.meret)and (not stop)do {bitshift} begin gyerek := 2 * i; {kisebb gyerek keresése} 15
PQ if gyerek <> H.meret then if H.elem[gyerek + 1] < H.elem[gyerek] then gyerek := gyerek + 1; if utelem > H.elem[gyerek] then {bugyburékoltat} begin H.elem[i] := H.elem[gyerek]; i := gyerek; end; else stop := true; end; H.elem[i] := utelem; End; End; wc O(log N), ac O(log N), mivel majdnem mindig végig kell bugyburékoltatni. 16
PQ További heap műveletek Bár a minimum elem megkeresése konstans erre terveztük a minimum heapet. A maximum elem megkeresése már gond, nincs rendezési információ. Egy bizonyos kulcsú elemet a heap teljes vizsgálatával tudunk csak megtalálni. A maximumról azt tudjuk, hogy levélen van, de ott van az elemek fele. A heap mellett más adatszerkezet is kell az elemek megtalálására, mint pl. egy hash tábla. Így további műveletek is olcsón megvalósíthatók. Az alábbi műveletek wc log (N). DecreaseKey(X, dp, H) Mivel ez megsértheti a heap ordert, felbugyborékoltatással javítunk. A rendszer adminisztrátor ezzel ad nagyobb prioritást. 17
PQ IncreaseKey(X, dp, H) Lelbugyborékoltatással állítjuk helyre. Sok ütemező ezzel csökkenti az olyan processzek prioritását ami túl sok CPU időt emészt. Delete(X,H) Az X csúcsot törli: DecreaseKey(X, maxp, H) majd DeleteMin(H). Ha a felhasználó megszakítja a processzt, azt ki kell törölni a PQ – ból. 18
PQ BuildHeap(H) N kulcsot berak az üres heap –be: N egymásutáni Insert általában tetszőleges sorrendben csak a szerkezeti tulajdonságot tartjuk be. Utána bugyborékoltatunk: For i:= N div 2 downto 1 do lebugyborekoltat(i); a heap order létrehozására. 19
40 110 20 100 90 60 30 10 80 120 50 140 130 70 40 10 120 150 100 90 80 30 30 70 150 70 140 150 50 110 PQ N = 15;i = 7,6,5,...1 20
PQ Mindegyik szaggatott vonal két összehasonlítást jelent, a csúcsok maximum száma az összes csúcs magasságainak összege. A h magasságú, tökéletes bináris fa, mely 2h+1 – 1 csúcsot tartalmaz, azaz, csúcsai magasságának összege: 2h+1 – 1 – (h+1) 1. 2. 1-2: A teljes fa 2h –2h+1 közötti csúcsot tartalmaz, így a fenti egy felső korlát. És ez O(N), de indukcióval N-b(N) (b(N) az egyesek száma N bináris ábrázolásában). 21
A PQalkalmazásai • Kiválasztás: • N elemű listából válasszuk ki a k-adik legnagyobb elemet. • beolvas N elemet, rendez és rámutat, O(N2), egyszerű rendezéssel • beolvas k elemet tömbbe, rendez (csökkenő sorrendbe), ezek legkisebbike a k-adik után egyesével olvas, a k-adikkal hasonlít, ha nagyobb akkor a k-adikat töröljük és a (k-1) közé a megfelelő helyre tesszük az új elemet: O(N*k) • Ha k = [N/2] akkor mindkettő O(N2) • Megjegyzés: bármely k-ra megoldhatjuk a szimmetrikus feladatot, azaz keressük az (N-k+1)-edik maximum elemet, így tényleg a k = [N / 2] a legkedvezőtlenebb eset. Ráadásul ez a medián. • A következő algoritmusok O(N log N) futásidejűek a k = [N /2] szélsőséges esetben is. 22
PQ • S1. algoritmus (a k-adik min) • Beolvas N elemet tömbbe, alkalmazzuk a BuildHeap eljárást, utána végrehajtunk k darab DeleteMin műveletet, az utolsó a keresett érték. • ha k = O(N / log N), akkor a BuildHeap dominál • nagyobb k esetén O(k log N) • k = [N / 2] : O(N log N) • Megjegyzés: k = N esetén a kijövő elemek rendezettek: O(N log N), ami a heapsorthoz közelít. 23
PQ S2. algoritmus Most a k-adik a maximumot keressük. Minden időpontban a k darab legnagyobb elem S halmazát tartjuk karban. Az első k elem beolvasása után a következő elemet összehasonlítjuk a k-adik maximummal (Sk) ez az S minimuma, ha az új elem nagyobb, akkor az Sk – t az S-ben kicseréljük ekkor az S-nek új minimum eleme lesz. A végén az S minimuma a keresett elem. De most az S megvalósítására heapet alkalmazunk. 24
PQ Az első k elemet a BuildHeap-pel a heapre tesszük, O(k) idővel, a további elemeknél O(1) a vizsgálat, hogy betegyük-e és O(log k) az Sk törlése és az új elem betételére, ha szükséges. A teljes idő tehát O(k+ (N-k) log k) = O (N log k), még javítható...., wc O(N)-re. 25
PQ Esemény szimuláció Egy fontos sorbanállási feladat: a bankba ügyfelek érkeznek, k darab pult van. Az ügyfelek érkezése és kiszolgálási ideje egy valószínűségi eloszlással jellemezhető. Kérdés: átlagban mennyit kell várnia az ügyfeleknek, vagy milyen hosszú lehet a sor. Bizonyos valószínűségi eloszlásoknál és k értékeknél ez kiszámítható pontosan. Nagyobb k értékeknél egyre nehezebb, ezért szimulációt alkalmazunk, és meghatározhatjuk az elviselhető hosszúságú sorhoz szükséges pultok számát. 26
PQ • A szimuláció események feldolgozásából áll: • ügyfél érkezik • ügyfél távozik (felszabadul egy pult). • Valószínűségi függvényeket használunk az érkezési idő és a kiszolgálási idő rendezett párok előállítására, melyeket az érkezési idő szerint rendezünk. A tényleges idő helyett, idő osztásokat használunk. • Az egyik módszer:elindítjuk a szimulációs órát 0 időnél, és egy-egy osztással léptetjük az órát és megnézzük történt-e valamilyen esemény, ha igen feldolgozzuk és összeállítjuk a statisztikát. Addig folytatjuk míg elfogy az ügyfél és minden pult kiürül. • A futási idő az időosztástól függ. 27
PQ • Másik módszer:az órát a következő eseményre igazítjuk. Két esemény történhet: ügyfél érkezik vagy távozik. Mivel minden időpont ismert, nekünk csak a legközelebbi eseményt kell megtalálnunk és feldolgoznunk: • ha ügyfél távozik, akkor:- statisztika a távozó ügyfélről,- a queue ellenőrzése, van-e még várakozó ügyfél, ha igen, akkor bevesszük, statisztika, kiszámítjuk, mikor végez, és távozását a bekövetkezésére váró események halmazába tesszük. • ha ügyfél érkezik, akkkor:ellenőrizzük van-e üres pult, ha igen kiszámítjuk a távozási idejét és a bekövetkezésére váró események halmazába tesszük a távozást, ha nincs, akkor a várakozósorra tesszük. 28
PQ Az ügyfelek várakozó sora queue, a távozásra várókat pedig priority queue-ba tesszük, mivel a legközelebbi jövőben beérkező eseményre van szükségünk. A következő esemény tehát vagy a következő érkezés vagy a következő távozás, ami így könnyen meghatározható. O(C log (k+1)), (k+1) a heap mérete, C ügyfél. 29
2 8 3 6 15 13 10 5 4 9 11 1 17 9 7 d-Heap Teljesen hasonló a bináris heap-hez, de minden csúcsnak d gyereke van. Sokkal laposabb. Insert O(logd N), DeleteMin O(d logd N) D gyerek minimumát kell meghatározni: d-1 összehasonlítással. Ha d konstans akkor ez is O(log N). 30
d-Heap Tömbben (ábrázolható) tárolható, de a gyerekek, szülők meghatározásához d-vel kell szorozni, osztani így a bitshift nem használható. Az olyan algoritmusoknál érdemes használni, ahol a beszúrások száma jóval nagyobb, mint a DeleteMin-ek száma. Ha nem fér a Priority Queue a fő memóriába, akkor a B-tree-hez hasonlóan előnyösen használható. A keresés mellett két heap összefűzése egy nehéz művelet: Merge. 31