Elsőbbségi (prioritásos) sor Közapi fogalma, megjeleése: pl. sürgősségi osztályo a páciesek em a beérkezési időek megfelelőe, haem a sürgősség mértéke szerit kerülek ellátásra. Az operációs redszerekbe a prioritásos jobok feldolgozása is hasoló elv alapjá törtéik. Keressük azt az adatszerkezetet, amelybe az elsőbbségi sor típus tárolása hatékoy módo lehetséges. Ez azt jeleti, hogy szereték, ha az elsőbbségi sor műveleteit a lehető leggyorsabba tudák végrehajtai. Jó lee olya struktúrát találi, amelybe a beérkező beteg elhelyezése, illetve az ellátásra következő pácies kiválasztása (együttese miél rövidebb időt vee igéybe. Műveletek Empty: P L Üres? Push: P E P Sorba Frot: P E Első Prior / Első Elem Pop: P P E Sorból Megszorítások: DFrot = DPop = P \ Empty Meg kell vizsgáli, hogy milye reprezetációval tudjuk leghatékoyabbá tei a típus műveleteit. A külöböző megvalósítási módok pedig külöböző szerkezeti tulajdoságokat eredméyezek. A következőkbe láti fogjuk, hogy bármely megvalósítást is választjuk, az Empty művelet () hatékoyságúak, ezért midig csak a többi művelet hatékoyságát vizsgáljuk.. Megvalósítás: Redezetle tömbbe kerülek az elemek, pl. a beírás sorredjébe. 0 db- - db jelzi a midekori elemszámot. Az egyes típusműveletek hatékoysága (az összehasolítások és mozgatások száma): Push: Ha a tömb ics tele, akkor t[db] értékét beállítjuk, db értékét öveljük -el, (). Frot: Ha a sor em üres, akkor egy MaxKer-rel megoldható a feladat: (. Pop: A maximális és egybe törledő elem megkeresése az előzőek alapjá törtéik (. Ha maxi a legagyobb elem idexe, akkor a tőle jobbra álló elemeket eggyel balra mozgatjuk ez O(: (.
template <class E> class priorsor public: priorsor(it maxdb) = maxdb; t = ew E[]; db = 0; bool empty() retur db==0; bool full() retur db==; void push(e adat) if(!full()) t[db++]=adat; void pop() it maxi = 0; for(it i=; i<db; ++i) if(t[i]>t[maxi]) maxi=i; for(it i=maxi+; i<db; ++i)
--db; t[i-]=t[i]; E frot() it maxi = 0; for(it i=; i<db; ++i) if(t[i]>t[maxi]) maxi=i; retur t[maxi]; ~priorsor() delete[] t; private: E* t; it ; it db; ; priorsor& operator=(cost priorsor& s) priorsor(cost priorsor& s costructor Javítás: Nem evezhetjük új megvalósítási módak az alábbiakat, az előzőhez képest csak új változót vezetük be: maxh maxh midig a maximális elem idexe (helye)
. Megvalósítás: Redezett tömbbe helyezzük el az elemeket. A maximális elem midig az utolsó, így a Pop és Frot műveletek ideje kostasra csökke. Azoba egy elem beszúrásakor meg kell keresi az elem helyét a redezett tömbbe (pl. beszúró redezés belső ciklusa) template <class E> class priorsor public: priorsor(it maxdb) = maxdb; t = ew E[]; db = 0; bool empty() retur db==0; bool full() retur db==; void push(e adat) if(!full()) it i = db-; while(i>=0 && t[i]>adat) t[i+]=t[i]; --i; t[i+]=adat; ++db; void pop() --db; E frot() retur t[db-]; ~priorsor()
delete[] t; private: E* t; it ; it db; ; priorsor& operator=(cost priorsor& s) priorsor(cost priorsor& s) Haszáljuk ki azt, hogy egy redezett tömbbe egy elemet logaritmikus kereséssel lehet megtaláli. Ha a keresett elem ics a tömbbe, akkor a logaritmikus keresés jelzi ezt és ebbe az esetbe a keresés idexeiek végső helyzete alapjá meg lehet modai, hogy hol lee a keresett elem helye. Oda be is szúrhatjuk az elemet, ha a tőle jobbra lévőket eggyel jobbra léptetjük. Megjegyzés: Ez a speciális Push már egy javítási kísérlet eredméye ahhoz a változathoz képest, amely lieárisa keresi meg a beszúrás helyét. Push: (. Frot: (). Pop: (). Az Push és a Pop műveletek hatékoyságára pot fordított eredméyt kaptuk, mit az előző reprezetációba. 3. Megvalósítás: Egy kupac tulajdoságú fát töltük fel az elemekkel. A kupac (heap) egy olya majdem teljes, balra tömörített biáris fa (tehát az utolsó szit jobb oldaláról esetleg hiáyozhatak elemek), amelybe mide belső elem agyobb, vagy egyelő, mit a gyermekei. 9 0 3 6 Push: Az új csúcs beszúrásával meg kell tartauk a kupac tulajdoságot, ezért az új csúcs az utolsó sorba, balról az első üres helyre, vagy ha az utolsó sor teljes, akkor egy új sor bal szélére kerül. De még redbe kell hozi a csúcsok értékeiek viszoyát, tehát elemcseréket végzük alulról a gyökér felé haladva (felfelé) ameddig szükséges (amíg a szülő kisebb, mit a gyerek). Nézzük eek működését az alábbi kupaco, ha a 5-ös értéket szúrjuk be:
A műveletigéy a legrosszabb esetbe is a fa magasságával lesz egy agyságredbe, ami elemű fa esetébe log. Tehát O(log. Frot: Ebbe az esetbe csak kiolvassuk a gyökérbe lévő értéket. Pop: A gyökérbe lévő értéket kiolvassuk, majd az utolsó (jobb alsó) értéket rakjuk a gyökérbe, az utolsó csúcsot töröljük. A kupac tulajdoság megtartása érdekébe a gyökérbe került értéket elemcserékkel lesüllyesztjük (midig a agyobb gyerekkel cserélve) a megfelelő helyre. Az alábbi kupaco láthatjuk eek működését: A műveletigéy itt is a fa magasságával aráyos: O(log. Foglaljuk össze egy hatékoysági táblázatba a külöböző megvalósítások jellemzőit: Redezetle tömb. Redezetle tömb. Redezett tömb Kupac Push () () O(log +O( = O( O(log Pop ( ( () O( log Frot ( () () ()
A Frot műveletre a javítás utá már midhárom reprezetációba kostas lépésszámot kaptuk. A két fotosabb művelet az Push és a Pop a kupac reprezetációba kiegyesúlyozott módo hatékoyabb, mit az első kettőbe. Ezt akkor látjuk igazá, ha egy olya művelet sorozatot hajtuk végre, amelybe vegyese szerepel beszúrás és a törlése. A prioritásos sor felhaszálása redezésre Találtuk egy agyo egyszerű és talá meglepő algoritmust, amely az említett két műveletet egyelő számba hajtja végre működése sorá. Empty (p) s ε Read (s,x) Isert (p,x) IsEmpty (p) DelMax (p,x) Write (x) Az eljárás az s szekveciális iputról beolvasott értékeket sorba beteszi egy (kezdetbe üres) elsőbbségi sorba. Azutá pedig sorba kiveszi az elemeket az elsőbbségi sorból. A kiírt sorozat yílvá redezett lesz! Ez a redezés mide bizoyal meglepő, hisze ics bee egymásba ágyazott ciklus. Eek az a magyarázata, hogy az algoritmus szitjé el va takarva előlük a felhaszált adatszerkezet megvalósításáak módja. Az alábbi elemzés alapjá joggal modhatjuk, hogy az elsőbbségi sorak kupaccal megvalósítása hatékoyabb a másik két ábrázolási módál! Reprezetációtól függetleül igaz, hogy MT( k MT Push ( k MT Pop ( Számítsuk ki a feti kifejezés agyságredjét a három reprezetációba. Redezetle tömb Redezett tömb Kupacos ábrázolás MT( () () ( ( MT( ( () ( MT( (log log... log ) ) )
Azt állítjuk, hogy eek az összegzések az eredméye agyságredbe log -es, azaz: Bizoyítás: MT( ( log. A kiszámítadó összeget, mit a log x függvéy beírt téglalapjaiak területösszegét, tekitsük itegrál közelítő összegek. Ekkor log log... log log x dx l x dx l xl x x ( )l( ) ( ),44 l l l log ( log log +
template <class E> class priorsor public: priorsor(it maxdb) = maxdb+; //0. hely ürese marad t = ew E[]; u = 0; //utolsó elem helye bool empty() retur u==0; bool full() retur u==-; void push(e adat) if(!full()) t[++u]=adat; emel(u); void pop() t[] = t[u--]; sullyeszt(); E frot() retur t[]; ~priorsor() delete[] t; private: E* t; it ;
it u; void emel(it i) while(i> && t[szulo(i)]<t[i]) csere(i,szulo(i)); i = szulo(i); void sullyeszt(it i) if(bal(i)>u) //ics gyerek, em kell süllyesztei retur; it iray; if(jobb(i)>u t[bal(i)]>t[jobb(i)]) //ics jobb gyerek vagy agyobb a balgyerek iray = bal(i); else iray = jobb(i); if(t[i]<t[iray]) //a agyobb gyerek agyobb csere(i,iray); sullyeszt(iray); it szulo(it i) retur i/; it bal(it i) retur *i; it jobb(it i) retur *i+; void csere(it i, it j) E tmp = t[i]; t[i] = t[j]; t[j] = tmp; ; priorsor& operator=(cost priorsor& s) priorsor(cost priorsor& s)
A prioritásos sor alkalmazásai. Ütemezési eljárásokál. Redezetleségi kofliktus: az iput és az output elemei egyértelműe egymáshoz redelhetők, de az elemek sorredje ütközik a feldolgozás sorredjével. 3. Gráfok: Dijkstra, Prim algoritmus (lásd ott).