Polia, vymenovaný typ, množiny
1. ukážeme prácu so zásobníkom
2. definujeme vymenovaný typ
3. naučíme sa používať typ množina
type pole = array[typ_indexu] of typ_prvkov;
Príklad: Zásobník je postupnosť prvkov, v ktorej je možné pridávať a odoberať prvky len na jednom konci. Tento koniec sa nazýva vrchol zásobníka. Teda zásobník môžeme považovať za istú štruktúru údajov.
procedúry pre prácu so zásobníkom:
Const nmax=100;
Type
zasobnik=array[1..nmax,1..3] of integer;
rozsah: 0..nmax;
var z: zasobnik; vrchol: rozsah;
procedure vytvor_z(var zz: zasobnik; var vrch:rozsah);
{Vytvori prazdny zasobnik}
begin
vrch:=0;
end;
procedure vloz_z(var zz: zasobnik; var vrch:rozsah; e,f,g: integer);
{Vlozi prvok do zasobnika}
if vrch<nmax then
begin zz[vrch,1]:=e; zz[vrch,2]:=f; zz[vrch,3]:=g;
inc(vrch) end
else writeln('Zasobnik je plny');
procedure vyber_z(var zz: zasobnik; var vrch:rozsah; var e, f, g: integer);
{Vyberie prvok zo zasobnika}
if vrch>0 then
begin e:=zz[vrch,1]; f:=zz[vrch,2];
g:=zz[vrch,3]; dec(vrch) end
else writeln('Zasobnik je prazdny');
Príklad na použitie zásobníka:
V nasledujúcom príklade si to ukážeme na Fibonacciho postupnosti. Definovaná je rekurentne takto:
F(0)=1; F(1)=1; F(N)=F(N-1)+F(N-2) pre N>1
F(2)=2
F(3)=3
F(4)=5
F(5)=8
F(6)=13
F(7)=21
F(7)= F(6) + F(5)
F(4) + F(3)
F(2) + F(1)
1
F(1) + F(0)
F(3) + F(2)
rekurzívna procedúra, ktorá počíta N-té Fibonacciho číslo:
Var
ff:integer; { globálna premenná, v ktorej je vypočítaná hodnota}
procedure fib(n:integer);
var
f : integer;
{časť 1:}
if n<2 then ff:=1
else begin
fib(n-1);
{časť 2:}
f := ff;
fib(n-2);
{časť 3:}
ff:=ff+f;
nerekurzívny tvar predchádzajúcej procedúry:
procedure fibN(n:integer);
f, e, v: integer;
z: zasobnik;
vr: rozsah;
v:=1;
f:=0;
vytvor_z(z, vr);
vloz_z(z,vr,n,f,v);
while vr>0 do begin
vyber_z(z,vr,n,f,v);
case v of
1:
vloz_z(z,vr,n,f, 2);
vloz_z(z,vr,n-1,f, 1); {rekurzívne volanie}
2:
f:=ff;
vloz_z(z,vr,n, f, 3);
Vloz_z(z,vr,n-2, f, 1); {fib(n-2)}
3: ff:=ff+f;
· je ordinálny typ, ktorý definujeme vymenovaním všetkých prípustných hodnôt daného typu
· vymenované hodnoty sú identifikátory konštánt (ich ordinálne hodnoty sú čísla od 0 do počet-1), napr. type nastroj = (husle,bubon,klavir,truba,saxofon,flauta,triangel);
· definuje nový ordinálny typ - premenné tohto typu môžu nadobúdať hodnotu len z tohto zoznamu konštánt
· vymenovaný typ, na rozdiel od intervalu, nie je kompatibilný so žiadnym iným typom (interval preberá všetky vlastnosti aj konštanty nadradeného typu a tiež je s ním kompatibilný - dovoľuje navzájom sa priraďovať, miešať sa v operáciách a pod.)
· deklarácia vymenovaného typu okrem samotného typu automaticky definuje aj identifikátory konštánt tohto typu, t.j. s deklaráciou typu nastroj sa zadeklarovalo aj 7 identifikátorov - ako keby const husle=...; bubon=...; truba=...; ...
· vymenovaný typ je ordinálny a teda s ním fungujú všetky štandardné funkcie a procedúry, ktoré pracujú s inými ordinálnymi typmi (integer, char, boolean) - napr. pred, succ, inc, dec, low, high, ord
ukážka:
type
tyzden=(pon,uto,str,stv,pia,sob,ned);
d:tyzden;
d:=pon;
d:=pred(pia);
d:=succ(sob);
d:=uto;
inc(d);
inc(d,3);
i:=ord(pon); { i=0 prvá konštanta vymenovaného typu má hodnotu 0}
i:=ord(uto); { i=1}
d:=tyzden(4); { d=pia - identifikátor typu sa dá použiť ako funkcia}
d:=low(tyzden); { d=pon
d:=high(d); { d=ned -- je to škaredé
· práca s vymenovaným typom:
o štandardné funkcie, procedúry: ord, pred, succ, low, high, inc, dec
o môžeme ho použiť ako index prvkov poľa, resp. riadiaca premenná cyklu
o fungujú všetky relácie: =, <>, <=, >=, <, >
o aj typ boolean je vymenovaný typ, t.j. ako keby type boolean=(false,true);
o vymenovaný typ sa nedá vypísať ani načítať
o ordinálna hodnota je definovaná tak, že prvá konštanta typu má vnútornú hodnotu 0 a všetky ďalšie postupne o 1 viac, t.j. ord(pon)=0; ord(uto)=1; ord(str)=2; ... ord(ned)=6;
o meno typu (v našom prípade tyzden) je automaticky menom konverznej funkcie, ktorá z celého čísla vyrobí príslušnú konštantu vymenovaného typu, napr. tyzden(2)=str; tyzden(5)=sob;
· ak potrebujeme hodnoty vymenovaného typu načítať alebo vypísať, tak buď pri vstupe/výstupe pracujeme iba s ordinálnymi hodnotami, alebo si vytvoríme pomocné pole mien konštánt, napr.
načítanie a výpis vymenovaného typu pomocou poľa mien konštánt:
const
a:array [tyzden] of string =
('pon','uto','str','stv','pia','sob','ned');
s:string[3];
readln(s);
d:=low(tyzden);
while (d<high(tyzden)) and (a[d]<>s) do inc(d);
if a[d]<>s then
writeln('... chyba ...')
else
writeln(a[succ(d)]); { spadne, ak d=ned}
· je taký údajový typ, ktorý umožňuje v pascale pracovať s istou triedou množín podobným spôsobom ako v je obvyklé v matematike
· v pascale je povolené vytvárať množiny len prvkov rovnakého a to ordinálneho typu - hovoríme mu bázový (základný) typ, napr. množina znakov, množina malých celých čísel, množina dní v týždni a pod.
· nemôžeme vytvoriť množinu, ktorá bude obsahovať napr. čísla aj znaky
· definícia množiny sa vždy skladá aj z definície jej bázového typu, napr. zápis set of 1..100 definuje typ množina, ktorá môže obsahovať len čísla z intervalu (to je ordinálny typ) 1 až 100 - zrejme premenná takéhoto typu môže byť napr. prázdnou množinou, alebo jednoprvkovou množinou s prvkom 13 alebo dvojprvkovou množinou s prvkami 2 a 3 a pod.
napr.
m=set of 1..100;
a,b:m;
· množinové konštanty: [], [2], [1,3], [1,2,3], [5..15,20,23..27]
· operácie (oba operandy musia byť kompatibilné množiny - majú kompatibilné bázové typy):
o zjednotenie a:=a+b;
o prienik a:=a*[2,3];
o rozdiel a:=b-[1,3];
· príslušnosť prvku (prvý operand je bázového typu, druhý je množina):
o číslo 3 je prvkom množiny a: if 3 in a then ...
· relácie:
o rovnosť, nerovnosť: if a=b then if c<>[] then ...
o podmnožiny: if (a<=b) or (a>=b) then ...
príklady:
z:char;
...
if z in ['A'..'Z','a'..'z'] then ...
if not (z in ['0'..'9']) then ...
testovanie odpovede áno/nie:
ano=['a','A','y','Y']; nie=['n','N'];
if (s<>'') and (s[1] in ano) then ...
else if (s<>'') and (s[1] in nie) then ...
else writeln('chybná odpoveď - ano/nie')
generovanie množiny for-cyklom:
x:set of 1..100;
x:=[];
for i:=1 to 100 do x:=x+[i];
for i:=1 to 50 do x:=x+[i,101-i];
na množinách nefunguje write - vypisujeme ich pomocou cyklu:
baza=1..100;
mnozina=set of baza;
procedure vypis(const m:mnozina);
i:baza;
s:string;
s:='[';
for i:=low(baza) to high(baza) do
if i in m then s:=s+chr(i....)+',';
writeln(s+']');
· pascalovská množina = postupnosť bitov
· napr. pre set of 0..99 je vyhradených 100 bitov, t.j. 13 bajtov
· v každom bite je buď 0 - prvok nepatrí do množiny alebo 1 - prvok patrí do množiny
· a:=[]; - vynuluje všetky bity
· a:=[5,7,8]; - nastaví iba bity 5,7,8, ostatné vynuluje
· a+b - ide po bitoch a robí operáciu binárne OR
· množina 0..255 zaberá 32 bajtov
Napíšeme program, ktorý vytvorí podmnožinu M množiny 1..250 takú, že
riešenie
m:set of 1..250;
i:integer;
m:=[1];
for i:=1 to 124 do
if i in m then begin
m:=m+[2*i+1]; {2*i+1 je vždy z 1..250}
if 3*i+1<=250 then m:=m+[3*i+1]
{ak je aj 3*i+1 z 1..250, pridáme ho do množiny}
m:array[0..max] of set of 0..255;
{ pridávame x do takejto množiny:}
m[x div 256]:=m[x div 256]+[x mod 256]
{ zistíme, či je x v množine:}
if [x mod 256] in m[x div 256] then ...
riešenie predchádzajúceho príkladu (pre množinu do 256*20-1 = 5119):
mnozina=set of byte; { t.j. 0..255}
mn=array[0..19] of mnozina;
m:mn;
i,j:integer;
m[0]:=[1];
for i:=1 to 19 do m[i]:=[];
for i:=1 to 2559 do
if (i mod 256) in m[i div 256] then begin
j:=2*i+1;
m[j div 256]:=m[j div 256]+[j mod 256];
j:=3*i+1;
if j div 256<=19 then
vypis; { procedúra, ktorá vypíše čísla z množiny}
Erathostenes pre malé množiny
m, prvoc:set of 1..255;
d: integer;
m:=[];
for i:=1 to 255 do m:= m+[i];
prvoc:=[2];
for i:=1 to 255 do
if i mod 2=0 then m:=m-[i];
d:=3;
while d<=123 do
j:= d;
while j<=255 do
if j in m then m:=m-[j];
j:= j+d;
d:=d+2;