Praktická cvičení algoritmů - Informatika Ostravská Univerzita

Transkript

Praktická cvičení algoritmů - Informatika Ostravská Univerzita
Praktická cvičení algoritmů
texty pro distanční studium
Ing. Eliška Treterová
Ostravská univerzita v Ostravě, Přírodovědecká fakulta
Katedra Informatiky a počítačů
Ostrava 2003
Praktická cvičení algoritmů
2
Praktická cvičení algoritmů
Úvod....................................................................................................................5
1. Jednoduchá proměnná..............................................................................6
1.1.
Číselná proměnná ................................................................................6
1.1.1.
Celá čísla .....................................................................................6
1.1.2.
Příklady použití jednoduché celočíselné proměnné. ...................7
1.1.3.
Korespondenční úkol č. 1..........................................................17
1.1.4.
Reálná čísla ...............................................................................17
1.1.5.
Příklady použití reálné proměnné. ............................................18
1.2. Znaková proměnná ............................................................................22
1.2.1.
Znaky.........................................................................................22
1.2.2.
Příklady použití znakové proměnné..........................................23
1.3. Logická proměnná.............................................................................28
1.3.1.
Logické konstanty .....................................................................28
1.3.2.
Příklady použití logické proměnné ...........................................29
1.3.3.
Korespondenční úkol č.2...........................................................33
2. Statické datové struktury .......................................................................34
2.1.
Řetězec znaků....................................................................................34
2.2.
Pole....................................................................................................39
2.2.1.
Jednorozměrné pole...................................................................40
2.2.2.
Dvourozměrné pole ...................................................................46
2.3.
Záznam ..............................................................................................53
2.4.
Množina.............................................................................................55
2.5. Korespondenční úkol č. 3..................................................................59
3. Uložení dat mimo operační paměť ........................................................60
3.1.
Textový soubor..................................................................................60
3.2.
Typový soubor...................................................................................64
3.3. Korespondenční úkol č.4...................................................................70
4. Závěr.........................................................................................................70
5. Literatura.................................................................................................71
3
Praktická cvičení algoritmů
4
Praktická cvičení algoritmů
Úvod
Studijní text je určen pro zájemce o studium problematiky tvorby algoritmů a
jejich zápisu v programovacím jazyku Borland Pascal. Je možné jej využít v
předmětu Praktická cvičení algoritmů.
Předpokladem úspěšného zvládnutí učiva tohoto studijního textu je dobrá
orientace v integrovaném prostředí Borland Pascalu a dobrá znalost základních
rysů tohoto programovacího jazyka. Studující musí byt schopen používat
jednoduché i strukturované příkazy jazyka Borland Pascal, vytvářet vlastní
podprogramy obou dovolených typů – procedury a funkce a znát problematiku
datových typů.
Studijní text je rozdělen do tří velkých kapitol. V úvodní kapitole jsou
vysvětleny základní principy práce s jednoduchou proměnnou. Další kapitola
se zabývá problematikou uložení dat pomocí datových struktura a jejich
následným zpracováním. Třetí kapitola pak je věnována ukládání dat mimo
operační paměť počítače. Studující se zde naučí uložit data do externího
souboru a následně pak také zpět do operační paměti.
Všechny kapitoly a podkapitoly jsou doplněny velkým množstvím příkladů. U
každého příkladu je proveden rozbor řešení a je vloženo řešení ve zdrojovém
kódu programovacího jazyka Borland Pascal.
5
Praktická cvičení algoritmů
1.
Jednoduchá proměnná
Cíl:
Po prostudování této kapitoly budete schopni:
- používat v programech číselné proměnné
- zařadit do algoritmů znakovou proměnnou
- rozlišit situace, kdy do algoritmů je vhodně zařadit logickou proměnnou
Klíčová slova:
Proměnná, celé číslo, reálné číslo, znak, logická proměnná, logická konstanta,
aritmetické operace, relační operace, logické operace, logický výraz, standardní
podprogramy, datový typ, předefinovaná konstanta.
Jednoduchá proměnná slouží k uložení jedné hodnoty. Jako hodnota se zde
může objevit celé číslo, desetinné číslo, znak nebo logická konstanta. Význam
jednoduché proměnné pro programování spočívá především v tom, že často
programátor potřebuje různá počítadla, přepínače a pomocné proměnné pro
uložení výsledků a mezivýsledků.
1.1.
Číselná proměnná
V programovacím jazyku Borland Pascal rozlišujeme čísla celá a čísla
desetinná. Obecně platí, že čísla desetinná v programování nazýváme reálná.
Rozdělení čísel do těchto dvou skupin vychází z odlišného způsobu jejich
vnitřního reprezentace a v závislosti na tom i provádění výpočtu.
1.1.1.
Celá čísla
Celá čísla se v paměti počítače ukládají přesně. Kladná část čísla je zobrazena
ve dvojkové soustavě, záporná čísla se ukládají v doplňkovém kódu. Nejvyšší
bit slouží k uložení znaménka. Pokud je tento bit roven nule, je číslo kladné,
pokud je roven 1, znamená to, že číslo je záporné. Další bity vymezeného
prostoru slouží k uložení vlastní hodnoty.
Velikost paměti přidělená jednomu číslu je přesně určena datovým typem
proměnné. V Borland Pascalu existuje 5 různých datových typů, kdy
nejběžnějším typem je typ INTEGER, který proměnné přiděluje paměť
velikosti 16 bitů. Z tohoto prostoru je jeden bit určen pro znaménko a
zbývajících 15 bitů pro uložení čísla. Z toho vyplývá, že v tomto prostoru lze
uložit libovolné celé číslo z rozmezí -215 až 215-1, tj. -32 768 do 32 767.
Překladač Borland Pascalu rozlišuje 5 datových typů pro celá čísla.
Typ
Množina hodnot (rozsah)
Velikost paměti v bytech
BYTE
0 .. 255
1
SHORTINT -128 .. 127
1
6
Praktická cvičení algoritmů
WORD
INTEGER
LONGINT
0 .. 65 535
-32 768 .. 32 767
-2 147 483 648 .. 2 147 483 647
1.1.2.
2
2
4
Příklady použití jednoduché celočíselné proměnné.
Při použití celočíselné proměnné je vhodné si zapamatovat, které operace
Borland Pascal pro celočíselné operace nabízí.
Dovolené operace s proměnnými celočíselných typů:
a) aritmetické operátory:
+
… sčítání
… odčítání
*
… násobení
DIV … celočíselné dělení
MOD… zbytek po celočíselném dělení
/
… přesné dělení
Použití operace dělení pomocí operátoru / je dovoleno pro celočíselné
proměnné, ale výsledek tohoto dělení je reálné číslo (číslo s desetinnou částí).
Výsledkem ostatních operací bude celočíselná hodnota.
Průvodce studiem:
Na tomto místě bych vás chtěla upozornit především na existenci operátorů
DIV a MOD. Programátor by se bez nich docela lehce obešel, ale proč je
nepoužívat, když jsou k dispozici ?
Jestliže vypočítáme:
7 : 2 = 3, zbytek je 1
Pak stejné výsledky dostaneme takto:
7 DIV 2 = 3
7 MOD 2 = 1
Vhodnost použití operátorů DIV a MOD a zároveň jejich nahraditelnost je
znázorněna v příkladu č.1-1 a příkladu č.1-2.
b) relační operátory:
=
… rovná se
<> … nerovná se
>
… větší než
>= … větší nebo rovno
<
… menší než
<= … menší nebo rovno
Výsledkem těchto operací je logická hodnota TRUE nebo FALSE !
7
Praktická cvičení algoritmů
Předdefinované celočíselné konstanty - není třeba je zavádět v deklarační
části programu.
MAXINT - obsahuje největší dovolenou hodnotu , kterou lze uložit do
proměnné typu INTEGER, což je 32 767.
MAXLONGINT - obsahuje největší dovolenou hodnotu , kterou lze uložit do
proměnné typu LONGINT, což je 2 147 483 647.
Průvodce studiem:
Je výhodné znát, že existují tzv. předdefinované konstanty. Tyto konstanty pak
můžete použít, aniž byste je museli uvádět v deklarační část programu a pak
také máte jistotu, že mají vždy stejnou hodnotu. V dalším textu jsou občas
použity.
Příklad 1-1:
Zjistěte celou část podílu celých čísel A,B. Předpoklad: máme deklarovány
proměnné Vysl, A a B jako celá čísla.
Řešení s využitím operátoru DIV:
Vysl := A DIV B;
Řešení bez použití operátoru DIV:
Vysl := trunc(A/B) ;
Výsledek obou řešení je stejný ! Druhé řešení je ale zbytečně složité, obvykle
se k němu uchýlí programátor, který neví o existenci standardního operátoru
DIV.
Příklad 1-2:
Zjistěte, zda je číslo A dělitelné číslem B. Předpoklad: máme deklarovány
proměnné A a B jako celá čísla.
Řešení s využitím operátoru MOD:
If A MOD B = 0 then { …………};
Řešení s využitím operátoru DIV a zpětné násobení podílu dělitelem:
If (A DIV B) * B = K then { …………};
Toto řešení je v podstatě správné, ale zbytečně složité.
Řešení bez použití operátoru MOD:
If (A DIV B) = A/B then { …………};
If round(A / B) * B = A then { …………};
Tato řešení jsou poněkud nešikovná, protože vyžadují přechod do reálných
čísel.
8
Praktická cvičení algoritmů
Příklad 1-3:
Zjistěte, kolikrát musí jet dopravní prostředek o kapacitě K, aby přepravil
skupinu cestujících o počtu P. Zajistěte regulérnost vstupní hodnoty a
nabídněte možnost opakování celého výpočtu na základě dotazu.
Rozbor řešení:
Použijeme aritmetické operace DIV a MOD, které jsou pro celá čísla dovolené.
Pomocí DIV zjistíme, kolik bude zcela plných dopravních prostředků, a
pomocí MOD zjistíme, zda je třeba poslat další dopravní prostředek, který
nebude plný.
Řešení v Borland Pascalu:
Program PR1_3;
uses crt;
var
K,P,pocet_jizd,zbytek:integer;
opakovani:integer;
begin
repeat
clrscr;
repeat
write('zadej pocet cestujicich: ');
readln(P);
write('zadej kapacitu dopr.prostredku vetsi nez nula:');
readln(K);
until (P>0) and (K>0);
pocet_jizd:=p div k;
zbytek:= p mod k;
if zbytek <> 0 then pocet_jizd := pocet_jizd + 1;
writeln('dopr.prostredek musi jet' ,pocet_jizd);
writeln;
Write('opakovat cely vypocet ? ');
Writeln('1=ano, ostatni cisla = konec programu');
readln(opakovani);
until opakovani <> 1;
end.
Průvodce studiem:
Algoritmus řešení tohoto problému byl vcelku jednoduchý, hlavně proto, že
jste využili operátory DIV a MOD. Do programu jsem zařadila nabídku
opakování celého výpočtu. To nemá vliv na vlastní algoritmus řešení, ale
uživateli programu tím umožníte pohodlným způsobem testovat různé varianty
řešení.
Často v programech tuto nabídku naleznete.
9
Praktická cvičení algoritmů
Příklad 1-4
Z klávesnice zadáváme předem známý počet celých čísel. Počet vstupních
hodnot je uložen v N. Zjistěte kolik ze zadaných hodnot bylo záporných a kolik
hodnot bylo dělitelných 5 (použijte operátor MOD). K řešení použijte
libovolný příkaz cyklu.
Rozbor řešení:
Dělitelnost čísla zde chápeme jako situaci, kdy nám po vydělení zůstane zbytek
roven nule. K tomuto účelu nám dobře poslouží operátor MOD. Zápornost
čísla zjistíme porovnáním čísla s nulou.
V programu není zařazena nabídka opakování výpočtu. Pro zamezení
automatického návratu do integrovaného prostředí Borland Pascalu po vytištění
výsledků je na konci programu vložen příkaz cyklu s podmínkou na konci ve
tvaru: repeat until keypressed; kde keypressed je logická funkce, která
vrací hodnotu TRUE při stisku libovolné klávesy.
Řešení v Borland Pascalu:
Program PR1_4;
uses crt;
var
i, cislo, pocet, zap, del:integer;
begin
Clrscr;
Write('Zadejte pocet cisel: ');
ReadLn(pocet);
del:=0;
zap:=0;
For i:=1 to pocet do
begin
Write('Zadejte cislo: ');
ReadLn(cislo);
if cislo mod 5 = 0 then inc(del);
{del:=del+1}
if cislo < 0 then inc(zap);
end;
Writeln('Z celk. poctu ', pocet,' cisel bylo: ');
Writeln('zapornych
: ',zap);
Writeln('delitelnych 5: ',del);
repeat until keypressed;
end.
Příklad 1-5
Sestavte proceduru, která čas zadaný v sekundách převede na hodiny, minuty a
sekundy. Načtení času a tisk výsledků bude provedeno v hlavním programu.
Zajistěte regulérnost vstupní hodnoty a nabídněte možnost opakování celého
výpočtu na základě dotazu.
Rozbor řešení:
Výsledkem by mělo být vyjádření času v tzv. digitální podobě. Jednoduchým
způsobem pomocí operátorů DIV a MOD získáme výsledek. Výpočet má smyl
pouze v případě, že na vstupu bude kladné číslo.
10
Praktická cvičení algoritmů
Řešení v Borland Pascalu:
program PR1_5;
uses crt;
var pocet_sec:longint;
h,m,sec:integer;
opakovani:integer;
procedure prevod(pocet:longint;var hod,min,sec:integer);
var
zb:integer;
begin
hod:= pocet div 3600;
zb:=pocet mod 3600;
min:= zb div 60;
sec:= zb mod 60;
end;
begin
repeat
clrscr;
repeat
write('Zadej cas v sekundach: ');
readln(pocet_sec);
If pocet_sec <= 0 then writeln('cas zadejte vetsi nez
nula!');
until pocet_sec > 0;
prevod(pocet_sec,h,m,sec);
writeln('Cas v hodinach: ',h,':',m,':',sec);
writeln;
Write('opakovat cely vypocet ? ');
writeln('1=ano, ostatni cisla = konec programu');
readln(opakovani);
until opakovani <> 1;
end.
Samostatný úkol č1:
Vyřešte úkol PR1_5 bez použití operátorů DIV a MOD.
Rozbor řešení:
Celočíselné dělení nahradíme postupným odčítáním dělitele od dělence.
Příklad 1-6
Sestavte funkci, která vypočítá N-tou mocninu reálného čísla Z, řešte i pro
případ záporného mocnitele. Funkce bude mít dva formální parametry. Tuto
funkci využijte v programu.
Rozbor řešení:
Platí: zn = z * z* z*…z . Pro záporného mocnitele se provede výpočet mocniny
s kladným mocnitelem a výsledek pak získáme jako převrácenou hodnotu
výsledku.
11
Praktická cvičení algoritmů
Průvodce studiem:
Překladač jazyka Borland Pascal obsahuje pouze standardní funkci SQR(x),
která vypočítá druhou mocninu čísla x. Pokud potřebujete vypočítat N-tou
mocninu nebo umocnit číslo na záporného mocnitele, musíte sestavit potřebný
algoritmus sami. Algoritmus výpočtu je vcelku jednoduchý, nezapomeňte
správně nastavit ve funkci počáteční hodnotu lokální proměnné V na
hodnotu 1.
Řešení v Borland Pascalu:
Program PR1_6;
var
cis,vysl:real;
moc:integer;
Function mocnina(z:real;n:integer):real;
var
i:integer;
v:real;
begin
v:=1;
for I:= 1 to abs(n) do v:=v*z;
if n<0 then v:= 1/v;
mocnina:=v;
end;
begin
Write('Zadej cislo: ');
readln(cis);
write('Zadej mocnitele: ');
readln(moc);
vysl:=mocnina(cis,moc);
writeln('N-ta mocnina cisla: ',vysl:5:2);
writeln;
write('zmackni ENTER: ');
readln;
end.
Příklad 1-7
Sestavte funkci pro výpočet N!. Funkce bude mít jeden formální parametr.
Funkci využijte v programu – v programu zajistěte, aby se funkce volala pouze
v případě, že lze N! vypočítat. Nabídněte možnost opakování celého výpočtu
na základě dotazu.
Rozbor řešení:
Pro faktoriál přirozeného čísla N platí: N! = 1*2*3*4*…*N
Pro nulu platí: 0! = 1
Pro záporná čísla není faktoriál definován.
Funkce pro výpočet faktoriálu netestuje správnost vstupní hodnoty, to je
zajištěno v hlavním programu návratem na opětovné zadání čísla, pokud je
číslo záporné.
12
Praktická cvičení algoritmů
Průvodce studiem:
Ve funkci, kterou sestavíte pro výpočet faktoriálu, musíte zavést dvě pomocné
lokální proměnné. Proměnná i slouží jako řídící proměnná cyklu a proměnná v
slouží pro uložení výsledku. Teprve na konci funkce přiřaďte obsah proměnné
v do názvu funkce. Pokud byste toto přiřazení neprovedli, funkce by vám
v místě svého volání nevracela vypočtenou hodnotu.
Také je důležité to, že ve funkce netestuje, zda lze či nelze faktoriál ze
zadaného čísla vypočítat. To musíte zajistit v programu dříve, než funkci
zavoláte.
Vzhledem k tomu, že hodnota faktoriálu roste velmi rychle, je důležité, abyste
stanovili návratový typ funkce (a také lokální proměnné v na longint. Pokud by
ani tento rozsah nestačil, tak zvolte jako návratový typ funkce datový typ real.
Nezapomeňte nastavit počáteční hodnotu proměnné v na jedničku. Kdybyste
do v dali nulu, byl by výsledek vašeho výpočtu pořád nulový.
Řešení v Borland Pascalu:
Program PR1_7;
uses crt;
var
F,opakovani:integer;
vysl:longint;
Function FAKT(n:integer):longint;
var
i:integer;
v:longint;
begin
v:=1;
for i:= 1 to n do v:=v*i;
fakt:=v;
end;
begin
repeat
clrscr;
repeat
Write('Zadej cislo N intervalu <0,15> ');
readln(f);
until (f>=0) and (f<=15);
vysl:=fakt(f);
writeln('faktorial cisla: ',vysl);
writeln;
Write('opakovat cely vypocet ? ');
writeln('1=ano, ostatni cisla = konec programu');
readln(opakovani);
until opakovani <> 1;
end.
13
Praktická cvičení algoritmů
Příklad 1-8
Sestavte funkci, která bude počítat součin dvou celých čísel pomocí
postupného sčítání. Řešte i pro záporné hodnoty. Tuto funkci využijte
v programu. Nabídněte možnost opakování celého výpočtu na základě dotazu.
Rozbor řešení:
Základem řešení je to, že násobení dvou celých čísel je ve své podstatě
opakované sčítání jednoho činitele. Počet opakování sčítání je dán hodnotou
druhého činitele. Např.: 3*4 = 4+4+4.
Pro záporné hodnoty pak je nutné především zajistit, aby výpočet vždy
proběhl. To zajišťuje použití standardní funkce ABS(cis1). Po výpočtu je třeba
upravit výsledek pro situaci, kdy cis1 je záporné číslo. Ostatní je v pořádku.
Např.:
3*4
= 4+4+4
= 12
3*(-4) = (-4) + (-4) + (-4) = -12
-3*4 = 4+4+4
= 12
-3*(-4) = (-4) + (-4) + (-4) =-12
Průvodce studiem:
Vyřešení tohoto úkolu je dosti snadné, zvláště, pokud si nepřečtete pozorně
zadání a opominete zajistit funkčnost algoritmu i pro záporné hodnoty. Jakmile
ale začne student předělávat svůj algoritmus tak, aby dával správné řešení i pro
záporné hodnoty, málokdy dojde k řešení, které jsem vám nabídla. Obvykle ke
správným výsledkům dospěje, ale v programu bývá velmi mnoho zbytečných
rozhodovacích bloků.
Proto jsem zařadila tento dosti podrobný rozbor vcelku jednoduchého
algoritmu.
Řešení v Borland Pascalu:
Program PR1_8;
uses crt;
var
c1,c2,opakovani:integer;
vysl:longint;
Function soucin(cis1,cis2:integer):longint;
var
i:integer;
v:longint;
begin
v:=0;
for i:= 1 to abs(cis1) do v:=v+cis2;
if cis1<0 then v:=-v;
soucin:=v;
end;
begin
repeat
clrscr;
write('zadej 1.cinitele: ');
14
Praktická cvičení algoritmů
readln(c1);
write('zadej 2.cinitele: ');
readln(c2);
vysl:=soucin(c1,c2);
writeln(c1,' * ',c2,' = ',vysl);
writeln;
Write('opakovat cely vypocet ? ');
writeln('1=ano, ostatni cisla = konec programu');
readln(opakovani);
until opakovani <> 1;
end.
Samostatný úkol č.2
Sestavte program, který vypočítá celočíselný podíl a zbytek po celočíselném
dělení dvou celých čísel. Řešte i pro záporné hodnoty dělence a dělitele.
Příklad 1-9
Sestavte funkci pro výpočet ciferného součtu přirozeného čísla. Použijte
v programu, funkci volejte pouze v případě, že číslo je přirozené. Nabídněte
možnost opakování celého výpočtu na základě dotazu.
Rozbor řešení:
Ciferný součet chápeme jako součet jednotlivých cifer zadaného přirozeného
čísla. Např: pro číslo 12345 je ciferný součet 10.
V algoritmu zjistíme zbytek čísla X po dělení 10 (pomocí MOD), který
přičteme do pomocné proměnné, a následně pak číslo X zmenšíme 10 krát
(pomocí DIV). Toto vše vložíme do cyklu, který končí v okamžiku, kdy X je
rovno 0.
Řešení v Borland Pascalu:
Program PR1_9;
uses crt;
var
x:longint;
soucet,opakovani:integer;
Function ciferny_soucet(a:longint):integer;
var
zb,souc:integer;
begin
souc:=0;
repeat
zb:=a mod 10;
souc:=souc+zb;
a:=a div 10;
until a = 0;
ciferny_soucet:=souc;
end;
begin
repeat
clrscr;
repeat
Write('Zadej cislo X >= 0
readln(x);
until x>=0;
15
');
Praktická cvičení algoritmů
soucet:=ciferny_soucet(x);
writeln('ciferny soucet : ',soucet);
writeln;
Write('opakovat cely vypocet ? ');
writeln('1=ano, ostatni cisla = konec programu');
readln(opakovani);
until opakovani <> 1;
end.
Příklad 1-10
Určete počet cifer daného přirozeného čísla X. Pro výpočet sestavte vlastní
funkci, kterou volejte jen v případě, že X je vyhovující hodnoty. Nabídněte
možnost opakování celého výpočtu na základě dotazu.
Rozbor řešení:
Algoritmus využívá pro zjištění počtu cifer pouze číselné proměnné. Celý
postu spočívá v tom, že vstupní hodnota X je postupně v cyklu zmenšována 10
krát (pomocí DIV) až se bude rovnat nule. Počet průchodů cyklem se rovna
počtu cifer.
Průvodce studiem:
Překladač jazyka Borland Pascal nabízí konverzní proceduru STR, která
převede číselnou hodnotu do podoby řetězce. Pak pomocí standardní funkce
length můžete zjistíte délku této řetězcové proměnné a bude mít v podstatě
počet cifer zadaného čísla.
Který způsob v praxi použijete závisí na vašem rozhodnutí.
Řešení v Borland Pascalu:
Program PR1_10;
uses crt;
var
poc,opakovani:integer;
cis:longint;
Function cifry(cislo:longint):integer;
var
p:integer;
begin
p:=0;
repeat
cislo:=cislo div 10;
inc(p);
until cislo = 0;
cifry:=p;
end;
begin
repeat
clrscr;
repeat
Write('Zadej cislo N >= 0
readln(cis);
until cis>=0;
16
');
Praktická cvičení algoritmů
poc:=cifry(cis);
writeln('pocet cifer: ',poc);
writeln;
Write('opakovat cely vypocet ? ');
writeln('1=ano, ostatni cisla = konec programu');
readln(opakovani);
until opakovani <> 1;
end.
Samostatný úkol č3:
Sestavte program, který načte přirozené číslo X, a vypočítá k němu číslo, které
má stejné cifry, ale v opačném pořadí. Použijte pouze číselné hodnoty
(neprovádějte konverzi na řetězec).
1.1.3.
Korespondenční úkol č. 1
Sestavte v programovacím jazyku Borland Pascal jeden ze samostatných úkolů
z této kapitoly.
1.1.4.
Reálná čísla
Pro reálná čísla nabízí překladač Borland Pascalu více datových typů.
TYP
Množina hodnot (rozsah) Velikost paměti v bytech
REAL
2.9 * 10-39 .. 1.7 * 1038
6
-45
38
SINGLE
1.5 * 10 .. 3.4 * 10
4
DOUBLE
5.0 * 10-324 .. 1.7 * 10308
8
-4932
4932
EXTENDED
3.4 * 10
.. 1.1 * 10
10
63
63
COMP
-2 + 1 .. 2 - 1
8
Nejpoužívanější je datový typ REAL. Tento datový typ má přesnost 11 až 12
platných číslic.
Dovolené operace s proměnnými reálného datového typu:
a) aritmetické:
+
… sčítání
… odčítání
*
… násobení
/
… dělení
Nelze použít operace DIV a MOD !!!
b) relační : = <> > >= < <=
Výsledkem těchto operací je logická hodnota TRUE nebo FALSE.
Předdefinované reálné konstanty - není třeba je zavádět v deklarační části
programu.
PI – Ludolfovo číslo, které má hodnotu 3,14
17
Praktická cvičení algoritmů
1.1.5.
Příklady použití reálné proměnné.
Příklad 1-21
Načtěte poloměr R a vypočítejte obvod a obsah kruhu. Ošetřete regulérnost
vstupních dat (výpočet má smysl pro R > 0). Nabídněte možnost opakování
celého výpočtu na základě dotazu.
Řešení v Borland Pascalu:
Program PR1_21;
var
r,opak:integer;
obvod,obsah:real;
begin
repeat
repeat
write('Zadej polomer (R>=0): ');
readln(r);
until r>=0;
obvod:=2*PI*r;
obsah:=PI*sqr(r);
writeln('obvod: ', obvod:0:2,' obsah: ',obsah:0:2);
writeln;
Write('opakovat cely vypocet ? ');
writeln('1=ano, ostatni cisla = konec programu');
readln(opak);
until opak <> 1;
end.
Průvodce studiem:
Algoritmus výpočtu je založen na triviálních matematických vzorcích. Zařadila
jsem jej tady proto, že se již nemůžete vyhnout nutnosti použít reálnou
proměnnou. I když zadáte poloměr jako celé číslo, použitím PI se nutně
dostanete do oboru desetinných čísel.
V souvislosti s reálnou proměnnou narazíte na problém tvaru výpisu čísla na
obrazovku. Reálná čísla se vypisuji ve tvaru 0.50000E+1. Pokud chcete, aby se
reálné číslo vytisklo ve tvaru se zadaným počtem desetinných míst, musíte
vložit do příkazu writeln za název proměnné informaci o počtu míst celkem a o
počtu desetinných míst, např.: obsah:10:2 znamená, že číslo na obrazopvce
zabere celkem 10 míst a z toho budou dvě desetinná.
Příklad 1-22
Sestavte program, který vypočítá kořeny kvadratické rovnice ax2 +bx+c = 0.
Program musí pracovat pro libovolné hodnoty koeficientů a, b,c.
Rozbor řešení:
Vyjdeme z obecného řešení kvadratické rovnice: x1,2 = (-b± √D) /2*a , kde
D = b2 – 4*a*c.
Nejdříve vypočteme hodnotu diskriminantu D. Pokud je tato hodnota záporná,
znamená to komplexně sdružené kořeny kvadratické rovnice.
18
Praktická cvičení algoritmů
Pak se musíme soustředit na eventuality, které mohu nastat při zadávání
vstupních hodnot. Pokud je a = 0, jedná se o lineární rovnici b*x+c=0 a jejím
řešením je kořen: x = -(c/b).
Řešení v Borland Pascalu:
Program PR1_22;
var
a,b,c,diskr:real;
begin
writeln('vypocet korenu kvadraticke rovnice');
writeln('Zadej koeficienty a,b,c:);
Readln(a);
Readln(b);
Readln(c);
diskr:=b*b - 4*a*c;
If diskr<0 then writeln('Rovnice ma komplexni koreny.')
else if a=0 then
begin
write('Rovnice je linearni s korenem');
writeln('x = ',(-c)/b:10:3);
end
else
begin
writeln('Prvni koren=',-b+sqrt(diskr)/2*a:10:3);
writeln('Druhy koren=',-b-sqrt(diskr)/2*a:10:3);
end;
end.
Příklad 1-23
Sestavte program pro výpočet přepony pravoúhlého trojúhelníka. Hodnoty
obou odvěsen načtěte z klávesnice. Zajistěte regulérnost vstupních dat.
Rozbor řešení:
K výpočtu přepony je použita Pythagorova věta. V algoritmu je zajištěna
regulérnost vstupních dat – hodnota odvěsen musí být větší než nula. Teprve
po splnění této podmínky proběhne výpočet.
Řešení v Borland Pascalu:
Program PR1_23;
var
odvesnaA,odvesnaB,prepona:real;
odp:integer;
begin
repeat
repeat
write('zadej 1.odvesnu: ');
readln(odvesnaA);
until odvesnaA>0;
repeat
write('zadej 2.odvesnu: ');
readln(odvesnaB);
until odvesnaB>0;
prepona:=sqrt(sqr(odvesnaA)+sqr(odvesnaB));
writeln('prepona: ',prepona:6:2);
19
Praktická cvičení algoritmů
writeln;
repeat
write('opakovat vypocet ? ');
writeln('1 = Ano, 2 = Ne');
readln(odp);
until (odp=1) or (odp=2);
until odp=2;
end.
Příklad 1-24
Přečtěte hodnotu úhlu ve stupních a napište hodnoty funkcí sinus a kosinus. Po
zobrazení výsledků nabídněte možnost opakování celého výpočtu.
Po naplnění stránky (asi 20 řádků) výpis zastavte a zajistěte, aby se další
stránka vytiskla až po zmáčknutí klávesy ENTER.
Rozbor řešení:
Překladač jazyka Borland Pascal má standardní funkce sin(x) a cos(x). Tyto
funkce pracují s argumenty v radiánech, proto je třeba zadanou hodnotu úhlu
přepočítat (1 stupeň = PI/180 rad.).
Pro zajištění průchodnosti řešení je v programu zařazeno volání procedury,
která provede záměnu dolní a horní hranice intervalu v případě, že dolní
hranice je větší než hranice horní. Záměna se provádí bez dotazu nebo
upozornění uživatele na chybu.
Řešení v Borland Pascalu:
program PR1_24;
uses crt;
var
stup1,stup2,i,k:integer;
rad:real;
procedure zmena(var a,b:integer);
var
pom:integer;
begin
pom:=a;
a:=b;
b:=pom;
end;
function radian (stupne:integer):real;
begin
radian:=stupne*(pi/180);
end;
procedure hlavicka;
begin
writeln(' Stupne
sin(x)
cos(x) ');
writeln('================================');
end;
begin
clrscr;
write('Zadejte prvni hodnotu: ');
readln(stup1);
write('Zadejte druhou hodnotu: ');
20
Praktická cvičení algoritmů
readln(stup2);
if stup1>stup2 then zmena(stup1,stup2);
hlavicka;
k:=0;
for i:= stup1 to stup2 do
begin
k:=k+1;
rad:=radian(i);
writeln('
',i:3,sin(rad):13:5,cos(rad):12:5);
if k=20 then begin
k:=0;
writeln;
writeln('Pro pokr. stiskni cokoli.');
readkey;
if i<>stup2 then begin
clrscr;
hlavicka;
end;
end;
end.
end;
Samostatný úkol č. 4
Doplňte do převodní tabulky další sloupec, ve kterém znázorněte hodnoty
funkce tangens. Pro funkci tangens není v prostředí Borland Pascalu standardní
funkce, proto musíme tangens vypočítat takto: tg(x) = sin(x)/cos(x). Také
musíme dát pozor na to, že funkce tangens není pro některé hodnoty
definována.
Příklad 1-25
Vypočítejte hodnotu Eulerova čísla e pomocí součtu řady:
Výpočet ukončete, až bude rozdíl sousedních členů řady menší než zadaná
hodnota, tzn. že bude platit: 1/n – 1/(n+1) < zadaná hodnota.
Rozbor řešení:
V takto zadaném úkolu neznáme dopředu počet opakování výpočtu, proto
můžeme použít příkaz cyklu s podmínkou na začátku nebo s podmínkou na
konci. Jako výhodnější se zde jeví příkaz cyklu s podmínkou na konci, jako
ukončující podmínka zde slouží porovnání rozdílu
Řešení v Borland Pascalu:
Program PR1_25;
uses crt;
var
n:integer;
e,clen,rozdil:real;
begin
clrscr;
repeat
Write('rozdil sousednich clenu 0=konec
readln(rozdil);
21
');
Praktická cvičení algoritmů
rozdil := abs(rozdil);
If rozdil <> 0 then
begin
e:=0;
n:=1;
clen:=1;
repeat
INC(n);
clen := clen/n;
e:=e + clen;
until (clen - clen/n) < rozdil;
writeln('e = ',e:10:8);
end;
until rozdil = 0;
end.
Průvodce studiem:
Proměnná typu Real je pro programátora důležitá. Pokud ale máte jistotu, že
při výpočtech zůstanete v oboru celých čísel, využijte toho a reálné proměnné
nezavádějte. Použitím celočíselných proměnných bude mít váš program menší
nároky na paměť a také výpočty budou rychlejší.
1.2.
Znaková proměnná
Znaková proměnná dovoluje zařadit do programu práci se znaky. Programátor
pak může například zlepšit komunikaci s uživatelem.
1.2.1.
Znaky.
Do znakové proměnné můžeme uložit libovolný znak z ASCII tabulky. Je
rozdíl mezi malým a velkým písmenem, protože malá a velká písmena jsou
v ASCII tabulce uložena na jiných místech.
Znaková proměnná zabere v operační paměti 1 B. V paměti se ukládá ve
dvojkové soustavě číselná hodnota ASCII kódu. ACSII kód je vzájemně
jednoznačné přiřazení mezi znakem a číslem (pořadí v ASCII tabulce).
Průvodce studiem:
Znakovou konstantu poznáme ve zdrojovém textu podle toho, že je znak
uzavřen mezi apostrofy. Toto lze ale použít pouze pro zobrazitelné znaky.
Pokud budete potřebovat přiřadit nebo vytisknout nezobrazitelný znak, pak
musíte znát jeho pořadí v ASCCI tabulce. Zápis pak provedete tak, že napíšete
symbol # a celé číslo bez znaménka vyjadřujícího pořadí znaku v ASCII
tabulce.
Např.: #7 … zvonek nebo #13 … enter
Stejný význam jako znak # má funkce CHR( ).
#7 a CHR(7) dávají stejný výsledek (zvonek).
22
Praktická cvičení algoritmů
Můžeme použít pouze relační operace:
=
… rovná se
<> … nerovná se
>
… větší než
>= … větší nebo rovno
<
… menší než
<= … menší nebo rovno
Standardní funkce
ORD(x) … funkce, která vrací číslo (pořadí) znaku v ASCII tabulce, tj. číslo
z intervalu 0 ..255.
CHR(c) … funkce, která vrací znak, který odpovídá danému číslu v ASCII
tabulce
PRED(x) … funkce, která vrací znak, který v ASCII tabulce má pořadové
číslo o 1 menší než znak uvedený jako argument funkce
SUCC(x) … funkce, která vrací znak, který v ASCII tabulce má pořadové
číslo o 1 větší než znak uvedený jako argument funkce
UPCASE(x) ..funkce, která převádí malé písmeno na velké. Pokud je
argumentem funkce jiný znak než malé písmeno, zůstává argument beze
změny.
1.2.2.
Příklady použití znakové proměnné
Příklad 1-31
Sestavte program, pro výpis části tabulky ASCII kódů. Zadávejte počáteční a
koncovou hodnotu ASCII kódu (vstup omezte na interval 32..255). Po naplnění
obrazovky, výpis zastavte.
Výstup upravte do tabulky takto: ASCII znak
Rozbor řešení:
Hodnoty ASCCI kódu se pohybují v intervalu 0..255. Pro každé číslo z tohoto
intervalu můžeme pomocí standardní funkce CHR(x) získat odpovídající znak.
Omezení dolní hranice intervalu na větší nebo rovno 32 je proto, že znaky
s číslem nižším než 32 jsou nezobrazitelné.
Řešení v Borland Pascalu:
Program PR1_31;
uses crt;
Var
poc,kon,i,radek:integer;
procedure zamena(var a,b:integer);
var
pom:integer;
begin
pom:=a;
a:=b;
b:=pom;
end;
23
Praktická cvičení algoritmů
begin
clrscr;
repeat
write('Zadej poc.hodnotu .. cislo z <32,255>: ');
readln(poc);
until (poc>=32) and (poc<=255);
repeat
write('Zadej konc.hodnotu..cislo z <32,255>: ');
readln(kon);
until (kon>=32) and (kon<=255);
zamena(poc,kon);
clrscr;
writeln('
ASCII
znak');
writeln('
---------------');
radek:=0;
for i:=poc to kon do
begin
writeln( i:8,'
',chr(i));
radek:=radek+1;
if radek = 20 then
begin
write('zmackni ENTER: ');
readln;
clrscr;
radek:=0;
writeln('
ASCII
znak');
writeln('
---------------');
end;
end;
write('zmackni ENTER: ');
readln;
end.
Příklad 1-32
Sestavte program, který načítá z klávesnice znaky. Pokud bude znak malé
písmeno, převede jej na písmeno velké pomocí standardní funkce UpCase.
Pokud bude znakem velké písmeno, převede jej pomocí vlastní funkce DnCase.
Ostatní znaky zůstanou nezměněny.
Znaky načítejte opakovaně, program ukončete po zadání znaku *.
Rozbor řešení:
Funkce pro převod velkého písmena na malé je založena na tom, že rozdíl
ASCII hodnoty malého a velkého písmena je stejný pro všechna písmena
abecedy. Ve funkci je tento rozdíl uložen do konstanty. Pokud je pak
argumentem funkce velké písmeno, dojde k přičtení zjištěného rozdílu k jeho
ASCII hodnotě a pak následuje zjištění znaku, který odpovídá vypočtené
číselné hodnotě.
Řešení v Borland Pascalu:
Program PR1_32;
uses crt;
var
znak:char;
24
Praktická cvičení algoritmů
Function DownCase(z:char):char;
const
posun = ord('a') - ord('A');
begin
if (z>='A')and(z<='Z') then z:=chr(ord(z)+posun) ;
DownCase:=z;
end;
begin
clrscr;
znak:=' ';
while znak <> '*' do
begin
write('Zadej znak, * = ukonceni programu: ');
readln(znak);
if (znak>='A') and (znak <='Z') then
znak:=DownCase(znak)
else if (znak>='a') and (znak <='z') then
znak:=UpCase(znak);
writeln('znak po konverzi: ',znak);
end;
end.
Příklad 1-33
Sestavte program, který bude číst větu jako posloupnost písmen a mezer
ukončenou tečkou. Zjistěte, kolik má věta písmen.
Rozbor řešení:
V zadání je uveden požadavek na načítání věty jako posloupnosti písmen.
Samozřejmě celou větu chceme zadat na jednom řádku, a proto je nutné pro
načítání jednotlivých znaků použít proceduru READ (ne READLN). Po
skončení cyklu ale musíme zařadit jednou proceduru READLN bez parametrů,
protože potřebujeme „načíst“ klávesu ENTER, která zadávání věty ukončuje.
Řešení v Borland Pascalu:
Program PR1_33;
uses crt;
var
znak:char;
pocet:integer;
begin
writeln('Zadej vetu ukoncenou teckou !');
repeat
read(znak);
if (znak <> ' ' ) and (znak <> '.')
then INC(pocet);
until znak = '.';
readln;
writeln('veta ma :',pocet,' pismen');
writeln;
writeln('zmackni ENTER');
readln;
end.
25
Praktická cvičení algoritmů
Průvodce studiem:
Načítání věty znak po znaku budete zařazovat, jen když se vám to bude pro
řešení algoritmu zdát výhodné. Programovací jazyk Borland Pascal totiž
umožňuje pracovat s proměnnou typu STRING a pak je možné provést načtení
věty jedním příkazem READLN. Je to rychlejší a pohodlnější. Podrobnější
informace a příklady pro práci s proměnnou typu STRING jsou v kapitole
2.1. Řetězec znaků.
Příklad 1-34
Sestavte program, který bude číst větu jako posloupnost písmen a mezer
ukončenou tečkou. Zkontrolujte, zda po písmenech h,k,r není písmeno i nebo í.
Rozbor řešení:
Větu zde načítáme opět znak po znaku pomocí příkazu READ a v pomocné
logické proměnné si pamatujeme, zda došlo k definované chybě. Pokud
chceme v řešení uvažovat malá i velká písmena a také krátká i dlouhá písmena,
tak podmínka zjišťující výskyt písmene je dosti dlouhá. Jako elegantní řešení
se tady nabízí použití množinového operátoru IN, který znamená „je prvkem“.
Relace pak má hodnotu TRUE, pokud proměnná na levé straně výrazu nabude
hodnoty uvedené v hranatých závorkách.
Řešení v Borland Pascalu:
Program PR1_34;
uses crt;
var
znak:char;
chyba:boolean;
begin
chyba := false;
writeln('Zadej vetu ukoncenou teckou !');
repeat
read(znak);
if znak IN ['h','H','k','K','r','R'] then
begin
read(znak);
if znak IN ['i','I',í,Í] then chyba := true;
end;
until znak = '.';
readln;
if chyba then writeln('chyba-vyskyt i po h,k,r')
else writeln('Bez chyby !');
writeln;
writeln('zmackni ENTER');
readln;
end.
26
Praktická cvičení algoritmů
Průvodce studiem:
Zařadila jsem opět načtení věty znak po znaku, protože práci s proměnnou
STRING ještě nemusíte umět, informace získáte až v kapitole 2.1. Řetězec
znaků. Velmi pohodlné a přehledné je použití množinového operátoru IN, který
můžete použít i bez jakýchkoliv dalších znalosti datového typu množina.
Příklad 1-35
Nalezněte maximální hodnotu mezi N zadanými čísly. Využijte příkaz cyklu
s podmínkou na začátku. Nabídněte možnost opakování celého výpočtu na
základě dotazu (v nabídce využijte datový typ CHAR).
Rozbor řešení:
Abychom mohli mezi N čísly najít číslo největší, musíme zavést pomocnou
proměnnou, ve které budeme uchovávat tzv. okamžité maximum – hodnota,
která byla dosud největší. Každou další hodnotu porovnáme s tímto okamžitým
maximem a pokud je nová hodnota větší, než hodnota v pomocné proměnné,
tak obsah pomocné proměnné přepíšeme touto hodnotou.
V předloženém řešení je jako počáteční hodnota použita předdefinovaná
konstanta Maxint se záporným znaménkem, což je nejmenší hodnota dovolena
pro datový typ INTEGER, a tudíž všechny prohledávané hodnoty by pak měly
být větší než je počáteční hodnota pomocné proměnné.
Nabídka opakování je řešena pomocí příkazu cyklu s podmínkou na konci, kdy
uživatel programu musí zadat konkrétní písmena pro opakování nebo konec. Je
zajištěna stejná reakce programu při zadání malých a velkých písmen.
Řešení v Borland Pascalu:
Program PR1_35;
uses crt;
var
a,max,p,n:integer;
odp:char;
begin
clrscr;
max:=-maxint; {maxint je preddefinovana konstanta,
ktera ma nejvetsi hodnotu dovolenou
pro dat. typ integer}
repeat
p:=1;
write('zadej pocet cisel: ');
readln(n);
while p<=n do
begin
write('zadej ',p,'. cele cislo: ');
readln(a);
p:=p+1;
if a>max then max:=a;
end;
writeln('maximalni hodnota: ',max);
writeln;
27
Praktická cvičení algoritmů
Write('opakovat cely vypocet ? ');
repeat
writeln(' A=ano, N = konec programu');
readln(odp);
until odp IN ['a','A','n','N'];
until (odp = 'n') or (odp = 'N');
end.
Průvodce studiem:
Algoritmus vyhledání extrémní hodnoty je velmi častým algoritmem. Věnujte
mu tedy dostatečnou pozornost. Setkáte se s tímto algoritmem i v dalších
úkolech. Vyhledání extrémní hodnoty je součástí některých řadících algoritmů.
Samostatný úkol č.5
Upravte program PR1_24 tak, aby došlo k vyhledání minimální hodnota a
zároveň ke zjištění, kolikrát se tato minimální hodnota mezi zadanými čísly
vyskytla.
1.3.
Logická proměnná
Logická proměnná dovoluje pracovat v programování s logickou hodnotou.
Logická proměnná je sice dobře nahraditelná celočíselnou proměnnou, ale
v mnoha případech použití této proměnné zajistí větší přehlednost zdrojového
textu a také sníží nároky na paměť.
1.3.1.
Logické konstanty
V Borland Pascalu jsou zavedeny logické konstanty s názvy true a false.
false - nepravda, logická 0
True - pravda, logická 1
Množina operací:
a) relační operace
=
… rovná se
<> … nerovná se
>
… větší než
>= … větší nebo rovno
<
… menší než
<= … menší nebo rovno
b) logické operace
NOT … logická negace
AND … logický součin
OR … logický součet
XOR … neekvivalence (exkluzivní součet)
28
Praktická cvičení algoritmů
Pravdivostní tabulka
R
S
FALSE
FALSE
FALSE
TRUE
TRUE
FALSE
TRUE
TRUE
1.3.2.
NOT R
TRUE
TRUE
FALSE
FALSE
R AND S R OR S
FALSE
FALSE
FALSE
TRUE
FALSE
TRUE
TRUE
TRUE
R XOR S
FALSE
TRUE
TRUE
FALSE
Příklady použití logické proměnné
Příklad 1-41
Napište program pro opakovaný výpočet druhé mocniny reálného čísla. Pro
opakování výpočtu použijte cyklus s podmínkou na začátku a logickou
proměnnou KONEC.
Rozbor řešení:
Algoritmus je velmi jednoduchý, je zařazen jako ukázka použití datového typu
boolean v podmínkách podmíněných příkazů a cyklů.
Řešení v Borland Pascalu:
Program PR1_41;
uses
CRT;
var
cislo:real;
konec:boolean;
begin
clrscr;
konec:=false;
while not(konec) do
begin
write('zadej cislo: ');
readln(cislo);
writeln('druha mocnina: ',sqr(cislo):10:2);
write('0 = konec, jine cislo = pokracovat: ');
readln(cislo);
konec:=cislo = 0;
end;
end.
Průvodce studiem:
Chtěla bych vás upozornit na příkaz konec:=cislo = 0; , který využívá možnosti
přiřazení výsledku logického výrazu do proměnné. Tento příkaz má stejný
význam, jako byste napsali:
if cislo = 0 then konec := TRUE else konec :=FALSE;
29
Praktická cvičení algoritmů
Příklad 1-42
Vytvořte program pro vyhodnocování logických operací NOT, AND a OR.
Zadejte druh operace a hodnotu jedné nebo dvou proměnných. Nabídněte
možnost opakování celého výpočtu.
Rozbor řešení:
Hodnotu do logické proměnné nemůžeme načíst příkazem READLN, proto
použijeme pomocnou číselnou proměnnou arg_cis, jejíž obsah při načítání
omezíme na 0 a 1. Podle obsahu této proměnné pak přiřadíme logickým
proměnných hodnotu TRUE nebo FALSE.
Řešení v Borland Pascalu:
Program PR1_42;
uses crt;
var
funkce,arg_cis,odp:integer;
arg_1,arg_2,vysledek:boolean;
begin
repeat
clrscr;
writeln(' OR ...0');
writeln(' AND...1');
writeln(' NOT...2');
write('vyber logickou funkci:');
repeat
readln(funkce);
until funkce IN [0,1,2];
write('zadej argument ');
write('0 = False
1 = True
: ');
repeat
readln(arg_cis);
until arg_cis IN [0,1];
arg_1 := arg_cis = 1;
If not(funkce = 2) then
begin
write('zadej druhy argument ');
write('0 = False
1 = True: ');
repeat
readln(arg_cis);
until arg_cis IN [0,1];
arg_2 := arg_cis = 1;
end;
case funkce of
0: vysledek := arg_1 or arg_2;
1: vysledek := arg_1 and arg_2;
2: vysledek := not arg_1;
end;
writeln('vysledek: ',ord(vysledek));
writeln;
Write('opakovat cely vypocet ? ');
writeln('1=ano, ostatni cisla = konec programu');
readln(odp);
until odp <> 1;
end.
30
Praktická cvičení algoritmů
Příklad 1-43
Napište program pro generování tabulky log. funkcí NOR, NAND a XOR
dvou logických proměnných.
Rozbor řešení:
Tento program nebude po uživateli požadovat žádná vstupní data, výsledkem
programu je pravdivostní tabulka požadovaných logických funkcí. Pro logické
funkce NOR a NAND není v Borland Pascalu standardní operátor, proto je
tedy musíme vyjádřit pomocí operátorů NOT, AND a OR. Pro operaci XOR je
sice standardní operátor, ale z cvičných důvodů vyjádříme neekvivalenci jako
kombinaci logického součtu, logického součinu a negace.
Řešení v Borland Pascalu:
Program PR1_43;
uses crt;
var
a_log,b_log,nor,nand,_xor:boolean;
begin
clrscr;
writeln;
writeln('
A
B
NOR
NAND
XOR');
writeln(' ---------------------------------');
for a_log:=false to true do
for b_log:=false to true do
begin
nor:=not(a_log or b_log);
nand:=not(a_log and b_log);
_xor:=(a_log and not b_log)or(not a_log and b_log);
writeln(a_log:7,b_log:7,nor:7,nand:7,_xor:7);
end;
writeln;
writeln('zmackni ENTER');
readln;
end.
Průvodce studiem:
Tady bych vás chtěla upozornit na využití logické proměnné jako řídící
proměnné cyklu FOR. Datový typ boolean patří mezi ordinální datové typy a
proto je možné logickou proměnou takto použít.
Příklad 1-44
Sestavte program, který po zadání souřadnic bodu v rovině, rozhodne, zda bod
leží uvnitř, vně nebo na obvodu kruhu o poloměru R se středem v bodě [0,0].
Nabídněte možnost opakování celého výpočtu.
Rozbor řešení:
Při řešení vyjdeme z rovnice kruhu: x2+y2 = r2 .
Pro body uvnitř platí nerovnost: x2+y2 < r2
Pro body vně platí nerovnost : x2+y2 > r2
31
Praktická cvičení algoritmů
Řešení v Borland Pascalu:
Program PR1_44;
uses crt;
const
R=10.0;
var
uvnitr,vne:boolean;
x,y:real;
odp:byte;
begin
repeat
clrscr;
writeln('!!! zadej souradnice bodu !!!');
write('zadej souradnici x: ');
readln(x);
write('zadej souradnici y: ');
readln(y);
uvnitr:=sqr(x)+sqr(y)<sqr(R);
vne
:=sqr(x)+sqr(y)>sqr(R);
write('bod lezi ');
if vne then write('vne ')
else if uvnitr then write('uvnitr ')
else write('na obvodu ');
writeln('kruhu');
writeln;
Write('opakovat cely vypocet ? ');
writeln('1=ano, ostatni cisla = konec programu');
readln(odp);
until odp <> 1;
end.
Průvodce studiem:
Pokud znáte rovnici kružnice, tak je algoritmus velmi dobře řešitelný. Chtěla
jsem vás upozornit na to, jak ovlivní přehlednost zdrojového textu využití
přiřazení výsledku logického výrazů do logických proměnných. Následně jsou
pak tyto logické proměnné použity v rozhodovacím příkazu. Určitou
zajímavostí pro vás může být to, že nemusíte v podmínce příkazu IF psát
porovnání logické proměnné s logickou hodnotou TRUE. Úplně stejný význam
má zapis: if vne then …. jako zápis If vne = TRUE then …
Také si všimněte, že použití vnořeného větvení vás nenutí vyjádřit třetí
podmínku, a sice podmínku kdy bod leží na kružnici.
Příklad 1-45
Sestavte program, který vypíše všechna prvočísla do zadané hranice. Pro
zjištění, zda se jedná o prvočíslo, sestavte logickou funkci, která bude vracet
TRUE v případě, že její argument je číslo. Nabídněte možnost opakování
celého výpočtu.
Rozbor řešení:
Prvočísla jsou čísla, která jsou dělitelná pouze sama sebou. Pro zadané číslo K
K tedy postupně testujeme, zda je dělitelné 2,3,…až po hodnotu K div 2.
Pokud taková dělitelnost nenastane, pak je číslo K prvočíslem.
32
Praktická cvičení algoritmů
Řešení v Borland Pascalu:
Program PR1_45;
uses crt;
var
n,i,odp:integer;
function prvocislo(k:integer):boolean;
var
i:integer;
neni:boolean;
begin
if k<=2 then prvocislo := true
else
begin
neni:=false;
i:=2;
repeat
neni:=k mod i =0;
inc(i);
until neni or (i>(k div 2));
prvocislo := not neni;
end;
end;
begin
repeat
clrscr;
writeln('program generuje prvocisla ');
write('zadej horni mez intervalu: ');
readln(n);
for i:= 2 to n do
if prvocislo(i) then writeln(i);
Write('opakovat cely vypocet ? ');
writeln('1=ano, ostatni cisla = konec programu');
readln(odp);
until odp <> 1;
end.
1.3.3.
Korespondenční úkol č.2
Zadání:
Upravte program PR1_45 tak, aby se vypisovaly všechny dvojice prvočísel do
zadané hranice, jejichž hodnoty se od sebe liší co nejméně, tedy o hodnotu 2.
Kontrolní otázky:
1. Které datové typy jsou dovoleny pro proměnnou, do které chcete uložit celé
číslo ?
2. Které datové typy jsou dovoleny pro proměnnou, do které chcete uložit
reálné číslo ?
3. Které aritmetické operace jsou dovoleny pro celočíselné proměnné ?
4. Které aritmetické operace jsou dovoleny pro celočíselné proměnné ?
33
Praktická cvičení algoritmů
5.
6.
7.
8.
Co znamená operátor DIV ?
Co znamená operátor MOD ?
Co jdou to relační operace a co je jejich výsledkem ?
Který datový typ je určen pro deklaraci proměnné, do které chcete uložit
znak ?
9. Které operace můžete provést s proměnnou typu CHAR ?
10. Kolik místa zabírá proměnná typu CHAR v paměti počítače?
11. Který datový typ je určen pro deklaraci proměnné, do které chcete uložit
logickou hodnotu ?
12. Lze do logické proměnné načíst hodnotu ?
13. Lze obsah logické proměnné tisknout ?
14. Které operace lze provádět s logickou proměnnou ?
15. Co znamená přiřazení výsledku logického výrazu do logické proměnné ?
2.
Statické datové struktury
Cíl:
Po prostudování této kapitoly budete umět:
- pracovat s řetězcem znaků
- využít v programech možnosti uložení dat ve formě jednorozměrného a
dvourozměrného pole
- použít proměnnou typu záznam pro uložení a následné zpracování dat
- zařadit do zpracování proměnnou typu množina
Klíčová slova:
Datová struktura, řetězec znaků, pole, záznam, pole záznamů, homogenní a
heterogenní datový typ, strukturovaný datový typ, množina hodnot, indexovaná
proměnná, tečková konvence.
2.1.
Řetězec znaků
Proměnná typu STRING je určena pro práci s řetězcem znaků, tzn. že je možné
do takto definované proměnné uložit i více než jeden znak (slovo, větu).
Proměnná tohoto typu se zavede v deklarační částí programu v úseku Var
pomocí klíčového slova STRING.
2 způsoby deklarace proměnné typu STRING:
• a:STRING[30]; … do proměnné a se uloží pouze 30 znaků, ostatní
budou ignorovány (proměnná v paměti zabere 31 B)
•
a: STRING;
… do proměnné a je možno uložit až 255 znaků
proměnná v paměti zabere 256 B
34
Praktická cvičení algoritmů
BORLAND PASCAL přidává k proměnné typu STRING na počátek řetězce
interně 1 byte, který obsahuje skutečnou délku řetězce. Tato délka je
indexována jako nultý byte . Skutečná délka řetězce je uložena ve formě znaku,
pro převod do číselné podoby použijeme standardní funkce ORD( ).
Délku řetězce lze také zjistit pomocí standardní funkce LENGTH( ).
Máme deklaraci … Retez:STRING;
Pak platí: ORD( Retez[0] ) = LENGTH(Retez)
Retez[0] slouží k uložení aktuální délky řetězce Retez, délka je uložena ve
formě znaku.
Proměnná typu STRING patří mezi strukturované proměnné, a proto je možno
pracovat:
• s jednotlivými byty (znaky). Pokud pracujeme s jednotlivými znaky,
přistupujeme ke znakům pomocí hranatých závorek.
• jako s celkem- existuje mnoho podprogramů pro práci s proměnnou typu
string
Příklad 2-1
Načtěte z klávesnice větu
- pokud začíná věta malým písmenem, tak jej převeďte na velké a pokud na
konci chybí tečka, tak ji vložte. Větu vytiskněte.
- převeďte všechna písmena na velká a větu opět vytiskněte, každé písmeno
na samostatný řádek.
- Proveďte obrácení pořadí písmen ve větě, větu vytiskněte.
Rozbor řešení:
Větu načteme do proměnné STRING jedním příkazem. Dále pak k této
proměnné přistupujeme znak po znaku pomocí příkazu cyklu s řídící
proměnnou a pomocí indexu v hranatých závorkách. Obrácení řetězce
provedeme tak, že postupně zaměňujeme první a poslední znak, pak druhý a
předposlední znak, atd. Tady je důležité zastavit cyklus s řídící proměnnou při
hodnotě řídící proměnné I = length(veta) div 2 (tedy v polovině řetězce).
Kdybychom nechali cyklus proběhnout až do hodnoty I=length(veta), řetězec
by nebyl obrácen !!!
Řešení v Borland Pascalu:
Program PR2_1;
uses crt;
Var
i,delka:byte;
veta:string;
pom:char;
begin
clrscr;
write('Napis vetu:');
readln(veta);
veta[1]:=upcase(veta[1]);
delka:=length(veta);
if veta[delka] <> '.' then begin
veta[delka+1]:= '.';
veta[0]:=chr(delka+1);
35
Praktická cvičení algoritmů
end;
writeln(veta);
writeln;
for i:=1 to length(veta) do
begin
veta[i]:=upcase(veta[I]);
writeln(veta[I]);
end;
for i:=1 to length(veta) div 2 do
begin
pom:=veta[i];
veta[i]:=veta[length(veta)+1-i];
veta[length(veta)+1-i]:=pom;
end;
writeln(veta);
writeln;
write('zmackni ENTER: ');
readln;
end.
Průvodce studiem:
Ke každému řetězci se po jeho načtení přidává tzv. nultý byte, ve kterém je
uložena aktuální délka řetězce. Pokud jste v programu k řetězci přidali další
znaky pomocí operátoru +, např. ve výše uvedeném algoritmu jste přidali na
konec tečku, je třeba opravit nultý byte. V programu se jedná o příkaz
veta[0]:=chr(delka+1).
Pokud neuděláte, nebudou nové znaky při zpracování brány v úvahu.
Příklad 2-2
Sestavte program, který přečte větu a zajistí, aby mezi slovy byla pouze jedna
mezera.
Rozbor řešení:
Řetězcovou proměnnou načteme jako celek, ale pak k ní přistupujeme znak po
znaku. Upravená věta je na vytvořena v pomocné proměnné veta2.
Řešení v Borland Pascalu:
Program PR2_2;
uses crt;
var
veta1,veta2:string;
i,j,opak:integer;
begin
repeat
clrscr;
write('zadej vetu: ');
readln(veta1);
veta2:=' ';
I:=1;
j:=1;
while i <= length(veta1) do
begin
veta2[j]:=veta1[i];
if veta1[i]=' ' then while veta1[i+1]=' ' do inc(i);
36
Praktická cvičení algoritmů
inc(i);
inc(j);
end;
veta2[0]:=chr(j);
writeln(veta2);
readln;
writeln;
write('opakovat cely vypocet ? ');
writeln('1=ano, ostatni cisla = konec programu');
readln(opak);
until opak <> 1;
end.
Příklad 2-3
Sestavte program, který načte z klávesnice řetězec znaků o maximální délce 30
znaků. Vyberte z řetězce malá a velká písmena a uložte jej do proměnné
Pismena, ostatní znaky uložte do proměnné Ostatní. Mezery vynechejte. Obě
proměnné vytiskněte.
Rozbor řešení:
Pro zjednodušení podmínky, která zjišťuje, zda znak je malé nebo velké
písmeno, je použita standardní funkce Upsace.
Řešení v Borland Pascalu:
Program PR2_3;
uses crt;
Var
i:integer;
v,pismena,ostatni:string[30];
begin
clrscr;
write('Napis vetu:');
readln(v);
for I:=1 to length(v) do
if ((upcase(v[I]))>='A')and(upcase(v[I])<='Z') then
pismena:=pismena+v[i]
else if v[I] <> ' ' then ostatni:=ostatni+v[I];
writeln;
writeln('zadana veta
: ',v);
writeln('pismena
: ',pismena);
writeln('ostatni znaky : ',ostatni);
writeln;
write('zmackni ENTER: ');
readln;
end.
Příklad 2-4
Z klávesnice načtěte do jedné proměnné jméno a příjmení v nezkrácené podobě
(např. JAN NOVAK). Výsledkem práce programu bude:
• zkratka jména s plným příjmením (J. NOVAK)
• zkratka jména a zkratka příjmení (J. N.)
• příjmení a jméno v nezkrácené podobě (NOVAK JAN)
Využijte standardní procedury a funkce pro práci s řetězcem jako s celkem
(např. DELETE, INSERT,POS ...).
37
Praktická cvičení algoritmů
Rozbor řešení:
Při řešení tohoto úkolu jsou využity standardní procedury a funkce, které
pracuji s řetězcem jako s celkem. Přesný význam jednotlivých podprogramů je
uveden v nápovědě Borland Pascalu.
Řešení v Borland Pascalu:
program PR2_4;
uses crt;
var jmeno,jm1,jm2,jm3:string[30];
i,del:integer;
k:char;
begin
repeat
clrscr;
repeat
write('Zadejte jmeno : ');
readln(jmeno);
i:=pos(' ',jmeno);
if i=0 then writeln('Jmeno musi obsahovat mezeru.')
until i<>0;
jm1:=jmeno;
delete(jm1,2,(i-1));
insert('.',jm1,2);
writeln(jm1);
del:=length(jm1);
delete(jm1,4,(del));
insert('.',jm1,4);
writeln(jm1);
jm2:=copy(jmeno,1,(i));
delete(jmeno,1,(i));
del:=length(jmeno);
insert(jm2,jmeno,(del+1));
insert(' ',jmeno,(del+1));
writeln(jmeno);
write('Chcete opakovat(A-opakovat, ostatni-ne)');
readln(k);
until Upcase(k) <> 'A';
writeln;
writeln('Konec programu. Stiskni ENTER.');
readln;
end.
Příklad 2-5
Sestavte program, který načte datum ve tvaru DD-MMM-RR, kde MMM je
zkratka anglického názvu měsíce, např. 01-AUG-03, a toto datum převede do
tvaru: 1.8.2003.
Rozbor řešení:
Při řešení je zde využita konstanta, která je tvořena řetězcem znaků. V řetězci
jsou za sebou uložena postupně vždy tři písmena, která jsou zkratkou
anglického názvu měsíců.
38
Praktická cvičení algoritmů
Řešení v Borland Pascalu:
Program PR2_5;
uses
crt;
const
mesice = 'JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC';
Var
angl_datum:string[10];
den,mesic:String[2];
rok:string[4];
datum:string[10];
mes,i,opak:integer;
pom:String[3];
begin
repeat
clrscr;
writeln('zadej datum ve tvaru dd-mmm-rr, kde mmm je
anglicka zkratka mesice');
readln(angl_datum);
for I:=1 to length(angl_datum) do
angl_datum[I]:=upcase(angl_datum[I]);
den:=copy(angl_datum,1,2);
if den[1] = '0' then delete(den,1,1);
rok:=copy(angl_datum,8,2);
rok:= concat('20',rok);
pom:=copy(angl_datum,4,3);
mes:=pos(pom,mesice);
mes:=(mes+2) div 3;
str(mes:2,mesic);
datum:=den+'.'+mesic+'.'+rok;
writeln;
writeln(datum);
writeln;
Write('opakovat cely vypocet ? ');
writeln('1=ano, ostatni cisla = konec programu');
readln(opak);
until opak <> 1;
end.
Samostatný úkol č. 6
Vytvořte program pro jednoduchou hru, kdy jeden z hráčů zadá jméno českého
města a druhý podle počátečního písmene a délky názvu hádá. K dispozici má
5 pokusů, pak se jméno objeví na obrazovce.
2.2.
Pole
Nejznámějším představitelem datové struktury je pole údajů. Je to datová
struktura, která má předem pevně stanovený počet prvků, proto také říkáme, že
je to statická datová struktura. Položky se vzájemně rozlišují pomocí indexu.
V operační paměti tato struktura zabírá souvislý úsek.
Datový typ pole je homogenní datový typ, což znamená, že všechny jeho prvky
jsou stejného datového typu.
39
Praktická cvičení algoritmů
Pole je strukturovaný datový typ a proto platí, že s proměnnou můžeme
pracovat jako s celkem nebo s jejími jednotlivými komponentami.
a) práce s polem jako s celkem
Lze provést pouze operaci přiřazení. Přiřazení lze provést, pokud jsou obě pole
totožného typu. Platí stejná pravidla jako u jednorozměrného pole.
b) práce s jednotlivými prvky pole
můžeme provádět takové operace, které jsou dovoleny pro datový typ, který
jsme pro prvky pole nadeklarovali
2.2.1.
Jednorozměrné pole
Při deklaraci proměnné typu pole se určuje jeho název, rozměr a datový typ
prvků pole. Rozměr pole určuje počet prvků, které se do pole mohou vložit.
Velikost pole je vždy omezena paměťovými nároky.
Jednorozměrné pole odpovídá matematickému objektu vektor.
Příklad 2-21
Pole o N prvcích naplňte náhodnými čísly z intervalu <1,10>, prvky pole
vytiskněte. Hodnotu N zadávejte z klávesnice. Sestavte funkci, která vypočítá
aritmetický průměr prvků pole. Vytvořte také vlastní procedury pro naplnění
pole a pro vytištění pole – obě budou mít jako formální parametr pole.
Rozbor řešení:
Pokud chceme používat v programu podprogramy s formálními parametry typu
pole, je nutné deklarovat vlastní datové typy v úseku TYPE a ty pak používat
pro deklaraci globálních, lokálních proměnných a formálních parametrů.
Dosáhneme tím kompatibility datových typů.
Ve zdrojovém textu jsou vloženy procedury pro naplnění pole a pro vytištění
pole, a funkce pro výpočet aritmetického průměru všech prvků pole.
Aritmetický průměr dostaneme jako součet všech prvků dělený počtem prvků.
Protože počítáme přesný podíl, dostaneme se do oboru reálných čísel, a proto
musí být návratový typ funkce REAL.
Řešení v Borland Pascalu:
program PR2_21;
{aritmeticky prumer}
uses crt;
type
tpole = array[1..100] of integer;
var
i,n:integer;
pole:Tpole;
40
Praktická cvičení algoritmů
Procedure Napln(var A:Tpole;n:integer);
var
I:integer;
begin
randomize;
for I:=1 to n do A[I]:=random(10)+1;
end;
Procedure Tiskni(A:Tpole;n:integer);
var
I:integer;
begin
for I:=1 to n do write(A[I]:3);
writeln;
end;
Function prumer(a:Tpole;n:Integer):real;
var
I:integer;
v:real;
begin
v:=0;
for i:= 1 to n do v:=v+a[i];
prumer:=v/n;
end;
begin
clrscr;
write('zadej pocet prvku pole: ');
readln(n);
Napln(pole,n);
Tiskni(pole,n);
writeln;
writeln('prumerna hodnota : ',prumer(pole,n):0:2);
writeln;
writeln('zmackni enter');
readln;
end.
Příklad 2-22
Sestavte program, který pole A o 20 prvcích naplní náhodnými čísly z intervalu
<1,20>, pole vytiskněte. Pak do pole SUDA přepište čísla sudá a do pole
LICHA přepište čísla lichá. Obě pole vytiskněte.
Rozbor řešení:
Protože ještě neumíme deklarovat rozměr pole až v průběhu výpočtu, musí mít
všechna pole – vstupní pole, pole pro čísla sudá i pole pro čísla lichá – stejný
rozměr. Aby byla pole pro čísla sudá a pro čísla lichá zaplňována správně,
zavedeme si samostatný index pro každé pole.
Řešení v Borland Pascalu:
program PR2_22;
{prepis do pole SUDA a LICHA}
uses crt;
const
N = 20;
type
Tpole = array [1..n] of integer;
41
Praktická cvičení algoritmů
var
i,j,k:integer;
a,suda,licha:Tpole;
Procedure Napln(var A:Tpole;n:integer);
var
I:integer;
begin
randomize;
for I:=1 to N do A[I]:=random(10)+1;
end;
Procedure Tiskni(A:Tpole;n:integer);
var
I:integer;
begin
for I:=1 to N do write(A[I]:3);
writeln;
end;
begin
clrscr;
Napln(a,n);
Tiskni(a,n);
writeln;
j:=0;
k:=0;
for i:= 1 to N do
if a[i] mod 2 = 0 then begin
j:=j+1;
suda[j]:=a[i];
end
else begin
k:=k+1;
licha[k]:=a[i];
end;
write('suda cisla : ');
tiskni(suda,j);
writeln;
write('licha cisla: ');
tiskni(licha,k);
writeln;
writeln;
write('zmackni ENTER');
readln;
end.
Příklad 2-23
Pole o N prvcích naplňte náhodnými čísly z intervalu <1,100>, prvky pole
vytiskněte. Napište proceduru, která z daného pole vybere minimální a
maximální hodnotu. Obě tyto hodnoty procedura vrátí jako výsledek.
Rozbor řešení:
Algoritmus vyhledání extrémní hodnoty je popsán v programu PR1_35. Postup
je stejný, rozdíl je pouze v uložení hodnot v paměti.
42
Praktická cvičení algoritmů
Řešení v Borland Pascalu:
program PR2_23;
{maximalni a minimalni hodnota v poli}
uses crt;
const
N = 20;
type
tpole = array[1..n] of integer;
var
i,mx,mn,poc:integer;
pole:Tpole;
procedure nacti(var a:Tpole;n:integer);
var
i:integer;
begin
randomize;
for i:= 1 to N do a[i]:=random(100)+1;
end;
procedure vytiskni(a:Tpole;n:integer);
var
i:integer;
begin
for i:= 1 to N do write(a[i],' ');
writeln;
end;
procedure max_min(a:Tpole; n:integer; var max,min:integer);
var
i:integer;
begin
max:= a[1];
min:= a[1];
for i:= 2 to N do
begin
if a[i] > max then max:=a[i];
if a[i] < min then min:=a[i];
end;
end;
begin
clrscr;
Write('zadej pocet prvku pole: ');
readln(poc);
nacti(pole,poc);
vytiskni(pole,poc);
max_min(pole,poc,mx,mn);
writeln('maximalni hodnota v poli: ',mx);
writeln('minimalni hodnota v poli: ',mn);
writeln;
writeln('zmackni enter');
readln;
end.
43
Praktická cvičení algoritmů
Průvodce studiem:
Algoritmus vyhledání extrémní hodnoty je zde zařazen znovu z toho důvodu,
že častější způsob uložení dat je ve formě datové struktury a ne tak jak je
provedeno v PR1_35.Všimněte si také počáteční hodnoty v pomocných
proměnných MAX a MIN. Do pomocných proměnných jsou uloženy hodnoty
prvního prvku pole a porovnávání dalších hodnot s těmito pomocnými
proměnnými začíná od druhého prvku pole.
Příklad 2-24
Sestavte program, který vygeneruje N čísel z intervalu <1,10>. Zjistěte četnost
výskytu jednotlivých číslic.
Rozbor řešení:
Četnost výskytu znamená, kolikrát se to které číslo vyskytlo. V řešení se
vychází z předpokladu, že vstupní hodnoty se generují z intervalu <1,10>,
proto pro uložení četnosti výskytu čísel je připraveno pole CETNOST o 10
prvcích. Podle hodnoty vygenerovaného čísla se pak zvyšuje o jedničku
hodnota toho prvku pole CETNOST, který má index shodný s vygenerovanou
hodnotou.
Řešení v Borland Pascalu:
program PR2_24;
uses crt;
const
N = 100;
type
tpole = array[1..N] of integer;
Tpole1 = array[1..10] of integer;
var
i,poc:integer;
A:Tpole;
cetnost:Tpole1;
procedure nacti(var a:Tpole;n:integer);
var
i:integer;
begin
randomize;
for i:= 1 to N do a[i]:=random(10)+1;
end;
procedure vytiskni(a:Tpole;n:integer);
var
i:integer;
begin
for i:= 1 to N do write(a[i],' ');
writeln;
end;
begin
clrscr;
Write('zadej pocet prvku pole: ');
readln(poc);
44
Praktická cvičení algoritmů
nacti(A,poc);
vytiskni(A,poc);
for I:=1 to poc do cetnost[A[I]]:=cetnost[A[I]]+1;
for I:= 1 TO 10 do
if cetnost[I]<>0 then writeln(I:3,'
',cetnost[I]);
writeln;
writeln('zmackni enter');
readln;
end.
Příklad 2-25
Sestavte program, ve kterém naplňte pole o N prvcích náhodnými čísly
z intervalu <1,50>. Pak načtěte z klávesnice číslo X (zajistěte opakování
načtení v případě, že zadané číslo leží mimo interval <1,50> ) a zjistěte, zda
toto číslo či není uloženo v poli (sestavte logickou funkci).
Rozbor řešení:
Při vyhledávání konkrétní hodnoty je vhodné zajistit, aby prohledávání
skončilo při nalezení hodnoty. Proto je v řešení zařazen jiný cyklus než cyklus
s řídící proměnnou. Musíme zajisti také, aby prohledávání skončilo, pokud
hledaná hodnota v poli není.
Řešení v Borland Pascalu:
program PR2_25;
uses crt;
const
N = 100;
type
tpole = array[1..N] of integer;
var
i,poc,x:integer;
A:Tpole;
ano:boolean;
procedure nacti(var a:Tpole;n:integer);
var
i:integer;
begin
randomize;
for i:= 1 to N do a[i]:=random(50)+1;
end;
procedure vytiskni(a:Tpole;n:integer);
var
i:integer;
begin
for i:= 1 to N do write(a[i],' ');
writeln;
end;
begin
clrscr;
Write('zadej pocet prvku pole: ');
readln(poc);
nacti(A,poc);
vytiskni(A,poc);
repeat
write('zadej cislo z intervalu <1,50> : ');
Readln(x);
until x in [1..50];
45
Praktická cvičení algoritmů
I:=1;
Ano:=false;
while (I<=poc) and not Ano do
begin
if a[i]=x then ano:=true;
inc(i);
end;
if ano then writeln('cislo ',x,' je v poli ulozeno')
else writeln('cislo ',x,' neni v poli ulozeno');
writeln;
writeln('zmackni enter');
readln;
end.
Průvodce studiem:
Uložení dat v paměti formou jednorozměrného pole je pro programátora hodně
důležité. Naučte se tento způsob práce efektivně využívat. Při práci s polem
dávejte pozor na to, abyste se nedostali mimo deklarovanou oblast a nesnažili
se pracovat s paměti, která není pro pole alokována. Pokud máte pole
indexováno např. pro 5 prvků (A:array[1..5] of integer) a provedete uložení
hodnoty do A[6], překladač nebude hlásit žádnou chybu a dojde k uložení
hodnoty do paměti. Nemusí tím dojít k žádným problémům, ale můžete si
přepsat jiná důležitá data a způsobit si naprosto nečekanou reakci programu.
Samostatný úkol č. 7
Sestavte program, který pole o N prvcích naplní náhodnými čísly a nalezne dvě
největší hodnoty v poli.
2.2.2.
Dvourozměrné pole
Borland Pascal dovoluje, aby prvky pole měly opět strukturu pole. Tímto
způsobem pak vznikne pole polí, nebo-li dvourozměrné pole.
Dvojrozměrné pole odpovídá matematickému objektu matice.
Jedná se o strukturovaný datový typ a proto platí, že s proměnnou můžeme
pracovat jako s celkem nebo s jejími jednotlivými komponentami.
Průvodce studiem:
Uložení dat ve formě dvourozměrného pole budete potřebovat v situaci, že data
tvoří jakousi tabulku. Musíte ale pamatovat na to, že se jedná o homogenní
datový typ, což znamená, že všechny hodnoty v poli musí být stejného typu.
V nabídnutých příkladech jsou pole vždy naplněna náhodnými čísly bez
návaznosti na nějaké konkrétní využití v praxi. Cílem je, abyste pochopili
indexaci této proměnné a bezpečně zvládli zpracování takto uložených dat.
46
Praktická cvičení algoritmů
Příklad 2-26
Naplňte dvojrozměrné pole o N řádcích a M sloupcích náhodnými čísly a
vytiskněte ve tvaru matice. Vypočítejte součet prvků v každém řádku a součet
prvků v každém sloupci.
Rozbor řešení:
Pro naplnění a tisk pole jsou zde sestaveny procedury. Pro výpočet potřebných
součtů jsou deklarována dvě jednorozměrná pole, jejichž rozměr odpovídá
počtu řádků a počtu sloupců. Výpočet součtů se provede najednou při jednom
průchodu polem.
Řešení v Borland Pascalu:
program PR2_26;
uses crt;
type
Tpole = array[1..20,1..30] of integer;
Tradek= array[1..20] of integer;
Tsloup= array[1..30] of integer;
var
pole:Tpole;
i,j,m,n:integer;
rad:Tradek;
slo:Tsloup;
procedure napln(var a:Tpole);
var
i,j:integer;
begin
randomize;
for i:= 1 to M do
for j:=1 to N do a[i,j]:=random(10)+1;
end;
procedure vytiskni(a:Tpole);
var
i,j:integer;
begin
for i:= 1 to M do
begin
for j:=1 to N do write(a[i,j]:3);
writeln;
end;
end;
procedure soucty(a:Tpole;var rad:Tradek;var
Sl:Tsloup;m,n:integer);
var i,j:integer;
begin
for i:= 1 to m do
for j:=1 to n do
begin
rad[i]:=rad[i]+a[i,j];
sl[j]:=sl[j] +a[i,j];
end;
end;
47
Praktická cvičení algoritmů
begin
clrscr;
write('zadej pocet radku: ');
readln(M);
write('zadej pocet sloupcu: ');
readln(N);
napln(pole);
vytiskni(pole);
writeln;
soucty(pole,rad,slo,M,N);
for i:= 1 to M do writeln('soucet ',i,'.radku: ',rad[i]);
writeln;
for i:= 1 to N do writeln('soucet ',i,'.sloupce: ',slo[i]:3);
writeln;
writeln;
write('zmackni ENTER: ');
readln;
end.
Příklad 2-27
Naplňte čtvercovou matici celými čísly, vytiskněte ve tvaru matice. Sestavte
funkci, která vypočítá součet prvků na hlavní diagonále. Pak sestavte funkci,
která vypočítá součet prvků na vedlejší diagonále. Výsledky vytiskněte.
Rozbor řešení:
Pod pojmem hlavní diagonála rozumíme prvky ležící na úhlopříčce zleva
doprava. Tyto prvky mají řádkový a sloupcový index stejný.
Vedlejší diagonálu tvoří prvky ležící na úhlopříčce zprava doleva. Řádkový
index těchto prvků začíná 1 a zvyšuje se o hodnotu jedna až do zadaného řádu
pole (N). Sloupcový index začíná číslem, které vyjadřuje zadaný řád pole (N) a
snižujeme se o 1 až po hodnotu 1.
Řešení v Borland Pascalu:
program PR2_27;
{soucet prvku na hlavni a vedlejsi diagonale}
uses crt;
type
Tpole = array[1..20,1..20] of integer;
var
pole:Tpole;
hlavni,vedlejsi,n:integer;
procedure napln(var a:Tpole);
var
i,j:integer;
begin
randomize;
for i:= 1 to n do
for j:=1 to n do a[i,j]:=random(10)+1;
end;
procedure vytiskni(a:Tpole);
var
i,j:integer;
48
Praktická cvičení algoritmů
begin
for i:= 1 to n do
begin
for j:=1 to n do write(a[i,j]:3);
writeln;
end;
writeln;
end;
function hlavni_diagonala(a:Tpole):integer;
var
i,s:integer;
begin
s:=0;
for I:=1 to n do s:=s+a[i,i];
hlavni_diagonala:=s;
end;
function vedlejsi_diagonala(a:Tpole):integer;
var
i,j,s:integer;
begin
s:=0;
j:=n;
for I:=1 to n do begin
s:=s+a[i,j];
j:=j-1;
end;
vedlejsi_diagonala:=s;
end;
begin
clrscr;
write('zadej rad matice: ');
readln(n);
napln(pole);
vytiskni(pole);
hlavni:=hlavni_diagonala(pole);
vedlejsi:=vedlejsi_diagonala(pole);
writeln('soucet na hlavni diagonale: ',hlavni);
writeln('soucet na vedlejsi diagonale: ',vedlejsi);
writeln;
write('zmackni ENTER: ');
readln;
end.
Příklad 2-28
Naplňte čtvercovou matici čísly, vytiskněte. Napište proceduru na výměnu
řádků v matici. Procedura bude mít 3 parametry. Prvním parametrem je matice,
dalšími dvěmi parametry jsou celá čísla v rozmezí od 1 do N. Procedura
vymění i-tý a j-tý řádek. Výslednou matici opět vytiskněte.
Rozbor řešení:
Záměna zadaných řádku matice je provedena pomocí procedury VYMEN,
která pracuje s celočíselnými hodnotami. Tato procedura je dobře použitelná,
při jejím volání se formální parametry nahradí konkrétními prvky pole.
49
Praktická cvičení algoritmů
Řešení v Borland Pascalu:
program PR2_28;
{vymena radku v matici}
uses crt;
const
n = 5;
type
Tpole = array[1..n,1..n] of integer;
var
pole:Tpole;
r1,r2:integer;
procedure napln(var a:Tpole);
var
i,j:integer;
begin
randomize;
for i:= 1 to n do
for j:=1 to n do a[i,j]:=random(10)+1;
end;
procedure vytiskni(a:Tpole);
var
i,j:integer;
begin
for i:= 1 to n do
begin
write(i,'. radek: ');
for j:=1 to n do write(a[i,j]:3);
writeln;
end;
writeln;
end;
procedure vymen(var a:Tpole; k,l:integer);
var
pom,i,j:integer;
begin
for j:= 1 to n do
begin
pom:=a[k,j];
a[k,j]:=a[l,j];
a[l,j]:=pom;
end;
end;
begin
clrscr;
napln(pole);
vytiskni(pole);
repeat
write('zadej cisla radku, ktere se maji vymenit(1 - 5): ');
readln(r1,r2);
until (r1>=1) and (r1<=N) and (r2>=1) and (r2<=N);
vymen(pole,r1,r2);
writeln('provedla se zamena ',r1,'. a ',r2,' . radku');
writeln;
vytiskni(pole);
writeln;
write('zmackni ENTER: ');
readln;
end.
50
Praktická cvičení algoritmů
Příklad 2-29
Naplňte čtvercovou matici celými čísly, vytiskněte ve tvaru matice. Sestavte
funkci, která vypočítá součet prvků pod hlavní diagonálou.
Rozbor řešení:
Hlavní diagonálu tvoří prvky ležící na úhlopříčce zleva doprava. Tyto prvky
mají index řádku stejný jako index sloupce. Pro všechny prvky pod hlavní
diagonálou platí, že mají index řádku větší než index sloupce.
Řešení v Borland Pascalu:
program PR2_29;
uses crt;
type
Tpole = array[1..20,1..20] of integer;
var
pole:Tpole;
vysl,N:integer;
procedure napln(var a:Tpole;N:integer);
var
i,j:integer;
begin
randomize;
for i:= 1 to N do
for j:=1 to N do a[i,j]:=random(10)+1;
end;
procedure vytiskni(a:Tpole;N:integer);
var
i,j:integer;
begin
for i:= 1 to N do
begin
for j:=1 to N do write(a[i,j]:3);
writeln;
end;
writeln;
end;
function soucet_pod_hl_diag(a:Tpole;N:integer):integer;
var
i,j,s:integer;
begin
s:=0;
for I:=1 to n do
for j:= 1 to N do
if I > J then s:=s+a[i,j];
soucet_pod_hl_diag:=s;
end;
begin
clrscr;
write('zadej rad matice: ');
readln(n);
napln(pole,N);
vytiskni(pole,N);
vysl:=soucet_pod_hl_diag(pole,N);
writeln('soucet prvku pod hl.diagonalou: ',vysl);
write('zmackni ENTER: ');
readln;
end.
51
Praktická cvičení algoritmů
Příklad 2-30
Naplňte dvojrozměrné pole o N řádcích a M sloupcích náhodnými čísly a
vytiskněte ve tvaru matice. Zjistěte a vytiskněte maximální hodnotu v každém
řádku pole.
Rozbor řešení:
Algoritmus nalezení extrémní hodnoty je vysvětlen v PR1_35 a jeho aplikace
je v PR2_23. Funkce pro vyhledání maximální hodnoty pracuje
s jednorozměrným polem, proto v okamžiku, kdy ji potřebujeme zavolat, je
třeba konkrétní řádek matice přepsat do jednorozměrného pole a to pak uvést
jako skutečný parametr funkce.
Řešení v Borland Pascalu:
program PR2_30;
uses crt;
type
Tpole = array[1..20,1..20] of integer;
Tradek = array[1..20] of integer;
var
pole:Tpole;
rad:Tradek;
vysl,N,I,J:integer;
procedure napln(var a:Tpole;N:integer);
var
i,j:integer;
begin
randomize;
for i:= 1 to N do
for j:=1 to N do a[i,j]:=random(10)+1;
end;
procedure vytiskni(a:Tpole;N:integer);
var
i,j:integer;
begin
for i:= 1 to N do
begin
for j:=1 to N do write(a[i,j]:3);
writeln;
end;
writeln;
end;
function maximum(a:Tradek;N:integer):integer;
var
i,max:integer;
begin
max:=0;
for I:=1 to n do
if A[I] > max then max:=A[I];
maximum:=max;
end;
52
Praktická cvičení algoritmů
begin
clrscr;
write('zadej rad matice: ');
readln(n);
napln(pole,N);
vytiskni(pole,N);
Writeln;
for I:=1 to N do
begin
for J:= 1 to N do rad[J]:=pole[I,j];
vysl:= maximum(rad,N);
writeln('Max.hodnota ',I,'.radku: ',vysl);
end;
writeln;
write('zmackni ENTER: ');
readln;
end.
Samostatný úkol č. 8
Naplňte dvojrozměrné pole o N řádcích a M sloupcích náhodnými čísly a
vytiskněte ve tvaru matice. Sestavte funkci, která zjistí součet prvků, které tvoří
obvod pole.
2.3.
Záznam
Při návrhu algoritmu řešení některých úloh se dostáváme do situace, kdy o
jednom objektu si musíme pamatovat informace různých datových typů.
Příkladem může být třeba informace o studentovi, kdy potřebujeme znát jeho
jméno, data narození, prospěch. Každý s těchto údajů je jiného datového typu,
ale patří ke stejnému objektu. A právě v takových případech je velmi vhodné
pro uložení dat použít datovou strukturu záznam.
Datový typ záznam je strukturovaný heterogenní datový typ. Proměnná typu
záznam se skládá z dílčích položek, které mohou být různých datových typů.
Příklad 2_31
Vytvořte kartotéku zaměstnanců o maximálním počtu 30 záznamů. O každém
zaměstnanci evidujeme :
Příjmení
Jméno
Věk
Měsíční plat.
Vytvořte komunikační prostředí, které uživateli umožní zvolit, zda chce
zadávat dalšího zaměstnance (na základě dotazu a odpovědi). Po ukončení
zadávání se automaticky vypíše obsah kartotéky na obrazovku ve formě jakési
tabulky (srovnat do sloupců). Pak zjistěte, zda je v kartotéce člověk s
příjmením, které načtete z klávesnice a uložíte do proměnné HL_PRIJM.
Pokud takové příjmení v kartotéce je, vypište na obrazovku všechny lidí
s tímto příjmením.
53
Praktická cvičení algoritmů
Rozbor řešení:
Definujeme v úseku TYPE vlastní datový typ záznam a typ pole záznamů.
Každý prvek pole bude tedy mít strukturu odpovídající položkám záznamu.
K prvkům pole přistupujeme přes jeden index, ale pak ještě přes tečkovou
konvenci přistupujeme k jednotlivým položkám.
Řešení v Borland Pascalu:
program PR2_31;
uses crt;
type
Tzam = record
prijm:string[20];
jmeno:string[10];
vek:byte;
plat:longint;
end;
Tpole = array [1.. 30] of Tzam;
var
osoba:Tzam;
pole:Tpole;
Hl_prijm:string[20];
i,odp,pom,p:integer;
Function prevod(s:string):string;
var
i:integer;
begin
for i:=1 to length(s) do s[I]:=upcase(s[i]);
prevod:=s;
end;
begin
clrscr;
i:=0;
repeat
Inc(i);
with pole[i] do
begin
write('zadej prijmeni: ');
readln(prijm);
write('zadej jmeno: ');
readln(jmeno);
write('Zadej vek: ');
readln(vek);
write('Zadej plat: ');
readln(plat);
end;
writeln;
repeat
write('chces zadat dalsi osobu ? 1= ano 2= Ne
readln(odp);
until (odp = 1) or (odp = 2);
until odp = 2;
writeln;
writeln('
prijm
jmeno
vek
plat');
for p:=1 to i do
with pole[p] do
begin
writeln(prijm:10,jmeno:10,vek:7,plat:8);
end;
54
:
');
Praktická cvičení algoritmů
writeln;
Write('zadej hledane prijmeni:');
readln(hl_prijm);
writeln;
pom:=0;
for p:=1 to i do
with pole[p] do
begin
if prevod(prijm) = prevod(hl_prijm) then
begin
writeln(prijm:10,jmeno:10,vek:7,plat:8);
pom:=1;
end;
end;
if pom=0 then writeln('clovek s hledanym prijmenim neni.');
writeln;
write('zmackni ENTER');
readln;
end.
Průvodce studiem:
Existence datové struktury záznam ulehčuje programátorům práci a napomáhá
větší přehlednosti zdrojového textu. Využití tohoto datového typu je ve větším
rozsahu vysvětleno v kapitole 3.2.Typový soubor.
2.4.
Množina
Základní charakteristika datové struktury množina:
• Všechny položky struktury musí být stejného datového typu, dovolené jsou
pouze ordinální datové typy
• Položky se ve struktuře nemohou opakovat
• Každé položce je přiděleno ordinální číslo z rozsahu 0 .. 255
Obecná definice typu množina v Pascalu: SET OF ordinální datový typ;
Základem pro definování typu množina je vždy určitý ordinální datový typ,
tzv. bázový typ.
Příklad 2-41
Přečtěte znak z klávesnice a určete, zda se jedná o malé nebo velké písmeno,
případně zda to vůbec není písmeno. Celý algoritmus se bude opakovat, jako
ukončující znak zvolíme hvězdičku.
55
Praktická cvičení algoritmů
Rozbor řešení:
V programu použijeme proměnnou typu množina, kterou můžeme deklarovat
např. takto:
var
PISMENA set of CHAR;
její hodnotu definujeme příkazem : PISMENA := [‘A’ .. ‘Z’];
Řešení v Borland Pascalu:
Program PR2_41;
uses crt;
var
velka_pism,mala_pism: set of char;
znak:char;
begin
clrscr;
velka_pism:=['A'..'Z'];
mala_pism:=['a'..'z'];
write('zadej znak * = konec programu: ');
readln(znak);
writeln;
while znak <>'*' do
begin
if znak in velka_pism then writeln('znak je
velke pismeno')
else if znak in mala_pism then writeln('znak
je male pismeno')
else writeln('znak neni pismeno');
writeln;
write('zadej znak * = konec programu: ');
readln(znak);
writeln;
end;
end.
Průvodce studiem:
Příklad 2_41 je docela dobře řešitelný bez znalosti datové struktury množina.
Stačí, když budete umět pracovat s proměnnou typu CHAR. Zařadila jsem
řešení pomocí množiny proto, abyste si vyzkoušeli tento datový typ použít.
Hlavně si všimněte operátoru IN, který zjišťuje náležitost prvku k množině.
Tento operátor vám umožňuje elegantním způsobem nahradit složité
sestavování logických podmínek.
Příklad 2-42
Sestavte program, který vygeneruje 6 různých čísel z intervalu 1 .. 49 (čísla do
SPORTKY). Využijte datový typ množina.
Rozbor řešení:
Deklarujeme proměnnou CISLA set of INTEGER;
její hodnotu definujeme příkazem: CISLA:= [1 ..49];
V programu pak postupně generujeme čísla. Pokud číslo je v dané množině,
uložíme jej do pole a z množiny jej odstraníme (odečteme).
56
Praktická cvičení algoritmů
Řešení v Borland Pascalu:
Program PR2_42;
{ program generuje 6 cisel v rozmezi 1 ..49
ukazka reseni s pouzitim datoveho typu mnozina }
uses crt;
type
inter = 1..49;
var
cis,i,opak:inter;
mn_cis:set of inter;
pole:array[1..6] of inter;
begin
randomize;
clrscr;
repeat
mn_cis:=[1..49];
i:=1;
repeat
cis:=random(49)+1;
if cis in mn_cis then
begin
pole[i]:=cis;
mn_cis:=mn_cis-[cis];
i:=i+1;
end;
until i>=7;
write('cisla do sportky: ');
for I:=1 to 6 do write(pole[i]:3);
writeln;writeln;
write('opakovat cely vypocet ? ');
writeln('1=ano, ostatni cisla = konec programu');
readln(opak);
until opak <> 1;
end.
Příklad 2-43
Přečtěte větu a zjistěte, kolik slov ve větě má více než 3 samohlásky.
Rozbor řešení:
Deklarujeme proměnnou var SAMOHL set of CHAR;
její hodnotu definujeme příkazem: SAMOHL:= [‘A’ , ‘E’, ‘I’, ‘O’, ‘U’, ‘Y’];
v programu použijeme možnost odčítání dvou množin
Řešení v Borland Pascalu:
Program PR2_43;
uses crt;
{ program zjisti, kolik slov ve vete ma alespon 3 ruzne
samohlasky
ukazka reseni s pouzitim datoveho typu mnozina }
var
s:string;
samohl:set of char;
i,p,p_slov,opak:integer;
begin
repeat
clrscr;
p:=0;p_slov:=0;
57
Praktická cvičení algoritmů
repeat
writeln('Napis vetu ukoncenou teckou:');
readln(s);
if s[length(s)]<>'.' then writeln('veta musi koncit
teckou, zadejte znovu');
until s[length(s)]= '.';
samohl:=['A','E','I','O','U'];
for I:= 1 to length(s) do
begin
if upcase(s[I]) in samohl then
begin
inc(p);
samohl:=samohl-[upcase(s[I])];
end
else if (s[i] = ' ') or (s[i] = '.') then
begin
if p>= 3 then inc(p_slov);
p:=0;
samohl:=['A','E','I','O','U'];
end;
end;
writeln('pocet slov,ktera maji alespon 3 ruzne
samohl.:',p_slov);
writeln;
write('opakovat cely vypocet ? ');
writeln('1=ano, ostatni cisla = konec programu');
readln(opak);
until opak <> 1;
end.
Příklad 2-44
Sestavte program, jehož vstupem jsou dvě posloupnosti čísel z intervalu
<1,50>. Každá posloupnost obsahuje N hodnot. Z každé posloupnosti vytvořte
množinu hodnot. Vytvořte průnik množin.
Rozbor řešení:
V programu postupně dochází ke generování čísel ze zadaného intervalu. Pro
každé vygenerované číslo zjistíme, zda je v množině pomocí operátoru IN.
Pokud tam číslo není, tak se do množiny vloží (pomocí operátoru +). Až jsou
tímto způsobem naplněny obě množiny, pak potřebujeme zjistit, která čísla
množiny tvoří. Prvky množiny ale nelze přímo tisknout, proto je tisk zajištěn
pomocí příkazu cyklu s řídící proměnnou. Hodnota této řídící proměnné se
mění v intervalu <1,50> , což je interval, ze kterého byla generována čísla.
Řešení v Borland Pascalu:
Program PR2_44;
uses crt;
type
inter = 1..50;
var
K,N,I:integer;
p:inter;
A,B,C:set of inter;
begin
clrscr;
randomize;
58
Praktická cvičení algoritmů
Write('Pocet prvku mnoziny A: ');
Readln(N);
A:=[];
I:=0;
while I<N do
begin
p:=random(50)+1;
if NOT (p IN A) then begin
A:= A+[p];
INC(I);
end;
end;
write('mnozina A obsahuje tyto prvky:');
for p:= 1 to 50 do if p IN A then write(p,',');
writeln;writeln;
Write('Pocet prvku mnoziny B: ');
Readln(N);
B:=[];
I:=0;
while I<N do
begin
p:=random(50)+1;
if NOT (p IN B) then begin
B:= B+[p];
INC(I);
end;
end;
write('mnozina B obsahuje tyto prvky:');
for p:= 1 to 50 do if p IN B then write(p,',');
writeln;writeln;
C := A*B;
If C = [] then writeln('Prunik A a B je prazdna mnozina ')
else
begin
write('Prunik mnozin A a B je mnozina: [');
for p:= 1 to 50 do if p IN C then write(p,',');
writeln(#8,']');
end;
writeln;
writeln('zmackni ENTER');
readln
end.
Samostatný úkol č.9
Program PR2_44 rozšiřte o ostatní množinové operace.
2.5.
Korespondenční úkol č. 3
Zadání:
Vyberte si jeden z úkolů určených pro samostatnou práci uvedených
v kapitole 2 a pošlete jej ke kontrole.
59
Praktická cvičení algoritmů
Kontrolní otázky:
1.
2.
3.
4.
5.
6.
7.
8.
Co je to datová struktura ?
Jak budete deklarovat proměnnou, do které chcete uložit textový řetězec ?
Co je to nultý byte v řetězci ?
Který datový typ použijete, jestliže potřebuje v paměti počítače uložit více
dat stejného typu ?
Který datový typ odpovídá matematickému pojmu vektor ?
Který datový typ odpovídá matematickému pojmu matice ?
Který datový typ použijete, jestliže potřebuje v paměti počítače uložit více
dat různého typu ?
Co platí pro proměnnou typu množina ?
3.
Uložení dat mimo operační paměť
Cíl:
Po nastudování této části textu byste měli umět:
- vytvořit soubor dat mimo operační paměť počítače
- uložit data do externího souboru
- uložit data z externího souboru do operační paměti
Klíčová slova:
Operační paměť, soubor, datový typ soubor, proměnná typu soubor, textový
soubor, typový soubor, sekvenční přístup, přímý přístup, otevření souboru,
zavření souboru.
Programovací jazyk využívá pro uložení dat a jejich následné zpracování
přednostně operační paměť počítače. Pokud ale nastane situaci, že se data do
paměti nevejdou, lze data uložit mimo operační paměť.
K uložení dat mimo operační paměť slouží v Borland Pascalu datový typ
soubor. Veškeré podprogramy, které jsou v následujících programech použity,
je možné vyhledat ve vestavěné nápovědě programovacího jazyka.
3.1.
Textový soubor
Textový soubor budeme vytvářet tehdy, pokud potřebujeme mimo operační
paměť uložit textové údaje. Textový soubor je pro programátory čitelný, je
možné se na něj podívat v nějakém textovém editoru a také přímo
v integrovaném prostředí Borland Pascalu, kde také můžeme tento soubor
editovat.
60
Praktická cvičení algoritmů
Příklad 3-1
Vytvořte textový soubor TEXT.TXT v pracovním adresáři, zapište do něj 5
vět. Vytvořte kopii tohoto textového souboru (KOPIE.TXT). Oba soubory
vypište na obrazovku.
Rozbor řešení:
Protože vytváříme nový soubor, musíme jej otevřít v režimu REWRITE.
Každou větu nejdříve načteme do operační paměti a pak ji teprve uložíme
externího souboru. Po skončení ukládání je nutné soubor uzavřít a pak znovu
otevřít pro čtení. Přesný popis významu použitých podprogramů vyhledejte
v nápovědě.
Řešení v Borland Pascalu:
Program PR3_1;
uses crt;
var
f,k:text;
s:string;
i,poc:integer;
begin
clrscr;
assign(f,'text.txt');
assign(k,'kopie.txt');
rewrite(f);
write('zadej pocet vet :');
readln(poc);
writeln;
writeln('**********
napis ',poc,' vet
**********');
writeln;
for i:=1 to poc do
begin
write('zadej ',I,'. vetu : ');
readln(S);
writeln(F,S);
end;
close(f);
reset(f);
writeln;
writeln('Obsah puvodniho souboru TEXT.TXT: ');
writeln;
while not eof(f) do
begin
readln(f,s);
writeln(s);
end;
close(f);
reset(f);
rewrite(k);
while not eof(f) do
begin
readln(f,s);
writeln(k,s);
end;
close(f);
close(k);
reset(k);
writeln;
61
Praktická cvičení algoritmů
writeln('obsah souboru kopie.txt: ');
writeln;
while not eof(k) do
begin
readln(k,s);
writeln(s);
end;
write('zmackni ENTER');
readln;
end.
Příklad 3-2
Do existujícího souboru TEXT.TXT přidejte další 3 věty. Obsah souboru
vytiskněte na obrazovku tak, že před každou větou napište její pořadové číslo.
Rozbor řešení:
V textovém souboru nejsou jednotlivé položky číslovány. Proto zavedeme
počítadlo, jehož hodnotu vždy před tiskem věty zvýšíme o jedničku.
Řešení v Borland Pascalu:
program PR3_2;
uses crt;
var f:text;
veta:string;
i,n:integer;
begin
clrscr;
assign(f,'text.txt');
reset(f);
i:=0;
Writeln('obsah souboru:');
while not eof(f) do
begin
inc(i);
readln(f,veta);
writeln(i,'. ',veta);
end;
append(f);
writeln('zadej vety, ktere se do souboru maji pridat:');
for i:=1 to 3 do
begin
write('Zadej ',i,'. vetu: ');
readln(veta);
writeln(f,veta);
end;
close(f);
reset(f);
i:=0;
while not eof(f) do
begin
inc(i);
readln(f,veta);
writeln(i,'. ',veta);
end;
close(f);
writeln('Konec programu. Stiskni ENTER');
readln;
end.
62
Praktická cvičení algoritmů
Příklad 3-3
Určete četnost výskytu velkých písmen v souboru TEXT.TXT.
Rozbor řešení:
Četnost výskytu písmen znamená, kolikrát se písmeno vyskytlo. V řešení je pro
uložení četnosti výskytu písmen připraveno pole CETNOST, které je
indexováno datovým typem CHAR, ale jednotlivé prvky tohoto pole jsou
celočíselné. Podle hodnoty znaku se pak zvyšuje o jedničku hodnota toho
prvku pole CETNOST, který má index shodný s právě zpracovávaným
znakem.
Řešení v Borland Pascalu:
Program PR3_3;
{cetnost vyskytu velkych pismen v textovem souboru}
uses crt;
var
cetnost:array['A'..'Z'] of integer;
veta:string;
delka,i:integer;
zn:char;
f:text;
Procedure vypis_souboru(var f:text);
var
v:string;
begin
reset(f);
while not eof(f) do
begin
readln(f,v);
writeln(v);
end;
writeln;
close(f);
end;
begin
clrscr;
assign(f,'text.txt');
writeln('obsah souboru text.txt');
writeln;
vypis_souboru(f);
reset(f);
for zn:='A' to 'Z' do cetnost[zn]:= 0;
while not eof(f) do
begin
readln(f,veta);
delka:=length(veta);
for i:=1 to delka do
if veta[i] in ['A'..'Z'] then
cetnost[veta[i]]:= cetnost[veta[i]]+1;
end;
writeln;
writeln('tabulka cetnosti vyskytu velkych pismen:');
writeln;
63
Praktická cvičení algoritmů
writeln('pismeno pocet vyskytu');
for zn:='A' to 'Z' do
if cetnost[zn]>0 then writeln(zn:3,cetnost[zn]:10);
writeln;
writeln('konec programu, zmackni Enter');
readln;
end.
Samostatný úkol č. 10
Sestavte program, který uloží obsah textového souboru TEXT.TXT do pole
řetězců. Pak pro každou větu zajistěte, aby začínala velkým písmenem, ostatní
písmena byla napsána malými písmeny, věta byla ukončena tečkou a mezi
jednotlivými slovy byla jen jedna mezera. Po této úpravě zjistěte, kolik nejvíce
slov je ve větě. Tuto větu vypište na obrazovku. Všechny věty uložte zpět do
původního souboru.
3.2.
Typový soubor
Typový soubor slouží k uložení dat mimo operační paměť. Při deklaraci
proměnné typu soubor stanovujeme, jaká data budeme do souboru ukládat.
Soubor patří mezi strukturované homogenní datové typy, proto je možné do
jednoho souboru uložit jen jeden typ dat.
Typový soubor je soubor s přímým přístupem, tzn. že je možný přímý přístup
k jednotlivým položkám. Položky jsou číslovány a v prostředí Borland Pascal
jsou podprogramy, které umožňují s tímto souborem dat celkem jednoduše
pracovat.
Typový soubor je pro programátora nečitelný. Jediný způsob, jak zjistit obsah
souboru, je výpis pomocí programu.
Příklad 3-21
Do souboru CISLA.DAT zapište N náhodně vygenerovaných čísel z intervalu
(1,100). Obsah souboru vypište na obrazovku. Pak do souboru přidejte 5
dalších čísel a opět souboru vypište. Pro výpis souboru sestavte vlastní
proceduru.
Rozbor řešení:
V tomto programu jsou zachyceny základní kroky, které je třeba dodržet při
práci s typovým souborem. Význam jednotlivých podprogramů je vhodné
dohledat v nápovědě jazyka Borland Pascal.
Řešení v Borland Pascalu:
program PR3_21;
uses crt;
const n =10;
type
Tsoubor = file of integer;
var
f:Tsoubor;
i,r:integer;
64
Praktická cvičení algoritmů
procedure vypis(var f:Tsoubor);
var
r:integer;
begin
reset(f);
while not eof(f) do
begin
read(f,r);
write(r:4);
end;
writeln;
end;
begin
clrscr;
randomize;
writeln;
assign(f,'cisla.dat');
rewrite(f);
for I:= 1 to n do
begin
r:=random(100);
write(f,r);
end;
reset(f);
writeln('obsah souboru: ');
vypis (f);
writeln;
writeln('zadej 5 cisel, ktera chces pridat do souboru:');
for I:= 1 to 5 do
begin
Write (i,'. cislo: ');
readln(r);
write(f,r);
end;
seek(f,0);
writeln;
writeln('novy obsah souboru:');
vypis(f);
close(f);
writeln;
write('zmackni ENTER');
readln;
end.
Příklad 3-22
Ze souboru CISLA.DAT vytvořte soubor NOVY.DAT, který bude obsahovat
každé třetí číslo z původního souboru.
Rozbor řešení:
Každá položka v typovém souboru má své číslo, číslování začíná od nuly. Pro
zajištění výpisu každé třetí položky je pro zjištění dělitelnosti čísla položky
číslem 3 zařazen operátor MOD, který zjišťuje zbytek po dělení.
65
Praktická cvičení algoritmů
Řešení v Borland Pascalu:
{$I-}
program PR3_22;
{program cte existujici soubor, do noveho souboru zapisuje
kazde treti cislo}
uses crt;
type
Tsoubor = file of integer;
var
f,f1:Tsoubor;
r,p:integer;
Iochyba:boolean;
procedure vypis(var f:Tsoubor);
var
r:integer;
begin
reset(f);
while not eof(f) do
begin
read(f,r);
write(r:5);
end;
writeln;
end;
begin
clrscr;
assign(f,'cisla.dat');
assign(f1,'novy.dat');
reset(f);
rewrite(f1);
Iochyba := Ioresult <> 0;
if Iochyba then writeln(#7,'chyba pri otevreni souboru')
else
begin
writeln('puvodni soubor:');
vypis(f);
seek(f,0);
while not eof(f) do
begin
read(f,r);
p:=filepos(f);
if p mod 3 = 0 then write(f1,r);
end;
seek(f1,0);
writeln('novy soubor:');
vypis(f1);
close(f);
close(f1);
end;
writeln;
write('zmackni ENTER');
readln;
{$I+}
end.
66
Praktická cvičení algoritmů
Průvodce studiem:
Ve zdrojovém textu programu je vypnuta automatická kontrola vstupně
výstupních operací (V/V). Kontrola se vypíná pomocí direktivy překladače ve
tvaru {$I-}, pak překladač kontrolu V/V operací neprovádí a správnost V/V
operací kontroluje programátor. Pokud funkce IOResult vrací nulu, byla V/V
operace provedena správně. Které hodnoty funkce IOResult může vracet a co
to znamená, naleznete v kontextové nápovědě Borland Pascalu.
Příklad 3-23
Sestavte program, který umožní vést evidenci osob. O jednotlivých osobách
evidujeme Příjmení, Jméno, Věk. Informace zapisujte do souboru EVID.DAT.
Po zápisu do souboru se program bude ptát, zda chceme zadávat další osobu.
Pokud si vybereme odpověď "ne" , zobrazí se dotaz, zda chceme obsah
souboru vypsat na obrazovku před ukončením programu.
Rozbor řešení:
Soubor, do kterého budeme informace zapisovat, musí mít jednotlivé položky
stejného datové typu, jako paměťová proměnná, do které se ukládají data
načtena z klávesnice. Při čtení ze souboru jsou jednotlivé položky souboru
ukládány do pole záznamů.
Řešení v Borland Pascalu:
program PR3_23;
uses crt;
type
tosoba = record
prijmeni:string;
jmeno:string;
vek:integer;
end;
type
tpole = array[1..50] of tosoba;
var
f:file of tosoba;
os:tosoba;
pole:tpole;
i,odp,o:integer;
begin
clrscr;
assign(f,'evid.dat');
rewrite(f);
repeat
with os do
begin
write('zadej prijmeni: ');
readln(prijmeni);
write('zadej jmeno: ');
readln(jmeno);
write('Zadej vek: ');
readln(vek);
write(f,os);
end;
writeln;
repeat
67
Praktická cvičení algoritmů
write('chces zadat dalsi osobu ? 1= ano 2= Ne : ');
readln(odp);
until (odp = 1) or (odp = 2);
until odp = 2;
writeln;
Writeln('chces vypsat obsah souboru ? 1 =ano 2 = ne :');
readln(o);
if o = 1 then
begin
reset(f);
i:=0;
while not eof(f) do
begin
i:=i+1;
read(f,pole[i]);
end;
for I:=1 to filesize(f) do
writeln(pole[i].jmeno:15,pole[i].prijmeni:20,pole[i].vek:10);
close(f);
end;
writeln;
write('zmackni ENTER');
readln;
end.
Příklad 3-24
Sestavte program, který na konec existujícího souboru EVID.DAT přidá
informace o třech dalších lidech. Pak vypíše informace o člověkovi, který je
nejstarší.
Rozbor řešení:
V programu pracujeme s existujícím souborem, proto je důležité tento soubor
otevřít pomocí procedury RESET a ne REWRITE (došlo by k vynulování
souboru). Obsah souboru pak uložíme do paměťového pole záznamů a
vyhledání informací o nejstarším člověku se pak provede v tomto poli. Jde pak
o nám již známý algoritmus vyhledání extrémní hodnoty a zapamatování si
místa jejího výskytu.
Řešení v Borland Pascalu:
program PR3_24;
{vypis existujiciho souboru, nalezeni nejstarsi osoby}
uses crt;
type
tosoba = record
prijmeni:string;
jmeno:string;
vek:integer;
end;
type
tpole = array[1..50] of tosoba;
var
f:file of tosoba;
os:tosoba;
pole:tpole;
i,p,nej:integer;
68
Praktická cvičení algoritmů
begin
clrscr;
i:=0;
assign(f,'evid.dat');
reset(f);
seek(f,filesize(f));
Writeln('zadejte informace o 3 novych osobach do souboru');
for I:= 1 to 3 do
with os do
begin
write('zadej prijmeni: ');
readln(prijmeni);
write('zadej jmeno: ');
readln(jmeno);
write('Zadej vek: ');
readln(vek);
write(f,os);
end;
close(f);
reset(f);
i:=0;
writeln('Obsah souboru:');
while not eof(f) do
begin
inc(i);
read(f,pole[i]);
end;
writeln('
jmeno
prijmeni
vek');
writeln;
for i:=1 to filesize(f) do
WITH pole pole[i] do
begin
writeln(jmeno:15,prijmeni:20,.vek:10);
if nej < vek then begin
nej:=vek;
p:=i;
end;
end;
writeln;
writeln('Nejstarsi osoba:');
writeln(pole[p].jmeno:15,pole[p].prijmeni:20,pole[p].vek:10);
writeln;
close(f);
writeln('Konec programu. Stiskni ENTER.');
readln;
end.
Samostatný úkol č. 11
Program PR2_31 upravte tak, aby se kartotéka lidí ukládala do souboru
Lide.dat.
69
Praktická cvičení algoritmů
3.3.
Korespondenční úkol č.4
Zadání:
Sestavte program, který vypíše na obrazovku obsah existujícího souboru
EVID.DAT a zároveň uloží informace do pole záznamů. Pak zjistí, jaký je
průměrný věk osob zapsaných v souboru. Na obrazovku vypíše informaci o
průměrném věku a také informace o všech osobách, které jsou starší než je
zjištěný průměrný věk.
Kontrolní otázky:
1. Jak je možné v prostředí Borland Pascalu uložit data mimo operační
paměť ?
2. Do které skupiny patří datový typ soubor ?
3. Které typy souborů dat je možné v Borland Pascalu vytvořit ?
4. Jaký je rozdíl mezi textovým a typovým souborem dat ?
5. Které režimy otevření souboru jsou zavedeny pro práci s textovým
souborem ?
6. Které režimy otevření souboru jsou zavedeny pro práci s typovým
souborem ?
7. Který se souborů je soubor s přímým přístupem a co to znamená?
8. Co znamená soubor se sekvenčním přístupem ?
4.
Závěr
Předložený text by vám měl pomoci v lepší orientaci při sestavování programů
v programovacím jazyku Borland Pascal. Pokud vás při studium toho kterého
algoritmu napadne řešení jiné, je to naprosto v pořádku. Zde uvedená řešení
jsou obvykle jednou z několika možných variant řešení a měla by vám být
návodem, jak postupovat při řešení konkrétních úkolů z praxe.
Prostudování uvedených zdrojových textů vám usnadní práci při analýze a
návrhu složitějších algoritmů, protože již víte jaké možností vám programovací
jazyk Borland Pascal nabízí při ukládání dat v operační paměti i mimo operační
paměť, vyzkoušeli jste si principy dalšího zpracování dat v závislosti na typu
uložených dat.
Algoritmy, se kterými jste se zde seznámili, vám mohou pomoci i v případech,
když se dostanete do situace, ve které vámi zvolené řešení se projeví jako
neefektivní nebo chybné. Nechat se inspirovat jiným pohledem na řešený
problém není chybou, může to být naopak velmi prospěšné.
Tento studijní text s programy sestavenými v jazyku Borland Pascal můžete
využít i při tvorbě programů v jiném programovacím jazyku, protože rozbor
řešení u každého zde vloženého příkladu vám postačí k pochopení algoritmu a
zápis v jiném programovacím jazyku je pak jen otázkou jiné syntaxe.
70
Praktická cvičení algoritmů
5.
Literatura
Základní literatura
Satrapa, P.: Pascal pro zelenáče, Neokortex, 2000
Kvoch, M.: Programování v TURBO PASCALU 7.0, KOPP, 1994
Töpfer, P.: Programovací techniky, Prometheus, 1995
Doporučená literatura
Kvoch, M.:Sbírka úloh z jazyka Pascal, KOPP, 1993
Drozd, J., Kryl, M.: Začínáme s programováním, GRADA, 1992
Ježowicz, E., Laga, J.: Základy programování v PASCALU, Státní
pedagogické nakladatelství, 1989
Mikula, P.: TURBO PASCAL 7.0 od příkladů k příkazům, GRADA 1993
Vogel, J.,Müller, K.,Jinoch, J.: Programování v jazyku PASCAL, SNTL 1988
71

Podobné dokumenty

Práce s daty 2 - Starší publikace a seriály

Práce s daty 2 - Starší publikace a seriály Šířka výstupního pole........................................................................................................ 97 Zobrazení znaménka u kladných čísel ...................................

Více

Modulární systém kurzů programovacích nástrojů Borland

Modulární systém kurzů programovacích nástrojů Borland jsou přiloženy jejich zdrojové soubory s příponou PAS a přímo spustitelné programy s příponou EXE. Výuka lze rozdělit do dvou částí. V první části si žáci osvojí a naučí používání základních strukt...

Více

Upravená učebnice C a C++

Upravená učebnice C a C++ Vlastní program, tedy náš seznam úkolů pro počítač, je mezi znaménky { a } (složené závorky). To co zbylo před našimi závorkami - main() - si také vysvětlíme v některém pozdějším díle (pro dnešek s...

Více

Programování v jazyku C-C++

Programování v jazyku C-C++ programu lišit, neboť paměť přiřazuje programu operační systém. V programu jsou chyby. Přímé přiřazení hodnoty do proměnné uf (uf = 50;) a pak v poslední funkci printf, kde se tiskne hodnota ukazat...

Více

Průvodce světem králíka Petra

Průvodce světem králíka Petra Každý z datových prvků při vytváření programu něco obsahuje. Číselná proměnná obsahuje číslo, obrázková proměnná obrázek, předmětová proměnná předmět (což je v podstatě obrázek o velikosti 32x32 b...

Více

1. DÚ

1. DÚ zadávat různé vstupy (po rozkliknutı́ odkazu hned pod oknem na zdrojový kód) do pole input, v poli output se objevı́ výsledek. (Pokud vaše programy nepoběžı́ bleskově rychle, je vhodné m...

Více

ZÁKLADY PROGRAMOVACÍHO JAZYKA TURBO PASCAL

ZÁKLADY PROGRAMOVACÍHO JAZYKA TURBO PASCAL - přečtením hodnoty do proměnné (ze vstupu, příkaz read nebo readln) - dosazením hodnoty do proměnné – přiřazovací příkaz, např. A:=7 (dosazení sedmičky do proměnné A) Aritmetické operátory a aritm...

Více