Projekt OP VK „Inovace studijních oborů zajišťovaných katedrami PřF UHK“ Registrační číslo: CZ.1.07/2.2.00/28.0118
8
Větvení programu
S větvením programu jsme se seznámili v předmětu Programování 1. Víme, že se jedná o tři varianty větvení: 1. neúplný podmíněný příkaz, 2. úplný podmíněný příkaz, 3. přepinač. Ve všech třech případech se vždy nejprve vyhodnocuje splnění či nesplnění podmínky, které tak jednoznačně určí další postup v rámci daného algoritmu. 8.1
Neúplný podmíněný příkaz
Základní vývojový diagram známe z předmětu Programování 1, viz obr. 8.1.
Ano
Ne Podmínka
Sekvence příkazů
Obr. 8.1 – Vývojový diagram neúplného podmíněného příkazu
1/18
Vladimír Jehlička
Programování 2 Větvení programu
Jestliže je podmínka splněna, pak se vykoná daná sekvence příkazů a algoritmus pokračuje dalšími příkazy. Není-li podmínka splněna, pak se sekvence příkazů nevykoná a algoritmus pokračuje přímo dalšími příkazy. V jazyku Object pascal se neúplný podmíněný příkaz zapisuje následujícím způsobem. if Podminka then begin ... end;
Příklad 08.01 Sestrojte program, který umožní načíst dvě celá čísla a vytiskne je v pořadí podle velikosti, tj, nejpve větší, potom menší. Výpis programu je uveden na obr. 8.2, příslušné okno aplikace je uvedeno na obr. 8.3.
2/18
Vladimír Jehlička
Programování 2 Větvení programu
Obr. 8.2 – Výpis programu pro porovnání velikosti dvou čísel
Obr. 8.3 – Okno aplikace pro porovnání velikosti dvou čísel 3/18
Vladimír Jehlička
Programování 2 Větvení programu
8.2
Úplný podmíněný příkaz
Základní vývojový diagram opět známe z předmětu Programování 1, viz obr. 8.4. Ano
Ne Podmínka
Sekvence příkazů 1
Sekvence příkazů 2
Obr. 8.4 – Vývojový diagram úplného podmíněného příkazu Jestliže je podmínka splněna, pak se vykoná daná sekvence příkazů číslo 1 a algoritmus pokračuje dalšími příkazy. Není-li podmínka splněna, pak se vykoná sekvence příkazů číslo 2 a algoritmus opět pokračuje dalšími příkazy. V jazyku Object pascal se úplný podmíněný příkaz zapisuje následujícím způsobem. if Podminka then begin ... end else begin ... end;
Je třeba si uvědomit, že celý tento zápis představuje jeden příkaz, který je ukončen středníkem. Proto se před else nikdy středník nepíše. Bývá to jedna z častých chyb začínajících programátorů.
4/18
Vladimír Jehlička
Programování 2 Větvení programu
Příklad 08.02 Sestrojte program pro výpočet kořenů kvadratické rovnice. Řešení realizujte nejenom v rámci množiny reálných čísel, ale také v množině komplexních čísel. Připomeňme si základní informace, které známe z předcházejícího studia matematiky. Kvadratickou rovnici zapisujeme ve tvaru:
ax 2 bx c 0 Pro výpočet jejích kořenů platí vztah: b 2 4ac x1, 2 2a Jestliže diskriminant je kladný, tj. b 2 4ac 0 , pak řešením kvadratické rovnice jsou dva kořeny reálné různé. Je-li diskriminant roven nule, tj. b 2 4ac 0 , pak řešením je reálný kořen dvojnásobný. Jestliže diskriminant je záporný, tj. b 2 4ac 0 , pak řešením kvadratické rovnice jsou dva kořeny komplexně sdružené. Jejich reálná část je b vypočtena ze vztahu Re a imaginární složka komplexních čísel je 2a b
b 2 4ac vypočtena ze vztahu Im . 2a Tím máme ukončenu analýzu zadaného úkolu a můžeme přistoupit ke tvorbě algoritmu řešení a jeho zápisu pomocí vývojového diagramu, viz obr. 8.5. Pro zjednudušení předpokládáme, že uživatel skutečně zadá koeficienty kvadratické rovnice, to znamená, že koeficient a 0 . Algoritmus začíná načtením koeficientů kvadratické rovnice. Uživatel aplikace musí mít v každém okamžiku přesnou informaci o tom, co se od něho vyžaduje. Proto je třeba před každým čtením zobrazit informaci uživateli o tom, jakou hodnotu právě má zadat. Začínající programátoři tento požadavek mnohdy podceňují. Neúplná, nepřesná, nebo dokonce chybějící informace může být příčinou toho, že se uživatel v ovládání aplikace nevyzná a omylem zadá jiná data, než je třeba. Po načtení hodnot koeficientů kvadratické rovnice je vypočtena hodnota diskriminantu. Pro nezápornou hodnotu diskriminantu jsou počítány 5/18
Vladimír Jehlička
Programování 2 Větvení programu
hodnoty reálných kořenů kvadratické rovnice. Není nutno samostatně řešit situaci, kdy hodnota diskriminantu je právě rovna nule. V tom případě jsou vypočteny stejné hodnoty pro oba reálné kořeny. Následuje tisk vypočtených hodnot reálných kořenů. Jestliže je hodnota diskriminantu menší než nula, pak je třeba samostatně vypočítat reálnou složku a samostatně imaginární složku komplexně sdružených kořenů. Následuje tisk vypočtených hodnot komplexně sdružených kořenů. Při psaní programu byly použity již známé podprogramy pro čtení i tisk dat, funkce pro výpočet hodnoty druhé mocniny, resp. duhé odmocniny ze zadané hodnoty a úplný podmíněný příkaz. Pokud při psaní programu zaváháte mezi funkcí pro výpočet druhé mocniny a funkcí pro výpočet druhé odmocniny (často se pletou), pak doporučuji podívat se do předcházející kapitoly těchto skript, nebo si vyvolat nápovědu vývojového prostředí Delphi. Výpis programu je uveden na obr. 8.6, příslušné okno aplikace je uvedeno na obr. 8.7.
6/18
Vladimír Jehlička
Programování 2 Větvení programu Začátek Piš: Zadejte koeficienty kvadratické rovnice Piš: Zadejte hodnotu koeficientu a Čti: a Piš: Zadejte hodnotu koeficientu b Čti: b Piš: Zadejte hodnotu koeficientu c Čti: c
D b2 Ano
x1 x2
b b
4ac Ne
D>=0
b 2 4ac 2a b 2 4ac 2a
Re
Im
b 2a
b 2 4ac 2a Piš: x1 =Re+Im i x2 =Re-Im i
Piš: x1, x2
Konec Obr. 8.5 – Vývojový diagram řešení kvadratické rovnice 7/18
Vladimír Jehlička
Programování 2 Větvení programu
Obr. 8.6 – Výpis programu pro řešení kvadratické rovnice
8/18
Vladimír Jehlička
Programování 2 Větvení programu
Obr. 8.7 – Okno aplikace s výpočtem hodnot komplexně sdružených kořenů kvadratické rovnice
8.3
Vícenásobný podmíněný příkaz
V některých případech nám pro větvení programu nestačí neúplný ani úplný podmíněný příkaz. Potřebujeme vytvořit algoritmus, ve kterém za sebou následují dva, tři nebo i více dotazů. Pak je možno použít vícenásobné větvení programu pomocí několika do sebe vnořených podmíněných příkazů. Pro ukázku je na obr. 8.8 zakreslen vývojový diagram se třemi podmínkami (P1 až P3) a čtyřmi sekvencemi příkazů (SP1 až SP4).
9/18
Vladimír Jehlička
Programování 2 Větvení programu
P1 SP1
P2 SP2
P3 SP3
SP4
Obr. 8.8 – Vývojový diagram vícenásobného podmíněného příkazu V jazyku Object pascal se vícenásobný podmíněný příkaz, který je uveden na obr. 8.8, zapisuje následujícím způsobem. if Podminka1 then begin ... end else begin if Podminka2 then begin ... end else begin if Podminka3 then begin ... end else end ... end; end; end;
10/18
Vladimír Jehlička
Programování 2 Větvení programu
Příklad 08.03 Vytvořte program, který po zadání čísla ročního období (1 = jaro, 2 = léto, 3 = podzim a 4 = zima) vypíše toto období a příslušné měsíce. Jádro algoritmu tvoří vícenásobný podmíněný příkaz, který již byl uveden na obr. 8.8. Proto můžeme přistoupit přímo k psaní programu, viz obr. 8.9. Obrazovka aplikace je uvedena na obr. 8.10.
11/18
Vladimír Jehlička
Programování 2 Větvení programu
Obr. 8.9 – Výpis programu pro roční období a jejich měsíce Máme-li psát programy čitelně a přehledně tak, abychom se v nich i s odstupem času vyznali, pak je třeba do nich nejenom vkládat dostatečné 12/18
Vladimír Jehlička
Programování 2 Větvení programu
množství komentářů, ale je nezbytné také dodržovat správnou grafickou úpravu. Programy, které píšeme ve vývojovém prostředí Delphi, mají blokovou strukturu. Je třeba, abychom každý blok odsadili od levého okraje stránky vždy alespoň o dvě mezery. Slova begin a end představují jakési závorky, ve kterých je uzavřen určitý blok našeho programu. Budeme-li důsledně psát program tak, aby každý end byl umístěn pod odpovídajícím begin, tj. že obě tato párová slova budou odsazena od levého okraje stránky stejným počtem mezer, pak bude daný blok na první pohled zřejmý. Dodržení tohoto pravidla je nezbytné např. při psaní vícenásobného podmíněného příkazu.
Obr. 8.10 – Okno aplikace s výpisem ročního období a příslušných měsíců 8.4
Přepinač
Některé algoritmy vyžadují větvení programu do více větví, a to na základě hodnoty jedné konkrétní proměnné. V předcházejícím příkladu takovou proměnnou bylo číslo ročního bdobí. Pak není vhodné do sebe neustále zanořovat další a další podmíněné příkazy, ale je třeba využít přepinač. Základní schema přepinače, které lze vyjádřit vývojovým diagramem, známe z předmětu Programování 1, viz obr. 8.11. 13/18
Vladimír Jehlička
Programování 2 Větvení programu
K
K1
K2
K3
Kn
SP1
SP2
SP3
SPn
Obr. 8.11 – Vývojový diagram pro přepinač V závislosti na hodnotě klíče K dojde k přepnutí chodu programu na spojku Ki, která má stejnou hodnotu jako klíč K, a vykoná se příslušná sekvence příkazů SPi. Jestliže ani jedna ze spojek nemá hodnotu klíče, pak se celá tato struktura vynechá a pokračuje se dalšími příkazy. Kromě toho je možno specifikovat sekvenci příkazů, která se vykoná, jestliže hodnota klíče neodpovídá žádné z hodnot uvedených spojek. V takovém případě je použita struktua else, jak uvádí následující nápověda vývojového prostředí Delphi.
Case Statements The case statement may provide a readable alternative to deeply nested if conditionals. A case statement has the form case selectorExpression of caseList1: statement1; ... caseListn: statementn; end where selectorExpression is any expression of an ordinal type smaller than 32 bits (string types and ordinals larger than 32 bits are invalid) and each caseList is one of the following: A numeral, declared constant, or other expression that the compiler can evaluate without executing your program. It must be of an ordinal type compatible with selectorExpression. Thus 7, True, 4 + 5 * 3, 'A', and Integer('A') can all be
14/18
Vladimír Jehlička
Programování 2 Větvení programu
used as caseLists, but variables and most function calls cannot. (A few built-in functions like Hi and Lo can occur in a caseList. See Constant expressions.) A subrange having the form First..Last, where First and Last both satisfy the criterion above and First is less than or equal to Last. A list having the form item1, ..., itemn, where each item satisfies one of the criteria above. Each value represented by a caseList must be unique in the case statement; subranges and lists cannot overlap. A case statement can have a final else clause: case selectorExpression of caseList1: statement1; ... caselistn: statementn; else statements; end where statements is a semicolon-delimited sequence of statements. When a case statement is executed, at most one of statement1 ... statementn is executed. Whichever caseList has a value equal to that of selectorExpression determines the statement to be used. If none of the caseLists has the same value as selectorExpression, then the statements in the else clause (if there is one) are executed.
Příklad 08.04 Vytvořte program, který po zadání čísla měsíce (1 = leden až 12 = prosinec) vypíše název měsíce a počet dní v měsíci. Pro zjednodušení neuvažujte únor v přestupném roce. Jestliže uživatel zadá číslo měsíce, které neodpovídá danému rozsahu, pak bude vypsáno chybové hlášení. Následující výpos programu vzhledem ke své délce není uveden formou kopie obrazovky, ale výpisem standardního textového souboru. Grafické uspořádání výpisu není zcela totožné s výpisem programu ve vývojovém prostředí Delphi, což souvisí s různou délkou řádku textu. Proto některé řádky textu, jsou rozepsány do dvou řádků. program Project1; {$APPTYPE CONSOLE} uses SysUtils; var CisloMesice,PocetDni: Integer; Mesic: String; Chyba: Boolean;
15/18
Vladimír Jehlička
Programování 2 Větvení programu
begin { Výpis názvu měsíce a počtu dní v daném měsíci } Write('Zadejte poradove cislo mesice: '); ReadLn(CisloMesice); WriteLn; Chyba:=False; // Nastavení výchozí hodnoty logické proměnné case CisloMesice of // Přepinač 1: begin Mesic:='leden'; PocetDni:=31; end; 2: begin Mesic:='unor'; PocetDni:=28; end; 3: begin Mesic:='brezen'; PocetDni:=31; end; 4: begin Mesic:='duben'; PocetDni:=30; end; 5: begin Mesic:='kveten'; PocetDni:=31; end; 6: begin Mesic:='cerven'; PocetDni:=30; end; 7: begin Mesic:='cervenec'; PocetDni:=31; end; 8: begin Mesic:='srpen'; PocetDni:=31; end;
16/18
Vladimír Jehlička
Programování 2 Větvení programu
9: begin Mesic:='zari'; PocetDni:=30; end; 10: begin Mesic:='rijen'; PocetDni:=31; end; 11: begin Mesic:='listopad'; PocetDni:=30; end; 12: begin Mesic:='prosinec'; PocetDni:=31; end; else Chyba:=True; // Změna hodnoty při chybně zadaném čísle měsíce end; WriteLn; If Chyba then WriteLn('Zadali jste nesmyslne cislo mesice!') else WriteLn(CisloMesice,'. mesic je ',Mesic,', ktery ma ',PocetDni,' dni.'); ReadLn; end.
V přepinači jsou pro jednotlivé měsíce zadány vždy dva dosazovací příkazy. Musejí tedy být uzavřeny do bloku pomocí slov begin a end. Za else následuje pouze jediný příkaz, který může, ale nemusí, být uzavřen do bloku pomocí slov begin a end. Proměnná Chyba je deklarována jako proměnná logického typu, která slouží pro identifikaci správného či naopak chybného zadání čísla měsíce. Na začátku je její obsah nastaven na hodnotu False. Pokud bylo zadáno chybné číslo měsíce, pak na konci přepinače je její hodnota nastavena na True. V následujícím úplném podmíněném příkazu se pak na základě aktuální hodnoty proměnné Chyba provede jeden nebo druhý typ výpisu výsledků. 17/18
Vladimír Jehlička
Programování 2 Větvení programu
Obrazovka aplikace je uvedena na obr. 8.11.
Obr. 8.11 – Okno aplikace s výpisem měsíce a počtu dní
18/18