• No results found

External Sorting

N/A
N/A
Protected

Academic year: 2021

Share "External Sorting"

Copied!
64
0
0

Loading.... (view fulltext now)

Full text

(1)

Katedra informatiky

Tˇr´ıd ˇen´ı na extern´ım ´

uloˇzi ˇsti

External sorting

(2)
(3)

V Ostravˇe 23. ˇcervence 2010 . . . .

Prohlaˇsuji, ˇze jsem tuto diplomovou pr´aci vypracoval samostatnˇe. Uvedl jsem vˇsechny liter´arn´ı prameny a publikace, ze kter ´ych jsem ˇcerpal.

(4)
(5)
(6)
(7)

velikost operaˇcn´ı pamˇeti poˇc´ıtaˇce. Sezn´amit se zn´am ´ymi algoritmy, jejich nedostatky a n´asledn ´ymi optimalizacemi, d´ale navrhnout komponentu pro tˇr´ıdˇen´ı dat s pouˇzit´ım tˇechto algoritm ˚u. Tuto komponentu implementovat v jazyce C++ nad jiˇz implementova-nou strukturou perzistentn´ıho pole a n´aslednˇe ji otestovat, popˇr. d´ale optimalizovat.

Kl´ıˇcov ´a slova: Tˇr´ıdˇen´ı dat, extern´ı tˇr´ıdˇen´ı, tˇr´ıd´ıc´ı algoritmus, sloˇzitost algoritmu, C++

Abstract

The aim of this thesis is to describe the problem of data sorting whose size is larger than the main memory. Familiarize with known algorithms, their shortcomings and subse-quent optimization, design component for sorting the data using these algorithms. This component implemented in C++ over the structure of the implemented persistent array and consequently they are tested, respectively. further optimize.

(8)
(9)

Obsah

1 Uvod´ 11

1.1 C´ıl diplomov´e pr´ace . . . 11

2 Uvod do tˇr´ıd´ıc´ıch algoritm ˚u´ 13 2.1 Algoritmus . . . 13

2.2 Tˇr´ıd´ıc´ı algoritmy . . . 13

2.3 Z´akladn´ı typy tˇr´ıd´ıc´ıch algoritm ˚u . . . 14

3 Algoritmy pro tˇr´ıdˇen´ı na extern´ım ´uloˇziˇsti 15 3.1 Uvaˇzovan ´y model . . . 15

3.2 Popis extern´ıho mergesortu . . . 15

3.3 Spojovac´ı algoritmy . . . 19

4 Komponenta perzistentn´ıho pole 23 4.1 Popis komponenty . . . 23

4.2 Pˇr´ıklad pr´ace s perzistentn´ım polem . . . 23

5 Anal ´yza a n´avrh komponenty pro extern´ı tˇr´ıdˇen´ı prvk ˚u 29 5.1 Specifikace poˇzadavk ˚u . . . 29

5.2 Specifikace pomoc´ı pˇr´ıpadu uˇzit´ı . . . 29

5.3 Tˇr´ıdn´ı diagram . . . 30

6 Implementace 33 6.1 Tˇr´ıda ArrayTest . . . 33

6.2 ˇSablona RunInfo . . . 34

6.3 ˇSablona SortArray . . . 34

6.4 Pouˇzit´e technologie a programov´e vybaven´ı . . . 39

7 Testy 41 7.1 Data pouˇzit´a pro testov´an´ı . . . 41

7.2 Grafy . . . 43 7.3 Shrnut´ı testov´an´ı . . . 45 8 Z´avˇer 49 9 Reference 51 Pˇr´ılohy 51 A Uˇzivatelsk´a pˇr´ıruˇcka 53 B Obsah pˇriloˇzen´eho CD 55

(10)
(11)

Seznam tabulek

1 Seznam vstupn´ıch soubor ˚u k testov´an´ı a jejich parametry . . . 42 2 Mˇeˇren´ı ˇcasu tˇr´ıdˇen´ı vstupn´ıch soubor ˚u pro r ˚uzn´e velikosti hlavn´ı pamˇeti . 42

(12)
(13)

Seznam obr ´azk ˚

u

1 Prvn´ı f´aze extern´ıho mergesortu . . . 16

2 Druh´a f´aze extern´ıho mergesortu vyuˇz´ıvaj´ıc´ı dva pr ˚uchody . . . 16

3 Diagram pˇr´ıpadu uˇzit´ı syst´emu . . . 30

4 Tˇr´ıdn´ı diagram komponenty pro tˇr´ıdˇen´ı prvk ˚u . . . 32

5 Graf tˇr´ıdˇen´ı souboru test setrideny.txt . . . 43

6 Graf tˇr´ıdˇen´ı souboru test1.txt . . . 44

7 Graf tˇr´ıdˇen´ı souboru test2.txt . . . 44

8 Graf tˇr´ıdˇen´ı souboru test3.txt . . . 45

9 Graf tˇr´ıdˇen´ı souboru test4.txt . . . 46

(14)
(15)

Seznam algoritm ˇ

u

1 Uk´azka pseudok ´odu extern´ıho mergesortu . . . 17

2 Uk´azka pseudok ´odu algoritmu posloupnosti spotˇreby . . . 21

3 Uk´azka pseudok ´odu algoritmu seskupov´an´ı blok ˚u . . . 22

4 Pseudok ´od algoritmu naˇcti-setˇr´ıd’-uloˇz . . . 36

5 Pseudok ´od k-cestn´eho sl´ev´an´ı bez rekurze . . . 37

6 Pseudok ´od metody Sl´evej() potˇrebn´e k algoritmu k-cestn´eho sl´ev´an´ı bez rekurze . . . 38

(16)
(17)

Seznam v ´ypis ˚

u zdrojov ´eho k ´

odu

1 Uk´azka v ´ypisu vektor ˚u ze souboru perzistentn´ıho pole . . . 24

2 V ´ystup z metody v ´ypisu vektor ˚u ze souboru perzistentn´ıho pole . . . 25

3 Uk´azka z´apisu vektor ˚u do souboru perzistentn´ıho pole . . . 26

(18)
(19)

1

Uvod

´

V dneˇsn´ı uspˇechan´e dobˇe si ˇclovˇek snaˇz´ı vˇsemoˇzn ´ymi zp ˚usoby ulehˇcit svou pr´aci. S ob-rovsk ´ym boomem poˇc´ıtaˇcov´e techniky v devades´at ´ych letech minul´eho stolet´ı postupnˇe nar ˚ustalo nasazov´an´ı poˇc´ıtaˇc ˚u i do dˇr´ıve tˇeˇzko pˇredstaviteln ´ych pozic. S poˇc´ıtaˇcem um´ı pracovat dˇeti, poˇc´ıtaˇce dnes dokonce ˇr´ıd´ı letouny. K denn´ı rutinˇe patˇr´ı komunikovat pˇres email, m´ıt pˇr´ıstup k bankovn´ımu kontu prostˇrednictv´ım internetu, v´est videokonference, pˇren´aˇset multim´edia. Um´ıte si bez poˇc´ıtaˇce pˇredstavit ˇzivot? Poˇcitaˇce zkr´atka pronikly do ˇzivot ˚u nˇekolika miliard lid´ı na t´eto planetˇe.

Z hlediska informatiky je to jistˇe pozitivn´ı informace. A nyn´ı si zkuste pˇredstavit, kolik dat vytvoˇr´ı dennˇe, t ´ydnˇe, mˇes´ıˇcnˇe kaˇzd ´y uˇzivatel pracuj´ıc´ı s poˇcitaˇcem. Kaˇzd ´ym n´akupem v internetov´em obchodˇe, kaˇzd ´ym odeslan ´y emailem. Pokud tyto data chceme d´ale vyuˇz´ıvat, je potˇreba je dˇr´ıve nebo pozdˇeji setˇr´ıd´ıt. Pokud se mnoˇzina dat k setˇr´ıdˇen´ı nevejde do hlavn´ı pamˇeti poˇc´ıtaˇce, kter ´y m´a dan´a data setˇr´ıdit, je nutno pouˇzit extern´ı tˇr´ıdˇen´ı. To zajist´ı spr´avn´e setˇr´ıdˇen´ı dat ˇr´adovˇe vˇetˇs´ıch neˇz samotn´a n´am dostupn´a ˇc´ast hlavn´ı pamˇeti.

1.1 C´ıl diplomov ´e pr ´ace

C´ılem m´e diplomov´e pr´ace je popsat souˇcasn ´y stav zn´am ´ych algoritm ˚u pro tˇr´ıdˇen´ı dat na extern´ım ´uloˇziˇsti a jejich optimalizace. D´ale se sezn´amit s jiˇz implementovan ´ymi tˇr´ıdami perzistentn´ıho pole, popsat jejich strukturu, chov´an´ı a pˇredv´est na nich nˇekolik z´akladn´ıch operac´ı.

Pro tyto tˇr´ıdy navrhnout obecnou komponentu pro tˇr´ıdˇen´ı vyuˇz´ıvaj´ıc´ı pro tento pˇr´ıpad co nejvhodnˇejˇs´ı tˇr´ıd´ıc´ı algoritmus. D´ale navrhnout a popsat vhodnou optimalizaci, kter´a bude posl´eze tak´e implementov´ana. Pot´e popsat v ´yslednou implementaci a v z´avˇeru prov´est nˇekolik srovn´avac´ıch test ˚u a uk´azku pr´ace s v ´yslednou aplikac´ı.

(20)
(21)

2

Uvod do tˇr´ıd´ıc´ıch algoritm ˚

´

u

2.1 Algoritmus

Algoritmus je pˇredpis, kter ´y se skl´ad´a z koneˇcn´eho poˇctu krok ˚u a kter ´y zajist´ı, ˇze na z´akladˇe vstupn´ıch dat budou poskytnuta data v ´ystupn´ı. Kaˇzd ´y algoritmus m´a n´asleduj´ıc´ı vlastnosti:

• Koneˇcnost - poˇzadovan ´y v ´ysledek mus´ı b ´yt poskytnut v rozumn´em ˇcase. Za ro-zumn ´y lze povaˇzovat ˇcas, po kter´em bude v ´ysledek v ´ypoˇctu relevantn´ı vzhledem ke vstupn´ım dat ˚um.

• Hromadnost – Vstupn´ı data nejsou v popisu algoritmu reprezentov´ana konkr´etn´ımi hodnotami, ale sp´ıˇse mnoˇzinami, ze kter ´ych lze data vybrat.

• Jednoznaˇcnost – Kaˇzd ´y pˇredpis je sloˇzen z krok ˚u, kter´e na sebe navazuj´ı. Kaˇzd ´y krok m ˚uˇzeme charakterizovat jako pˇrechod z jednoho stavu algoritmu do jin´eho, pˇriˇcemˇz kaˇzd ´y stav je urˇcen zpracov´avan ´ymi daty. Vˇzdy mus´ı b ´yt urˇceno, kter ´y krok n´asleduje.

• Opakovatelnost – Pˇri pouˇzit´ı stejn ´ych vstupn´ıch dat mus´ıme dostat stejn´a data v ´ystupn´ı.

• Resultativnost – Algoritmus vede ke spr´avn´emu v ´ysledku [2]. 2.2 Tˇr´ıd´ıc´ı algoritmy

Tˇr´ıd´ıc´ı algoritmus je ´uloha, jej´ımˇz c´ılem je zajistit seˇrazen´ı dan´eho souboru dat podle pˇredem urˇcen´eho kl´ıˇce (numericky, abecednˇe, atd.) v co nejkratˇs´ım ˇcase. Probl´em tˇr´ıdˇen´ı patˇr´ı mezi nejv´ıce studovan´e probl´emy v poˇc´ıtaˇcov´e vˇedˇe, s nar ˚ustaj´ıc´ım trendem za-znamen´av´an´ı a shromaˇzd’ov´an´ı digit´aln´ıch ´udaj ˚u rostou i poˇzadavky na tˇr´ıdˇen´ı velk´eho mnoˇzstv´ı dat [1].

2.2.1 D ˇelen´ı tˇr´ıd´ıc´ıch algoritm ˚u

Pokud se vˇsechna data k seˇrazen´ı nevejdou do hlavn´ı pamˇeti poˇc´ıtaˇce, prob´ıh´a extern´ı tˇr´ıdˇen´ı, kdy je k mezioperac´ım pouˇzito ˇr´adovˇe pomalejˇs´ı pamˇeti, dnes pˇrev´aˇznˇe pevn´e disky. Tyto algoritmy narozd´ıl od klasick ´ych tˇr´ıd´ıc´ıch algoritm ˚u mus´ı br´at v ´uvahu mno-hem vˇetˇs´ı n´aklady pˇri ˇcten´ı nebo z´apisu na extern´ı m´edium. Algoritmy pro tˇr´ıdˇen´ı se tedy podle pamˇeti, ve kter´e prob´ıhaj´ı, dˇel´ı na:

• Vnitˇrn´ı – cel ´y soubor dat k setˇr´ıdˇen´ı se vejde do hlavn´ı pamˇeti poˇc´ıtaˇce, k poloˇzk´am lze pˇristupovat n´ahodnˇe se zanedbateln ´ymi n´aklady.

• Vnˇejˇs´ı – do hlavn´ı pamˇeti poˇc´ıtaˇce se vejde jen ˇc´ast dat k setˇr´ıdˇen´ı, algoritmy pro vnˇejˇs´ı tˇr´ıdˇen´ı minimalizuj´ı poˇcet pˇr´ıstup ˚u na disk, pˇr´ıpadnˇe ˇreˇs´ı dalˇs´ı optimalizace pro co moˇzno nejlepˇs´ı pˇrekr ´yv´an´ı procesorov´eho a vstupnˇe/v ´ystupn´ıho ˇcasu [1].

(22)

14

Podle dalˇs´ıch vlastnost´ı pak na:

• Pˇrirozen´e - pˇrirozen ´y algoritmus pracuje rychleji na jiˇz ˇc´asteˇcnˇe setˇr´ıdˇen´e mnoˇzinˇe dat.

• Stabiln´ı - stabiln´ı tˇr´ıd´ıc´ı algoritmy zachov´avaj´ı relativn´ı poˇrad´ı z´aznam ˚u se stejnou hodnotou kl´ıˇce. Pokud tedy v souboru dat existuj´ı dva z´aznamy se stejnou hodno-tou kl´ıˇce, mus´ı algoritmus zachovat jejich vz´ajemn´e poˇrad´ı.

2.2.2 Sloˇzitost tˇr´ıd´ıc´ıch algoritm ˚u

• ˇCasov´a - ˇcasovou sloˇzitost´ı rozum´ıme funkci, kter´a kaˇzd´e mnoˇzinˇe vstupn´ıch dat pˇriˇrazuje poˇcet operac´ı vykonan ´ych pˇri v ´ypoˇctu podle dan´eho algoritmu.

• Pamˇet’ov´a - pamˇet’ovou sloˇzitost definujeme jako z´avislost pamˇet’ov ´ych n´arok ˚u al-goritmu na vstupn´ıch datech.

ˇ

Casov´a sloˇzitost v ´ypoˇcetn´ıch metod zpravidla vzbuzuje menˇs´ı respekt neˇz sloˇzitost pamˇet’ov´a [2].

2.3 Z ´akladn´ı typy tˇr´ıd´ıc´ıch algoritm ˚u

• Bubblesort - Pˇri neust´al´em proch´azen´ı seznamu porovn´av´ame dva sousedn´ı prvky, pokud nejsou ve spr´avn´em poˇrad´ı, vymˇen´ıme je. Proch´azen´ı seznamu skonˇc´ı, po-kud je cel ´y setˇr´ıdˇen. Jednoduch ´y na implementaci. Pˇrirozen ´y, stabiln´ı. Vyˇzaduje velk´e mnoˇzstv´ı z´apis ˚u do pamˇeti. Pr ˚umˇern´a i maxim´aln´ı sloˇzitost: O(n2).

• Quicksort - Patˇr´ı mezi algoritmy typu rozdˇel a panuj. Nejprve na seznamu zvol´ıme pivota (nejl´epe medi´an cel´eho seznamu). Algoritmus pak seznam rozdˇel´ı na dva znamy, v nˇemˇz v jednom jsou prvky menˇs´ı neˇz pivot, ve druh´em vˇetˇs´ı. Oba tyto se-znamy se stejn ´ym postupem rekurzivnˇe setˇr´ıd´ı. Sloˇzitost algoritmu z´avis´ı na volbˇe pivota, poˇc´ıtat medi´an u velk´eho mnoˇzstv´ı dat vˇsak nen´ı efektivn´ı, pouˇz´ıv´a se tedy n´ahodnˇe vybran ´y prvek (nepˇr´ıliˇs efektivn´ı), nebo medi´an n´ahodnˇe vybran´e mal´e ˇc´asti seznamu. Nepˇrirozen ´y, nestabiln´ı. Pr ˚umˇern´a sloˇzitost O(n · log n), maxim´aln´ı sloˇzitost: O(n2)(pˇri pouˇzit´ı vˇzdy nejhorˇs´ıho moˇzn´eho pivota).

• Mergesort - ˇRazen´ı sl´ev´an´ım, dalˇs´ı z algoritm ˚u typu rozdˇel a panuj. Algoritmus postupnˇe dˇel´ı seznam na menˇs´ı ˇc´asti, dokud nen´ı rozdˇelen ´y na jednotliv´e prvky (trivi´aln´ı probl´em). Pak jej postupnˇe spojuje zp´atky s pˇrihl´ednut´ım na hodnoty kl´ıˇc ˚u (v ´ybˇer nejvhodnˇejˇs´ıho kl´ıˇce). Pˇrirozen ´y, stabiln´ı.

Pr ˚umˇern´a i maxim´aln´ı sloˇzitost: O(n · log n).1

(23)

3

Algoritmy pro tˇr´ıd ˇen´ı na extern´ım ´

uloˇzi ˇsti

Jak jsme jiˇz uvedli dˇr´ıve, tˇr´ıdˇen´ı mimo hlavn´ı pamˇet sebou pˇrin´aˇs´ı nov´e n´aroky na efek-tivitu algoritmu, jde pˇredevˇs´ım o probl´emy spojen´e s ukl´ad´an´ım na ˇr´adovˇe pomalejˇs´ı m´edium, pevn ´y disk. Ten dnes pˇredstavuje nejpomalejˇs´ı ˇc´ast poˇc´ıtaˇce, jeho typick´e vlast-nosti vych´az´ı ze star´e kontrukce vyuˇz´ıvaj´ıc´ı magnetickou indukci a mechanick´e pˇresouv´an´ı z´aznamov ´ych hlav. Naˇstˇest´ı jsou dostupn´e plnˇe elektronick´e SSD disky, u kter ´ych odpa-daj´ı mechanick´e neduhy pˇri z´apisu ˇci ˇctˇen´ı dat. Vyhneme se tak dosti velk´e pˇr´ıstupov´e dobˇe a z´avislosti na fyzick´em um´ıstˇen´ı zapsan ´ych dat, nemluvˇe o pˇr´ıpadn´e fragmentaci soubor ˚u [4].

3.1 Uvaˇzovan ´y model

V cel´e diplomov´e pr´aci i pozdˇejˇs´ım ˇreˇsen´ı uvaˇzuji n´asleduj´ıc´ı model: Pˇredpokl´ad´am, ˇze poˇc´ıtaˇc, na kter´em bude tˇr´ıdˇen´ı prob´ıhat, m´a jednu hlavn´ı pamˇet’, jeden procesor a je-den disk, kter´e budu pouˇz´ıvat pro operace potˇrebn´e k bˇehu algoritmu. Jako jednu stranu pamˇeti uvaˇzuji takovou ˇc´ast hlavn´ı pamˇeti, kter´a m´a stejnou velikost, jako alokaˇcn´ı jed-notka pouˇz´ıvan´eho souborov´eho syst´emu.

Pˇrev´aˇzn´a vˇetˇsina algoritm ˚u pro vnitˇrn´ı tˇr´ıdˇen´ı nem ˚uˇze b ´yt upravena tak, aby efek-tivnˇe pracovala jako algoritmus pro vnˇejˇs´ı tˇr´ıdˇen´ı. Metody vyuˇz´ıvaj´ıc´ı sekvenˇcn´ıho pˇr´ıstupu jako je napˇr. insertsort a selectsort m ˚uˇzeme z dalˇs´ıch ´uvah rovnou vylouˇcit. V milu-losti byly algoritmy pro vnitˇrn´ı tˇr´ıdˇen´ı studov´any tak´e v souvislost´ı s virtu´aln´ı pamˇet´ı, v ´ysledky vˇsak nebyly tak slibn´e d ˚usledkem nadmˇern´eho poˇctu odkl´adac´ıch str´anek. Snaha pˇrepracovat heapsort a quicksort pro vnˇejˇs´ı tˇr´ıdˇen´ı nebyla efektivn´ı, nepodaˇrilo se dos´ahnout tak mal´eho poˇctu vstupnˇe v ´ystupn´ıch operac´ı jako u mergesortu, kter ´y je z tohoho hlediska nejlepˇs´ım algoritmem pro vnˇejˇs´ı tˇr´ıdˇen´ı.

V posledn´ıch letech se v ´yzkum zamˇeˇruje na jeho optimalizaci vedouc´ı k co nejvˇetˇs´ımu zefektivnˇen´ı a optim´aln´ımu pˇrekr ´yv´an´ı procesorov´eho a vstupnˇe/v ´ystupn´ıho ˇcasu [1]. 3.2 Popis extern´ıho mergesortu

Pˇredpokl´adejme, ˇze soubor, kter ´y m´a b ´yt setˇr´ıdˇen, m´a N stran a ˇze m´ame k dispozici B stran v hlavn´ı pamˇeti. Tˇr´ıd´ıc´ı algoritmus pak prob´ıh´a ve dvou f´az´ıch:

• V prvn´ı f´azi je soubor rozdˇelen do ˇc´ast´ı, kter´e se naz ´yvaj´ı skupiny nebo vl´akna. Cel´a skupina m ˚uˇze b ´yt zcela uloˇzena v B stran´ach hlavn´ı pamˇeti a tud´ıˇz existuje N/B skupin vyprodukovan ´ych v t´eto f´azi. Kaˇzd´a skupina je setˇr´ıdˇena nez´avisle v hlavn´ı pamˇeti nˇekter ´ym z vnitˇrn´ıch tˇr´ıd´ıc´ıch algoritm ˚u a pak zaps´ana zpˇet na disk, viz Obr´azek 1.

• V pr ˚ubˇehu druh´e f´aze jsou skupiny sl´ev´any tak, aby vyrobily menˇs´ı poˇcet sku-pin a nakonec byly spojeny do jedin´e v ´ysledn´e. Spojovac´ı f´aze se m ˚uˇze skl´adat z nˇekolika pr ˚uchod ˚u. Dostupnou pamˇet’ ve druh´e f´azi rozdˇel´ıme tak, aby vznikla jedna vyrovn´avac´ı pamˇet’ pro v ´ystupn´ı soubor a zbytek pamˇeti se rozdˇelil jako ˇctec´ı vyrovn´avac´ı pamˇet jednotliv ´ych skupin. V kaˇzd´em pr ˚uchodu se z kaˇzd´e skupiny,

(24)

16

Obr´azek 1: Prvn´ı f´aze extern´ıho mergesortu

Obr´azek 2: Druh´a f´aze extern´ıho mergesortu vyuˇz´ıvaj´ıc´ı dva pr ˚uchody

resp. jej´ıho ˇctec´ıho z´asobn´ıku, vybere nejmenˇs´ı popˇr. nejvˇetˇs´ı prvek a ten se po-rovn´av´a s dalˇs´ımi takto z´ıskan ´ymi prvky z ostatn´ıch skupin. Na konci kaˇzd´eho pr ˚uchodu dostaneme vˇzdy jeden prvek, kter ´y zap´ıˇseme na v ´ystupn´ı z´asobn´ık. Po-kud je v ´ystupn´ı z´asobn´ık pln ´y, zap´ıˇse se do v ´ysledn´eho souboru, obdobnˇe, poPo-kud je nˇekter ´y ze vstupn´ıch z´asobn´ık ˚u pr´azdn ´y, naˇcte se do nˇej dalˇs´ı ˇc´ast pˇr´ısluˇsn´e sku-piny [3], viz Obr´azek 2.

V ´ykonnost extern´ıho mergesortu z´aleˇz´ı mj. na v ´ybˇeru spojovac´ıho sch´ema, jak ´ym se vyb´ıraj´ı skupiny pro spojov´an´ı ve druh´e ˇc´asti algoritmu. R ˚uzn´e postupy totiˇz mohou v´est ke znaˇcn ´ym v ´ykonov ´ym rozd´ıl ˚um [1].

3.2.1 Algoritmy pro tvorbu skupin

Pro tvorbu skupin se bˇeˇznˇe pouˇz´ıvaj´ı dva algoritmy:

Prvn´ı, naz ´yvaj´ıc´ı se naˇcti-setˇrid’-uloˇz, napln´ı vˇsechny dostupn´e str´anky hlavn´ı pamˇeti z´aznamy ze souboru k seˇrazen´ı a spust´ı vnitˇrn´ı tˇr´ıdic´ı algoritmus heapsort nebo quicksort. V ´ysledek je zaps´an zpˇet na disk jako setˇr´ıdˇen´a skupina. Tento postup se opakuje, dokud nejsou setˇr´ıdˇeny vˇsechny z´aznamy. Jednotliv´e skupiny tedy maj´ı velikost shodnou s ve-likost´ı dostupn´e hlavn´ı pamˇeti.

Druh ´y algoritmus se naz ´yv´a v´ymˇenn´y v´ybˇer. Vyuˇz´ıv´a minim´aln´ı haldu k v ´ybˇeru kl´ıˇce s minim´aln´ı hodnotou. Halda se nejprve napln´ı, pak je z´aznam s nejmenˇs´ı hodnotou kl´ıˇce (vrchol haldy) pˇresunut z haldy do v ´ystupn´ıho z´asobn´ıku a t´ım uvoln´ı m´ısto pro nov ´y prvek. Dalˇs´ı prvek, kter ´y m´a b ´yt pˇresunut do v ´ystupn´ıho z´asobn´ıku, mus´ı m´ıt vˇetˇs´ı

(25)

Algoritmus 1: Uk´azka pseudok ´odu extern´ıho mergesortu Input: file BLOCKSIZE; RAMSIZE; N=size(file)/BLOCKSIZE; B=RAMSIZE/BLOCKSIZE; //prvn´ı ˇc´ast

while file != empty do for i:=1 to N/B do ram:=load(file)/RAMSIZE; sort(ram); write(filesort, i); // druh´a ˇc´ast for b:=1 to B-1 do alokuj(Bi, B/ N+1); alokuj(Bout, B/ N+1); for b:=1 to N/B do Bb:=read(filesort, b, B/ N+1);

while filesort != empty do

Bout= merge(B1... BN/B);

if Bxis empty then

dopl ˇn(filesort, x + pˇreˇcteno);

if Boutis full then

write(Bout, finallyfile);

(26)

18

kl´ıˇcovou hodnotu, neˇz posledn´ı vyjmut ´y prvek. Pokud se v souboru vyskytnou z´aznamy s menˇs´ı kl´ıˇcovou hodnotou, neˇz posledn´ı prvek vloˇzen ´y do v ´ystupn´ıho z´asobn´ıku, um´ıst´ı se do nov´e minim´aln´ı haldy. T´ım se postupnˇe prvn´ı halda zmenˇsuje a druh´a zvˇetˇsuje. Pˇri vypr´azdnˇen´ı prvn´ı haldy je dokonˇcena tvorba prvn´ı skupiny a prvky z dalˇs´ı haldy jiˇz pln´ı dalˇs´ı skupinu. Tento proces konˇc´ı, kdyˇz v souboru nezb ´yvaj´ı ˇz´adn´e dalˇs´ı z´aznamy k setˇr´ıdˇen´ı [3].

Jak bylo prok´az´ano [3], pr ˚umˇern ´y poˇcet skupin vytvoˇren ´ych v ´ymˇenn ´ym v ´ybˇerem je poloviˇcn´ı oproti velikosti skupin, vytvoˇren ´ych algoritmem naˇcti-setˇrid’-uloˇz. To m´a vliv na v ´ypoˇcetn´ı ˇcas druh´e ˇc´asti algoritmu, menˇs´ı poˇcet skupin totiˇz zkr´at´ı ˇcas potˇrebn ´y k vy-kon´an´ı druh´e ˇc´asti extern´ıho mergesortu. Algoritmus v ´ymˇenn ´y v ´ybˇer m´a st´alejˇs´ı pr ˚ubˇeh vstupnˇe/v ´ystupn´ıch operac´ı a dosahuje lepˇs´ıch v ´ysledk ˚u na jiˇz ˇc´asteˇcnˇe pˇredtˇr´ıdˇen ´ych datech. Mezi jeho nev ´yhody patˇr´ı nutnost souˇcasn´eho ˇcten´ı z´aznam ˚u ze vstupn´ıho z´asob-n´ıku a z´apis na v ´ystupn´ı z´asobn´ık. Jsou-li oba soubory uloˇzeny na stejn´em disku, je potˇreba v´ıce ˇcasu na reˇzii pˇri ˇcten´ı a z´apisu dat, vypl ´yvaj´ıc´ı z tˇechto poˇzadavk ˚u. Pokud ovˇsem m´ame k dispozici dva disky, je v ´ymˇenn ´y v ´ybˇer lepˇs´ı volbou [1].

3.2.2 Spr ´ava pam ˇeti pro z ´aznamy r ˚uzn ´ych d ´elek

V re´aln´em svˇetˇe potˇrebujeme pracovat se z´aznamy r ˚uzn ´ych d´elek. V ´yˇse popsan´e algo-ritmy vˇsak nejsou pˇr´ımo pouˇziteln´e pro z´aznamy s r ˚uzn ´ymi d´elkami, protoˇze pamˇet’ov ´y prostor pro tˇr´ıdˇen´ı je pevnˇe d´an a poˇcet z´aznam ˚u, kter´e mohou b ´yt vyjmuty z tohoto prostoru, nen´ı pˇredem zn´am. Budeme pˇredpokl´adat, ˇze se pamˇet’ov ´y prostor skl´ad´a z nˇekolika rozsah ˚u, protoˇze nen´ı moˇzn´e alokovat libovolnˇe velk´e ˇc´asti soused´ıc´ı pamˇeti. Postup je n´asleduj´ıc´ı: Pˇri spuˇstˇen´ı algoritmu pro tvorbu skupin jsou z´aznamy s promˇennou d´elkou ˇcteny ze vstupu a vkl´ad´any do pamˇet’ov´eho prostoru. Tato metoda m´a naj´ıt m´ısto pro kaˇzd ´y nov ´y z´aznam uvnitˇr existuj´ıc´ıho pamˇet’ov´eho prostoru. Pokud nen´ı nalezeno ˇz´adn´e voln´e m´ısto, je z´aznam pˇresunut z pamˇet’ov´eho prostoru na v ´ystup a t´ım vytvoˇr´ı prostor pro nov ´y vstup. Pokud z´aznamy neobsad´ı vˇsechna vytvoˇren´a voln´a m´ısta, mus´ı pak syst´em sledovat voln´e segmenty a kontrolovat moˇznost slouˇcen´ı potencion´aln´ıch sousedn´ıch voln ´ych segment ˚u. V n´asleduj´ıc´ıch dvou heuristick ´ych metod´ach je pops´ano hled´an´ı voln ´ych segment ˚u.

Dalˇs´ı vyhovuj´ıc´ı - tato metoda sekvenˇcnˇe vyhled´av´a vˇsechny voln´e segmenty pamˇeti, zaˇc´ın´a od pozice, kde doˇslo k posledn´ımu vloˇzen´ı, a prob´ıh´a, dokud nenalezne dostateˇcnˇe velkou ˇc´ast pamˇeti pro uloˇzen´ı nov´eho z´aznamu. Jelikoˇz m ˚uˇze b ´yt vyhled´av´an´ı dosti n´aroˇcn´e, zav´ad´ı se prahov´a hodnota k omezen´ı poˇctu zkouman ´ych voln ´ych segment ˚u. Pokud je tento limit dosaˇzen a nebyl nalezen ˇz´adn ´y voln ´y segment, snaˇz´ı se algorit-mus pˇresunout z´aznam soused´ıc´ı s voln ´ym segmentem z jeho aktu´aln´ı pozice k dalˇs´ımu voln´emu segmentu, kter ´y byl zkoum´an v pr ˚ubˇehu stejn´eho vyhled´av´an´ı. Pokud tento pˇresun vytvoˇr´ı poˇzadovan´e m´ısto, je z´aznam vloˇzen do pamˇet’ov´eho prostoru, pokud nevytvoˇr´ı, je jeden nebo v´ıce existuj´ıc´ıch z´aznam ˚u odstranˇeno z pamˇet’ov´eho prostoru a vytvoˇr´ı tak vhodn´e voln´e m´ısto.

Nejlepˇs´ı vyhovuj´ıc´ı - v t´eto metodˇe jsou nov´e z´aznamy vkl´ad´any do nejmenˇs´ıho voln´eho segmentu, kter ´y je natolik velk ´y, aby dan ´y z´aznam pˇrijal. Pro efektivn´ı vyhled´av´an´ı vhodn´eho voln´eho segmentu sleduje algoritmus velikosti voln ´ych segment ˚u v bin´arn´ım

(27)

stromu. Pˇri vkl´ad´an´ı nov´eho z´aznamu prohled´a algoritmus bin´arn´ı strom, aby nalezl voln ´y segment minim´aln´ı velikosti, kter ´y je vˇetˇs´ı nebo roven velikosti nov´eho z´aznamu. V pˇr´ıpadˇe, ˇze neexistuje ˇz´adn ´y voln ´y segment, jsou existuj´ıc´ı z´aznamy odstranˇeny, do-kud nen´ı dostatek voln´eho m´ısta.

Podle test ˚u, kter´e byly provedeny, dosahuje metoda nejlepˇs´ı vyhovuj´ıc´ı aˇz 95% vyuˇzit´ı pamˇeti pro velk´e pamˇet’ov´e rozsahy. Pro menˇs´ı pamˇet’ov´e rozsahy je vyuˇzit´ı kolem 75%. Metoda nejlepˇs´ı vyhovuj´ıc´ı je d´ale ˇcasovˇe ´uspornˇejˇs´ı - n´aklady na vyhled´av´an´ı v t´eto metodˇe totiˇz nar ˚ustaj´ı s poˇctem voln ´ych segment ˚u logaritmicky (d´ıky vyuˇzit´ı bin´arn´ıho stromu). Pro z´aznamy s promˇennou velikost´ı je tedy metoda nejlepˇs´ı vyhovuj´ıc´ı s meto-dou v ´ymˇenn´eho v ´ybˇeru tou nejlepˇs´ı kombinac´ı [1].

3.3 Spojovac´ı algoritmy

Vzhledem k tomu, ˇze je spojov´an´ı skupin pˇrev´aˇznˇe vstupnˇe/v ´ystupn´ı operac´ı, snaˇz´ı se vˇsechny algoritmy minimalizovat poˇcet pˇr´ıstup ˚u na disk. Vyv´aˇzen ´y k-cestn´y mergesort tˇr´ıd´ı data pouˇzit´ım opakovan´eho sluˇcov´an´ı. Rozdˇel´ı vstup do dvou skupin opakovan ´ym ˇcten´ım blok ˚u dat ze vstupu, kter´e zapln´ı hlavn´ı pamˇet’, skupina se setˇr´ıd´ı, a pak se zap´ıˇse do dalˇs´ı skupiny. Ve druh´e f´azi se opakovanˇe spojuj´ı dvˇe skupiny do jedn´e ze dvou v ´ystupn´ıch skupin, dokud nevznikne jedna setˇr´ıdˇen´a skupina [7].

Dˇr´ıvˇejˇs´ı studie uk´azaly, u v´ıcecestn´eho spojov´an´ı, obecnˇe k-cestn´eho spojov´an´ı, zvo-len´ım k co nejvyˇsˇs´ıho nemus´ı vˇzdy v´est ke zlepˇsen´ı v ´ykonnosti. Jedno z ˇreˇsen´ı je vloˇzit nejprve tolik pr´azdn ´ych skupin, kolik je potˇreba k vytvoˇren´ı vˇsech skupin-1, dˇeliteln ´ych k-1. Pak algoritmus spoj´ı v kaˇzd´em pr ˚uchodu k nejkratˇs´ıch skupin, dokud nez ˚ustane jen jedna. Tento postup vˇsak nedosahuje pˇrekr ´yv´an´ı mezi vstupnˇe/v ´ystupn´ım a CPU ˇcasem: procesor z ˚ustane v neˇcinnosti, zat´ımco je k z´asobn´ık ˚u plnˇeno ˇc´astmi odpov´ıdaj´ıc´ıch sku-pin naˇc´ıtan ´ych z disku. Tento probl´em ˇreˇs´ı prognostick´a metoda, metoda dvojit´eho vy-rovn´av´an´ı nebo metoda prokl´adan´eho rozvrˇzen´ı.

Prognostick´a metoda - tato metoda sleduje ˇctec´ı z´asobn´ık, kter ´y bude vypr´azdnˇen jako prvn´ı a pouˇz´ıv´a dalˇs´ı zvl´aˇstn´ı z´asobn´ık ke ˇcten´ı dalˇs´ı vhodn´e ˇc´asti z disku, dokud obsah zb ´yvaj´ıc´ıch z´asobn´ık ˚u nepokraˇcuje ke zpracov´an´ı. Vylepˇsen´a prognostick´a metoda zav´ad´ı posloupnost spotˇreby k urˇcen´ı, kter ´y ze z´asobn´ık ˚u bude vypr´azdnˇen jako prvn´ı a ˇcten´ı dat z disku zaˇc´ın´a jiˇz ve chv´ıli, kdy je v pamˇeti voln ´ych m stran. Nemus´ıme tedy ˇcekat na uvolnˇen´ı cel´eho z´asobn´ıku nˇekter´e skupiny [1].

Dvojit´e vyrovn´av´an´ı - v t´eto metodˇe se pro kaˇzdou skupinu vytvoˇr´ı dva z´asobn´ıky, je-den pro prov´adˇen´ı V/V operac´ı a druh ´y pro zpracov´an´ı. M ˚uˇze b ´yt pouˇzita bud’ pˇri ˇcten´ı z disku nebo pˇri z´apisu na nˇej. Oproti prognostick´e metodˇe vyˇzaduje tato metoda v´ıce pamˇeti, nebo sn´ıˇzen´ı velikosti st´avaj´ıc´ıho z´asobn´ıku. D´ıky dvˇema z´asobn´ık ˚um m ˚uˇze b ´yt dosaˇzeno pˇrekr ´yv´an´ı mezi V/V a CPU ˇcasem, ale nutno poznamenat, ˇze nem´a vyuˇzit´ı u t´emˇeˇr setˇr´ıdˇen ´ych dat [5]. V rozˇs´ıˇren´ı t´eto metody, naz ´yvaj´ıc´ım se rovnomˇern´e vyrovn´av´an´ı, se pro kaˇzdou skupinu vytvoˇr´ı m z´asobn´ık ˚u. Nyn´ı nast´av´a ot´azka, jak brzy zah´ajit nov´e ˇcten´ı pro zaplnˇen´ı pr´azdn ´ych z´asobn´ık ˚u. Pokud zaˇcneme ˇc´ıst, kdyˇz je pr´azdn ´ych m-1 z´asobn´ık ˚u, minimalizujeme vyhled´avac´ı ˇcas, nebot’ vˇsech m-1 blok ˚u bude ˇcteno z po sobˇe jdouc´ıch m´ıst. T´ım vˇsak nen´ı zaruˇceno ´upln´e pˇrekryt´ı CPU a V/V ˇcasu, protoˇze pˇri ˇcten´ı m-1 blok ˚u m ˚uˇze CPU z ˚ustat neˇcinn ´y. V tomto okamˇziku se vyuˇz´ıv´a vlastnosti

(28)

20

modern´ıch diskov ´ych syst´em ˚u, kter´e rozdˇel´ı ˇcten´ı velk´eho mnoˇzstv´ı dat na ˇcten´ı po-sloupnosi nˇekolika menˇs´ıch datov ´ych blok ˚u. V pr ˚ubˇehu plnˇen´ı z´asobn´ık ˚u sekvenˇcn´ım ˇcten´ım z disku, jsou jiˇz nˇekter´e z´asobn´ıky naplnˇeny a mohou b ´yt pouˇzity k dalˇs´ımu zpra-cov´an´ı. Nev ´yhodou je, ˇze ˇcten´ı nem ˚uˇze zaˇc´ıt dˇr´ıve, dokud nen´ı pr´azdn ´ych m-1 z´asobn´ık ˚u patˇr´ıc´ıch ke stejn ´ym skupin´am, operaˇcn´ı pamˇet’ tedy nen´ı plnˇe vyuˇzita.

V pr ˚ubˇehu sluˇcovac´ı f´aze jsou data ˇctena v odliˇsn´em poˇrad´ı, neˇz v jak´em byla za-pisov´ana ve f´azi tvorby skupin. Ve f´azi pro tvorbu skupin se totiˇz skupiny zapisuj´ı na po sobˇe jdouc´ı m´ısta na disku, narozd´ıl od spojovac´ı f´aze, kde jsou data ˇctena v urˇcit´em poˇrad´ı, kter´e z´avis´ı na poˇrad´ı vstupn´ıch z´aznam ˚u. To m´a dopad na celkov´e pˇr´ıstupov´e n´aklady na disk, zvyˇsuje se totiˇz vyhled´avac´ı doba. Metoda prokl´adan´e rozvrˇzen´ı [6] umist’uje z´aznamy z r ˚uzn ´ych skupin do souvisl ´ych pozic podle algoritmu robin-round. Je zaloˇzena na oˇcek´av´an´ı, ˇze m´ısto nov´eho z´aznamu je bl´ıˇze k poˇrad´ı, v jak´em budou ˇcteny z´aznamy z disku a takto sniˇzuje vyhled´avac´ı ˇcas. Pˇredstavuje vˇsak reˇzii v pr ˚ubˇehu f´aze pro tvorbu skupin.

3.3.1 Pl ´anov ´an´ı ˇcten´ı

Kaˇzd´a skupina je rozdˇelena do blok ˚u o d´elce rovnaj´ıc´ı se velikosti vyrovn´avac´ı pamˇeti. Uloˇzen´ım maxim´aln´ı kl´ıˇcov´e hodnoty z kaˇzd´eho bloku dat jsme schopni urˇcit poˇrad´ı, ve kter´em budou bloky poˇzadov´any v pr ˚ubˇehu spojovac´ı f´aze. Toto poˇrad´ı se naz ´yv´a posloupnost spotˇreby [6]. Ukl´ad´an´ı maxim´aln´ı kl´ıˇcov´e hodnoty nepˇredstavuje v ´yznamnou reˇzii, protoˇze lze prov´est v hlavn´ı pamˇeti. Tyto kl´ıˇce by mˇely b ´yt setˇr´ıdˇeny, coˇz je moˇzno prov´est, kdyˇz se zaˇc´ın´a zapisovat posledn´ı skupina na disk (v pr ˚ubˇehu tvorby skupin) nebo bˇehem pˇredch´azej´ıc´ı spojovac´ı f´aze.

Pokud jsou bˇehem spojovac´ı f´aze dostupn´e nˇejak´e extra z´asobn´ıky, lze je pouˇz´ıt pro ˇcten´ı datov ´ych blok ˚u, kter´e nejsou aktu´alnˇe potˇrebn´e v nˇejak´e ˇc´asti spojov´an´ı. ˇCten´ı tˇechto blok ˚u nepˇredstavuje rotaˇcn´ı nebo vyhled´avaj´ıc´ı zpoˇzdˇen´ı, jelikoˇz bloky jsou v po sobˇe jdouc´ıch pozic´ıch. Posloupnost spotˇreby m ˚uˇzeme pouˇz´ıt k urˇcen´ı, kter´e bloky bu-dou potˇrebn´e v n´asleduj´ıc´ıch f´az´ıch, naˇc´ıst je za n´ızk´e n´aklady a urychlit tak spojovac´ı ˇc´ast.

Tento probl´em lze formulovat n´asledovnˇe [6]: Bud’ n poˇcet skupin, T poˇcet datov ´ych blok ˚u, B poˇcet z´asobn´ık ˚u. Pak C = {C1, C2, ..., CT} je blok posloupnosti spotˇreby, R =

{R1, R2, ..., RT} je ˇctec´ı sekvence, L je mapovac´ı funkce mezi datov ´ymi bloky a

pozi-cemi disku, kter´e jsou oznaˇceny ˇc´ısly 1, 2, ..., T. Kaˇzd´a ˇctec´ı sekvence R je charakteri-zov´ana svou cenou, kter´a je rovna souˇctu celkov´eho vyhled´avac´ıho ˇcasu a celkov´eho pˇrenosov´eho ˇcasu potˇrebn´eho ke ˇcten´ı datov ´ych blok ˚u v poˇrad´ı urˇcen´em R. Vzhledem k tomu, ˇze kaˇzd´a ˇctec´ı sekvence m´a stejou dobu pˇrenosu, v ´ybˇer nejlepˇs´ı sekvence je zaloˇzen na v ´ypoˇctu hledac´ıho ˇcasu. ˇCtec´ı sekvence nav´ıc mus´ı spl ˇnovat dalˇs´ı podm´ınku - v kaˇzd´e f´azi mus´ı b ´yt uchov´an nejm´enˇe jeden blok dat z kaˇzd´e skupiny v jednom z dostupn ´ych z´asobn´ık ˚u. Sekvence spl ˇnuj´ıc´ı tuto podm´ınku se naz ´yv´a provediteln´a. Mus´ıme tedy naj´ıt proveditelnou sekvenci, kter´a m´a minim´aln´ı hledac´ı ˇcas.

Lze snadno odvodit, ˇze probl´em nalezen´ı optim´aln´ı provediteln´e ˇctec´ı sekvence je ekvivalentn´ı s probl´emem obchodn´ıho cestuj´ıc´ıho, proto m ˚uˇze b ´yt navrˇzeno jen heuris-tick´e ˇreˇsen´ı. Heuristika je zaloˇzen´a na um´ıstˇen´ı kaˇzd´eho Ci ´udaje z bloku posloupnosti

(29)

spotˇreby C uvnitˇr ˇctec´ı sekvence R v pozici, kter´a minimalizuje vyhled´avac´ı ˇcas. Ten se vypoˇcte podle L(Ri)pozice disku, kde jsou uloˇzeny ´udaje o ˇctec´ı sekvenci. Aby byla ˇctec´ı

sekvence provediteln´a, je udrˇzov´ana dalˇs´ı sekvence F. J-t ´y ´udaj sekvence F pˇredstavuje poˇcet voln ´ych z´asobn´ık ˚u pˇred pˇreˇcten´ım ´udaje Rjve ˇctec´ı sekvenci. Pokud je Civloˇzeno

na pozici p ˇctec´ı sekvence, dostaneme Rp, kde p < i, pak je pro jeho uloˇzen´ı potˇreba

dalˇs´ıho z´asobn´ıku. Proto je Fj zmenˇseno o 1, kdyˇz p ≤ j < i, ve smyslu, ˇze pro bloky

Rp, ..., Ri−1bude o jeden z´asobn´ık m´enˇe, neˇz kdyˇz zaˇcaly b ´yt ˇcteny. Pokud je Fj = 0pro

dan´e j, pak ˇz´adn ´y blok za j z posloupnosti spotˇreby nem ˚uˇze b ´yt um´ıstˇen pˇred j ve ˇctec´ı sekvenci. Promˇenn´a s zaznamen´av´a posledn´ı hodnotu j, kde je Fj = 0.

Algoritmus 2: Uk´azka pseudok ´odu algoritmu posloupnosti spotˇreby R1:=C1; s:=1; for j:=1 to T do Fj:=B-n; for i:=2 to T do p:=i; for j:=s to i-1 do

if Rj se nach´az´ı na stejn´e stopˇe na disku jako CiAND L(Ri) > L(Ci) then

p:=j; break;

for k:=i downto p+1 do

Rk:= Rk− −;

Fk:= Fk−1− −;

if Fk=0 AND s¡=k then

s:=k+1; Rp:=Ci;

Popsan ´y algoritmus m´a sloˇzitost O(T2)a m ˚uˇze b ´yt spuˇstˇen, dokud je na disku uloˇzena posledn´ı skupina. Metoda pl´anov´an´ı ˇcten´ı s pouˇzit´ım posloupnosti spotˇreby dok´azala pˇrekonat metody dvojit´eho vyrovn´av´an´ı i prognostickou metodu [6].

3.3.2 Seskupov ´an´ı blok ˚u

Tato metoda se snaˇz´ı o nalezen´ı heuristick´eho ˇreˇsen´ı probl´emu optim´aln´ı ˇctec´ı cesty. Je zaloˇzena na seskupen´ı takov´eho mnoˇzstv´ı sousedn´ıch blok ˚u dat ze stejn´e skupiny, jak je jen moˇzn´e. Nˇekolik sousedn´ıch blok ˚u ze stejn´e skupiny tvoˇr´ı celek, kter ´y m ˚uˇze b ´yt pˇreˇcten sekvenˇcnˇe. ˇC´ım menˇs´ı je poˇcet skupin, t´ım m´enˇe vyhled´avac´ıho ˇcasu bude potˇreba bˇehem spojov´an´ı. Tato ˇctec´ı sekvence (celek) je provediteln´a, pokud je v pr ˚ubˇehu spojovac´ı ˇc´asti pˇreˇcten kaˇzd ´y blok pr´avˇe jednou. Metoda pro stanoven´ı proveditelnosti ˇctec´ı sekvence je zaloˇzena na poˇctu voln ´ych z´asobn´ık ˚u, F. Fi je rovno poˇctu voln ´ych

(30)

22

z´asobn´ıkov ´ych str´anek po pˇreˇcten´ı i-t´eho celku. Velikosti celk ˚u jsou oznaˇceny L = {L1, L2, ..., LN}

pro dan´e N [6].

Algoritmus 3: Uk´azka pseudok ´odu algoritmu seskupov´an´ı blok ˚u R:=C;

//ˇctec´ı sekvence se inicializuje podobnˇe jako posloupnost spotˇreby

for i:=1 to T do

Li:=1;

//nastaven´ı prvotn´ı velikosti celku lastC1:=n;

for i:=n+1 to T do

for j:=lastC1 downto 1 do

if Rj.runNumber=Ri.runNumber then

k:=j; break;

if lze Rizkombinovat s RK pˇri zachov´an´ı proveditelnosti then

LK++;

else

//Rise stane nov ´ym celkem lastC1++;

RlastC1++;

N:=lastC1;

Seskupov´an´ı blok ˚u je nejefektivnˇejˇs´ı metodou ze vˇsech variant pro zlepˇsen´ı spojo-vac´ıch algoritm ˚u. Oproti metodˇe pl´anov´an´ı ˇcten´ı, kter´a je druh´a nejlepˇs´ı, dosahuje n´ar ˚ust v ´ykonu 30%. Nav´ıc je schopna vyuˇz´ıt jiˇz ˇc´asteˇcnˇe pˇredtˇr´ıdˇen´a data [1].

Extern´ı mergesort je doposud nejlepˇs´ı tˇr´ıd´ıc´ı algoritmus pro vnˇejˇs´ı tˇr´ıdˇen´ı [1], zde uveden´e optimalizace jeˇstˇe d´ale vylepˇsuj´ı jeho v ´ykonnost. Obecnˇe jde o snahu minimali-zovat prodlevu pˇri ˇcten´ı a ukl´ad´an´ı na pevn ´y disk (ˇci ji co nejv´ıce vyuˇz´ıt k dalˇs´ı optima-lizaci) nebo pˇrekr ´yv´an´ı procesorov´eho a vstupnˇe/v ´ystupn´ıho ˇcasu.

(31)

4

Komponenta perzistentn´ıho pole

4.1 Popis komponenty

Pˇri ´uvahami nad anal ´yzou tˇr´ıdˇen´ı dat na extern´ım ´uloˇziˇsti podle popsan ´ych algoritm ˚u se n´am nask ´yt´a nˇekolik probl´em ˚u. Mezi jeden z nich patˇr´ı jak ´ym zp ˚usobem navrhnout a implementovat vyrovn´avac´ı pamˇet’ pro ˇcten´ı a z´apis soubor ˚u. Jelikoˇz je nutno m´ıt kon-trolu nad volbou velikost´ı jednotliv ´ych vyrovn´avac´ıch pamˇet´ı, je vyrovn´avac´ı pamˇet’ v souborov´em syst´emu operaˇcn´ıho syst´emu nevyhovuj´ıc´ı. Rozhodl jsem se vyuˇz´ıt ˇreˇsen´ı, kter´e je jiˇz naimplementov´ano a vˇsechny potˇrebn´e podm´ınky spl ˇnuje - perzistentn´ı pole. Perzistentn´ı pole se z hlediska program´atora tv´aˇr´ı jako dynamick´e pole vektor ˚u, kter´e vˇsechna sv´a data samostatnˇe ukl´ad´a do extern´ıho souboru a napodobuje sv ´ym chov´an´ım re´aln ´y souborov ´y syst´em operaˇcn´ıho syst´emu. Hlav´ı v ´yhoda perzistentn´ıho pole na-rozd´ıl od bˇeˇzn´eho datov´eho souboru uloˇzen´em v souborov´em syst´emu spoˇc´ıv´a ve vlastn´ı vyrovn´avac´ı pamˇet’ cache, kter´a umoˇz ˇnuje l´epe ˇr´ıdit, co bude uloˇzeno na pevn´em disku a co v hlavn´ı pamˇeti. Vˇsechny tˇr´ıdy implementuj´ıc´ı toto pole jsem pˇrevzal z aplikaˇcn´ıho r´amce ATOM implementovan ´y datab´azovou skupinou na Katedˇre informatiky Fakulty elektrotechniky a informatiky, Vysok´e ˇskoly B´a ˇnsk´e - Technick´e univerzity Ostrava.

Nyn´ı jiˇz k samotn ´ym tˇr´ıd´am implementuj´ıc´ım perzistentn´ı pole. To v sobˇe ukl´ad´a vektory typu zdˇedˇen´eho ze tˇr´ıdy cBasicType, v n´asleduj´ıc´ıch pˇr´ıkladech i v t´eto pr´aci budu pouˇz´ıvat prvky, jeˇz reprezentuje tˇr´ıda cNTreeTuple NoEncodeType. Nezbytnou souˇc´ast´ı je ˇsablona cSizeInfo, kter´a zajiˇst’uje spr´avn ´y v ´ypoˇcet velikosti poloˇzky, d ˚uleˇzit ´y pˇredevˇs´ım u sloˇzitˇejˇs´ıch typ ˚u. Parametrizuje se poloˇzkami konkr´etn´ıho typu zdˇedˇen´e z jiˇz zmi ˇnovan´e tˇr´ıdy cBasicType. Pro vkl´ad´an´ı prvk ˚u typu cNTreeTuple je pˇripraven´a tˇr´ıda cNTupleSizeInfo parametrizuj´ıc´ı ˇsablonu cSizeInfo typem cNTreeTuple. Tato tˇr´ıda obsahuje informace i pro zde pouˇz´ıvan ´y typ prvk ˚u cNTreeTuple NoEncodeType.

4.2 Pˇr´ıklad pr ´ace s perzistentn´ım polem

Pro pr´aci se samotn ´ym perzistentn´ım pole potˇrebujeme vytvoˇrit nˇekolik pomocn ´ych ob-jekt ˚u a definovat parametry pˇri jejich vytv´aˇren´ı:

• Nejprve je tˇreba definovat typ vkl´adan ´ych prvk ˚u. V n´asleduj´ıc´ıch pˇr´ıkladech bu-dou jednotliv´e prvky typu cNTreeTuple NoEncodeType, jednotliv´e vektory mohou m´ıt promˇennou d´elku, tedy kaˇzd ´y z nich nemus´ı m´ıt d´elku urˇcenou dimenz´ı. Po-sledn´ı definic´ı typu tPersistentArray jen vloˇz´ıme pˇredchoz´ı typy do ˇsablony sa-motn´eho perzistentn´ıho pole.

• D´ale je tˇreba popisovaˇc m´ısta, pˇri jehoˇz vytv´aˇren´ı vkl´ad´ame do kontruktoru hod-noty maxim´aln´ı dimenze vektor ˚u a jejich datov ´y typ, dˇed´ıc´ı ze tˇr´ıdy cDataType. Popisovaˇc m´ısta je nov´a instance tˇr´ıdy zdˇedˇen´e z obecn´eho popisovaˇce cTreeSpa-ceDescriptor. V tomto pˇr´ıpadˇe tedy bude maxim´aln´ı dimenze vektor ˚u 10 prvk ˚u a jednotliv´e prvky vektoru budou neznam´enkov´e celoˇc´ıseln´e, viz ˇr´adek 7 ve zdro-jov´em k ´odu 1.

(32)

24

• Hlaviˇcka perzistentn´ıho pole je zdˇedˇen´a ze tˇr´ıdy cHeader. Jak jiˇz n´azev napov´ıd´a, jde o hlaviˇcku ekvivalentn´ı ke zvolen´emu typu prvku i samotn´eho perzistentn´ıho pole, tj. cPersistentArrayHeader VarLen. Jako parametry konstruktoru vkl´ad´am informace o voln´em m´ıstˇe, kter´emu d´ale pˇred´am dˇr´ıve vytvoˇren ´y popisovaˇc m´ısta. Tato infor-mace o voln´em m´ıstˇe dˇed´ı ze z´akladn´ı tˇr´ıdy cSizeInfo a odpov´ıd´a zvolen´emu typu prvku pole. Druh ´y vkl´adan ´y parametr je velikost uzlu vkl´adan´eho prvku, tˇret´ı pak urˇcuje velikost bloku, v podstatˇe jde velikost alokaˇcn´ı jednotky, zde tedy 4kB. • Nyn´ı jiˇz m ˚uˇzeme vytvoˇrit samotn´e perzistentn´ı pole, jako parametr konstruktoru

pˇred´av´am dˇr´ıve vytvoˇrenou hlaviˇcku, viz ˇr´adek 15 ve zdrojov´em k ´odu 1.

• Pro ˇcten´ı vektor ˚u z pole pouˇz´ıv´am kontext, slouˇz´ıc´ı k uloˇzen´ı informac´ı potˇrebn ´ych pro pr´aci s perzistentn´ım polem s promˇennou d´elkou vektor ˚u. Sleduje uzel, aktu´aln´ı m´ısto v uzlu a aktu´aln´ı poloˇzku. Ukl´ad´a tak´e dalˇs´ı pomocnou pamˇet’. Jde o tˇr´ıdu zdˇedˇenou ze z´akladn´ı tˇr´ıdy cDataStructureContext. Jej´ı typ opˇet odpov´ıd´a typu per-zistentn´ıho pole. Jako parametr kontruktoru vkl´ad´am hlaviˇcku, kter´a obsahuje vˇsechny potˇrebn´e ´udaje pro jeho spr´avnou inicializaci.

Nyn´ı chv´ıli m´ame vytvoˇreny a inicializov´any vˇsechny potˇrebn´e objekty a m ˚uˇzeme zaˇc´ıt pracovat se samotn ´ym polem. Vstupn´ı soubor pole naˇcteme metodou Open() (ˇr´adek ˇc. 21), kde jako parametry uvedeme n´azev otev´ıran´eho souboru, d´ale logickou hodnotu, m´a-li b ´yt dan ´y soubor otevˇren jen pro ˇcten´ı a velikost vyrovn´avac´ı pamˇeti v poˇctech blok ˚u. Dalˇs´ı metodou OpenContext() (ˇr´adek ˇc. 23) otevˇru kontext dan´eho pole na indexu a pozici, kter´e mi urˇcuj´ı prvn´ı dva parametry. Zde je to logicky zaˇc´atek cel´eho pole. D´ale v jednoduch´em cyklu vypisuji vˇsechny vektory a jejich jednotliv´e prvky ze souboru per-zistentn´ıho pole, dokud kontext nedojde na jeho konec. Metodou Advance() (ˇr´adek ˇc. 29) posunu kontext z aktu´aln´ıho vektoru vˇzdy o jeden d´ale, pokud kontext dojde na ko-nec souboru, vrac´ı metoda logickou hodnotu false. Po ukonˇcen´ı pr´ace s kontextem staˇc´ı zavolat metodu CloseContext() (ˇr´adek ˇc. 31), obdobnˇe zavol´ame po skonˇcen´ı pr´ace s per-zistentn´ım polem metodu Close() (ˇr´adek ˇc. 32).

Nyn´ı se jiˇz pod´ıvejme na samotn ´y zdrojov ´y k ´od:

1 void Ukazka::Vypis ze souboru(){

2

3 typedef cNTreeTuple NoEncodeType Type;

4 typedef cPersistentArrayNode VarLen<Type> tNode;

5 typedef cPersistentArray VarLen<Type, tNode> tPersistentArray;

6

7 cNTreeSpaceDescriptor ∗popisovac =new cNTreeSpaceDescriptor(10, new cUIntType());

8

9 cPersistentArrayHeader VarLen<Type> ∗hlavicka =

10 new cPersistentArrayHeader VarLen<Type>(

11 new cNTupleSizeInfo(popisovac),

12 tNode::GetNodeExtraSize(), 13 4096);

14

15 tPersistentArray ∗pole =new tPersistentArray(hlavicka) ;

16

(33)

18 new cPersistentArrayContext VarLen<Type>(hlavicka); 19 20 21 pole−>Open(”Output.dat”,true, 8); 22 23 pole−>OpenContext(0, 0, kontext); 24 25 do{ 26 27 kontext−>GetItem()−>Print(”\n”); 28 29 }while(pole−>Advance(kontext)); 30 31 pole−>CloseContext(kontext); 32 pole−>Close(); 33 34 delete pole; 35 delete kontext; 36 delete hlavicka; 37 delete popisovac; 38 39 }

V ´ypis 1: Uk´azka v ´ypisu vektor ˚u ze souboru perzistentn´ıho pole V ´ypis z uveden´eho zdrojov´eho k ´odu bude podobn ´y tomuto:

(34, 8, 28, 68, 3, 29),realSize: 6 (0, 51, 70, 19, 8, 18, 16, 14, 99, 17),realSize: 10 (1, 23, 71, 36, 61, 57, 77, 16),realSize: 8 (79, 72, 77, 34, 69, 12, 1, 70, 55, 41),realSize: 10 (1, 39, 80, 81, 24, 90, 94, 82, 94, 91),realSize: 10 (2, 35, 9, 81, 11, 92, 30),realSize: 7

V ´ypis 2: V ´ystup z metody v ´ypisu vektor ˚u ze souboru perzistentn´ıho pole

Na druh´em pˇr´ıkladu si uk´aˇzeme jednoduch´e vkl´ad´an´ı vektor ˚u do souboru. Vyuˇzijeme typy a objekty pops´any v pˇr´ıkladˇe 1, novˇe n´am pˇribyde objekt prvek (ˇr´adek ˇc. 20), kter ´y zde pˇredstavuje vektor ukl´adan ´y do perzistentn´ıho pole. Jako parametr kontruktoru zde pˇred´av´am hlaviˇcku perzistentn´ıho pole.

Nov ´y soubor perzistentn´ıho pole vytvoˇr´ıme metodou Create() (ˇr´adek ˇc. 18), kde jako parametry vloˇz´ıme n´azev souboru, kter ´y se m´a vytvoˇrit a velikost vyrovn´avac´ı pamˇeti v poˇctech blok ˚u. Metodou SetValue() (ˇr´adek ˇc. 24) nastavujeme jednotliv´e poloˇzky vek-toru, zde neznam´enkov´a cel´a ˇc´ısla. Prvn´ım parametrem metody je pozice ve vekvek-toru, kterou chceme nastavit, t´ım druh ´ym pak samotn´a hodnota. Metoda AddItem() (ˇr´adek ˇc. 28) pak vytvoˇren ´y prvek uloˇz´ı do perzistentn´ıho pole. Tato metoda vrac´ı index a po-zici pr´avˇe vloˇzen´eho prvku, tˇret´ım parametrem je prvek, kter ´y chceme vloˇzit. Pro v ´ypis prvku slouˇz´ı metoda Print() (ˇr´adek ˇc. 29), kde vloˇzen ´y parametr pln´ı funkci oddˇelovaˇce. Stejnˇe jako pˇri ˇcten´ı z pole je tˇreba jej po ukonˇcen´ı pr´ace zavˇr´ıt metodou Close() (ˇr´adek ˇc. 33).

(34)

26

Tento k ´od vytvoˇr´ı perzistentn´ı pole o 10 prvc´ıch, kde na nultou pozici uloˇz´ı jeho poˇrad´ı od 0 a na dalˇs´ıch pozic´ıch postupnˇe ukl´ad´a druh´e mocniny aˇz do hodnoty aktu´aln´ı pozice. V ´ysledek bude zaps´an v souboru mojepole.dat.

1 void Ukazka::Zapis do souboru(){

2

3 typedef cNTreeTuple NoEncodeType Type;

4 typedef cPersistentArrayNode VarLen<Type> tNode;

5 typedef cPersistentArray VarLen<Type, tNode> tPersistentArray;

6

7 unsigned int index, pozice;

8 cNTreeSpaceDescriptor ∗popisovac =new cNTreeSpaceDescriptor(10, new cUIntType());

9

10 cPersistentArrayHeader VarLen<Type> ∗hlavicka =

11 new cPersistentArrayHeader VarLen<Type>(

12 new cNTupleSizeInfo(popisovac),

13 tNode::GetNodeExtraSize(), 14 4096);

15

16 tPersistentArray ∗pole =new tPersistentArray(hlavicka) ;

17

18 pole−>Create(”mojepole.dat”, 8); 19

20 cNTreeTuple ∗prvek =new cNTreeTuple(popisovac);

21

22 for(unsigned int i=0; i <10; i++){

23 for(unsigned int j=1; j<=i; j ++){

24 prvek−>SetValue(0, i); 25 prvek−>SetValue(j, j∗j); 26 }

27

28 pole−>AddItem(index, pozice, ∗prvek); 29 prvek−>Print(”\n”); 30 prvek−>Clear(); 31 } 32 33 pole−>Close(); 34 35 delete prvek; 36 delete pole; 37 delete hlavicka; 38 delete popisovac; 39 40 }

V ´ypis 3: Uk´azka z´apisu vektor ˚u do souboru perzistentn´ıho pole V ´ypis z uveden´eho zdrojov´eho k ´odu bude n´asleduj´ıc´ı:

() ,realSize: 0 (1, 1),realSize: 2 (2, 1, 4),realSize: 3 (3, 1, 4, 9),realSize: 4 (4, 1, 4, 9, 16),realSize: 5 (5, 1, 4, 9, 16, 25),realSize: 6

(35)

(6, 1, 4, 9, 16, 25, 36),realSize: 7 (7, 1, 4, 9, 16, 25, 36, 49),realSize: 8 (8, 1, 4, 9, 16, 25, 36, 49, 64),realSize: 9 (9, 1, 4, 9, 16, 25, 36, 49, 64, 81),realSize: 10

V ´ypis 4: V ´ystup z metody v ´ypisu vektor ˚u ze souboru perzistentn´ıho pole

Jak lze vidˇet z pˇredchoz´ıch pˇripad ˚u, samotn´a pr´ace s perzistentn´ım polem je intu-itivn´ı a velice podobn´e pr´aci s bˇeˇzn ´ymi soubory. Pˇri vytv´aˇren´ı pol´ı a potˇrebn ´ych typ ˚u je dobr´e b ´yt pozorn ´y a pˇr´ıpadnou alokaci prvk ˚u prov´adˇet mimo ˇcasto pouˇz´ıvan´e me-tody. Uˇsetˇr´ıme tak nemal´e mnoˇzstv´ı pamˇeti, jelikoˇz C++ nem´a tak propracovanou spr´avu pamˇeti jako modernˇejˇs´ı jazyky jako C# nebo Java. Napˇr. opakovanou alokaci jednoho prvku v cyklu ˇreˇs´ı alokac´ı nov´eho m´ısta na haldˇe a pamˇet’ potˇrebn´a k alokaci jednoho prvku tak m ˚uˇze v extr´emn´ım pˇr´ıpadˇe nar ˚ust na souˇcin velikosti prvku a d´elky cyklu!

(36)
(37)

5

Anal ´yza a n ´avrh komponenty pro extern´ı tˇr´ıd ˇen´ı prvk ˚

u

5.1 Specifikace poˇzadavk ˚u

M ´ym ´ukolem bylo navrhnout a implementovat komponentu pro tˇr´ıdˇen´ı prvk ˚u ze struk-tury perzistentn´ıho pole vyuˇz´ıvaj´ıc´ı jen pˇredem definovanou velikost hlavn´ı pamˇeti. Po prostudov´an´ı teorie t ´ykaj´ıc´ı se tˇr´ıdˇen´ı dat na extern´ım ´uloˇziˇsti jsem musel vz´ıt v potaz samotn´a data, nad kter ´ymi bude pozdˇeji algoritmus bˇeˇzet. Jelikoˇz jde o data s relativnˇe velk ´ym hodnotov ´ym rozsahem, zvolil jsem ve sv´e implementaci k algoritmu pro tˇr´ıdˇen´ı dat na extern´ım ´uloˇziˇsti, extern´ımu mergesortu, optimalizaci posloupnosti spotˇreby, viz. kapitola 3.3. Prvn´ı f´aze algoritmu vyuˇz´ıv´a sch´ema naˇcti-setˇrid’-uloˇz popsan´e v kapitole 3.2.1.

Celou komponentu bylo nutno navrhnout obecnˇe, jelikoˇz komponenta perzistentn´ıho pole je navrhnov´ana pro mnoˇzstv´ı typ ˚u, kde kaˇzd ´y z nich rozˇsiˇruje z´akladn´ı tˇr´ıdu typu o metody nutn´e ke spr´avn´emu chodu konkr´etn´ıho typu. Mnou navrˇzen´a komponenta tedy mus´ı umˇet tˇr´ıd´ıt typy rozˇsiruj´ıci z´akladn´ı tˇr´ıdu cDataType, jin ´ymi slovy, tˇr´ıdˇen ´y typ bude mou tˇr´ıdu parametrizovat.

Komponenta mus´ı spl ˇnovat:

• Tˇr´ıdit prvky rozˇsiˇruj´ıc´ı tˇr´ıdu cDataType, resp. jej´ıho potomka cBasicType. • Pˇri tˇr´ıdˇen´ı pouˇz´ıvat jen pˇredem zn´amou velikost hlavn´ı pamˇet’i.

• Komponentu optimalizovat pro re´aln´a data, nad kter ´ymi bude bˇeˇzˇet.

• Pro testov´an´ı implementovat metodu pro naˇc´ıt´an´ı dat z textov´eho souboru, d´ale vhodn ´ym zp ˚usobem umoˇznit zad´avat jednotliv´e parametry tˇr´ıdˇen´ı.

Jako omezen´ı se aˇz v pr ˚ubˇehu implementace uk´azala b ´yt nespr´avnˇe pracuj´ıc´ı vy-rovn´avac´ı pamˇet perzistentn´ıho pole, kv ˚uli kter´e bylo nutno ´uplnˇe odstranit rekurzi ve druh´e ˇc´asti mergesortu a nahradit ji upraven ´ym nerekurzivn´ım algoritmem. Bylo tedy nutno upravit anal ´yzu a n´aslednou imlementaci tak, abych se tomuto probl´emu vyva-roval. I tak jsem se ale nevyhnul omezen´ı v podobˇe nadmˇernˇe nar ˚ustaj´ıc´ıch n´aroc´ıch na dalˇs´ı hlavn´ı pamˇet’ pˇri bˇehu v ´ysledn´e aplikace.

Dostupn´a pamˇet’ pˇredstavuje pro algoritmus v prvn´ı ˇc´asti mnoˇzstv´ı hlavn´ı pamˇeti (v bloc´ıch definovan ´ych pˇri vytv´aˇren´ı hlaviˇcek pole, viz ˇr´adek 9 ve zdrojov´em k ´odu 1) pouˇzitou ke tˇr´ıdˇen´ı jednotliv ´ych skupin. Velikost skupin v prvn´ı f´azi algoritmu je tedy rovna velikosti dostupn´e hlavn´ı pamˇeti. Ve druh´e f´azi n´am velikost hlavn´ı pamˇeti definuje maxim´aln´ı poˇcet skupin otevˇren ´ych souˇcasnˇe pˇri bˇehu sl´evac´ı ˇc´asti algotimu. Vstupn´ı a v ´ystupn´ı z´asobn´ık o kter ´ych jsme mluvili v ´uvodu zde nejsou potˇreba, tuto reˇzii za n´as ˇreˇs´ı samotn´e perzistentn´ı pole.

5.2 Specifikace pomoc´ı pˇr´ıpadu uˇzit´ı

Diagram pˇr´ıpadu uˇzit´ı, tzv. Use Case, n´am popisuje, jak akt´eˇri, stoj´ıc´ı vnˇe syst´emu, pra-cuj´ı s jednotliv ´ymi funkcemi syst´emu.

(38)

30

Obr´azek 3: Diagram pˇr´ıpadu uˇzit´ı syst´emu

V tomto pˇr´ıpadˇe jde o velice jednoduch ´y model, kdy uˇzivatel, pracuj´ıc´ı se syst´emem, pouˇz´ıv´a jen se samotnou komponentou pro testov´an´ı tˇr´ıdˇen´ı, kter´a vyuˇz´ıv´a tˇr´ıdy pro tˇr´ıdˇen´ı na extern´ım ´uloˇziˇsti a tˇr´ıdy perzistentn´ıho pole. Komponenty pro tˇr´ıdˇen´ı samozˇrejmˇe tak´e vyuˇz´ıvaj´ı tˇr´ıdy perzistentn´ıho pole.

5.3 Tˇr´ıdn´ı diagram

Pomoc´ı tˇr´ıdn´ıho diagramu (Obr´azek 4) je zde nast´ınˇena statick´a struktura syst´emu prostˇrednictv´ım jednotliv ´ych tˇr´ıd a vz´ajemn ´ych vztah ˚u mezi nimi:

• SortArray je ˇsablona implementuj´ıc´ı samotn´e tˇr´ıdˇen´ı dat za pomoc´ı omezen´eho mnoˇzstv´ı hlavn´ı pamˇeti. Parametrizuje se konkr´etn´ı typem, pˇredstavuj´ıc´ı tˇr´ıdˇen ´y prvek, dˇed´ıc´ı ze tˇr´ıdy cBasicType. Jsou zde jednotliv´e metody pro tˇr´ıdˇen´ı i d´ale po-psan´a optimalizace.

• ˇsablona RunInfo slouˇz´ı k ukl´ad´an´ı ´udaj ˚u o jednotliv ´ych setˇr´ıdˇen ´ych skupin´ach vzni-kaj´ıc´ıch v prvn´ı ˇc´asti algoritmu. Zaznamen´av´a se zde index a pozice posledn´ıho

(39)

prvku skupiny, jej´ı maxim´aln´ı a minim´aln´ı prvek a logickou hodnotu vypov´ıdaj´ıc´ı o pouˇzit´ı dan´e skupiny ve druh´e ˇc´asti algoritmu.

• tˇr´ıda ArrayTest je tˇr´ıdou pro testov´an´ı v ´yˇse uveden ´ych tˇr´ıd, jej´ı souˇc´ast´ı je gener´ator n´ahodn ´ych vektor ˚u a naˇc´ıt´an´ı textov ´ych soubor ˚u. Uˇzivatel s touto tˇr´ıdou komuni-kuje pˇres rozhran´ı pˇr´ıkazov´e ˇr´adky, kde zad´av´a odpov´ıdaj´ıc´ı parametry.

• tˇr´ıda cNTreeTuple NoEncodeType zde pˇredstavuje konkr´etn´ı tˇr´ıdˇen ´y prvek, jedin´a vazba na nˇej bude ze samotn´e testovac´ı tˇr´ıdy.

• ˇsablona cPersistentArrayNode VarLen pˇredstavuje vektor vkl´adan ´y do perzistentn´ıho pole, parametrizuje se konkr´etn´ım tˇr´ıdˇen ´ym typem.

• ˇsablona cPersistentArray VarLen odpov´ıd´a jiˇz zmi ˇnovan´emu konkr´etn´ımu perzis-tentn´ımu poli. Parametrizuje se konkr´etn´ım tˇr´ıdˇen ´ym typem a jemu odpov´ıdaj´ıc´ım uzlem.

Uˇzivatel bude s aplikac´ı kominukovat prostˇrednictv´ım pˇr´ıkazov´e ˇr´adky, kde bude zad´avat potˇrebn´e parametry. Samotn´a tˇr´ıda ArrayTest v sobˇe zahrnuje jak generov´an´ı n´ahodn ´ych vektor ˚u dle uˇzivatelem zadan ´ych parametr ˚u, tak i naˇc´ıt´an´ı textov ´ych sou-bor ˚u a jejich n´asledn´e pˇreveden´ı do perzistentn´ıho pole tak, aby danou mnoˇzinu dat bylo moˇzno d´ale setˇr´ıdit. Setˇr´ıdˇen´ı perzistentn´ıho pole pak probˇehne zavol´an´ım metody Sort() ze tˇr´ıdy SortArray s odpov´ıdaj´ıc´ımi parametry.

(40)

32

(41)

6

Implementace

C´ılem t´eto kapitoly je popsat samotnou implementaci vych´azej´ıc´ı z pˇredchoz´ı anal ´yzy a n´avrhu, popsat nejd ˚uleˇzitˇejˇs´ı metody komponenty pro tˇr´ıdˇen´ı prvk ˚u na extern´ım ´uloˇziˇsti a jejich optimalizaci. Aplikace je naprogramov´ana jako konzolov´a v jazyce C++, pˇred´av´an´ı informac´ı a pˇrep´ınaˇc ˚u je realizov´ano pomoc´ı voliteln ´ych parametr ˚u, kter ´ym se podrobnˇeji vˇenuji v pˇr´ıloze A.

V dalˇs´ıch kapitol´ach si pˇredstav´ıme implementovan´e tˇr´ıdy, jejich v ´yznam a nejd ˚uleˇzitˇejˇs´ı metody.

6.1 Tˇr´ıda ArrayTest

Tˇr´ıda ArrayTest slouˇz´ı k otestov´an´ı n´ıˇze popsan ´ych ˇsablon pro tˇr´ıdˇen´ı prvk ˚u na extern´ım ´uloˇziˇsti, obsahuje metodu main, kter´a je po spuˇstˇen´ı aplikace vol´ana. Pro optim´aln´ı tes-tov´an´ı m´a uˇzivatel k dispozici jak vygenerov´an´ı n´ahodn ´ych vektor ˚u pole podle pˇredem nastaven ´ym parametr ˚u tak moˇznost naˇcten´ı textov´eho souboru s jednotliv ´ymi vektory, kde kaˇzd ´y ˇr´adek odpov´ıd´a jednomu vektoru a prvky kaˇzd´eho vektoru jsou oddˇeleny ˇc´arkou (dalˇsi popis je uveden v pˇr´ıloze A). Po vygenerov´an´ı, resp. naˇcten´ı dat, jsou vektory uloˇzeny do struktury perzistentn´ıho pole pˇripraveny na samotn´e tˇr´ıdˇen´ı. Ty-pem tˇr´ıdˇen´eho prvku parametrizujeme obˇe potˇrebn´e ˇsablony a vol´ame potˇrebn´e me-tody. Kromˇe n´azvu extern´ıho souboru perzistentn´ıho pole obsahuj´ıc´ı vektory ke tˇr´ıdˇen´ı a nˇekolika zadan ´ych parametr ˚u, jako je poˇcet vektor ˚u, jejich dimenze, typ tˇr´ıdˇen´eho prvku a velikost bloku perzistentn´ıho pole, je nutno pˇredat tˇr´ıdˇe SortArray tak´e instanci po-tomka tˇr´ıdy cSizeInfo obsahuj´ıc´ı informace potˇrebn´e k v ´ypoˇctu m´ısta podle zadan´eh ´ych parametr ˚u a hlaviˇcku vytvoˇren´eho perzistentn´ıho pole.

Nyn´ı si pop´ıˇseme nˇekter´e d ˚uleˇzit´e metody tˇr´ıdy ArrayTest. Vˇsechny metody jsou pops´any vygenerovanou program´atorskou dokumentac´ı na pˇriloˇzen´em CD.

6.1.1 Generov ´an´ı n ´ahodn ´ych dat

Metoda ArrayTest::Generate(cDataType *typ prvku, char *input file) je urˇcen´a ke generov´an´ı n´ahodn ´ych vektor ˚u, tedy vektor ˚u, kter´e maj´ı n´ahodnou dimenzi od 1 do zadan´e ma-xim´aln´ı dimenze a jejich prvky jsou n´ahodnˇe vygenerovan´e od 0 do hodnoty glob´aln´ı konstanty MAX GEN, nastaven´e standardnˇe na 1000. Poˇcet vektor ˚u a jejich maxim´aln´ı dimenzi urˇcuj´ı glob´aln´ı promˇenn´e count a dim. V t´eto metodˇe se tak´e vytv´aˇr´ı hlaviˇcka perzistentn´ıho pole, kter´a bude pouˇzita jako parametr tˇr´ıdy pro tˇr´ıdˇen´ı prvk ˚u.

Metoda m´a dva argumenty:

• prvn´ım je typ prvku, kter ´y bude pˇredstavovat jednotliv ´y prvek vektoru, jde o no-vou instanci potomka tˇr´ıdy cBasicType.

• t´ım druh ´ym je n´azev souboru perzistentn´ıho pole, kter ´y se vytvoˇr´ı touto metodou. Vkl´ad´an´ı n´ahodn ´ych dat prob´ıh´a vˇzdy pro jeden prvek, ten je uloˇzen do struktury per-zistentn´ıho pole a pot´e vypr´azdnˇen a t´ım pˇripraven pro dalˇs´ı plnˇen´ı.

(42)

34

6.1.2 Na ˇcten´ı dat z textov ´eho souboru

Metoda ArrayTest::GenerateFromTextFile(char *soubor, char *vstupni soubor) prov´ad´ı naˇc´ıt´an´ı vektor ˚u uloˇzen ´ych v textov´em souboru do perzistentn´ıho pole. Nejprve jsou z prvn´ıho ˇr´adku textov´eho souboru naˇcteny ´udaje o konkr´etn´ım typu tˇr´ıdˇen ´ych vektor ˚u, opˇet jde o jednoho z potomk ˚u tˇr´ıdy cBasicType, d´ale o maxim´aln´ı dimenzi vektor ˚u a nakonec o jejich celkov´em poˇctu. Pot´e je podle naˇcten´eho typu zavol´ana pˇretypovan´a metoda ArrayTest::LoadFromText(), kter´a zajist´ı spr´avn´e naˇcten´ı zbyl ´ych vektor ˚u do struktury per-zistentn´ıho pole.

Metoda vyˇzaduje dva argumenty:

• prvn´ı pˇredstavuje n´azev vstupn´ıho textov´eho souboru.

• druh ´y je vygenerovan ´y soubor struktury perzistentn´ıho pole, tedy vstupn´ı soubor pro tˇr´ıd´ıc´ı algoritmus.

6.2 Sablona RunInfoˇ

Jak jsme jiˇz popsali v kapitole Anal ´yza a n´avrh, ˇsablona RunInfo slouˇz´ı k ukl´ad´an´ı in-formac´ı o jednotliv ´ych skupin´ach vznikaj´ıc´ıch v prvn´ı ˇc´asti tˇr´ıd´ıc´ıho algoritmu. ˇSablona je parametrizov´ana konkr´etn´ım typem tˇr´ıdˇen´eho prvku a je poˇc´ıt´ano, ˇze jedna instance bude pˇredstavovat popis jedn´e skupiny. Lok´aln´ı promˇenn´e index a position zaznamen´avaj´ı index a pozici posledn´ıho vloˇzen´eho prvku, logick´a hodnota used urˇcuje, zda jiˇz byla tato skupina pouˇzita ve druh´e ˇc´asti tˇr´ıd´ıc´ıho algoritmu a max a min pˇredstavuj´ıc´ı maxim´aln´ı a minim´aln´ı prvek skupiny (tyto ´udaje se ukl´adaj´ı kv ˚uli pozdˇejˇs´ı optimalizaci). Pˇr´ıstup k tˇemto promˇenn ´ym je zapouzdˇren do metod Set a Get, maj´ıc´ıch standardn´ı konvenci, tedy napˇr. SetIndex() a GetIndex(). Pro jednoduˇsˇs´ı kop´ırov´an´ı cel ´ych ˇsablon je zde implemen-tov´an tak´e oper´ator rovn´a se.

6.3 Sablona SortArrayˇ

Nyn´ı se koneˇcnˇe dost´av´ame k ˇsablonˇe, ˇreˇs´ıc´ı poˇzadovan´e tˇr´ıdˇen´ı prvk ˚u na extern´ım ´uloˇziˇsti. Tato ˇsablona se, obdobnˇe jako ˇsablona RunInfo, parametrizuje konkr´etn´ım ty-pem tˇr´ıdˇen´eho prvku. Z veˇrejn ´ych metod obsahuje kromˇe konstruktoru metodu Sort(), jej´ıˇz zavol´an´ım dojde k postupn´emu spuˇstˇen´ı prvn´ı a druh´e ˇc´asti vnˇejˇs´ıho tˇr´ıd´ıc´ıho algo-ritmu.

Obˇe tyto ˇc´asti si podrobnˇe pop´ıˇseme.

6.3.1 Algoritmus pro vytvoˇren´ı setˇr´ıd ˇen ´ych skupin

Metoda pro vytvoˇren´ı setˇr´ıdˇen ´ych skupin implementovan´a podle algoritmu naˇcti-setˇr´ıd’-uloˇz popsan´eho v kapitole 3.2.1 se jmenuje SortArray<TupleType>::MakeRuns( cPersisten-tArrayHeader VarLen<TupleType> *mHeader, unsigned int ram size, unsigned int count). Jej´ı argumenty jsou:

(43)

• hlaviˇcka perzistentn´ıho pole, kterou jsme dˇr´ıve vytvoˇrili, zde se pˇred´av´a hlaviˇcka z testovac´ı tˇr´ıdy ArrayTest.

• velikost dostupn´e hlavn´ı pamˇeti pro algoritmus, je definovan´a poˇctem voln ´ych blok ˚u, kde jeden blok hlavn´ı pamˇeti odpov´ıd´a velikosti jednomu bloku perzis-tentn´ıho pole. Je stejn´a pro prvn´ı i druhou f´azi algoritmu. V t´eto f´azi velikost do-stupn´e hlavn´ı pamˇeti urˇcuje velikost jednotliv ´ych setˇr´ıdˇen ´ych skupin.

• posledn´ı poloˇzkou je poˇcet vektor ˚u, kter´e vstupn´ı perzistentn´ı pole obsahuje. Metoda vrac´ı logickou 1, pokud algoritmus probˇehne korektnˇe a v jeho pr ˚ubˇehu ne-dojde k ˇz´adn´e chybˇe, logickou nulu, pokud tomu tak nen´ı.

6.3.2 Algoritmus pro sl ´ev ´an´ı setˇr´ıd ˇen ´ych skupin

Metoda zajiˇst’uj´ıc´ı sl´ev´an´ı setˇr´ıdˇen ´ych skupin implementovan´a podle algoritmu vyuˇz´ıvaj´ıc´ıho k-cestn ´y mergesort, popsan ´y v kapitole 3.2, m´a n´azev

SortArray<TupleType>::Merge( unsigned int ram size, char *vystupni soubor, bool use optimalization) a n´asleduj´ıc´ı argumenty:

• velikost dostupn´e hlavn´ı pamˇeti pro algoritmus, je definovan´a poˇctem voln ´ych blok ˚u, kde jeden blok hlavn´ı pamˇeti odpov´ıd´a velikosti jednomu bloku perzis-tentn´ıho pole. Je stejn´a pro prvn´ı i druhou f´azi algoritmu. V t´eto f´azi velikost do-stupn´e hlavn´ı pamˇeti urˇcuje poˇcet najednou otevˇren ´ych skupin pro sl´ev´an´ı.

• dalˇs´ım parametrem je jm´eno v ´ystupn´ıho souboru, jde o v ´ysledn ´y soubor obsahuj´ıc´ı setˇr´ıdˇen´e perzistentn´ı pole.

• posledn´ım parametrem je logick´a hodnota urˇcuj´ıc´ı, zd´a m´a algoritmus vyuˇz´ıvat implementovanou optimalizaci.

Metoda vrac´ı, stejnˇe jako metoda implementuj´ıc´ı prvn´ı ˇc´ast tˇr´ıd´ıc´ıho algoritmu, logic-kou 1, pokud algoritmus probˇehne korektnˇe a v jeho pr ˚ubˇehu nedojde k ˇz´adn´e chybˇe, logickou nulu, pokud tomu tak nen´ı.

Mimo algoritm ˚u pro samotn´e tˇr´ıdˇen´ı je zde i nˇekolik pomocn ´ych metod, at’ uˇz jde o metodu Quicksort(), vyuˇz´ıvanou pˇri tˇr´ıdˇen´ı ˇc´asti prvk ˚u v hlavn´ı pamˇeti potˇrebnou v prvn´ı f´azi tˇr´ıd´ıc´ıho algoritmu, nebo metodu Zformuj pole bin(), kter´a novˇe vloˇzen ´y prvek do pole index ˚u skupin bin´arnˇe zaˇrad´ı podle jeho velikosti na patˇriˇcn´e m´ısto v poli.

6.3.3 Optimalizace algoritmu pro sl ´ev ´an´ı setˇr´ıd ˇen ´ych skupin

Optimalizace implementov´ana ve druh´e ˇc´asti algoritmu pro tˇr´ıdˇen´ı na extern´ım ´uloˇziˇsti vyuˇz´ıv´a prognostickou metodu, konkr´etnˇe upravenou posloupnost spotˇreby, popsanou v kapitole 3.3.

Pˇri sl´ev´an´ı m´ame k dispozici pouze N stran voln´e hlavn´ı pamˇeti, znamen´a to, ˇze m ˚uˇzeme najednou otevˇr´ıt a sl´evat jen N skupin. Pokud se jedna ze vkl´adan ´ych skupin vypr´azdn´ı, hled´ame na jej´ı m´ısto jinou vyhovuj´ıc´ı skupinu. Nejprve z jeˇstˇe nesl´evan ´ych

(44)

36

Algoritmus 4: Pseudok ´od algoritmu naˇcti-setˇr´ıd’-uloˇz

Input: hlaviˇcka vstupn´ıho pole, velikost pamˇeti, poˇcet vektor ˚u vytvoˇr a inializuj potˇrebn´e promˇenn´e;

vstupn´ı soubor.otevˇri();

kontext.otevˇri(vstupn´ı soubor.zaˇc´atek()); v ´ystupn´ı soubor.vytvoˇr();

poˇcet prvk ˚u ve skupinˇe := (ram size * block size) / (dim * sizeof(typ)); poˇcet skupin := poˇcet vektor ˚u / poˇcet prvk ˚u ve skupinˇe;

if (poˇcet vektor ˚u % ((int)(ram size * block size) / (dim * sizeof(typ))) != 0) then

poˇcet skupin++;

vytvoˇr a inicializuj In desc[poˇcet skupin+1]; //popisovaˇc skupin

inicializuj pole[poˇcet prvk ˚u ve skupinˇe];

//pole pˇredstavuj´ıc´ı data z perzistentn´ıho pole v hlavn´ı pamˇeti i:=0;

p i:=0;

for do

pole[i++] = kontext.vrat’Prvek();

if kontext != vstupn´ı soubor.konec then if i == poˇcet prvk ˚u ve skupinˇe then

Quicksort(pole, 0, i);

for x:=0 to i do

v ´ystupn´ı soubor.pˇridej(pole[x]); Uloˇz informace o skupinˇe do In desc[p i]; i:=0; p i++; else Quicksort(pole, 0, i); for x:=0 to i do v ´ystupn´ı soubor.pˇridej(pole[x]); Uloˇz informace o skupinˇe do In desc[p i]; break;

kontext.zavˇri();

vstupn´ı soubor.zavˇri(); v ´ystupn´ı soubor.zavˇri(); smaˇz jiˇz nepotˇrebn´e objekty;

(45)

Algoritmus 5: Pseudok ´od k-cestn´eho sl´ev´an´ı bez rekurze

Input: velikost pamˇeti, v ´ystupn´ı soubor vytvoˇr a inializuj potˇrebn´e promˇenn´e; Out poˇcet skupin := 0;

for do

vytvoˇr a inicializuj Out desc[poˇcet skupin]; vstup.otevˇri();

v ´ystup.vytvoˇr();

vytvoˇr a inicializuj pole kontext ˚u[poˇcet skupin+1]; i := 0;

dolni := 0; horni := 0;

Out poˇcet skupin := 0;

max = (velikost pamˇeti > poˇcet skupin)?poˇcet skupin:velikost pamˇeti;

repeat

vektor<unsigned int> pole sk;

for i:=dolni to horni do

inicializuj kontext In pole ctx[i];

In pole ctx[i].otevˇriKontext(zaˇc´atek it´e skupiny); pole sk.dejNaKonec(i);

In desc[i].NastavPouˇzit´ı(true);

if pole sk.velikost() == max then

break;

vyvtoˇr a inicializuj pole index ˚u skupin; dolni := pole sk[0];

horni := pole sk[pole sk.velikost()-1]; horni++;

setˇrid’ pole index ˚u skupin podle nejmenˇs´ıho prvku In pole ctx; Sl´evej skupiny();

uloˇz informace o v ´ysledn´e skupinˇe do Out desc[Out poˇcet skupin]; dolni := horni;

until horni != poˇcet skupin; vstup.zavˇri();

v ´ystup.zavˇri(); celk poˇcet++;

poˇcet skupin := Out poˇcet skupin; In desc = Out desc;

if Out poˇcet skupin == 1 then

break;

je-li posledn´ım v ´yst. souborem soubor doˇcasn ´y, naˇcti jej do souboru v ´yst.; smaˇz jiˇz nepotˇrebn´e objekty;

(46)

38

Algoritmus 6: Pseudok ´od metody Sl´evej() potˇrebn´e k algoritmu k-cestn´eho sl´ev´an´ı bez rekurze

Input: Pole index ˚u skupin, In pole ctx, In desc, vstupn´ı a v ´ystupn´ı perz. pole mnoˇzstv´ı opakov´an´ı = 0;

poˇcet sk = pole sk.velikost();

for do

if je-li prvek ze skupiny uloˇzen´e na nult´em indexu v poli pole index ˚u skupin > neˇz

prvek ze skupiny uloˇzen´e na dalˇs´ım indexu then

bin´arnˇe zatˇrid’ prvek na nult´em indexu v poli pole index ˚u skupin pomoc´ı kontextu In pole ctx;

v ´ystup.pˇridej(prvek odpov´ıdaj´ıc´ı In pole ctx[pole index ˚u skupin[0]]);

if jde-li o prvn´ı prvek vloˇzen´y do skupiny then

uloˇz jej jako minimum;

if nen´ı-li pr´azdn´a skupina, ze kter´e byl vloˇzen posledn´ı prvek then

posu ˇn kontext In pole ctx[pole index ˚u skupin[0]];

else

if m´a-li b´yt pouˇzita optimalizace then

Optimalizuj();

if byla nalezena optimalizace then

pokraˇcuj ve sl´ev´an´ı;

else

uloˇz posledn´ı prvek jako maximum skupiny; zavˇri kontext In pole ctx[pole index ˚u skupin[0]]; odeber ukonˇcenou skupinu z pole index ˚u skupin; poˇcet sk–;

if poˇcet sk == 0 then

break;

(47)

skupin vybereme ty, kter´e maj´ı minimum vˇetˇs´ı nebo rovno naposledy vloˇzen´emu prvku, logicky n´as zaj´ımaj´ı jen skupiny, kter´e m´a cenu v aktu´aln´ım bodˇe d´ale sl´evat. Z tˇechto skupin pak vyberemu tu, jej´ıˇz maximum m´a nejmenˇs´ı hodnotu.

Tento postup m ˚uˇze uˇsetˇr´ıt nˇekolik pr ˚uchod ˚u v druh´e ˇc´asti algoritmu, v ide´aln´ım pˇr´ıpadˇe by sl´ev´an´ı probˇehlo jen v jednom pr ˚uchodu, v nejhorˇs´ım algoritmus probˇehne stejnˇe rychle, jako bez optimalizace.

Algoritmus 7: Pseudok ´od upraven´e posloupnosti spotˇreby

ve chv´ıli, kdy dojde k vypr´azdnˇen´ı jedn´e ze vstupn´ıch skupin ve druh´e ˇc´asti algoritmu prov´adˇej:

ind dalˇs´ıho := -1;

for pp:=horni to poˇcet skupin do

if !In desc[pp].BylaPouˇzita() and In desc[pp].Minimum() >= posledn´ı vloˇzen´y prvek then

if pp == -1 then

maximum := In desc[pp].Maximum(); ind dalˇs´ıho := pp;

else if In desc[pp].Maximum() < maximum then

ind dalˇs´ıho := pp;

if ind dalˇs´ıho != -1 then

naˇcti na pozici posledn´ı vypr´azdnˇen´e skupiny skupinu s indexem ind dalˇs´ıho; vytvoˇr a otevˇri pro ni kontext;

In desc[ind dalˇs´ıho].BylaPouˇzita(true);

6.4 Pouˇzit ´e technologie a programov ´e vybaven´ı

• Pro v ´yvoj komponenty pouˇz´ıv´am Visual Studio ve verzi 2008 od spoleˇcnosti Micro-soft. Jde o integrovan´e v ´yvojov´e prostˇred´ı pro v ´yvoj aplikac´ı s podporou nˇekolika programovac´ıch jazyk ˚u, obsahuje propracovan ´y editor k ´odu podporuj´ıc´ı Intelli-Sense a refaktoring, v ´ykonn ´y debugger, grafick ´y editor webov ´ych str´anek, atd. • Pro modelov´an´ı syst´emu pomoc´ı jazyka UML vyuˇz´ıv´am n´astroje Enterprise

Archi-tect od spoleˇcnosti Sparx Systems ve verzi 7.

• Aplikace byla vyv´ıjena a testov´ana na operaˇcn´ım syst´emu Windows XP s bal´ıkem SP3 spoleˇcnosti Microsoft.

(48)

References

Related documents

Distribution of distinct EGFr cysteine altering NOTCH3 mutations in ExAC compared to those reported in cerebral autosomal dominant arteriopathy with subcortical infarcts

As long as bicycle carriage of ‘complete’ bicycles is not the standard, all online timetable search engines should come with a bicycle carriage query function. Deutsche Bahn

You can get one at the Arrivals (approximately €70,00 to go to Milano Stazione Centrale). 3) On arrival at Bergamo Railway Station, you will need to get to Porta Nuova, two bus

Looking to both feminist linguistic and social-science research, I argue that Pinterest exhibits a unique traffic in visual and verbal codes—an emerging online rhetoric that allows

In summary, our basic model suggests that the health share rises over time as income grows if the joy associated with living an extra year does not diminish as quickly as the

Furthermore, traditional livestock farming directly fosters the usage of groundwater and dug wells (Oshikweyo) and indirectly reduces the water supply security by, for in-

or information about their expertise, which is repeated mainly with Negation feedback. Social: we mean context information related to a user’s role at work, and

In addition to the positive implications already mentioned, it should also be considered that standard language ideology and the imposition of native speaker models onto