Az algoritmusok elemei

1 Szorgalmi: Csala Tamás gyökvonógépe

Hérón masina
L

Használati útmutató:

1. Írj be az SZ-be azt a számot, aminek érdekel a gyöke
2. Nyomd meg a T↓1 gombot
3. Nyomd meg a ↑T gombot
4. Nézd meg hogy világít-e a lámpa,
ha igen akkor lépj az 6. lépésre
5. Lépj a 3. lépésre
6. Kész, az eredmény a T-ben :)

2 Emlékeztető: A programozás menete


A feladattól a kész programig

  1. Specifikáció: a feladat megfogalmazása
  2. Algoritmizálás: a megoldás módszerének kitalálása
  3. Kódolás: a megoldás leírása egy programozási nyelven
  4. Tesztelés: a program kipróbálása

Részfeladatok

3 Emlékeztető: C program

#include <stdio.h>

int main()
{
   double a, b, osszeg;

   printf("Összeadó\n\n");
   printf("a=");
   scanf("%lf", &a);
   printf("b=");
   scanf("%lf", &b);
   printf("\n");

   osszeg=a+b;
   printf("a+b=%f\n", osszeg);

   return 0;
}
Összeadó

a=1.2
b=2.5

a+b=3.700000

A program kér két számot, és kiírja az összegüket.

4 Elemi lépések

Elemi lépések, műveletek a számítógépen


Egyszerű program

PROGRAM
  KIÍR: "Helló, világ!" egyetlen elemi lépés
PROGRAM VÉGE

5 Programok egynél több lépésből – hogyan?


A gyakorlaton szerepeltek algoritmusok: prímtényezős felbontás, rendezés, számlálás…

6 Programvezérlés: lehetőségek

Strukturált programok (structured programs)

  • Amelyek szekvenciából, elágazásból és ciklusból épülnek fel
  • Matematikailag bizonyított: minden megoldható így
  • Tapasztalat: sokkal jobban, mint spagetti kóddal!

Feltétel folyamatábrán Programvezérlés (control flow): az utasítások végrehajtásának sorrendje

A vezérlési szerkezetek lényege az, hogy valamilyen döntés (egy feltétel teljesülése) alapján máshol folyatódik általuk a program végrehajtása – nem a pszeudokódban következő utasításnál.

7 Szekvencia: egymás utáni lépések

folyamatábra (flow chart)

Szekvencia folyamatábrán

struktogram (structogram)

Szekvencia struktogramon

8 Szekvencia: szám négyzete

Program

PROGRAM
    KIÍR: "Kérem a számot!"    
    BEOLVAS: a    
    a=a·a    
    KIÍR: a    
PROGRAM VÉGE

Működés


a: 




Mire használjuk itt a változót? Arra, hogy megjegyezzük a felhasználótól származó értéket – és később a négyzetét.

9 Elágazás: feltételes végrehajtás

Feladat: Írjunk programot, amely kér egy számot a felhasználótól.
Mondja meg, hogy páros vagy nem.


A programsorok végrehajtása feltételhez köthető.

Feltétel folyamatábrán
Feltétel struktogramon

Fogalmak: elágazás (conditional), feltétel (condition, predicate), igaz ág (consequent), hamis ág (alternative).

10 Elágazás: páros vagy páratlan

Program

PROGRAM
    BEOLVAS: szam    
    HA szam/2 maradéka 0, AKKOR    
        KIÍR: "páros"             ha teljesül
    EGYÉBKÉNT
        KIÍR: "páratlan"         ha nem teljesül
    FELTÉTEL VÉGE
PROGRAM VÉGE

Működés


szam: 




11 Elágazás: pozitív, nulla vagy negatív

Ez a programrész megnézi, hogy egy szám pozitív, nulla vagy negatív. Mire jó ez? Pl. egy másodfokú egyenlet diszkussziójához használható. Ha a diszkrimináns pozitív, két valós megoldás van. Ha nulla, akkor csak egy. Ha negatív, egy sem.

PROGRAM
    BEOLVAS: szam    

    HA szam>0, AKKOR    
        KIÍR: "pozitív"    
    FELTÉTEL VÉGE

    HA szam=0, AKKOR    
        KIÍR: "nulla"    
    FELTÉTEL VÉGE

    HA szam<0, AKKOR    
        KIÍR: "negatív"    
    FELTÉTEL VÉGE
PROGRAM VÉGE


Az elágazásoknál fontos látni azt, hogy akár teljesül a feltétel, akár nem, a program folytatása mindenképp az elágazás utáni műveletnél lesz.

12 Ciklus: számok 1-től 10-ig

Feladat: írjunk programot, amelyik növekvő sorrendben kiírja a számokat.

sorminta
:-(
KIÍR: 1
KIÍR: 2
KIÍR: 3
…
KIÍR: 8
KIÍR: 9
KIÍR: 10

Probléma


Sorminták – máshol tök jó, programozásban ne

A programozásban inkább ne!

13 Ciklus: folyamatábra és struktogram

Ciklus (loop): programrész ismétlése, amíg egy feltétel fennáll

Ciklus folyamatábrán
Ciklus struktogramon

Fogalmak: ciklusmag (loop body), ciklusfeltétel (loop condition), iteráció (iteration), ciklusváltozó (iterator).

14 Ciklus: számok kiírása

PROGRAM
    KIÍR: "Meddig írjam ki?"    
    BEOLVAS: n    

    i=1    
    CIKLUS AMÍG i≤n    
        KIÍR: i    
        i=i+1    
    CIKLUS VÉGE

    KIÍR: "."    
PROGRAM VÉGE


i: 
n: 

Itt mire jó a változó? Azzal tudjuk elérni azt, hogy a ciklus törzsében lévő kiírás utasítás mindig más számot írjon a képernyőre! Azzal számoljuk, hogy éppen hol tartunk.

15 Ciklus: Hérón módszere – feladat

Feladat: számoljuk ki a felhasználó által megadott szám négyzetgyökét Hérón módszerével (babilóniai módszer).


A módszer

Hérón módszere számegyenesen

Ezt a módszert alexandriai Hérón találta ki – ugyanaz a Hérón, aki a háromszög területének kiszámítására használható képletet is. Ugyanazt elmondhatjuk a programozásról, mint amit sok más tudományról is el lehet mondani: „már a régi görögök is”.

16 Ciklus: Hérón módszere – megoldás

PROGRAM
    szam=2    
    tipp=1    
    CIKLUS AMÍG |tipp-szam/tipp|>0.001    
        tipp=(tipp + szam/tipp)/2    
    CIKLUS VÉGE
    KIÍR: "A keresett gyök: ", tipp    
PROGRAM VÉGE

Hérón módszere - közelítés
szam:      
tipp:      

szam/tipp: 
különbség: 
átlag:     

17 Ciklusszervezés: áttekinthetőség!

Számok kiírása 1-től 10-ig:

i=0

CIKLUS AMÍG i≤9

    i=i+1

    KIÍR: i

CIKLUS VÉGE

rossz, követhetetlen

i=1 első

CIKLUS AMÍG i≤10  utolsó

    KIÍR: i               teendők

    i=i+1     következő

CIKLUS VÉGE

jól megírt

Ha áttekinthetően szeretnénk ciklust írni, akkor érdemes a fenti sémát megtartani. Az ismérvek:

  • A ciklus előtt közvetlenül a ciklusváltozó inicializálása szerepel. Ez lesz az első iterációban az értéke. Egyben az első feldolgozott elem.
  • A ciklustörzsben elöl a teendők szerepelnek. Mivel ez elöl van, ezért a ciklusváltozó értéke az első iterációban éppen a cikluson kívül beállított érték, vagyis az első elem! (Különben a ciklusváltozót olyan értékre kellene inicializálni, amit aztán nem dolgozunk fel, ahogyan az a bal oldalon is látszik.)
  • A ciklustörzs végén az utasítás, amely lép a következő elemre. Ez változtatja a ciklusváltozót. Utána már nem írunk semmit, hiszen akkor egy iteráción belül némely utasítások még a régi, némelyek pedig már az új értékére vonatkoznának.

18 Ciklus: számlálásos változat

„Amíg” (while) ciklus

i=1

CIKLUS AMÍG i≤10

    KIÍR: i

    i=i+1

CIKLUS VÉGE

Számlálásos ciklus



CIKLUS i=1-től, i≤10-ig, +1-esével

    KIÍR: i



CIKLUS VÉGE

19 Ciklusok: tudnivalók

Ciklusfeltételek


Ciklusok

A feltétel hamissá kell váljon előbb-utóbb: praktikusan ez azt is jelenti, hogy a ciklusváltozónak, ha van, az egyes iterációk között változnia kell. Különben ugyanaz marad az értéke, és a ciklus feltételének igazságértéke sem fog változni! Ha nincs olyan utasítás a ciklusban, amely a ciklusváltozó értékét változtatja, az gyanús.

20 Vezérlési szerkezetek: összefoglalás

szerkezethasználatpszeudokód
szekvenciaEgymás utáni utasítások.utasítás1
utasítás2
utasítás3
elágazásFeltételhez között végrehajtás.
0-szor vagy 1-szer.
Lehet „hamis” ága is.
HA feltétel, AKKOR
   utasítás
FELTÉTEL VÉGE
ciklusIsmétlés.
0-tól ∞-ig akárhányszor.
CIKLUS AMÍG feltétel
   utasítás
CIKLUS VÉGE

21 Vezérlési szerkezetek kombinációja

Feladat: írjunk programot, amelyik kér egy valós számot a felhasználótól, és Hérón módszerével kiszámolja a gyökét.

Tudjuk, hogy negatív számnak nincsen gyöke a valós számok körében. Ez nem csak definíciós kérdés, hanem a programunkat is érinti. Ugyanis ha Hérón algoritmusa negatív számot kap, akkor ide-oda ugrál pozitív és negatív tippek között. Így végtelen ciklus keletkezik: a program soha nem áll le. Ezért a felhasználótól kapott számot az algoritmus futtatása előtt ellenőrizni kell. Ha negatív, akkor nincs gyök, és ezt jelenzni kell. Ha nem, akkor indulhat a számítás.

A bemeneti adatok érvényességi köre része kell legyen a specifikációnak! Jelen esetben például meg kell mondani azt, hogy a program egy valós számot kell kérjen (ez a bemenet), amelynek a gyökét fogja meghatározni (ez a kimenet), de a beolvasott szám nem lehet negatív.

figyel, hogy
pozitív legyen
PROGRAM
      KIÍR: "Melyik szám gyöke?"
      BE: szam
      HA szam≤0, AKKOR
            KIÍR: "A szám pozitív kell legyen!"
      EGYÉBKÉNT
            tipp=1
            CIKLUS AMÍG |tipp-szam/tipp|>0.001
                  tipp=(tipp + szam/tipp)/2
            CIKLUS VÉGE
            KIÍR: "A keresett gyök: ", tipp
      FELTÉTEL VÉGE
PROGRAM VÉGE

A vezérlési szerkezetek tetszőleges mélységben egymásba ágyazhatóak. A lenti program egy szekvenciát tartalmaz, amelynek része a szám beolvasása és egy feltétel. A feltétel hamis ágában egy újabb szekvencia van, amely egy ciklust is tartalmaz.

C forráskódok

23 Szintaxis (syntax)

Nyelvtani szabályok


Szintaktikai hibák

int x, a, b, c;

printf("Az eredmény:")  // lemaradt pontosvessző

printf("%d\n", y);      // y: ismeretlen változó

x=2*(a+b+c;             // lemaradt bezáró zárójel

24 EBNF: Extended Backus-Naur Form

EBNF: formalizmus a szintaxis leírására.

JelölésJelentésPélda
=definíciónévelő = 'egy';
;definíció vége
' 'szöveg
|„vagy”számjegy = '0' | '1' | …
,összefűzésnegatív = '-', szám;
[ ]elhagyhatópozitív = ['+'], szám
{ }ismétlésszó = betű, { betű };

Példa: pozitív
egész szám
szám = nemnulla, { számjegy };
nemnulla = '1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9';
számjegy = '0' | nemnulla;

A C nyelv összes nyelvtani szabálya kb. 5 oldalnyi EBNF-fel leírható. De ezt most nem fogjuk megtenni.

EBNF leírást használnak a programozók is, akik egy nyelvet használnak, és szintaxisát szeretnék megérteni. De ebből dolgoznak azok is, akik a fordítóprogramot írják: ha matematikai precizitással adottak a nyelvtani szabályok, akkor a nyelv minden mondatát könnyű értelmezni. Ezzel még fogunk foglalkozni.

25 A C nyelv elemei

NévPéldaHasználat
kulcsszó
(keyword)
int, double, returna nyelv része, valamilyen kifejezett jelentése van
azonosító
(identifier)
x, teruletvalami neve, pl. változóé
operátor
(operator)
* + /számítási művelet
blokk
(block)
{ }több utasítás, csoportosítás
sztring
(string)
"helló, világ\n"szöveg
megjegyzés
(comment)
/*  */programozónak szóló, megértést könnyítő szöveg

26 Utasítások fajtái a C nyelvben

int x;

double pi=3.14159265;

változódefiníció

x = y+z;

printf("x=%d\n", x);

kifejezés


{
    printf("Helló!");
    return 0;
}

utasításblokk

if (x<0)
    printf("Negatív");
else
    printf("Nem negatív");

vezérlési szerkezet

27 Kifejezések

printf("Helló, világ!\n");

x=3;
printf("x+1=%d\n",              // több sorba is írható
       x+1);

printf("A négyzet oldalhossza?\n");
scanf("%lf", &a);
printf("Átló=%f\n", a*sqrt(2)); // négyzetgyök (square root)

28 Változódefiníciók

Egy vagy több változó definíciója „kvázi EBNF”-ben:

típus név [=kezdeti érték] {, név [=kezdeti érték]};


Példák C-ben:

int x=3;              // x nevű egész, kezdeti értéke 3

double f_1=0, f_2=0;  // két valós, f_1 és f_2

int szam, SZAM;       // inicializálatlanok. ez két különböző!
_
alulvonás
underscore

Egy változónak adhatunk kezdeti értéket (rögtön a definíciójakor). Ezt inicializálásnak is hívjuk, és pontosan ugyanaz, mint az értékadás. (Értéket többször is kaphat.) A változókat nem kötelező inicializálni, azonban figyelni kell arra, hogy ne használjuk az értéküket addig, amíg nem adtunk nekik.

29 Utasításblokk és egy C program váza

#include <stdio.h>
                        // bemenet/kimenet utasításokhoz
int main()
{
    int x;              // változó definíciók

    x=2*3;
    printf("%d\n", x);  // utasítások


    return 0;           // program vége
}

A programunk maga is egy utasításblokk.

A blokkoknak csak az elején lehetnek változódefiníciók. Ez azt jelenti, hogy az összes szükséges változót az elején meg kell adnunk, neveikkel és típusaikkal együtt. Az nem baj, ha csak később kapnak értéket.

30 Vezérlési szerkezet: if() elágazás

if (feltétel)
    utasítás;
[ else utasítás; ]


if (x>0)                       // a feltétel zárójelben
   printf("pozitív!\n");
else
   printf("nem pozitív.\n");   // hamis ág (elmaradhat)

if (x<0) {                   // több utasítás: { } között
   x=-x;
   printf("x negatív volt.\n");
}                            // itt nem kell pontosvessző

Ha a feltétel következményében vagy hamis ágában több utasítás is van, az egy szekvencia, ami C-ben utasításblokként jelenik meg. Ezért kellenek a kapcsos zárójelek. Ha csak egyetlen utasítás van, akkor nincsen rájuk szükség, de nem is hiba kiírni őket.

31 Vezérlési szerkezet: while() ciklus

elöltesztelő
ciklus

while (feltétel)
    utasítás;


while (x>0)              // a feltétel zárójelben
    x=x-1;

while (x>0) {            // több utasítás: { } között
    printf("x=%d\n", x);
    x=x-1;
}

32 Elöltesztelő ciklus: Hérón módszere (példa)

#include <stdio.h>
#include <math.h>

int main()
{
    double szam, tipp;

    printf("Szám: ");
    scanf("%lf", &szam);

    tipp=1;
    while (fabs(tipp-szam/tipp) > 0.001) // |tipp-szam/tipp|
        tipp=(tipp + szam/tipp)/2;

    printf("%f gyöke %f.\n", szam, tipp);

    return 0;
}

33 Vezérlési szerkezet: for() ciklus

számlálásos
ciklus

for (innentől; idáig; így)
    utasítás;


1 2 3 4 5
for (x=1; x<=5; x=x+1) // pontosvesszők!
    printf("%d ", x);

for every value of x from (x=1; to x<=5; step by x=x+1)

34 while() és for() ciklus: összehasonlítás

/* számok egytől tízig */

for (x=1; x<=10; x=x+1)
    printf("%d ", x);
x=1;
while (x<=10) {
    printf("%d ", x);
    x=x+1;
}

„A programok írásakor mindig figyeljük arra, hogy emberek olvassák majd azt. Az mellékes, hogy gépek hajtják végre.”
– Harold Abelson, Gerald Jay Sussman

A két kódrészlet pontosan ugyanazt csinálja.

Érdekesség: Harold Abelson az MIT egyetem professzora, a Creative Commons és a Free Software Foundation alapítványok egyik alapító tagja. (Az utóbbi alapítványhoz tartozik a GNU projekt, amely keretében a Linux rendszert is fejlesztik. Ez az androidos okostelefonok alapja.) Társszerzője a Structure and Interpretation of Computer Programs könyvnek, amelyből a fenti gondolat is származik.

35 Számlálásos ciklus: szorzótábla

#include <stdio.h>

int main()
{
   int y;

   for (y=1; y<=5; y=y+1) {
      int x;

      for (x=1; x<=5; x=x+1)
         printf("%2d ", x*y);
      printf("\n");
   }

   return 0;
}

A szorzótábla kirajzolása két ciklussal. Kívül a sorok ciklusa (y, öt iteráció), és azon belül soronként öt szám (x, öt iteráció soronként) és egy újsor karakter. Az x változó csak a belső ciklushoz van, így azt érdemes belül definiálni, mert csak ott használjuk. A változódefiníció szabályait viszont ott is betartjuk: a blokkok elejére kerül a definíció, és utána az utasítások.

36 A kód tördelése – „indentálás”

#include <stdio.h>
#include <math.h>

int main()
{
│   double szam;
│
│   printf("Szám: ");
│   scanf("%lf", &szam);
│   if (szam<=0) {
│   └─  printf("Pozitív kell legyen!\n");
│   } else {
│   │   double tipp=1;
│   │   while (fabs(tipp-szam/tipp) > 0.001) {
│   │   └─  tipp=(tipp + szam/tipp)/2;
│   │   }
│   └─  printf("%f gyöke %f.\n", szam, tipp);
│   }
│
└─  return 0;
}

Ez a program a vezérlési szerkezetek rész végén bemutatott négyzetgyökszámoló C nyelvű változata. Három dolgot kell megfigyelni rajta:

  1. A kód szedése. Az egyes vezérlési szerkezetek belsejében lévő utasítások beljebb kezdődnek (indent). A programon belüli utasítások is, ahogyan az if()-en belüliek és a cikluson belüliek is. Ez nagyban megkönnyíti a program áttekintését.
  2. A kapcsos zárójelek {} használata. Ha egy vezérlési szerkezeten belül csak egy utasítás van (mint pl. az if() igaz ágában vagy a ciklusban), akkor nem szükséges köré kapcsos zárójelet tenni. Azonban nem is lenne hiba sem, sőt talán attól is áttekinthetőbb kicsit a program. (Sokan azt vallják, jobb úgy használni.) A szintaktikai szabályok bemutatása miatt a fenti program a minimális számú kapcsos zárójelet tartalmazza.
  3. Változódefiníció utasításblokk elején. A C megengedi azt, hogy bármely utasításblokk elején változót hozzunk létre. Az a változó azonban csak az adott utasításblokkban fog élni. Jelen esetben a tipp nevű változó ilyen. Csak akkor van rá szükség, ha nem negatív számot kapott a program, és el kell végezni a számítást.
Egyiptomi zárójelezés
Klikk a képre!

Hogy ki pontosan hova helyezi el a nyitó és záró kapcsos zárójeleket, hova tesz szóközöket a műveleti jelek köré stb. – ez ízlés kérdése. Rengeteg stílus alakult ki, amelyek közül a tananyagban az ún. K&R stílust fogjuk használni. (Persze itt-ott ettől eltérünk, főleg ha ezt az előadásban a dia szűkös mérete kényszeríti.) Ezt a stílust tréfásan egyiptomi zárójelezésnek is szokták nevezni, a kapcsos zárójelek elhelyezése miatt.