JEDNOROZMERNÉ POLIA, RIEŠENIE ÚLOH Doposiaľ sme pracovali s premennými jednoduchých typov (integer, real, boolean, longint), ktoré si pamätajú jedno číslo, jeden údaj (vždy ten posledne načítaný). Ak však potrebujeme pracovať naraz s viacerými údajmi súčasne a všetky si ich pamätať, je výhodné pracovať s inou štruktúrou dát. Štruktúrovaná premenná jednorozmerné pole Jednoduché premenné si môžeme predstaviť ako okienko v operačnej pamäti s istou veľkosťou, napr. ak deklarujeme var a: integer; v pamäti sa rezervujú 2B pre jedno celé číslo. a 20 Štruktúrované premenné sú zložitejšie štruktúry, umožňujú zapamätať si oveľa viacej údajov v jednej premennej, pričom jednotlivé prvky sú indexované - pristupujeme k nim cez ich index. Jednorozmerné pole si môžeme predstaviť ako rad okienok s istým poradím. Napríklad teploty za istých 10 dní, by sme mohli vložiť do poľa s deklaráciou: Deklarácia poľa var P: array [1..10] of integer; p 2 0-5 -3 2 5 7 3-2 -1 P[1] P[2] P[3] P[4] P[5] P[6] P[7] P[8] P[9] P[10] var meno_prem: array [typ_indexu] of typ_zloziek; meno_prem meno premennej typu pole. typ indexu ľubovoľný ordinálny (kde je jednoznačný nasledovník a predchodca) typ interval (od ľavej hranice do pravej hranice napr. 1..20). Cez index sa pristupuje k jednotlivým okienkam prvkom poľa. Ako príklad typu interval uvádzame 1..100, -5..5, A.. Z, a.. e a podobne. typ_zloziek typ zložiek pre prvky v okienkach (real, integer, boolean,..., vlastný typ). Príklady deklarácií: a : array [1..25] of integer; b : array [2..1000] of boolean; poc : array [-10..10] of integer; tepl: array [1..31] of real; 1
Načítanie prvkov poľa Ak chceme načítať hodnoty do jednotlivých okienok v poli, budeme k nim pristupovať prostredníctvom ich indexov. Keďže vždy poznáme počet prvkov poľa, najvýhodnejšie je použiť pre opakované zadávanie údajov do okienok poľa cyklus for. Napríklad do poľa o 10 prvkov z úvodnej tabuľky by sme načítali odpovedajúce čísla nasledujúcim kódom: for i:=1 to 10 do writeln ( Zadajte, i. prvok poľa ); readln (p[i]) Ak chceme mať premenlivú dĺžku poľa (počet jeho prvkov), necháme cyklus for bežať od 1 do N, kde N má istú konkrétnu hodnotu. Pre vypísanie prvkov poľa o N prvkov použijeme nasledujúcu štruktúru: Výpis prvkov poľa for i:=1 to N do writeln (p[i]); Ak sme v úlohách zisťovali počty výskytov, súčty, museli sme premennú pre počet či súčet vynulovať. Pole ponúka zisťovať početnosti viacerých prvkov naraz, ale ho tiež musíme na začiatku vynulovať: Nulovanie prvkov poľa for i:=1 to n do p[i]:=0; Príklad 1 Ako sme hádzali kockou? Budeme opäť hádzať kockou a pri N pokusoch zistíme, koľkokrát padla každá strana kocky, teda čísla od 1 do 6. Bez štruktúry poľa by sme si na tieto počty hodov museli zaviesť 6 premenných a o každom padnutom hode sa pýtať, či padla, 1, alebo 2, alebo... 6. Ak si však zadeklarujeme pole h: array [1..6] of integer, tak si počet hodov jednotky budeme pamätať v okienku h[1], počet hodov dvojky budeme pamätať v okienku h[2],,,, až počet hodov šestky budeme pamätať v okienku h[6]. Všeobecne: počet hodov čísla c budeme pamätať v okienku h[c]. 2
Teda ak hodíme číslo c, netreba o ňom zisťovať, aké je to číslo, ale rovno inkrementovať premennú h[c] (zvýšiť počet hodov čísla c o jednotku). program statistika_hodov_kocky; var h: array [1..6] of integer; i,c,n: integer; randomize; for i:=1 to 6 do h[i]:=0; {vynulovanie pola pre pocty} writeln ('Zadajte pocet hodov'); readln (N); for i:=1 to N do c:= random(6)+1; inc(h[c]); {pripocitanie padnuteho hodu} for i:=1 to 6 do writeln('cislo ',i,' padlo ',h[i],' krat'); Úloha 1 (Čo generuje generátor): Vygenerujte N náhodných čísel z intervalu <a, b> a uložte ich do poľa. Vygenerované pole čísel vypíšete. Prechodom cez pole zistíte, či viac krát padlo číslo c1, alebo číslo c2 (Čísla c1, c2, a, b, N zadá užívateľ). Úloha je opačná oproti príkladu 1, tu si samotné vygenerované čísla dáme do poľa a počet padnutí čísel c1 a c2 si budeme pamätať v jednoduchých premenných. Poznámka: Náhodné čísla z intervalu <a, b> vygeneruje príkaz random(b-a+1)+a program statistika_cisel; var cisla: array [1..1000] of integer; a, b, c1, c2, N, i, poc1, poc2: integer; poc1:=0; poc2:=0; randomize; writeln ('Zadajte pocet cisel a hranice intervalu') readln (N,a,b); for i:=1 to N do cislo[i]:= random(b-a+1)+a; writeln ('Zadajte dve sledované celé čísla') readln (c1,c2); for i:=1 to N do write(cislo[i]:6); for i:=1 to N do if cislo[i]=c1 then inc(poc1) else if cislo[i]=c2 then inc(poc2); if poc1>poc2 then writeln('cislo ',c1,' padlo viac krat- ',poc1) else if poc1<poc2 then writeln('cislo ',c2,' padlo viac krat- ',poc2) else writeln('cisla ',c1,c2' padli rovnako'); 3
Príklad 2 Mincovka : Ak chceme vyplatiť istú sumu peňazí napr. 2653 Sk, môžeme ju zložiť aj zo stokorunáčiek a nejakých drobných, ale existuje aj najmenší počet bankoviek, ktorými sa táto suma dá vyplatiť 2653=2x1000+1x500+1x100+1x50+1x2+1x1 7 bankoviek a mincí. Pri vyplácaní väčších obnosov je efektívne zistiť počty potrebných bankoviek od tých s najvyššou sumou príkazom pocet := suma div bankovka. Keďže hodnoty bankoviek sú rôzne, aby sme tento príkaz nepísali 11 krát pre 11 druhov bankoviek (od 5000 Sk až do 1 Sk), vložíme si ich do poľa, rovnako aj počty odpovedajúcich bankoviek získame do poľa. Nezabudnime po každom vyčíslení počtu bankoviek vyplatenú sumu odobrať príkazom suma :=suma mod bankovka. a) Napíšeme program, ktorý načíta istý obnos peňazí a vypíše nám, koľko ktorých bankoviek potrebujeme na jeho vyplatenie: program mincovka; var b, poc: array [1..11] of integer; suma, i,: integer; b[1]:=5000; b[2]:=1000; b[3]:=500; b[4]:=200; b[5]:=100; b[6]:=50; b[7]:=20; b[8]:=10; b[9]:=5; b[10]:=2; b[11]:=1; writeln ('Zadajte sumu penazi') readln (suma); for i:=1 to 11 do poc[i]:=suma div b[i]; suma:= suma mod b[i]; writeln}( Pocty bankoviek na vyplatenie sumy: ) for i:=1 to 11 do if poc[i]<>0 then writeln(b[i],,poc[i], ks ) b) Doplňte program tak, aby zistil aj počet všetkých vyplatených bankoviek spolu. c) Doplňte program tak, aby spočítal počty všetkých druhov bankoviek, potrebných k vyplateniu N výplat zamestnancov istej firmy, aby si pokladníčka mohla nasáčkovať peniaze do obálok pre každého zamestnanca. Úloha 2 (Otočenie, či obrátenie?): Zostavte program, ktorý otočí pole celých čísel, t.j. vymení prvý prvok s posledným, druhý s predposledným a t.ď. Teda ktorý prvok s ktorým je potrebné vymeniť zapíšeme pre N prvkov poľa a: 1... N 2... N 1 3... N 2 4
4... N 3... i ty... N i +1... N div 2... N (N div 2) + 1 Je zrejmé, že vymieňať budeme len prvky do polovice poľa, lebo inak by sme ich vymenili dva krát čiže vôbec nevymenili. Ak je počet prvkov párny, vytvoríme presne istý počet dvojíc a[i] a a[n-i+1]. Ak je počet prvkov nepárny, tak prostredný prvok ostáva na svojom mieste a nepotrebujeme ho s ničím vymieňať. program otocenie_pola; var a: array [1..100] of integer; N, i, pom: integer; writeln ('Zadajte pocet prvkov') readln (N); for i:=1 to N do writeln ( Zadajte, i. prvok poľa ); readln (a[i]) for i:=1 to N div 2 do pom:= a[i]; a[i]:= a[n-i+1]; a[n-i+1]:= pom; writeln}( Otocene pole prvkov: ) for i:=1 to N do write(a[i]:6) Úloha 3 (Správne miesto): P. učiteľ má v klasifikačnom hárku zoradené priezviská žiakov podľa abecedy, ale po polroku prišiel nový žiak a toho treba zaradiť na správne miesto. Keďže s reťazcami sme ešte nepracovali, ukážeme si analogický problém na číslach. Máme teda vzostupne zoradenú postupnosť celých kladných čísel a nové číslo je potrebné zaradiť na správne miesto. Keďže sa zväčší pole o 1 prvok, bude výhodné presúvať prvky odzadu: N-tý dať na miesto N+1, (N-1) tý na miesto N,... až kým sa nám neuvoľní to správne miesto pre načítaný prvok (viď obrázok pre N=10). Posúvanie prvkov poľa budeme vykonávať dovtedy, kým je prvok menší ako prvky v poli, resp. ho budeme zaradzovať na 1 miesto je najmenší a vtedy už bude index prvku poľa rovný nule: a 2 8 12 23 28 32 36 39 43 54 prvok 34 5
program zaradenie_prvku; var a: array [1..100] of integer; N, i, prvok: integer; writeln ('Zadajte pocet prvkov') readln (N); writeln ('Zadajte vzostupnu postupnost ',N' celych cisel'); for i:=1 to N do readln(a[i]) writeln ('Zadajte prvok, ktorý treba zaradit') readln (prvok); i:=n; while i>0 and prvok<a[i] do a[i+1]:= a[i]; dec(i); a[i+1]:=prvok; writeln}('novy zoznam prvkov:') for i:=1 to N+1 do writeln(a[i]) Ak by sme chceli riešiť pôvodný problém s postupnosťou mien žiakov nie čísel, jediným rozdielom je v type premennej prvok a položiek poľa a (čísla - integer, mená - napr. string[15], taktiež prvok - string[15] ) Úloha 4 (Živé noviny): Určite ste sa stretli so živými novinami kde sa svetelné písmená posúvajú smerom doľava, čím môže pozorovateľ čítať informácie na tabuli. Správy sa neskôr cyklicky opakujú. Predstavme si dlhé pole písmen, ktoré budeme cyklicky posúvať doľava (prvé písmenko zaradíme vždy na koniec). Opäť si urobíme program na cyklický posun číselnej postupnosti a ukážeme si zmenu oproti živým novinám. Príklad cyklického posunu textu a čísel: Reklama eklamar klamare lamarek amarekl marekla areklam Reklama 1234567 2345671 3456712 4567123 5671234 6712345 7123456 1234567 program cyklicky_posun_dolava; var a: array [1..100] of integer; N, i, j, pom: integer; writeln ('Zadajte pocet prvkov postupnosti') readln (N); for i:=1 to N do writeln ('Zadajte ', i. ' prvok poľa'); 6
readln (a[i]) for i:=1 to N do pom:= a[1]; for j:=1 to N-1 do a[j]:= a[j+1]; a[n]:= pom; writeln ('Otocene pole prvkov: ') for i:=1 to N do write(a[i]) Príklad 3 Eratostenes a jeho sito: Eratostenes z Kyrény (asi 276-194 pred nl). bol grécky matematik a astronóm považovaný za najväčšieho geografa antiky. Veľmi známy je jeho efektívny algoritmus na vyhľadanie prvočísel. Už sme vytvorili program na výpis všetkých prvočísel napr. od 2 do 2000, v ktorom trocha neefektívne o každom čísle zisťujeme, či je prvočíslo. Uvedomme si ale, že žiadne párne číslo okrem čísla 2 nie je prvočíslo a zisťovanie ich deliteľností je zbytočné. Rovnako môžeme vylúčiť nielen násobky 2, ale aj násobky 3, 5,... Eratostenovo sito je teda pole, v ktorom ostanú len prvočísla, všetky ich násobky cez sito prepadnú. Čo ostane v site si budeme značiť v poli typu boolean (true prvočíslo, false zložené číslo), pričom index je samotné prvočíslo, resp. zložené číslo. Algoritmus zoberieme prvé číslo v poli s hodnotou true (if E[i] then...) a pre všetky jeho násobky si poznačíme false, potom zoberieme ďalšie číslo s hodnotou true a pre všetky jeho násobky si poznačíme false, potom zoberieme ďalšie číslo s hodnotou true... až kým nie sme na konci poľa. Vypíšeme len tie čísla, ktoré majú v poli hodnotu true. program eratostenovo_sito; var E: array [2..2000] of boolean; i,j,n: integer; for i:=2 to N do E[i]:=true; i:=2; repeat j:=i; if E[i] then while j<n do j:= j+i; {vytvoríme všetky násobky} E[j]:=false; {tie sú zložené čísla} inc(i); until i>n; writeln( Vypis prvocisel ); for i:=2 to N do if E[i] then write(i:5) 7
Úloha 5 (Odchýlky teplôt): Už sme naprogramovali štatistiku teplôt v mesiaci december, hľadali sme priemernú, maximálnu a minimálnu teplotu. Ďalšou zaujímavou informáciou je rozptyl teplôt, či počas mesiaca skáču, alebo sa teplota pohybuje vždy niekde okolo priemeru. Tento krát si musíme teploty uložiť do poľa, keďže ich budeme prehľadávať viackrát. Zostavme program, ktorý pre vstupné teploty v mesiaci zistí teploty, ktoré sa najviac a najmenej odchyľovali od priemeru. program odchylky_teplot; var t: array [1..31] of integer; i : integer; maxodch, minodch, priem, odch : real; writeln ('Zadajte teploty za kazdy den'); for i:=1 to 31 do readln(t[i]) priem:=0; maxodch:=0; minodch:=100; for i:=1 to 31 do priem:=priem+t[i]); priem:=priem/31; for i:=1 to 31 do odch:=abs(priem-t[i]); if od>maxodch then maxodch:=odch else if od<minodch then minod:=odch; writeln('najvacsia odchylka:', maxodch); writeln('najmensia odchylka:', minodch); Úloha 6 (Komprimácia?): Niektoré komprimačné ( stláčacie ) programy pracujú na princípe úsporného zápisu sekvencií zhodných čísel (číslic), napr. postupnosť 1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,0,0 môžeme skrátene zapísať ako 4,1,8,0,4,1,2,0, (4x1, 8x0, 4x1, 2x0) čo je o niečo kratšia postupnosť. Zostavte program, ktorý na vstupe dostane postupnosť cifier 1 a 0 a vytvorí z neho komprimované pole. program komprimacia; var p, kp: array [1..1000] of integer; N, i, j, p0, p1: integer; writeln ('Zadajte pocet prvkov postupnosti') readln (N); writeln ('Zadajte postupnost jednotiek a nul'); for i:=1 to N do readln (a[i]); i:=1; j:=1; repeat p0:=0; p1:=0; while (p[i]=0) and (i<=i) do inc(p0); inc(i); 8
if p0>0 then kp[j]:=p0; inc(j);kp:=0;inc(j); while (p[i]=1) and (i<=i) do inc(p1); inc(i); if p1>0 then kp[j]:=p1; inc(j);kp:=1;inc(j); until i>n; for i:=1 to j do write(pk[i]) Úloha 7 (Dlhéééééé čísla): Doposiaľ sme pracovali prevážne s celými číslami typu integer resp. longint. Napriek tomu nám často rozsah hodnôt, ktoré tieto typy umožňujú, nestačí. Predstavme si veľmi dlhé čísla s počtom cifier viac ako 10, ktoré potrebujeme sčítať. S takými to číslami môžeme pracovať aj tak, že si ich cifry vložíme do poľa a pracujeme s jednotlivými ciframi. Pri súčte čísel vzniká prenos do vyššieho rádu (celý počet desiatok), ktorý nesmieme zabudnúť pripočítať. Prenos do vyššieho rádu... sucet div 10 (počet desiatok, ktorý pri sčítavaní vznikol) Výsledok sčítania v istom ráde... sucet mod 10 Nezabudnime nato, že čísla majú rôzne dĺžky (počet číslic) a keď ich načítame, budú ich odpovedajúce cifry od konca posunuté. Ak prvé číslo má dĺžku N a druhé M, tak potom ak N>M posun je N-M resp. ak M>N posun je M-N. Sčítavame teda číslice na pozícii a[i] a b[i- N+M] resp. a[i] a b[i-m+n]. (Iná možnosť je polia najskôr otočiť, sčítať odpredu a výsledok opäť otočiť.) a 1 0 9 8 7 2 7 0 5 9 a[1] a[2]... a[n] a[i] b 7 5 6 0 6 4 0 9 b[1] b[2]... b[m] b[i-(n-m)] N-M program sucet_dlhych_cisel; var a, b, c: array [1..100] of integer; N, M, i, prenos: integer; writeln ('Zadajte pocet cifier 1. cisla') readln (N); writeln ('Zadajte postupne cifry 1. cisla') for i:=1 to N do readln (a[i]); writeln ('Zadajte pocet cifier 2. cisla') readln (M); writeln ('Zadajte postupne cifry 2. cisla') for i:=1 to M do readln (b[i]); prenos:=0; if N>M then 9
for i:=1 to N do pom := a[i]+b[i-n+m]+prenos; c[i] := pom mod 10; prenos := pom div 10; K:=N; end else for i:=1 to M do pom := a[i-n+m]+b[i]+prenos; c[i] := pom mod 10; prenos := pom div 10; K:=M; if prenos>0 then c[0]:=prenos write('sucet cisel:'); for i:=0 to N do write(a[i]); write('+'); for i:=0 to M do write(b[i]); writeln; for i:=0 to K do write(c[i]) 10
Neriešené úlohy: 1. Vyhľadávanie. Zostavte program, ktorý vygeneruje postupnosť náhodných čísel a program bude hľadať istý prvok a vypíše miesto jeho prvého výskytu, alebo ak sa v postupnosti prvok nenachádza vypíše o tom komentár. 2. Tipovanie. Vyskúšajte si svoje šťastie v tipovacích hrách ako je lotto, keno 10 a pod. Počítač vygeneruje 5 rôznych čísel od 1 do 35 (pozor, ak vygenerujete číslo, musí byť iné ako predošlé vygenerované čísla), čím zrealizuje losovanie výherných čísel. Váš program bude načítavať päticu čísel a vyhodnocovať počet uhádnutých čísel. 3. Logic. Určite poznáte hru Logic (Mastermind), kde hrajú dvaja hráči, jeden si zvolí 4 kamene rôznych farieb zo 6 možných v istom poradí a druhý hráč háda ich postavenie, pričom mu prvý hráč po každom pokuse oznámi počet uhádnutých farieb a počet správne uhádnutých pozícií. Naprogramujte túto hru, pričom farby môžu byť čísla od 1 do 6, prvého hráča nahradí počítač, ktorý vygeneruje 4 náhodné čísla od 1 do 6 do poľa a hráč háda. Počítač mu na konci oznámi aj počet pokusov hádania. 4. Vyčítanka. Mnohí z vás sa určite hrali hry, v ktorých bol jeden z hráčov vyčlenený na špeciálne účely v dobrom či zlom. Napríklad naháňal alebo hľadal ostatných. Ako určiť obeť? Slúžili k tomu od nepamäti rôzne riekanky vyčítanky. Všetci hráči sa postavia do kruhu a na koho to slovo padne, ten musí ísť z kola von. Zostavte program, ktorý nám vypíše deti v poradí, v akom budú z kruhu vypadávať. (Deti zatiaľ označíme číslom od 1 do N, neskôr ich budeme volať aj menami, vyčítanka má K slabík, kruh vytvoríme cyklickým posunom od posledného prvku poľa opäť k prvému). 5. Faktoríál 100? Rovnako, ako sme sčítavali dlhé čísla, môžeme čísla aj násobiť. Na výpočet faktoriálu čísla 100 nám určite nestačí typ longint a typ real vypočíta len približné číslo (v exponenciálnom tvare zaokrúhlené na istý počet des. miest). Preto si ho môžeme vypočítať sami, pričom každú jeho cifru budeme ukladať do poľa, čiže postupne cifry násobiť číslom a pripočítavať prenos z nižšieho rádu a celé desiatky prenášať do vyššieho rádu. (Na začiatku si do poľa vložíme len číslo 1 a postupne ho násobíme 2,3,4,...,100, do aktuálneho prvku vkladáme len zvyšok po delení 10 a nenulový celý počet desiatok prenášame do vyššieho rádu). 6. Program ZMEN zamení v postupnosti n čísel všetky nepárne čísla opačnými hodnotami (so záporným znamienkom) a vypíše novú postupnosť čísel. Doplňte chýbajúce časti programu: 11
program ZMEN; var i,n:integer; s:array[1..100]of integer; for i:=1 to... do if s[i]... then s[i]:=...; write(...); 7. Skonči program KONIEC, alebo nie? Porozmýšľajte možnosti jeho ukončenia pre rôzne hodnoty X: program KONIEC; readln(x); repeat X:=X-2; until X=0; writeln(x); var X:integer; 12
ZADANIE 6.1: V triede ideme zisťovať, aký je rozptyl výšok žiakov, či sa ich výšky od seba veľmi líšia, alebo sú približne rovnaké. Uložte výšky N žiakov do premennej typu pole, vypočítajte priemernú výšku žiaka. Potom nájdite, ktorý žiak sa najviac odchyľuje od priemeru a o koľko (môže to byť najvyšší, alebo najnižší žiak triedy) a ktorý žiak sa najmenej odchyľuje od priemeru a o koľko. Nezáleží, či sa odchyľuje nahor, či nadol, hľadajte absolútnu odchýlku (absolútnu hodnotu rozdielu výšok od priemernej hodnoty). Program vypíše priemernú výšku, na ďalší riadok poradové číslo žiaka s najväčším rozptylom aj samotnú odchýlku a na ďalší riadok poradové číslo žiaka s najmenšou odchýlkou aj samotnú odchýlku. ZADANIE 6.2: Očistite postupnosť od nulových prvkov! Zostavte program, ktorý vo vstupnej postupnosti vyhádže nuly, čiže zmenší pole o nulové prvky, výsledné pole bude menšie. Vstupom programu je ľubovoľná postupnosť N celých čísel, výstupom je tá istá skrátená postupnosť, kde chýbajú nulové prvky. POZOR! V zadaní použite len jedno pole (Nekopírujte nenulové prvky z jedného do druhého poľa)! Úloha nie je vyriešená, ak len vypíšete nenulové prvky, tie sú stále v poli! 13