Szelekciós vezérlés
Szelekciós vezérlések¶
Amikor véges sok rögzített művelet közül véges sok feltétel alapján választjuk ki, hogy melyik művelet kerüljön végrehajtásra, szelekciós vezérlésről beszélünk.
Attól függően, hogy a kiválasztás milyen módszerrel történik meg, különböző altípusai vannak ennek a vezérlésnek. Ezek az
- egyszerű szelekciós vezérlés,
- többszörös szelekciós vezérlés,
- esetkiválasztásos szelekció,
- illetve a föntiek kiegészítve egyébként ágakkal.
Egyszerű szelekciós vezérlés¶
Egyszerű szelekció esetén egyetlen feltétel és egyetlen művelet van (amely művelet persze lehet összetett).
Legyen F egy logikai kifejezés, A pedig tetszőleges művelet. Az F feltételből és az A műveletből képzett egyszerű szelekciós vezérlés a következő vezérlési előírást jelenti:
- Értékeljük ki az F feltételt és folytassuk a 2.) lépéssel.
- Ha F értéke igaz, akkor hajtsuk végre az A műveletet és fejezzük be az összetett művelet végrehajtását.
- Egyébként, vagyis ha F értéke hamis, akkor fejezzük be az összetett művelet végrehajtását.
A vezérlés bővíthető úgy, hogy a 3. pontban üres művelet helyett egy B műveletet hajtunk végre. Ekkor az alábbiak szerint módosíthatjuk a vezérlés megadását.
Legyen F egy logikai kifejezés, A és B pedig tetszőleges műveletek. Az F feltételből és az A és B műveletekből képzett egyszerű szelekciós vezérlés a következő vezérlési előírást jelenti:
- Értékeljük ki az F feltételt és folytassuk a 2.) lépéssel.
- Ha F értéke igaz, akkor hajtsuk végre az A műveletet és fejezzük be az összetett művelet végrehajtását.
- Egyébként, vagyis ha F értéke hamis, akkor hajtsuk végre a B műveletet és fejezzük be az összetett művelet végrehajtását.
A szerkezeti ábrán most is azt látjuk, hogy milyen részproblémák megoldása lesz a szelekció megoldása. A szerkezeti ábrákon a szelekciót egy téglalappal jelöljük, ami vízszintesen két részre van osztva. Ha tudjuk, a felső részbe kerül a feltétel, vagy az az elem, ami a feltételt meghatározza, a téglalaphoz csatolt műveletek pedig azok a műveletek lesznek, amelyek a feltétel(ek) bizonyos teljesülése mellett hajtódnak végre. Egyszerű szelekció esetében maga a feltétel egyértelműen beírható a téglalap felső részébe, az alsó résznél pedig jelölni tudjuk, hogy a feltétel igaz, vagy hamis értéke mellett mely alművelet végrehajtása jelenti a művelet befejezését.
Az egyszerű szelekciót C nyelven az if
utasítással valósítjuk meg.
A szelekció C megvalósítása:
1 2 3 |
|
Ha van egyébként ág is, akkor pedig:
1 2 3 4 5 |
|
Többszörös szelekciós vezérlés¶
Előfordulhat, hogy egyetlen feltétel nem elegendő ahhoz, hogy eldöntsük, mit is kellene csinálni, merre kellene haladni a vezérlésnek. Ilyenkor, ha több feltételünk van több művelettel, akkor többszörös szelekcióról beszélünk.
Legyenek Fi logikai kifejezések, Ai pedig tetszőleges műveletek 1 <= i <= n-re (azaz mind feltételből, mint A műveletből van n darab). Az Fi feltételekből és Ai műveletekből képzett többszörös szelekciós vezérlés a következő vezérlési előírást jelenti:
- Az Fi feltételek sorban történő kiértékelésével adjunk választ a következő kérdésre: van-e olyan i (1 <= i <= n), amelyre teljesül, hogy az Fi feltétel igaz és az összes Fj (1 <= j < i) feltétel hamis? (Azaz keressük az első Fi feltételt, ami igaz.)
- Ha van ilyen i, akkor hajtsuk végre az Ai műveletet és fejezzük be az összetett művelet végrehajtását.
- Egyébként, vagyis ha minden Fi feltétel hamis, akkor fejezzük be az összetett művelet végrehajtását.
Természetesen most is ki lehet egy egyébként ággal egészíteni a vezérlést, azaz definiálhatjuk azt a feladatot, amit akkor kell végrehajtani, amikor egyik feltétel sem teljesül. Ekkor az alábbiak szerint módosítsuk a többszörös szelekció formális leírását!
Legyenek Fi logikai kifejezések, Ai és B pedig tetszőleges műveletek 1 <= i <= n-re (azaz mind feltételből, mint A műveletből van n darab). Az Fi feltételekből, Ai és B műveletekből képzett többszörös szelekciós vezérlés a következő vezérlési előírást jelenti:
- Az Fi feltételek sorban történő kiértékelésével adjunk választ a következő kérdésre: Van-e olyan i (1 <= i <= n), amelyre teljesül, hogy az Fi feltétel igaz és az összes Fj (1 <= j < i) feltétel hamis? (Azaz keressük az első Fi feltételt, ami igaz.)
- Ha van ilyen i, akkor hajtsuk végre az Ai műveletet és fejezzük be az összetett művelet végrehajtását.
- Egyébként, vagyis ha minden Fi feltétel hamis, akkor hajtsuk végre B-t és fejezzük be az összetett művelet végrehajtását.
A többszörös szelekció folyamatábráin is látható, hogy egész addig, amíg nem találunk igaz feltételt, folytatódnak a feltétel kiértékelések. Ha találunk igaz feltételt, akkor az ahhoz tartozó utasítás végrehajtásával fejeződik be az összetett utasítás végrehajtása, ha egyik feltétel sem igaz, illetve ha van egyébként ág, akkor annak a végrehajtásával.
A többszörös szelekció szerkezeti ábrája a következőképpen alakul:
Ahogy azt már az egyszerű szelekciónál is láttuk, a szelekciót egy vízszintesen felezett téglalappal jelöljük.
Mivel a dobozkába nem férne el az összes feltétel, és nem is lenne utána egyértelmű, hogy melyik feltételhez melyik utasítás tartozik, így a dobozba csak egy ?
kerül.
A doboz alatt sorakoznak fel az egyes feltételek, és az azokhoz tartozó műveletek.
A többszörös szelekcióra tulajdonképpen tekinthetünk úgy is, mint egyszerű szelekciókra egymás után, ahol az egyébként ágakhoz tartozik mindig egy újabb egyszerű szelekció:
A többszörös szelekció megvalósítására nincs külön C konstrukció, így az egymásba ágyazott egyszerű szelekciókkal tudjuk megvalósítani:
1 2 3 4 5 6 7 8 9 10 |
|
Az if utasítások ismételt alkalmazása¶
Talán az eddigi példákból már feltűnt, hogy amikor egy kódot írunk, akkor bizonyos dolgok "beljebb" kezdődnek. A kód tabulálása azt a célt szolgálja, hogy a kód áttekinthetőbb legyen, látszódjék, hogy egy utasítás, vagy utasítás blokk mely másik utasítás része.
Láttuk, hogy a függvények utasításai blokkba rendeződnek, a blokkon belüli utasításokat pedig beljebb tabulálva írjuk. Ugyanígy teszünk egy szelekciós utasításunk ágaival is. Az abban levő utasításokat blokkosítjuk, a blokkon belüli utasításokat pedig beljebb tabuláljuk. Amennyiben egy összetett utasítás részutasítása egyetlen utasításból áll, akkor a blokk persze elmaradhat, de fontos, hogy a tabulálás megmaradjon. Egyes esetekben viszont jobb, ha a blokkokat sem hagyjuk el a biztonság kedvéért.
Vegyük a következő esetet, amikor két egyszerű szelekció van egymásba ágyazva:
Írjuk le ezt C kóddal:
1 2 3 4 5 6 |
|
Mivel a belső if
egyetlen utasítás, így akár a zárójelezés elmaradhat.
De vajon egyértelmű ebben, hogy az else
melyik if-hez tartozik?
Mi van, ha elcsúszik a tabulálás?
1 2 3 4 5 |
|
Mivel a C nyelv nem érzékeny az úgynevezett whitespace, azaz nem látható karakterekre (szóköz, tabulátor, sortörés), az else
ebben az esetben is a második if
-hez tartozik, azaz a két kód ekvivalens.
(Csak megjegyezzük: vannak olyan programozási nyelvek, ahol ez nemigaz, vagyis a kód tabulálása, formája az értelmezését is befolyásolja.)
Ha azt szeretnénk, hogy az else
az első if
-hez tartozzon, akkor azt zárójelezéssel jelezni kell:
1 2 3 4 5 6 |
|
Esetkiválasztásos szelekciós vezérlés¶
Ha a többszörös szelekció valamennyi feltételét átírhatjuk úgy, hogy azok elemek valamilyen halmazokba való tartozását vizsgálja, akkor esetkiválasztásos szelekcióról beszélünk.
Legyen K egy adott típusú kifejezés, és legyenek Hi-k olyan halmazok, melynek elemeinek típusa megegyezik K típusával. Legyenek továbbá Ai tetszőleges műveletek, ahol 1<=i<=n teljesül. A K szelektor kifejezésből, Hi kiválasztó halmazokból és Ai műveletekből képzett esetkiválasztásos szelekciós vezérlés a következő vezérlési előírást jelenti:
- Értékeljük ki a K kifejezést és folytassuk a 2.) lépéssel.
- Adjunk választ a következő kérdésre: Van-e olyan i (1<=i<=n), amelyre teljesül, hogy a K ∈ Hi, és K ∉ Hj, ahol (1<=j<i)?
- Ha van ilyen i, akkor hajtsuk végre az Ai műveletet és fejezzük be az összetett művelet végrehajtását.
- Egyébként, vagyis ha K nem eleme egyetlen Hi halmaznak sem, akkor fejezzük be az összetett művelet végrehajtását.
Itt is természetesen lehet egyébként águnk, amit akkor hajtunk végre, amikor egyik feltétel sem teljesül. Ekkor a 4. lépést egészítsük ki egy nemüres B művelet végrehajtásával.
Legyen K egy adott típusú kifejezés, és legyenek Hi-k olyan halmazok, melynek elemeinek típusa megegyezik K típusával. Legyenek továbbá Ai és B tetszőleges műveletek, ahol 1<=i<=n teljesül. A K szelektor kifejezésből, Hi kiválasztó halmazokból és Ai és B műveletekből képzett esetkiválasztásos szelekciós vezérlés a következő vezérlési előírást jelenti:
- Értékeljük ki a K kifejezést és folytassuk a 2.) lépéssel.
- Adjunk választ a következő kérdésre: Van-e olyan i (1<=i<=n), amelyre teljesül, hogy a K ∈ Hi, és K ∉ Hj, ahol (1<=j<i)?
- Ha van ilyen i, akkor hajtsuk végre az Ai műveletet és fejezzük be az összetett művelet végrehajtását.
- Egyébként, vagyis ha K nem eleme egyetlen Hi halmaznak sem, akkor hajtsuk végre B-t és fejezzük be az összetett művelet végrehajtását.
Amennyiben a szelektor kifejezés, amelynek értékét egy v változóban elmentük benne van valamelyik Hi halmazban, úgy az adott esethez tartozó Ai műveletet hajtjuk végre, egyébként pedig ellenőrizzük a következő halmazba való tartozást.
A szerkezeti ábráknál szintén egy osztott téglalappal jelezzük a szelekciót, ahol a téglalap felső felében megadjuk a szelekciót meghatározó kifejezést, az egyes halmazokat pedig az átláthatóság érdekében a téglalap alatt adjuk meg, a hozzájuk tartozó műveletekkel együtt.
A C nyelvben az esetkiválasztásos szelekciót a switch
utasítással valósítjuk meg.
Fontos, hogy a switch
szelektor kifejezés valamilyen felsorolási típusú legyen (azaz nem lehet például valós típus).
A switch
utasítás szelektorától csak az függ, hogy mely ponton kezdjük el végrehajtani a switch
magját.
Ha a végrehajtás elkezdődött, akkor onnantól kezdve az első break
vagy return
utasításig megy a switch
utasításainak a végrehajtása.
Ha ilyen nincs, akkor akár az utolsó utasításig.
Ebben a fázisban már nincs annak jelentősége, hogy van-e további case
vagy default
címke.
Vagyis ahhoz, hogy a switch
utasítás az esetkiválasztásos szelekció megvalósítása legyen, szükséges, hogy az esetkiválasztásos szelekció egy ághoz tartozó utasítások után egy break
segítségével megszakítsuk a switch
további utasításainak (és így magának a switch
utasításnak) a végrehajtását.
A break
helyett speciális esetekben a return
utasítás is megfelelő lehet.
A switch
utasítást tehát például a következő implementációval tudja az esetkiválasztásos szelekciót megvalósítani:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
A kiválasztó halmazok megadása az esetkiválasztásos szelekció kritikus pontja. Algoritmusok tervezése során bármilyen effektív halmazmegadást használhatunk, azonban a tényleges megvalósításkor csak a választott programozási nyelv eszközeit alkalmazhatjuk.
A Hi halmazok elemszáma tetszőleges lehet, a case
-ek után viszont csak egy-egy érték állhat.
Viszont kihasználhatjuk a switch
működési elvét, miszerint a címkék csak a belépési pontot határozzák meg.
Ha Hi = {xi,1, xi,2, . . . , x i,ni }, akkor az adott ág lekódolható a következő kódrészlettel:
1 2 3 4 5 6 |
|
Feltételes kifejezés¶
Az előző példában a kiíratás kissé összetettre sikeredett, gyakorlatilag 3 printf
függvény hívásával oldottuk meg egyetlen mondat kiírását:
1 2 3 4 5 |
|
Ez lerövidíthető az úgynevezett feltételes kifejezéssel így:
1 2 3 |
|
vagy még rövidebben így:
1 |
|
A feltételes operátor a C nyelv egyetlen három operandusú művelete, amely már a nyelv kezdetei óta a nyelv része. Három kifejezésből áll:
1 |
|
A teljes kifejezés kiértékelése során először kiértékelésre kerül a kifejezes_1
kifejezés.
Amennyiben ez igaz (azaz az érték nem 0), akkor a teljes kifejezés értéke a kifejezes_2
lesz, egyébként ha hamis (azaz 0), akkor a kifejezés értéke a kifejezes_3
lesz.