6. Rad
6.2 Problém - Banka
Do
banky prichádzajú k okienku s platobnými kartami klienti
v priemere každých 75 sekúnd. Obslúženie zákazníka trvá
pracovníkovi banky priemerne 2 minúty. Ak je pri príchode zákazníka do
banky okienko obsadené, postaví sa na koniec radu a čaká.
Predbiehanie nie je dovolené, z priestorových dôvodov môže pred
okienkom stáť v rade najviac 30 ľudí. Predpokladáme tiež, že zákazníci
sú trpezliví a v priebehu čakania už nikto z radu
neodchádza. Hneď ako je zákazník pri okienku vybavený, odíde
a k okienku môže pristúpiť prvý v rade. Vytvorte
program, ktorý bude simulovať popísanú situáciu a po uplynutí
"simulačného" času oznámi koľko zákazníkov bolo oblúžených, aká bola
stredná dĺžka radu pred okienkom resp. koľko zákazník v priemere
čakal v rade.
Riešenie
Zákazníci prichádzajúci do banky vytvárajú pred okienkom
rad a zdá sa preto celkom prirodzené, že aj v programe bude
tento rad reprezentovaný rovnakou dynamickou údajovou štruktúrou.
O zákazníkoch prichádzajúcich do banky však nemáme k dispozícii
žiadne informácie, ktoré by bolo potrebné uchovávať, zaujímajú nás len
ich počty (celkový počet, počet ľudí v rade, počet obslúžených
zákazníkov, ...). Na to nám postačia "obyčajné" celočíselné
premenné. Dynamickú údajovú štruktúru front použijeme na reprezentáciu
úplne iného radu!
Chceme simulovať dej prebiehajúci v čase. Zákazníci
prichádzajú, čakajú v rade, sú obsluhovaní, odchádzajú. V istom
časovom okamihu sa odohrá najviac jedna udalosť. Budeme sledovať dve
udalosti: príchod zákazníka ("zákazník vošiel do banky" ) a koniec obsluhy ("zákazník je vybavený, odchádza od okienka").
Výskyt jednotlivých udalostí môžeme znázorniť na časovej osi:
t0 = 0 s je okamih začiatku simulácie. V čase t1, t2, t4 prichádza zákazník, v čase t3, t5 skončila obsluha zákazníka, ktorý bol práve pri okienku atď.
Na každú udalosť je potrebné správnym spôsobom zareagovať - obslúžiť ju. Aj podľa obrázku je zrejmé, že udalosti tvoria rad.
Obslúžená bude vždy tá udalosť, ktorá je práve na začiatku radu t.j. je
aktuálna. Časovú os tvorenú postupnosťou udalostí je preto vhodné
implementovať v programe ako front. Jeho prvky budú typu TUdalost :
typedef struct udalost {
double cas;
TypUdalosti typ;
struct udalost *nasl;
} TUdalost;
TUdalost *Zac, *AktUdal;
|
| Čas príchodu
ďalšieho zákazníka (presnejšie dĺžku intervalu medzi dvoma príchodmi) ako
aj dĺžku trvania obsluhy budeme generovať náhodne
(využijeme generátor pseudonáhodných čísel rand ).
Každú novú udalosť zaradíme do frontu na správne miesto podľa času.
Nepôjde teda o "klasický" front, do ktorého sa môžu prvky pridávať
výlučne na koniec. Udalosti, ktoré majú nastať skôr, majú prednosť.Najskôr vytvoríme prázdnu časovú os:
| Zac = (TUdalost*)malloc(sizeof(TUdalost));
Zac->cas = 1.7E38;
Zac->nasl = Zac;
Prvok, na ktorý ukazuje Zac nie je udalosťou, poslúži len ako zarážka uľahčujúca vkladanie novej udalosti na správne miesto. Hodnotou položky cas v zarážke môže byť nejaké "dostatočne veľké" reálne číslo. |
Naplánujeme príchod prvého zákazníka a vložíme novú udalosť do frontu:
| Prvý zákazník príde napríklad v čase 20 s.
Údajový typ TypUdalosti bude definovaný takto: typedef enum {
PrichodZakaznika, KoniecObsluhy
} TypUdalosti; Ak teda ide o príchod zákazníka, tak príslušná udalosť má v položke typ uloženú hodnotu 0, pre koniec
obsluhy hodnotu 1.
|
Všimnite si, že
na prvú udalosť vo fronte ukazuje Zac->nasl !!!
Teraz už môžeme odštartovať simuláciu. Kým neuplynie
zvolený simulačný čas (načítaný na vstupe), opakujeme v cykle uvedený
postup:
Simuláciu ukončíme, keď uplynie simulačný čas - testujeme či
nasledujúca udalosť, ktorá má byť vybratá z frontu nenastane až po
uplynutí simulačného času.
Aby
sme mohli na výstupe oznámiť požadované výsledky, musíme počas
simulácie počítať prichádzajúcich zákazníkov, koľko z nich po príchode
čakalo, koľkí boli odmietnutí, koľko času strávili čakajúci spolu v
rade, momentálnu dĺžku radu. Pre výpočet je tiež potrebné priebežne
uchovávať čas aktuálnej a predchádzajúcej udalosti ako aj dĺžku
časového intervalu od poslednej udalosti.
Výber aktuálnej udalosti zo začiatku frontu sa realizuje v dvoch krokoch:
AktUdal = Zac->nasl;
Zac->nasl = AktUdal->nasl;
Vloženie novej udalosti do frontu na správne miesto:
V cykle prechádzame zoznamom, hľadáme miesto, kam sa má nová udalosť zaradiť. Smerník p2 ukazuje na prvok, ZA ktorý vložíme novú udalosť.
Ak pri prehľadávaní zoznamu dosiahneme zarážku (p1 == Zac ), nová udalosť bude vložená na koniec frontu!
[Program]
|