Professional Documents
Culture Documents
PROGRAMOZÁS
1. kötet
TERVEZÉS
egyetemi jegyzet
2011
1
ELŐSZÓ
TARTALOM
ELŐSZÓ ...................................................................................................................... 4
BEVEZETÉS .............................................................................................................. 6
I. RÉSZ PROGRAMOZÁSI FOGALMAK ............................................................. 9
1. ALAPFOGALMAK................................................................................................. 10
1.1. Az adatok típusa ......................................................................................... 10
1.2. Állapottér ................................................................................................... 14
1.3. Feladat fogalma ......................................................................................... 15
1.4. Program fogalma ....................................................................................... 17
1.5. Megoldás fogalma ...................................................................................... 21
1.6. Feladatok ................................................................................................... 25
2. SPECIFIKÁCIÓ...................................................................................................... 28
2.1. Kezdőállapotok osztályozása...................................................................... 28
2.2. Feladatok specifikációja ............................................................................ 31
2.3. Feladatok ................................................................................................... 37
3. STRUKTURÁLT PROGRAMOK ............................................................................... 38
3.1. Elemi programok ........................................................................................ 40
3.2. Programszerkezetek ................................................................................... 43
3.3. Helyes program, megengedett program ..................................................... 55
3.4. Feladatok ................................................................................................... 58
II. RÉSZ PROGRAMTERVEZÉS MINTÁK ALAPJÁN .................................... 61
4. PROGRAMOZÁSI TÉTELEK ................................................................................... 63
4.1. Analóg programozás .................................................................................. 64
4.2. Programozási tétel fogalma ....................................................................... 69
4.3. Nevezetes minták ........................................................................................ 72
4.4. Feladatok ................................................................................................... 84
5. VISSZAVEZETÉS .................................................................................................. 85
5.1. Természetes visszavezetés .......................................................................... 85
5.2. Általános visszavezetés ............................................................................... 86
5.3. Alteres visszavezetés ................................................................................... 87
5.4. Paraméteres visszavezetés.......................................................................... 91
5.5. Visszavezetési trükkök ................................................................................ 94
5.6. Rekurzív függvény kiszámítása ................................................................... 99
5.7. Feladatok ................................................................................................. 105
6. TÖBBSZÖRÖS VISSZAVEZETÉS ........................................................................... 106
6.1. Alprogram ................................................................................................ 108
6.2. Beágyazott visszavezetés .......................................................................... 111
6.3. Program-átalakítások .............................................................................. 129
6.4. Rekurzív függvény kibontása .................................................................... 136
6.5. Feladatok ................................................................................................. 147
III. RÉSZ TÍPUSKÖZPONTÚ PROGRAMTERVEZÉS................................... 149
2
ELŐSZÓ
3
ELŐSZÓ
4
ELŐSZÓ
5
BEVEZETÉS
6
BEVEZETÉS
7
BEVEZETÉS
8
I. RÉSZ
PROGRAMOZÁSI FOGALMAK
9
1. Alapfogalmak
10
1.1. Az adatok típusa
11
1. Alapfogalmak
1
A típus korszerű definíciója ennél jóval árnyaltabb, de egyelőre ez a
„szűkített” változat is elegendő lesz az alapfogalmak bevezetésénél. A
részletesebb meghatározással a 7. fejezetben találkozunk majd.
12
1.1. Az adatok típusa
13
1. Alapfogalmak
1.2. Állapottér
14
1.3. Feladat fogalma
15
1. Alapfogalmak
16
1.3. Feladat fogalma
17
1. Alapfogalmak
program első utasítása vagy a (6,2), vagy a (6,5) állapotba vezet el. Az
első utasítás ugyanis nem egyértelmű, ettől a program működése nem-
determinisztikus lesz. Természetesen egyszerre csak az egyik
végrehajtás következhet be, de hogy melyik, az nem számítható ki
előre. Ha az első utasítás a d-t 2-re állítja be, akkor a második utasítás
elkezdi növelni azt. Ellenkező esetben, d=5 esetén, csökkenni kezd a d
értéke addig, amíg az nem lesz osztója az n-nek. Ezért az egyik esetben
– amikor d értéke 2 – rögtön meg is áll a program, a másik esetben
pedig érintve a (6,5), (6,4) állapotokat a (6,3) állapotban fog terminálni.
Bármelyik olyan kiinduló állapotból elindulva, ahol az első komponens
6, az előzőekhez hasonló végrehajtási sorozatokat kapunk: a program a
működése során egy (6,*) alakú állapotból elindulva vagy a (6,*) (6,2)
állapotsorozatot, vagy a (6,*) (6,5) (6,4), (6,3) állapotsorozatot futja
be. Ezek a sorozatok csak a legelső állapotukban különböznek
egymástól, hiszen egy végrehajtási sorozat első állapota mindig a
kiinduló állapot.
Induljunk el most egy (5,*) alakú állapotból. Ekkor az első
utasítás eredményétől függően vagy a (5,*) (5,2) (5,3) (5,4) (5,5) ,
vagy a (5,*) (5,4) (5,3) (5,2) (5,1) végrehajtás következik be. A (4,*)
alakú állapotból is két végrehajtás indulhat, de mindkettő ugyanabban
az állapotban áll meg: (4,*) (4,2) , (4,*) (4,3) (4,2)
Érdekes végrehajtások indulnak az (1,*) alakú állapotokból. Az
első utasítás hatására vagy az (1,2) , vagy az (1,0) állapotba kerülünk.
Az első esetben a második utasítás elkezdi a d értékét növelni, és mivel
az 1-nek nincs 2-nél nagyobb osztója, ez a folyamat soha nem áll le.
Azt mondjuk, hogy a program a (1,*) (1,2) (1,3) (1,4) … végtelen
végrehajtást futja be, mert végtelen ciklusba esik. A másik esetben
viszont értelmetlenné válik a második utasítás, hiszen azt kell vizsgálni,
hogy a nulla értékű d osztja-e az n értékét, de a nullával való osztás
nem értelmezhető. Ez az utasítás tehát itt illegális, abnormális lépést
eredményez. Ilyenkor a program „abnormálisan” működik tovább,
amelyet az (1,*) (1,0) (1,0) … végtelen végrehajtási sorozattal
modellezünk. Ez azt fejezi ki, mintha a program megpróbálná újra és
újra végrehajtani az illegális lépést, majd mindig visszatér az utolsó
legális állapothoz. Hasonló a helyzet a (0,*) kiinduló állapotokkal is,
amelyekre az első utasítás megkísérli a d értékét (ennek tetszőleges
értékék rögzítsük és jelöljük y-nal) -1-re állítani. A (0,-1) ugyanis nem
tartozik bele az állapottérbe, így az első utasítás a program abnormális
18
1.4. Program fogalma
19
1. Alapfogalmak
20
1.4. Program fogalma
21
1. Programozási alapfogalmak
2
Ismert a megoldásnak ennél gyengébb meghatározása is, amelyik nem
követeli meg a leállást, csak azt, hogy ha a program leáll, akkor egy
megfelelő célállapotban tegye azt.
22
1.5. Megoldás fogalma
23
1. Programozási alapfogalmak
24
1.6. Feladatok
1.6. Feladatok
25
1. Programozási alapfogalmak
1) „Legyen a d értéke 1”
2) „Legyen a d értéke n”
3) „ Legyen a d értéke n-1. Amíg a d nem osztja n-t addig
csökkentsük a d-t.”
Melyik program melyik feladatot oldja meg? Válaszát indokolja!
1.6. Tekintsük az A=(m:ℕ+, n:ℕ+, x:ℤ) állapottéren működő alábbi
programokat!
1) Ha m<n, akkor legyen az x értéke először a (-1)m, majd
adjuk hozzá a (-1)m+1-t, utána a (-1)m+2-t és így tovább,
végül a (-1)n-t!
Ha m=n, akkor legyen az x értéke a (-1)n!
Ha m>n, akkor legyen az x értéke először a (-1)n, majd
adjuk hozzá a (-1)n+1-t, utána a (-1)n+2-t, és így tovább,
végül a (-1)m-t!”
26
1.6. Feladatok
27
2. Specifikáció
28
2.1. Kezdőállapotok osztályozása
(6,8)
(6,3)
n
1 2 3 4 5 6
d
F
(6,3)
{(0, *)} (4,2) (6,2)
n
1 2 3 4 5 6
2.1. Ábra
Egy feladat: Keressük egy összetett szám valódi osztóit.
A feladat például a (6,8) kezdőállapothoz a (6,3) és a (6,2)
célállapotokat rendeli. De ugyanezek a célállapotok tartoznak a (6,6), a
(6,3) vagy a (6,127) kezdőállapotokhoz is, mivel ezek első
komponensében ugyancsak a 6 áll. Tehát az összes (6,*) alakú állapot (a
* itt egy tetszőleges értéket jelöl) ugyanazon csoportba (halmazba)
sorolható az alapján, hogy hozzájuk egyformán a (6,3) és a (6,2)
célállapotokat rendeli a feladat. Úgyis fogalmazhatunk, hogy a feladat a
29
2. Specifikáció
30
2.1. Kezdőállapotok osztályozása
31
2. Specifikáció
32
2.2. Feladatok specifikációja
***
Specifikáljuk most azt a feladatot, amikor egy összetett szám
legnagyobb valódi osztóját keressük. A feladatnak két lényeges adata
van: az adott természetes összetett szám és a keresett valódi osztó.
Mindkét adat természetes szám típusú. Ezt a tényt rögzíti az állapottér.
A = (n:ℕ, d:ℕ)
A két adat közül az első a bemeneti, a második a kimeneti adat. Legyen
n’ a tetszőlegesen kiválasztott bemenő érték. Mivel a feladat nem
értelmes a 0-ra, az 1-re és a prímszámokra; ezért az n’ csak összetett
szám lehet. Az előfeltétel:
Ef = ( n = n’ és n’ összetett szám )
Kiköthetjük, hogy a célállapot első komponensének, azaz a bemeneti
adatnak értéke ne változzon meg, maradjon továbbra is n’; a második
adat pedig legyen az n’ legnagyobb valódi osztója:
Uf = ( Ef és d valódi osztója n-nek és bármelyik olyan k szám
esetén, amelyik nagyobb mint d, a k nem valódi osztója n-nek )
Ha elemi matematikai jelöléssel akarjuk az állításainkat
megfogalmazni, azt is megtehetjük. Az utófeltételben egy osztó
"valódi" voltát egyszerűen kifejezhetjük a d [2..n–1] állítással, hiszen
az n szám valódi osztói csak itt helyezkedhetnek el. (Választhatnánk a
[2..n div 2] intervallumot is, ahol az n div 2 az n felének egészértéke.)
Ha az intervallum egy eleme osztója az n-nek, akkor valódi osztója is.
Alkalmazzuk a d n jelölést arra, hogy a d osztója az n-nek. Ennek
megfelelően például azt az állítást, hogy a "d valódi osztója n-nek" úgy
is írhatjuk, hogy "d [2..n–1] és d n". Aki otthonosan mozog az
elsőrendű logika nyelvében, tömörebben is felírhatja a specifikáció
33
2. Specifikáció
34
2.2. Feladatok specifikációja
35
2. Specifikáció
A = (n:ℕ, l: , d:ℕ)
Ef = ( n=n’ )
Uf = ( n=n’ l=összetett(n) l d=LVO(n) )
Ugyanazt a feladatot többféleképpen is lehet specifikálni. Minél
összetettebb egy probléma, annál változatosabb lehet a leírása. A
következő igen egyszerű példát háromféleképpen specifikáljuk:
növeljünk meg egy egész számot eggyel. Az első két változatban külön
komponens képviseli a bemenő (a változó) és külön a kimenő adatot (b
változó). Az első változat nem tartalmaz semmi különöset a korábbi
specifikációkhoz képest. A bemeneti adat megőrzi a kezdő értékét a
célállapotban is, ezért a kimeneti változó értékének meghatározásánál
mindegy, hogy a bemeneti változó vagy a paraméter változó értékére
hivatkozunk. A második specifikációnál nem követeljük meg, hogy az
a változó ne változzon meg, ezért a b változó értékének
meghatározásánál az a változó kezdő értékét jelző a' paramétert kell
használnunk. Egészen más felfogáson alapul a harmadik specifikáció.
Ez úgy értelmezi a feladatot, hogy van egy adat, amelynek értékét
„helyben” kell megnövelni eggyel. Ilyenkor az állapottér
egykomponensű és az utófeltétel megfogalmazásánál elengedhetetlenül
fontos, hogy a kezdőértéket rögzítő paraméter használata. Ez a
specifikáció rávilágít arra is, hogy egy feladatban nem feltétlenül
különülnek el a bemeneti és a kimeneti adatok.
A = (a:ℤ, b:ℤ) A = (a:ℤ, b:ℤ) A = (a:ℤ)
Ef = ( a=a’ ) Ef = ( a=a’ ) Ef = ( a=a’ )
Uf = ( a=a’ b=a+1 ) Uf = ( b=a’+1 ) Uf = ( a=a’+1 )
Végül egy bemeneti adat nélküli feladat: Adjunk meg egy prímszámot!
A = (p:ℤ)
Ef =( igaz )
Uf =( p egy prímszám ) = ( k [2..p-1] : (k p) )
Ez a specifikáció az összes állapotot kezdőállapotnak tekinti,
amelyek mindegyikéhez az összes prímszámot rendeli. Az előfeltétel
egy azonosan igaz állítás, hiszen semmilyen korlátozást nem kell
bevezetni a p változóra, az kezdetben tetszőleges értéket vehet fel,
amelytől nem függ az eredmény. ( Az utófeltételben a [2..p-1]
intervallum helyett írhatnánk a [2.. n ] intervallumot is.)
36
2.3. Feladatok
2.3. Feladatok
37
3. Strukturált programok
38
programszerkezet segítségével kell egy programmá építeni. A
programtervezés közbülső szakaszában tehát egy struktogramm nem
elemi programokból, hanem megoldandó részfeladatokból építi fel a
programot. Ez azért nem ellentmondás, mert elméletben minden feladat
megoldható egy elemi programmal (lásd 3.3. alfejezet), és ezért csak
nézőpont kérdése, hogy egy részfeladatot feladatnak vagy programnak
tekintünk-e.
A programkészítés során lépésről lépésre jelennek meg az egyre
mélyebben beágyazott programszerkezetek, ami a feladat egyre
finomabb részletezésének eredménye. Ezáltal a program kívülről befelé
haladva, úgynevezett felülről-lefele (top-down) elemzéssel születik. A
feladat finomításának végén a struktogrammban legbelül levő,
szerkezet nélküli egységeknek már magától értetődően megoldható
részfeladatokat kell képviselniük.
39
3. Strukturált programok
40
3.1. Elemi programok
3.1.3. Értékadás
41
3. Strukturált programok
42
3.1. Elemi programok
3.2. Programszerkezetek
3.2.1. Szekvencia
43
3. Strukturált programok
44
3.2. Programszerkezetek
S1
S2
45
3. Strukturált programok
x:=x–y
y:=x+y
x:=y–x
46
3.2. Programszerkezetek
z:=x z:ℤ
x:=y
y:=z
47
3. Strukturált programok
3.2.2. Elágazás
7
A magas szintű programozási nyelvek többsége ettől eltérő módon
definiálja az elágazást. Egyrészt rögzítik az ágak közti sorrendet azzal,
hogy mindig az első olyan ágat hajtják végre, amelyiknek feltételét
kielégíti az aktuális állapot. Másrészt, ha egyik feltétel sem teljesül,
akkor az elágazás az üres programmal azonos. Mi ezt azért nem
vesszük át, hogy a programjaink helyessége nem függjön attól, hogy
egyrészt az elágazás eseteit milyen sorrendben gondoltuk végig,
másrészt, ha egy esetre elfelejtettünk gondolni (egyik feltétel sem
teljesül), akkor a program erre figyelmeztetve hibásan működjön.
48
3.2. Programszerkezetek
f1 ... fn
S1 ... Sn
49
3. Strukturált programok
f f f
S1 S2 S1 S2
50
3.2. Programszerkezetek
3.2.3. Ciklus
51
3. Strukturált programok
cf
S
52
3.2. Programszerkezetek
53
3. Strukturált programok
d n
d:=d–1
54
3.2. Programszerkezetek
a 0
a 0 a 0
a:=a–1 a: ℕ
55
3. Strukturált programok
8
A modellünkben bevezetett feladatok általános leképezések,
amelyekből jóval több van, mint az úgynevezett parciális rekurzív
függvényekből. Említettük már, hogy csak ez utóbbiak megoldásához
lehet olyan programokat készíteni, amelyek algoritmizálhatóak is.
Modellünkben ellenben bármelyik feladathoz kreálható megoldó
program (például a triviális megoldás), ezek között tehát bőven vannak
olyanok, amely nem algoritmizálhatók.
56
3.3. Helyes program, megengedett program
9
A típusműveletek valójában leképezések, ezért általános esetben
relációként írhatók fel. Maga a kifejezés is egy leképezés, amely a
típusműveleteknek, mint leképezéseknek a kompozíciójaként
(összetételeként) áll elő. A fenti meghatározásban említett alaki
szabályok tehát jól definiáltak.
57
3. Strukturált programok
3.4. Feladatok
f1 f1
S1 SKIP f2
f2 f3
S2 SKIP S1 S2 S3 SKIP
f3
S3 SKIP
3.6. Értelmezze az alábbi feladatot! Adja meg néhány végrehajtási
sorozatát a megadott elágazásnak! Mutassa meg, hogy a feladatot
megoldja a program!
58
3.4. Feladatok
A = (x:ℤ, n:ℕ)
Ef = ( x=x’ )
Uf = ( n=abs(x’) )
x≥0 x 0
a:=x a:=-x
59
3. Strukturált programok
f:=1
n 0 hátralevő lépések: n
f:=f n invariáns: f n!=n’!
n:=n-1
z:=1
n 0 hátralevő lépések: n
n páros invariáns: z (x)n=(x’)n’
x,n:=x x, n/2 z,n:=z x, n-1
60
II. RÉSZ
PROGRAMTERVEZÉS MINTÁK ALAPJÁN
61
Ebben a részben egy olyan lépésenkénti finomítást mutatunk be,
amely korábbi megoldások analógiájára épül. Ennek lényege az, hogy
egy feladat megoldását egy ahhoz hasonló, korábban már megoldott
feladat megoldására támaszkodva állítjuk elő. Ennek az analóg
programozásnak egyik fajtája a visszavezetés, amihez a 4. fejezetben
nevezetes minta-megoldásokat (úgynevezett programozási tételeket)
vezetünk majd be, és ezek gyakorlatban történő alkalmazását az 5.
fejezet példáival illusztráljuk. A 6. fejezetben olyan összetett
feladatokat vizsgálunk, amelyek megoldása visszavezetéssel előállított
részprogramokból épül fel.
62
4. Programozási tételek
63
4. Programozási tételek
64
4.1. Analóg programozás
i:=i+1
65
4. Programozási tételek
66
4.1. Analóg programozás
67
4. Programozási tételek
A = (m:ℤ, n:ℤ, l: )
Ef = ( m=m’ n=n’ )
n
Uf = ( Ef s ( g (i) páros ) )
i m
[1..n] ~ [m..n]
+, 0 ~ , igaz
s:=s+v[i]2 ~ l:= l (az g(i) páros)
68
4.1. Analóg programozás
h, i := ,1 i:ℕ
i n
x[i] páros
h := h {x[i]} SKIP
i := i+1
69
4. Programozási tételek
70
4.2. Programozási tétel fogalma
n
f (k ) f (m) f (m 1) ... f (n) kifejezés értékét! (m>n esetén
k m
ennek az értéke definíció szerint a nulla elem). Az előző alfejezet példái
mind ráillenek erre a feladatra.
Ezt az általánosan megfogalmazott feladatot specifikálhatjuk is.
Az állapottérbe a függvény értelmezési tartományának végpontjait és az
eredményt vesszük fel, előfeltétele rögzíti a bemenő adatokat,
utófeltétele pedig az összegzési feladatot írja le.
A = (m:ℤ, n:ℤ, s:H)
Ef = ( m=m’ n=n’ )
n
Uf = ( Ef s f (i) )
i m
A kívánt összeget fokozatosan állítjuk elő. Ehhez végig kell
vezetnünk egy i egész típusú változót a tömb indexein, és minden
lépésben hozzá kell adni a kezdetben nullára beállított s változóhoz az
f(i) értéket. A megoldó program tehát a kezdeti értékadások után (ahol
az s változó értékét nullára, az i változóét m-re állítjuk) egy ciklus,
amely az i változót egyesével növeli egészen n-ig. A ciklus működése
alatt az s változó mindig az f függvény [m..i–1] intervallumon felvett
értékeinek összegét tartalmazza, Kezdetben, amikor az i értéke 1, ez az
érték még nulla, befejezéskor, amikor eléri az n+1 értéket, már a
végleges eredmény.
s, i := 0, m i:ℤ
i n
s := s + f(i)
i := i + 1
71
4. Programozási tételek
72
4.3. Nevezetes minták
73
4. Programozási tételek
1. Összegzés
Az összegzés programozási tételét az előző alfejezetekben
alaposan elemeztük. Most csak a teljesség igénye miatt ismételjük meg.
Feladat: Adott az egész számok egy [m..n] intervalluma és egy
f:[m..n] H függvény. A H halmaz elemein értelmezett egy asszociatív,
baloldali nulla elemmel rendelkező művelet (nevezzük összeadásnak és
jelölje ezt a +). Határozzuk meg az f függvény [m..n]-en felvett
n
értékeinek az összegét, azaz a f(k) kifejezés értékét! (m>n esetén
k m
ennek az értéke definíció szerint a nulla elem).
Specifikáció:
A = (m:ℤ, n:ℤ, s:H)
Ef = ( m=m’ n=n’ )
n
Uf = ( Ef s f(i) )
i m
Algoritmus:
s, i := 0, m i:ℤ
i n
s := s + f(i)
i := i + 1
74
4.3. Nevezetes minták
2. Számlálás
Gondoljunk arra a feladatra, amikor egy 20 fős osztályban azon
diákok számát kell megadnunk, akik ötöst kaptak történelemből. A
diákokat 1-től 20-ig megsorszámozzuk, és a történelem jegyeiket egy
1-től 20-ig indexelt t tömbben tároljuk: az i-edik diák osztályzata a t[i].
Definiálunk egy :[1..20] logikai függvényt, amely azokhoz a
diákokhoz rendel igaz értéket, akik ötöst kaptak, más szóval (i) =
(t[i]=5). Azt kell meghatároznunk, hogy a által felvett értékek között
hány igaz érték szerepel. Ilyenkor valójában 0 illetve 1 értékeket
összegzünk attól függően, hogy a logikai kifejezés hamis vagy igaz. A
számlálás tehát az összegzés speciális eseteként fogható fel, amelyben
az s:=s+1 értékadást csak a (i) feltétel teljesülése esetén kell
végrehajtani.
Feladat: Adott az egész számok egy [m..n] intervalluma és egy
:[m..n] feltétel. Határozzuk meg, hogy az [m..n] intervallumon a
feltétel hányszor veszi fel az igaz értéket! (Ha m>n, akkor egyszer
sem.)
Specifikáció:
A = (m:ℤ, n:ℤ, c:ℕ)
Ef = ( m=m’ n=n’ )
n
Uf = ( Ef c 1)
i m
β (i)
Algoritmus:
c, i := 0, m i:ℤ
i n
(i)
c := c+1 SKIP
i := i + 1
75
4. Programozási tételek
3. Maximum kiválasztás
Ha arra vagyunk kíváncsiak, hogy egy 20 fős osztályban kinek
van a legjobb jegye történelemből, akkor ehhez a diákokat 1-től 20-ig
megsorszámozzuk, és a történelem jegyeiket egy 1-től 20-ig indexelt t
tömbben tároljuk: az i-edik diák osztályzata a t[i]. Ez a tömb tekinthető
egy f:[1..20] ℕ függvénynek (f(i)=t[i]), amely értékei között keressük
a legnagyobbat.
Feladat: Adott az egész számok egy [m..n] intervalluma és egy
f:[m..n] H függvény. A H halmaz elemein értelmezett egy teljes
rendezési reláció. Határozzuk meg, hogy az f függvény hol veszi fel az
[m..n] nem üres intervallumon a legnagyobb értéket, és mondjuk meg,
mekkora ez a maximális érték!
Specifikáció:
A = (m:ℤ, n:ℤ, ind:ℤ, max:H)
Ef = ( m=m’ n=n’ n m )
Uf = ( Ef ind [m..n] max=f(ind) i [m..n]: max f(i) ) =
másképpen jelölve, illetve rövidített jelölést használva:
n
= ( Ef ind [m..n] max = f(ind) = max f(i) )
i m
n
= ( Ef max,ind= max f(i) )
i m
Algoritmus:
max, ind, i := f(m), m, m+1 i:ℤ
i n
max<f(i)
max, ind := f(i), i SKIP
i := i + 1
Az ind változó értékadásai törölhetők az algoritmusból, ha nincs
szükség az ind-re.
76
4.3. Nevezetes minták
4. Feltételes maximumkeresés
A maximum kiválasztást sokszor úgy kell elvégezni, hogy a
vizsgált elemek közül csak azokat vesszük figyelembe, amelyek eleget
tesznek egy adott feltételnek. Például, egymás utáni napi
átlaghőmérsékletek között azt a legmelegebb hőmérsékletet keressük,
amelyik fagypont alatti.
Feladat: Adott az egész számok egy [m..n] intervalluma, egy
f:[m..n] H függvény és egy :[m..n] feltétel. A H halmaz elemein
értelmezett egy teljes rendezési reláció. Határozzuk meg, hogy az
[m..n] intervallum feltételt kielégítő elemei közül az f függvény hol
veszi fel a legnagyobb értéket, és mondjuk meg, mekkora ez az érték!
(Lehet, hogy egyáltalán nincs feltételt kielégítő elem az [m..n]
intervallumban vagy m>n.)
Specifikáció:
A = (m:ℤ, n:ℤ, l: , ind:ℤ, max:H)
Ef = ( m=m’ n=n’ )
Uf = ( Ef l = i [m..n]: (i) l ind [m..n] max=f(ind)
(ind) i [m..n]: (i) max f(i) )
Itt is bevezetünk rövid jelölést.
Uf = ( Ef l,max,ind) = )
m
i
a
n
(
m
i
)
x
f
(
i
)
Algoritmus:
l, i := hamis, m i:ℤ
i n
(i) l (i) l (i)
SKIP max< f(i) l, max, ind :=
max, ind := f(i), i SKIP igaz, f(i), i
i := i + 1
77
4. Programozási tételek
Algoritmus:
ind := m
(ind)
ind := ind + 1
78
4.3. Nevezetes minták
10
A lineáris keresés algoritmusának más változatai is ismertek:
l, ind := hamis, m–1 l, ind := hamis, m ind := m
l ind<n l ind n ind n (ind)
ind := ind+1 (ind) ind := ind+1
l := (ind) l:=igaz ind := ind+1 l := ind n
79
4. Programozási tételek
7. Logaritmikus keresés
Speciális feltételek megléte esetén a lineáris keresésnél jóval
gyorsabb kereső algoritmust használhatunk. Amíg a lineáris keresés
egy h elemű intervallumot legrosszabb esetben h lépésben tud
átvizsgálni (a lépések száma az elemszám lineáris függvénye), addig a
most bemutatásra kerülő keresésnek legrosszabb esetben ehhez csak
log2h lépésre van szüksége.
A logaritmikus kereséssel növekedően rendezett értékek között
kereshetünk egy adott értéket. Ennek során a keresési intervallumot
felezzük el, és a felező pontnál levő értéket összevetjük a keresettel. Ha
megegyeznek, akkor megtaláltuk a keresett értéket, ha a vizsgált érték
nagyobb a keresett értéknél, akkor a keresett érték (ha egyáltalán ott
van az értékek között) a keresési intervallum első felében található, ha
kisebb, akkor a második felében, azaz a keresés intervalluma
elfelezhető.
Feladat: Adott az egész számok egy [m..n] intervalluma és egy
f:Z H függvény, amelyik az [m..n] intervallumon monoton növekvő.
(A H halmaz elemei között értelmezett egy rendezési reláció.)
Keressünk meg a függvény [m..n] intervallumon felvett értékei között
egy adott értéket!
Specifikáció:
A = (m:ℤ, n:ℤ, h:H, l: , ind:ℤ)
Ef = ( m=m’ n=n’ h=h’ j [m..n-1]: f(j) f(j+1) )
Uf = ( Ef l=( j [m..n]:f(j)=h) l (ind [m..n] f(ind)=h))
Algoritmus:
ah,fh,l := m,n,hamis ah, fh:ℤ
l ah fh
ind := (ah+fh) div 2
f(ind)>h f(ind)<h f(ind)=h
fh := ind-1 ah := ind+1 l := igaz
80
4.3. Nevezetes minták
81
4. Programozási tételek
i := m
i n rövidebben i = m .. n
feldolgozás feldolgozás
i := i + 1
82
4.3. Nevezetes minták
83
4. Programozási tételek
4.4. Feladatok
84
5. Visszavezetés
85
5. Visszavezetés
m..n ~ a+1..b
s ~ db
i ~ j
(i) ~ f(j)*f(j-1)<0
db := 0
j = a+1 .. b j:ℤ
f(j) * f(j-1) < 0
db := db+1 SKIP
86
5.2. Általános visszavezetés
m..n ~ m+1..n-1
(i) ~ f(i)=(f(i–1)+ f(i+1))/2
ind ~ ki
l, i := hamis, m+1
l i n-1 i:ℤ
l, ki := f(i)=(f(i–1)+ f(i+1))/2, i
i := i+1
87
5. Visszavezetés
88
5.3. Alteres visszavezetés
m..n ~ a..b
f(i) ~ g(i)
89
5. Visszavezetés
l, i := hamis, a i:ℤ
l i b
l := g(i)=0
i := i+1
90
5.3. Alteres visszavezetés
A = (n:ℕ, s:ℕ)
Ef = ( n=n’ )
n div2
Uf = ( Ef s 1)
i 2
in
s := 0
i = 1 .. n div 2 i:ℤ
i n
s := s+1 SKIP
91
5. Visszavezetés
m..n ~ a..b
f(i) ~ g(i)
(i) ~ 2 g(i)
l: = hamis
i = a .. b i:ℤ
2 g(i) l 2 g(i) l 2 g(i)
SKIP max<g(i) l, max, ind :=
max, ind := g(i), i SKIP igaz, g(i), i
92
5.4. Paraméteres visszavezetés
l:= hamis
i = a .. b i:ℤ
k g(i) l k g(i) l k g(i)
SKIP max<g(i) l, max, ind :=
max, ind := g(i), i SKIP igaz, g(i), i
93
5. Visszavezetés
m..n ~ 0..n-1
(i) ~ x[i] = b[i mod m]
s := 0
i = 0 .. n-1 i:ℕ
x[i] = b[i mod m]
s := s+1 SKIP
94
5.5. Visszavezetési trükkök
11
Itt hívjuk fel a figyelmet az olyan feladatokra is, amelyekben egy
intervallum pontjai között keressük a legnagyobb adott tulajdonságút.
Ilyen például a legnagyobb közös osztó keresése. Ezeket a feladatokat
nem érdemes feltételes maximumkeresésre visszavezetni, tökéletesen
megfelel az intervallumban egy fordított irányú kiválasztás vagy
lineáris keresés is.
95
5. Visszavezetés
96
5.5. Visszavezetési trükkök
97
5. Visszavezetés
98
5.5. Visszavezetési trükkök
n
Uf = ( Ef s f(i) )
i m
(i)
s: = 0
i = m .. n i:ℤ
(i)
s := s + f(i) SKIP
99
5. Visszavezetés
m..n ~ 2..n
y ~ (max, min)
e0 ~ (x[1], x[1])
h1(i, f1(i–1)) ~ max( f1(i–1), x[i] )
h2(i, f2(i–1)) ~ min( f2(i–1), x[i] )
100
5.6. Rekurzív függvény kiszámítása
k 1
101
5. Visszavezetés
f: [0..n] ℕ
f(0) = 0
f(i) = f(i–1)*b+x[i] i [1..n]
Ekkor a feladat visszavezethető a rekurzív függvény
kiszámításának tételére.
m .. n ~ 1..n
y ~ s
e0 ~ 0
h(i, f(i–1)) ~ f(i–1)*b+x[i]
s := 0
i = 1 .. n i:ℕ
s := s*b+x[i]
12
Ezt az algoritmust szokták Horner algoritmusnak is nevezni, mert az
alábbi Hornerről elnevezett séma alapján számolja ki egy természetes
számnak az értékét a szám számjegyei alapján:
n
x[k ] b n k
(...(( x[1] b x[2]) b x[3])...) b x[n]
k 1
102
5.6. Rekurzív függvény kiszámítása
103
5. Visszavezetés
m .. n ~ 1..n
y ~ z,c
e0 ~ *,0
h1(i, f(i–1))[n–i+1] ~ (x[n–i+1]+y[n–i+1]+f2(i–1)) mod b
h1(i, f(i–1))[n–i+2..n]~ f1(i–1)[n–i+2..n]
h2(i, f(i–1)) ~ (x[n–i+1]+y[n–i+1]+f2(i–1)) div b
c := 0
i = 1 .. n i:ℕ
z[n–i+1] := (x[n–i+1]+y[n–i+1]+c) mod b
c := (x[n–i+1]+y[n–i+1]+c) div b
104
5.7. Feladatok
5.7. Feladatok
105
6. Többszörös visszavezetés
106
bemutatjuk, hogyan alkalmazható többszörösen a visszavezetés
technikája az összetett feladatok megoldásánál, és az így kapott
programot a feladat részfeladatai mentén hogyan tördeljük
alprogramokra. A harmadik alfejezetben áttekintjük azokat a program-
átalakító szabályokat, amelyek alkalmazása kényelmesebbé teszi a
programkészítést, hatékonyabbá az elkészített programot. Az utolsó
alfejezetben egy különleges program-átalakítást mutatunk arra az
esetre, amikor egy ciklusban szereplő részfeladat eredménye rekurzív
függvénnyel számolható ki.
107
6. Többszörös visszavezetés
6.1. Alprogram
108
6.1. Alprogram
109
6. Többszörös visszavezetés
13
A függvényszerű hívással elindított alprogramot a konkrét
programozási nyelvek függvénynek, az önálló utasítással (értékadással)
meghívott alprogramot eljárásnak nevezik.
110
6.2. Beágyazott visszavezetés
111
6. Többszörös visszavezetés
színjeles :[1..n]
színjeles(i) = j [1..m]: t[i,j]=5
Ennek segítségével könnyen felírható a feladat utófeltétele: az l
pontosan akkor igaz, ha van olyan diák, azaz 1 és n közé eső egész
szám, amelyre a színjeles feltétel igazat ad.
Uf = ( Ef l = i [1..n]: színjeles(i) )
Ez a feladat visszavezethető a lineáris keresés programozási
tételére. A lineáris keresés specifikációs jelölésénél most csak a logikai
komponens van eredményként feltüntetve, hiszen csak ennek megadása
a feladat.
m..n ~ 1..n
(i) ~ színjeles(i)
112
6.2. Beágyazott visszavezetés
113
6. Többszörös visszavezetés
i := 1
színjeles(i)
i := i+1
114
6.2. Beágyazott visszavezetés
i, l := 1, színjeles(1) l: i, l := 0, hamis l:
l l
i := i+1 i := i+1
l := színjeles(i) l := színjeles(i)
115
6. Többszörös visszavezetés
116
6.2. Beágyazott visszavezetés
117
6. Többszörös visszavezetés
Lássuk a specifikációt!
A = (t:ℕn×m, s:ℕ)
Ef = ( t=t’ )
n
Uf = ( Ef s= 1)
i 1
színjeles( i )
ahol
színjeles :[1..n]
színjeles(i) = j [1..m]: t[i,j]=5
A feladatot tehát egy számlálásra vezetjük vissza, ahol az
intervallum az [1..n], a (i) feltétel a színjeles(i).
s:=0
i = 1 .. n i:ℕ
színjeles(i)
s := s+1 SKIP
118
6.2. Beágyazott visszavezetés
A = (t:ℕn×m, ind:ℕ )
Ef = ( t=t’ n>0 m>0 )
n
Uf = ( Ef négyesdb(ind) = max négyesdb (i) )
i 1
A feladatot egy maximum kiválasztásra vezetjük vissza, ahol az
intervallum az [1..n], és az f(i) kifejezést a négyesdb(i) helyettesíti.
119
6. Többszörös visszavezetés
120
6.2. Beágyazott visszavezetés
l := hamis
i =1 .. n i:ℕ
jó(i) l jó(i) l jó(i)
SKIP max<összeg(i) l, max, ind :=
max, ind := SKIP igaz, összeg(i), i max:ℕ
összeg(i), i
l
átl := max/m SKIP
u:=jó(i) össz:=összeg(i)
u,j := igaz,1 össz := 0
u j m j:ℕ j = 1..m j:ℕ
u := t[i,j]=5 t[i,j]=4 össz := össz +t[i,j]
j := j+1
121
6. Többszörös visszavezetés
l := hamis
i =1..n i:ℕ
u := jó(i) u:
u l u l u
SKIP össz := összeg(i) l, max, ind := össz,max:ℕ
max<össz igaz, összeg(i), i
122
6.2. Beágyazott visszavezetés
l, i := hamis, 1 i:ℕ
l i k–1
l, j := igaz, k j:ℕ
l j n
l := v[i] v[j]
j := j + 1
i := i + 1
123
6. Többszörös visszavezetés
k 1 n
Uf = ( Ef l = k>1 max v[i] max v[ j ] )
i 1 j k
Az utófeltételből kiolvasható, hogy ha k 2, akkor a k
vizsgálatával együtt n+1 összehasonlítást kell végezni, k=1 esetén csak
egyet.
k=1
max1 := v[1] max1:ℤ
i = 2..k–1 i:ℕ
max1<v[i]
max1 := v[i] SKIP
max2 := v[k] max2:ℤ
j = k..n j:ℕ
max2<v[j]
max2 := v[j] SKIP
l := hamis l := max1 max2
124
6.2. Beágyazott visszavezetés
125
6. Többszörös visszavezetés
126
6.2. Beágyazott visszavezetés
127
6. Többszörös visszavezetés
m, k:=g(i)
m, k:=táv(i,1), 1
j = 2 .. i-1 j:ℕ
s := táv(i,j) s:ℝ
s>m
m, k:=s, j SKIP
14
Ez a megfordítás bizonyításra szorul. A k=(i–1)(i–2)/2+j (j<i) miatt
(i-1)(i-2)<2k≤i(i–1), amiből (i–2)< 2k <i összefüggést kapjuk. Ebből
látszik, hogy a 2k az (i–1) környezetébe esik: a 2k (felső
egészrész) vagy i, vagy i–1. Ha 2k> 2k ( 2k –1), akkor 2k =i–
1, ugyanis az ellenkezőjét ( 2k =i) feltéve a 2k>i(i–1) összefüggést
kapnánk, ami ellentmond az első megállapításnak. Ha viszont 2k≤ 2k
( 2k –1), akkor i= 2k , ugyanis az ellenkezőjét ( 2k =i–1)
feltéve a 2k≤(i–1)(i–2) összefüggést kapnánk, ami ugyancsak
ellentmondás.
128
6.2. Beágyazott visszavezetés
n ( n 1) / 2
Uf = ( Ef max, knd = max táv(h(k)) (ind,jnd)=h(knd) )
k 1
h:[1..n(n–1)/2] ℕ×ℕ
6.3. Program-átalakítások
129
6. Többszörös visszavezetés
130
6.3. Program-átalakítások
y1:=x1 y1:=x1
… …
yn-1:=xn-1 yn-1:=xn-1
x1:=F1(x1, x2, … , xn-1, xn) vagy x1:=F1(y1, y2, … , yn-1, xn)
x2:=F2(y1, x2, … , xn-1, xn) x2:=F2(y1, y2, … , yn-1, xn)
… …
xn-1:=Fn-1(y1, y2, … , yn-1, xn) xn-1:=Fn-1(y1, y2, … , yn-1, xn)
xn:=Fn(y1, y2, … , yn-1, xn) xn:=Fn(y1, y2, … , yn-1, xn)
131
6. Többszörös visszavezetés
S11 S11
i = m .. n …
S1 Sk1
… i =m..n
Sk1 helyett S1
i = m..n …
Sk Sk
132
6.3. Program-átalakítások
i = 0..10 S1
i=0 helyett i = 1 .. 10
S1 S2 S2
pont:[1..n] ℝ
m m m
pont(i) = ( t[i, j ] - max t[i, j ] - min t[i, j ] )/(m–2)
j 1 j 1
i 1
133
6. Többszörös visszavezetés
134
6.3. Program-átalakítások
max, p := inicializálás
135
6. Többszörös visszavezetés
p[1] := pont(1)
max := p[1]
i = 2..n i:ℕ
p[i]:=pont(i)
p[i]>max
max := p[i] SKIP
136
6.4. Rekurzív függvény kibontása
137
6. Többszörös visszavezetés
s := be[1]–ki[1] s:ℕ
max, ind := s, 1 max:ℕ
i = 2 .. n i:ℕ
s := s+be[i]–ki[i]
max<s
max, ind := s, i SKIP
138
6.4. Rekurzív függvény kibontása
S1
i = m .. n
S2(f(i))
S1
i = m .. n
s1:=f(i)
S2(s1)
15
Mindegyik programozási tétel ciklusához választhatunk egy
invariáns állítást (lásd 3.4. alfejezet), amely segítségével a tétel és az
abból származtatott programok helyessége is bizonyítható. Itt
tulajdonképpen ennek az invariánsnak a kiegészítéséről van szó. Ezt
követően úgy kell módosítani a programot, hogy annak helyességét
ezzel a bővített ciklus-invariánssal be lehessen látni.
139
6. Többszörös visszavezetés
S1
i = m .. n
s1, … ,sk := f(i), … , f(i–k+1)
S2(s1)
140
6.4. Rekurzív függvény kibontása
f:[0..n] ℕ
f(0) = 0
f(i 1) 1 ha x[i ] 0
f(i) = i [1..n]
0 ha x[i ] 0
A feladat megoldásához elég ennek a függvénynek megtalálni a
maximumát. Ahol ez a függvény a maximális értékét felveszi, ott van a
leghosszabb sziget végpontja, amelyből a szigethosszának ismeretében
a sziget kezdőpontja is könnyen meghatározható. (Megjegyezzük, hogy
ha a rekurzív függvényt nem a vektor elejéről hátrafelé haladva
képeznénk, hanem a végéről az eleje felé, akkor egy hátulról előre
haladó maximum kiválasztással közvetlenül a leghosszabb sziget elejét
találnánk meg.)
A = (x:ℕn, hossz:ℕ, kezd:ℕ, végz:ℕ )
Ef = ( x=x’ )
n
Uf = ( Ef hossz,végz = max f (i ) kezd=végz–hossz+1 )
i 1
A feladat egy maximum kiválasztás és egy értékadás
szekvenciájaként oldható meg. A nem-megengedett f(i) kifejezéseket
egy segédváltozó segítségével kiemeltük.
h := f(1) h:ℕ
hossz, ind := h, 1
i = 2 .. n i:ℕ
h := f(i)
hossz<h
hossz, ind := h, i SKIP
kezd := végz–hossz+1
141
6. Többszörös visszavezetés
x[1]>0
h := 1 h := 0 h:ℕ
hossz, ind := h, 1
i = 2..n i:ℕ
x[i]>0
h := h+1 h := 0
hossz<h
hossz, ind := h, i SKIP
kezd := végz–hossz+1
142
6.4. Rekurzív függvény kibontása
143
6. Többszörös visszavezetés
i := i+1 i := i+1
i, l, j := 1, igaz, 1 i,j:ℕ
l i m
l := hamis
l j n
l := szöveg[i]=tábla[j]
j := j+1
i := i+1
144
6.4. Rekurzív függvény kibontása
145
6. Többszörös visszavezetés
i := 0 i:ℕ
j = 1 .. n j:ℕ
tábla[j]=szöveg[i+1]
i := i+1 SKIP
l := i=m
146
6.5. Feladatok
6.5. Feladatok
147
6. Moduláris programtervezés
148
III. RÉSZ
TÍPUSKÖZPONTÚ PROGRAMTERVEZÉS
149
7. Típus
150
7. Típus
16
A műveletek implementációja a reprezentációra épül, ezért sokszor
az implementáció fogalmába a reprezentációt is beleértik, azaz típus-
implementáció alatt a teljes típus-megvalósításra gondolnak.
151
7. Típus
152
7.1. A típus fogalma
153
7. Típus
154
7.1. A típus fogalma
155
7. Típus
156
7.1. A típus fogalma
157
7. Típus
h :=
i = 1 .. n
h := h {a[i]}
s := h
158
7.2. Típus-specifikációt megvalósító típus
h= 6 8
2 5
1 2. 3. 4. 5. 6. 7. 8. 9. 100.
v= hamis igaz hamis hamis igaz igaz hamis igaz hamis . . . hamis
db=4
7.1. Ábra
Egy halmaz és azt reprezentáló logikai tömb
A logikai tömbben az e-edik elem akkor és csak akkor legyen
igaz értékű, ha a tömb által reprezentált halmaz tartalmazza az e-t.
Vegyük még hozzá ehhez a tömbhöz külön azt az értéket, amely
mindig azt mutatja, hogy hány igaz érték van a tömbben (ez éppen a
reprezentált halmaz elemszáma). Ez a kapcsolat a logikai tömb és e
darabszám között a típus-invariáns.
Itt a reprezentációs függvény egy (logikai tömb, darabszám)
párhoz rendeli azon egész számoknak a halmazát, amely a logikai tömb
azon indexeit tartalmazza, ahol a tömbben igaz értéket tárolunk.
Nyilvánvaló, hogy minden (tömb, darabszám) pár kölcsönösen
egyértelműen reprezentál egy halmazt.
Térjünk most rá a típusműveletek implementálására. Az egyes
műveleteket először átfogalmazzuk úgy, hogy azok ne közvetlenül a
halmazra, hanem a halmazt reprezentáló tömb-darabszám párra
legyenek megfogalmazva. Például a h:= feladatnak az a feladat
159
7. Típus
h :=
db := 0
i = 1 .. 100
v[i] := hamis
160
7.2. Típus-specifikációt megvalósító típus
típusértékek típusműveletek
típus- betesz
specifikáció 2
{1..100}
h:=h {e}
1 és 100 közé eső egész legyen üres
számokat tartalmazó
halmazok h :=
elemszáma
s:= h
{1..100}
: 100
ℕ 2
100
(v,db) = v[i]
i 1
100 v: 100, db:ℕ,
I(v,db) =( db= 1) e: ℕ, l: , s:ℕ
i 1
v[i ]
típus betesz
megvalósítás
100
ℕ v[e]=hamis
logikai tömb és egy szám
v[e]:=igaz SKIP
db:=db+1
legyen üres
db := 0
i [1..100]: v[i]:=hamis
elemszáma
s:=db
7.2. Ábra
Halmaz típusa
161
7. Típus
h:=h {e}
v[e]=hamis
v[e] := igaz SKIP
db := db+1
s:= h
s := db
162
7.3. Absztrakt típus
17
Ez magyarázza, hogy miért használják sokszor az absztrakt típus
elnevezést magára a típus-specifikációra. Könyvünkben azonban az
absztrakt típus tágabb fogalom, mint egy típus-specifikáció, hiszen
tartalmazhat olyan elemeket is (például reprezentáció vagy
típusművelet hatása, esetleg a részletes programja), amelyek nem részei
a típus-specifikációnak.
18
Egy típus-specifikációt nemcsak a könyvünkben alkalmazott,
úgynevezett elő- utófeltételes módszerrel adhatunk meg közvetlen
módon. Más leírások is léteznek, ilyen például az úgynevezett algebrai
specifikáció is. Ezek tárgyalásával itt nem foglalkozunk.
163
7. Típus
164
7.3. Absztrakt típus
b :=
i = 1 .. n
b := b {t[i]}
e := MAX(b)
165
7. Típus
166
7.3. Absztrakt típus
típusértékek típusműveletek
típus legfeljebb 100 különböző legyen üres
specifikáció egész számot tartalmazó
Zsák betesz
maximum
{1..100}×ℕ {1..100}×ℕ
:2 Zsák b: 2 ,
I(b)= e1, e2 b: e1.1 e:{1..100}
e2.1
absztrakt {1..100}
×ℕ
2 -beli b:=
típus
számpárok halmaza b:= b {e}
e:=MAX(b)
{1..100}×ℕ
: ℕ100 2
100 v: ℕ100, e:{1..100}
ρ (v) {(i, v[i])}
i 1
konkrét típus ℕ100 e [1..100]: v[e]:=0
előfordulás számok v[e]:=v[e]+1
tömbje
100
max, e : max v[i]
i 1
7.3. Ábra
Zsák absztrakt típusa és annak megvalósítása
167
7. Típus
el! Ügyeljünk arra is, hogy a szavakat továbbra is vesszők válasszák el.
(Feltehetjük, hogy a szavak 30 karakternél nem hosszabbak.)
Ennek a feladatnak a megoldásához egy vermet használunk. A v
verem egy olyan gyűjtemény, amelyből a korábban beletett elemeket a
betevésük sorrendjével ellentétes sorrendben lehet kiolvasni. Egy
veremre öt műveletet vezetünk be. Egy elemnek a verembe rakása
(v:=push(v,e)), a legutoljára betett elem kiolvasása (top(v)), a
legutoljára betett elem elhagyása (v:=pop(v)), annak lekérdezése, hogy
a verem üres-e (empty(v)) illetve a verem kiürítése (v:= ). Tegyük be
sorban egymás után a verembe a feldolgozandó szöveg karaktereit, de
valahányszor a szövegben egy vesszőhöz érünk, akkor ürítsük ki a
vermet, és írjuk át a veremből kivett karaktereket az eredmény-tömb
soron következő helyeire, amelyek után írjunk még oda egy vesszőt is.
A feldolgozás legvégén tegyük az új szöveg végére a veremben maradt
karaktereket.
A fenti leírásban körvonalazódik ugyan a veremtípus
specifikációja, de ennek pontos megadása közvetett módon
szemléletesebb. (7.4.ábra)
Ábrázoljuk a legfeljebb 30 karaktert tartalmazó vermeket
legfeljebb 30 elemű, karaktereket tartalmazó sorozatokkal. Ha s a
vermet reprezentáló s1 , … , s s sorozat, akkor ezen a verem
műveletei könnyen definiálhatóak. Ezt az absztrakt típust kell ezek után
megvalósítanunk. Reprezentáljuk a vermet leíró legfeljebb 30 hosszú
karaktersorozatokat egy 30 elemű, karaktereket tartalmazó tömbbel,
valamint egy természetes számmal, amely azt mutatja, hogy a tömb
első hány eleme alkotja a vermet leíró sorozatot. Ha ez a szám nulla,
akkor a verem üres. Ha ezt a számot nullára állítjuk, akkor ezzel a
vermet kiürítettük. A verembe egy új elemet úgy teszünk be, hogy
megnöveljük ezt a számlálót, és a tömbben a számláló által mutatott
helyre beírjuk az új elemet. A veremből való kivétel a tömb-számláló
által mutatott elemének kiolvasását, majd a számláló csökkentését
jelenti. A reprezentációs függvény nem kölcsönösen egyértelmű, hiszen
a reprezentáció szempontjából közömbös, hogy a t tömbben milyen
karakterek találhatók az m-nél nagyobb indexű helyeken.
168
7.3. Absztrakt típus
kivesz: v := pop(v)
olvas: e := top(v)
üres-e: l := empty(v)
legyen üres: v :=
*
I(s)= s 100 s: , e: , l:
absztrakt típus legfeljebb 30 hosszú s := s, e
*
-beli sorozat
s := s1, … ,s s -1
e := s s
l := s=
s :=
: 30
ℕ *
m t: 30
, m: ℕ, e: , l:
(t,m) = t[i ]
i 1
konkrét típus ℕ
30
t[m+1], m :=e, m+1
tömb-szám pár m := m-1
e := t[m]
l := (m=0)
m := 0
7.4. Ábra
Verem absztrakt típusa és annak megvalósítása
Az eredeti feladatot egy rekurzív függvény segítségével
specifikáljuk.
169
7. Típus
A = (a: n, b: n)
Ef = ( a=a’ )
Uf = ( Ef b=f1(n+1) )
n
Az f:[0..n+1] ×ℕ×Verem egy három-értékű függvény.
Tetszőleges i [0..n] index esetén az f(i)-nek három komponense van:
f1(i) az n hosszúságú eredmény tömb; f2(i) ennek egy olyan indexe,
amely azt mutatja, hogy az eredmény tömb első hány elemét állítottuk
már elő eddig; és végül az f3(i), amely a feldolgozáshoz használt verem.
A rekurzív definícióban sokszor kell az f(i-1) komponenseit
használnunk, amelyekre az átláthatóság végett rendre b, k, és s névvel
hivatkozunk majd. (Célszerű lesz később ugyanezen neveket választani
segédváltozóknak a rekurzív függvény kiszámításának programozási
tételében.) Az egyszerűbb jelülés érdekében az <s> szimbólummal
hivatkozunk a veremben levő karakterek sorozatára (ennek első eleme a
verem teteje, és így tovább), az s szimbólum pedig a verembeli
elemek számára utal majd.
f(0)=( b, 0, )
i [1..n]:
(b, k , push(s , a[i] )) ha a[i] ' , '
f(i)
(b[1..k ] s ', ', k s 1, ) ha a[i] ' , '
A rekurzív képletnek az első sora azt írja le, hogy egy karaktert, ami
nem vessző, a verembe kell betenni, a tömb és az index komponensek
ilyenkor nem változnak; a második sora pedig azt, hogy vessző esetén a
verem tartalmát a b tömb k-adik indexe utáni helyeire kell átmásolni
majd utána írni még a vesszőt is. Ilyenkor új értéket kap a k index is, a
verem pedig kiürül.
Mivel a legutolsó szót nem zárja le vessző, ezért az a tömb
végére (n-hez) érve a legutolsó szó még a veremben marad. Ezért
definiáljuk a rekurzív függvényt az n+1-edik helyen, amely a verembe
(f3(n), amit továbbra s jelöl) levő elemeket átmásolja az
eredménytömbbe (b-vel jelölt f3(n), amelynek első k, azaz f2(n) eleme
után kell az újabb karaktereket írni).
f(n 1) b[1..k ] s ,k s,
A rekurzív függvény kiszámításának programozási tételét
felhasználva kapjuk a megoldó programot. Hatékonysági okból a
függvény n+1-dik helyen történő kiszámolását kiemeljük a ciklusból,
170
7.3. Absztrakt típus
k, s := 0,
i = 1 .. n
a[i]=’,’
empty(s) s:= push(s, a[i])
b[k+1], k:=top(s), k+1
s:=pop(s)
b[k+1], k:= ’,’ , k+1
empty(s)
b[k+1], k:=top(s), k+1
s:=pop(s)
171
7. Típus
172
7.4. Típusok közötti kapcsolatok
173
7. Típus
19
Az adatszerkezeteket középpontba állító vizsgálatoknál célszerű a
típus szerkezetének definiálásánál egy típusértéket helyettesítő
174
7.4. Típusok közötti kapcsolatok
175
7. Típus
alt( m1:T1; … ; mn:Tn ) azt jelöli, hogy T egy alternatív (unió) típus,
azaz minden típusértékét egy T1 … Tn-beli elem reprezentál. Ha t
egy ilyen T típusnak egy értéke (alternatív típusú objektum), akkor a
t.mi logikai érték abban az esetben igaz, ha t-t éppen a Ti típus egyik
értéke reprezentálja. Példaként tekintsük azt a típust, amely egy
fogorvosi rendelőben egy páciensre jellemző adatokat foglalja össze.
Mivel egy páciens lehet felnőtt és gyerek is, akiket fogorvosi
szempontból meg kell különböztetnünk, hiszen például a gyerekeknél
külön kell nyilván tartani a tejfogakat: Páciens=alt(f:Felnőtt;g:Gyerek).
Természetesen egy ilyen példa akkor teljes, ha definiáljuk a Felnőtt és
a Gyerek típusokat is. Ezek rekord típusok lesznek: Felnőtt=rec(nev:
*
, fog:ℕ, kor:ℕ), Gyerek=rec(nev: *, fog:ℕ, tej:ℕ, kor:ℕ). Ha p egy
Páciens típusú objektum, akkor a p.f állítással dönthetjük el, hogy a p
páciens felnőtt-e; a p.fog:=p.fog-1 értékadás pedig azt fejezi ki, hogy
kihúzták a p egyik fogát.
Ha egy típus tetszőleges értékét sok azonos típusú elemi érték
reprezentálja, akkor azt iterált (felsorolható, gyűjtemény) típusnak is
szokták nevezni. Az elnevezés onnan származik, hogy a típusértéket
reprezentáló elemi értékeket azok egymáshoz való viszonyától függő
módon sorban egymás után fel lehet sorolni. Az elemi értékek
kapcsolata a reprezentált típusérték belső szerkezetét határozza meg. Ez
lehet olyan, amikor nincs kijelölve az elemi értékek között sorrendiség;
a típusértéket elemi értékek közönséges halmaza reprezentálja. Ez a
halmaz lehet multiplicitásos halmaz (zsák) is, amelyben megengedjük
ugyanazon elem többszöri előfordulását. Lehet a reprezentáló
elemsokaság egy sorozat is, amely egyértelmű rákövetkezési
kapcsolatot jelöl ki az elemek között, de lehet egy olyan irányított gráf,
amelynek csúcsai az elemi értékek, az azok közötti élek pedig sajátos,
egyedi rákövetkezési relációt jelölnek. A T=it(E) azt a T iterált
(szerkezetű) típust jelöli, amelynek típusértékeit az E elemi típus
értékeiből építjük fel. A következő fejezetben számos nevezetes iterált
szerkezetű típust fogunk bemutatni.
A típusszerkezethez kötődő típusok közötti kapcsolat a típusok
közti szerkezeti rokonság. Két típust akkor nevezünk rokonnak, ha
típusértékeik ugyanazon típus (esetleg típusok) elemeiből hasonló
szerkezet alapján épülnek fel. Szerkezetileg rokon például egy egész
számokat tartalmazó tömb és egy egész számokból álló sorozat. Rokon
típusok műveletei természetesen különbözhetnek. Ilyenkor
megkísérelhetjük az egyik típus műveleteit a rokon típus műveleteinek
176
7.4. Típusok közötti kapcsolatok
177
7. Típus
178
7.4. Típusok közötti kapcsolatok
179
7. Típus
7.5. Feladatok
180
8. Programozási tételek felsoroló objektumokra
181
8. Programozási tételek felsoroló objektumokra
182
8.1. Gyűjtemények
8.1. Gyűjtemények
183
8. Programozási tételek felsoroló objektumokra
184
8.1. Gyűjtemények
185
8. Programozási tételek felsoroló objektumokra
21
Amikor a felsorolható adat egy gyűjtemény (iterált), akkor a
felsoroló objektumot szokták bejárónak vagy iterátornak is nevezni,
míg maga a felsorolható gyűjtemény a bejárható, azaz iterálható adat.
22
A műveletek jelölésére az objektum orientált stílust használjuk:
t.First() a t felsorolóra vonatkozó First() műveletet jelöli.
186
8.2. Felsoroló típus specifikációja
187
8. Programozási tételek felsoroló objektumokra
t.First()
t.End()
F( t.Current() )
t.Next()
188
8.3. Nevezetes felsorolók
i := m
i n i = m .. n
F(i) F(i)
i := i+1
189
8. Programozási tételek felsoroló objektumokra
i := 1
i s i = 1 .. s
F(si) F(si)
i := i+1
23
Könyvünkben úgy tekintünk a vektor indextartományára, mint egy
egész intervallumra. A vektor típus fogalma azonban általánosítható
úgy, hogy indextartományát egy felsoroló objektum írja le. Ilyenkor a
vektort felsoroló objektum műveletei megegyeznek az ő
indextartományát felsoroló objektum műveleteivel egyet kivéve: a
Current() műveletet a v[i.Current()] implementálja, ahol i az
indextartomány elemeit felsoroló objektumot jelöli.
190
8.3. Nevezetes felsorolók
i := 1
i s i = 1 .. s
F(si) F(si)
i := i+1
k = 0 .. n*m-1
F(a[k div m, k mod m])
191
8. Programozási tételek felsoroló objektumokra
i, j := 1, 1
i n
F( a[i,j] )
j<m
j := j+1 i, j := i+1, 1
i = 1 .. n
j = 1 .. m
F( a[i,j] )
st, e, f : read
st=norm
F(e)
st, e, f : read
192
8.3. Nevezetes felsorolók
193
8. Programozási tételek felsoroló objektumokra
h
F(mem(h))
h := h – {mem(h)}
194
8.4. Programozási tételek általánosítása
195
8. Programozási tételek felsoroló objektumokra
1. Összegzés
Feladat: Adott egy E-beli elemeket felsoroló t objektum és egy
f:E→H függvény. A H halmazon értelmezzük az összeadás asszociatív,
baloldali nullelemes műveletét. Határozzuk meg a függvénynek a t
elemeihez rendelt értékeinek összegét! (Üres felsorolás esetén az
összeg értéke definíció szerint a nullelem: 0).
Specifikáció: Algoritmus:
A = (t:enor(E), s:H) s := 0
Ef = ( t=t’ )
t.First()
t'
Uf = ( s = f (ti, ) ) = t.End()
i 1
s := s+f(t.Current())
=( s f(e) )
e t' t.Next()
2. Számlálás
Feladat: Adott egy E-beli elemeket felsoroló t objektum és egy
:E feltétel. A felsoroló objektum hány elemére teljesül a feltétel?
Specifikáció: Algoritmus:
A = (t:enor(E), c:ℕ) c:=0
Ef = ( t=t’ )
t.First()
t'
Uf = ( c 1 )= t.End()
i 1
( t.Current() )
β(t i, )
c := c+1 SKIP
=( c 1)
e t' t.Next()
β(e )
196
8.4. Programozási tételek általánosítása
3. Maximum kiválasztás
Feladat: Adott egy E-beli elemeket felsoroló t objektum és egy
f:E→H függvény. A H halmazon definiáltunk egy teljes rendezési
relációt. Feltesszük, hogy t nem üres. Hol veszi fel az f függvény a t
elemein a maximális értékét?
Specifikáció:
A = (t:enor(E), max:H, elem:E)
Ef = ( t=t’ t >0 )
t'
'
Uf = ( ind [1.. t’ ]:elem= t ind '
max=f( t ind )= max f(ti, ) ) =
i 1
t'
, ,
= ( (max, ind ) max f(ti ) elem= tind ) =
i 1
= ( max, elem max f(e) )
e t'
Algoritmus:
t.First()
max, elem:= f(t.Current()), t.Current()
t.Next()
t.End()
f(t.Current())>max
max, elem:= f(t.Current()), t.Current() SKIP
t.Next()
197
8. Programozási tételek felsoroló objektumokra
4. Kiválasztás
Feladat: Adott egy E-beli elemeket felsoroló t objektum és egy
:E feltétel. Keressük a t bejárása során az első olyan elemi értéket,
amely kielégíti a :E feltételt, ha tudjuk, hogy biztosan van ilyen.
Specifikáció: Algoritmus:
A = (t:enor(E), elem:E) t.First()
Ef = ( t=t’ i [1.. t ]: (ti) )
Uf = ( ind [1.. t’ ]: elem=t’ind (t.Current())
(elem) j [1..ind-1]: ( t 'j ) t.Next()
t = t’[ind+1.. t’ ] ) = elem:=t.Current()
' '
= ( (ind,t) select β (t ind ) elem= tind ) = ( (elem, t) select β (elem) )
ind 1 elem t '
5. Lineáris keresés
Feladat: Adott egy E-beli elemeket felsoroló t objektum és egy
:E feltétel. Keressük a t bejárása során az első olyan elemi értéket,
amely kielégíti a feltételt.
Specifikáció: Algoritmus:
A = (t:enor(E), l: , elem:E) l := hamis; t.First()
Ef = ( t=t’ )
l t.End()
Uf = ( l= i [1.. t’ ]: ( ti' )
l ind [1.. t’ ]:elem=t’ind elem := t.Current()
(elem) l := (elem)
'
j [1..ind-1]: (t j ) t.Next()
t = t’[ind+1.. t’ ] ) =
t'
= ( (l,ind,t) search β (t i' ) '
elem= tind ) = ( (l, elem,t) search β (e) )
i 1 e t'
198
8.4. Programozási tételek általánosítása
6. Feltételes maximumkeresés
Feladat: Adott egy E-beli elemeket felsoroló t objektum, egy
:E feltétel és egy f:E→H függvény. A H halmazon definiáltunk
egy teljes rendezési relációt. Határozzuk meg t azon elemeihez rendelt f
szerinti értékek között a legnagyobbat, amelyek kielégítik a feltételt.
Specifikáció:
A = (t:enor(E), l: , max:H, elem:E)
Ef = ( t=t’ )
Uf = ( l = i [1.. t’ ]: ( ti' ) l '
ind [1.. t’ ]: elem= t ind
(elem) max=f(elem) i [1.. t’ ]: ( ( ti' ) f( ti' ) max) ) =
t'
= ( (l, max, ind) = max f(t i, ) '
elem= tind )=
i 1
β (t'i )
= ( (l, max, elem) = max f(e) )
e t'
β(e)
Algoritmus:
l:= hamis; t.First()
t.End()
(t.Current()) (t.Current()) l ( t.Current()) l
SKIP f(t.Current())>max l, max, elem :=
max, elem:= SKIP igaz, f(t.Current()),
f(t.Current()), t.Current()
t.Current()
t.Next()
199
8. Programozási tételek felsoroló objektumokra
200
8.4. Programozási tételek általánosítása
201
8. Programozási tételek felsoroló objektumokra
202
8.4. Programozási tételek általánosítása
még fel nem dolgozott elemek az ind index után állnak, ezért azok
külön jelölésére nincs szükség.
d) Az n×m-es mátrixokra bevezetett specifikációs jelölések
(standard felsorolás esetén) csak abban térnek el a vektorokétól, hogy
indexpárokat tartalmaznak.
n, m
összegzés: s= f(a[i, j ] )
i 1, j 1
n, m
számlálás: c 1
i 1, j 1
β (a[i , j ] )
n, m
maximum kiválasztás: max, ind, jnd = max f(a[i, j ] )
i 1, j 1
n, m
feltételes maximumkeresés: l, max, ind, jnd = max f(a[i, j ] )
i 1, j 1
β (a[i , j ] )
n, m
lineáris keresés: l , ind, jnd search β (a[i, j ] )
i 1, j 1
m
kiválasztás: ind, jnd select β (a[i, j ] )
i 1, j 1
203
8.5. Visszavezetés nevezetes felsorolókkal
204
8.5. Visszavezetés nevezetes felsorolókkal
A = (h:set(ℤ), max:ℤ)
Ef = ( h=h’ )
Uf = ( max = max e )
e h'
Ebben a specifikációban nem jelenik meg explicit módon a
felsoroló, de átalakítható úgy, hogy annak állapotterében a halmaz
helyett, a halmaz elemeit felsoroló objektum szerepeljen:
A = (t:enor(ℤ), max:ℤ)
Ef = ( t=t’ )
Uf = ( max = max e )
e t'
Ez a forma nem mond el többet a feladatról, mint az előző, de az
általános maximum kiválasztás programozási tételére való
visszavezetés most már formálisan végrehajtható: az általános
specifikáció és az itt látható specifikáció néhány, jól azonosítható
ponton tér csak el. A felsoroló egész számokat állít elő, a feldolgozást
végző függvény pedig az egész számokon értelmezett identitás.
E ~ ℤ
H ~ ℤ
f(e) ~ e
Az identitás miatt a feldolgozásnak most csak egy eredménye
(max) van, hiszen a megtalált maximális értékű elem és annak értéke
egy és ugyanaz. Ennek megfelelően átalakítjuk az általános
algoritmust:
t.First()
max:= t.Current()
t.Next()
t.End()
t.Current()>max
max:=t.Current() SKIP
t.Next()
205
8. Programozási tételek felsoroló objektumokra
max:= mem(h)
h:=h-{max}
h
e:= mem(h)
e>max
max:= e SKIP
h:=h-{e}
206
8.5. Visszavezetés nevezetes felsorolókkal
Visszavezetés Felsorolás
E ~ felsoroló ~ f:infile( ),
(e) ~ st=abnorm st:Státusz, e:
e ’’ First() ~ st,e,f:read
Next() ~ st,e,f:read
Current() ~ e
End() ~ st = abnorm
st,e,f:read
st=norm e=’ ’
st,e,f:read
207
8. Programozási tételek felsoroló objektumokra
Visszavezetés Felsorolás
E ~ ℕ×ℕ felsoroló ~ a:ℤ n×m, i, j:ℕ
(i,j) ~ 2 a[i,j] First() ~ i, j:=1,1
Next() ~ ha j=m
akkor i, j:=i+1,1
különben j:=j+1
Current( ~ i, j
)
End() ~ i>n
l, i, j:=hamis, 1, 1
l i≤ n
l, ind, jnd := 2 a[i,j], i, j
j<m
j:=j+1 i, j:=i+1, 1
208
8.5. Visszavezetés nevezetes felsorolókkal
l, i:=hamis, 1
l i≤ n
j:=1
l j≤m
l, ind, jnd := 2 a[i,j], i, j
j:=j+1
i:=i+1
209
8. Programozási tételek felsoroló objektumokra
E ~
+,0 ~ ,<>
f(e) ~ <e,e>
s ~ y
210
8.5. Visszavezetés nevezetes felsorolókkal
y:=<>
st,e,x:read
st = norm
y:write(<e, e>)
st,e,x:read
24
Megjegyezzük, hogy itt az y:=y {e} értékadás implementációja itt
egyszerűbb, mint általában. Ugyanis biztosak lehetünk abban, hogy az
e elem még nincs az y halmazban, ezért ezt nem is kell külön vizsgálni.
Az elem-unió műveletének tehát ugyanúgy az egyszerűsített
változatával dolgozhatunk itt, mint az x:=x–{e} elemkivonás esetében,
ahol meg azt nem kell ellenőrizni, hogy az e elem tényleg benne van-e
az x halmazban.
211
8. Programozási tételek felsoroló objektumokra
E ~ ℤ
+,0 ~ ,
f(e) ~ ha e páros akkor {e}
különben
s ~ y
y:=
x
e:=mem(h)
e páros
y:=y {e} SKIP
x:=x–{e}
212
8.5. Visszavezetés nevezetes felsorolókkal
E ~ ℕ
+,0 ~ ,
f(i) ~ {xi mod 7}
s ~ y
y:=
i = 1 .. n
y:=y {xi mod 7}
213
8. Programozási tételek felsoroló objektumokra
Ef = ( x=x’ )
Uf = ( y
e x'
e z {e}
e x'
e.mag 180 e.súly 60
e.haj 'barna' e.haj ' fekete'
v[1..n] e )
e x'
e.haj ' fekete'
e.alibi
A specifikációban jól elkülönül a feladat három önállóan is
megoldható része. Mindhárom egy esetszétválasztásos függvény
összegzésére épül, amelyhez ugyanazon x szekvenciális inputfájl
st,e,x:read segítségével soroljuk fel az elemeket.
Itt három elemenkénti feldolgozás (három kiválogatás) szerepel,
amelyek ugyanazon szekvenciális fájlból (st,e,x:read) egy szekvenciális
fájlba, egy halmazba és egy sorozatba írnak:
214
8.5. Visszavezetés nevezetes felsorolókkal
215
8. Programozási tételek felsoroló objektumokra
8.6. Feladatok
216
9. Visszavezetés egyedi felsorolókkal
218
9.1. Egyedi felsoroló
219
9. Visszavezetés egyedi felsorolókkal
(e)
lineáris keresés esetén: l , elem , t search (e) .
e t'
220
9.2. Feltétel fennállásáig tartó felsorolás
Ef = ( f=f’ f >0
f azon szerint rendezett )
'
e.azon f 1.azon
Uf = ( max, maxelem, ( st , e, f ) max e.össz )
e f'
Ezt visszavezethetjük a maximum kiválasztás tételére. Az
eredmények közül nincs szükség külön a maximális tranzakciós összeg
értékére, hiszen azt a maximális elem (a rekord) tartalmazza.
221
9. Visszavezetés egyedi felsorolókkal
l := hamis; t.First()
222
9.3. Csoportok felsorolása
l t.End()
l := t.Current().ma- t.Current().tegnap < 0
t.Next()
223
9. Visszavezetés egyedi felsorolókkal
t.First()
t.End()
t.Current().össz<-100000
v:write(t.Current()) SKIP
t.Next()
224
9.3. Csoportok felsorolása
225
9. Visszavezetés egyedi felsorolókkal
t.Next()
sx=norm
vége := hamis
egyl.azon, egyl.össz:=dx.azon, 0 vége := igaz
sx=norm dx.azon=egyl.azon
egyl.össz := egyl.össz+dx.össz
sx, dx, x: read
t.First()
sx, dx, x:read
t.Next()
226
9.3. Csoportok felsorolása
227
9. Visszavezetés egyedi felsorolókkal
t.Next()
228
9.3. Csoportok felsorolása
i n x[i] = 0
i:=i+1
nincs_több_sziget:= i >n
nincs_több_sziget
akt_sziget.eleje:= i
SKIP
i n x[i] 0
i:=i+1
akt_sziget.hossz:=
i – akt_sziget.eleje
t.First()
i:=1
t.Next()
t.First()
max, kezd:= t.Current().hossz,
t.Current().eleje
t.Next()
t.End()
229
9. Visszavezetés egyedi felsorolókkal
t.Current().hossz>max
max, kezd := t.Current().hossz, SKIP
t.Current().eleje
t.Next()
230
9.3. Csoportok felsorolása
t.First()=t.Next()
sf, df, f : read
sf = norm df=’ ’
sf, df, f : read
nincs_szó:= sf=norm
231
9. Visszavezetés egyedi felsorolókkal
nincs_szó
van_w:=hamis
van_w sf = norm df ’ ’
SKIP
van_w:=(df=’w’)
sf, df, f: read
sf = norm df ’ ’
sf, df, f: read
232
9.3. Csoportok felsorolása
t.First()
sf, df, f : read
sf = norm df=’ ’
sf, df, f : read
t.Next()
t.Next()
nincs_szó:= sf=norm
nincs_szó
van_w:=hamis
sf = norm df ’ ’ SKIP
233
9. Visszavezetés egyedi felsorolókkal
9.4. Összefuttatás
234
9.4. Összefuttatás
A = (t:enor(E), z:set(E))
Ef = ( t = t’ )
Uf = ( z = f(e) )
e t'
Az összefuttató felsorolás tulajdonképpen az x y halmaz
elemeinek bejárása lesz. Ez akkor ér véget, ha x y üres lesz (t.End()).
A t.Current() az x y halmazból választ ki determinisztikus módon egy
elemet (mem(x y)), amelyet majd a t.Next() művelet fog elvenni az
x y-ból, pontosabban x-ből, ha az x-beli, y-ból, ha y-beli,
mindkettőből, ha mindkettőnek eleme. A t.First() művelet – mint azt a
halmazok bejárásánál korábban láttuk – az üres program.
z:=
x y
e:=mem(x y)
e x e y e x e y e x e y
SKIP SKIP z:= z {e}
x:=x–{e} y:=y–{e} x, y := x–{e}, y–
{e}
235
9. Visszavezetés egyedi felsorolókkal
z:=
x y
e:=mem(x)
e x e y e x e y
SKIP z:= z {e}
x:=x–{e} x, y := x–{e}, y–{e}
236
9.4. Összefuttatás
237
9. Visszavezetés egyedi felsorolókkal
z := <>
x.First(); y.First();
x.End() y.End()
y.End() x.End() x.End()
( x.End() ( y.End() y.End()
x.Current()< x.Current()> x.Current()=
y.Current() ) y.Current() ) y.Current()
z:write( z:write( z:write(
f1(x.Current())) f2(y.Current())) f3(x.Current()))
x.Next(); y.Next() x.Next(); y.Next()
238
9.4. Összefuttatás
z := <>
x.First(); y.First();
x.End() y.End()
x.Current()< x.Current()> x.Current()=
y.Current() y.Current() y.Current()
SKIP SKIP z:write(f3(x.Current()))
x.Next(); y.Next() x.Next(); y.Next()
239
9. Visszavezetés egyedi felsorolókkal
e ha e {x '} e { y '}
f(e) ha e {x '} e { y '}
ha e {x '} e { y '}
Halmazokkal megfogalmazva a feladatot, itt tulajdonképpen két
halmaz különbségét kell meghatározni. A feladat a két szekvenciális
inputfájl összefuttatására épített összegzéssel oldható meg. Az általános
megoldást most úgy kell alkalmazni, hogy az x és y elemeinek
felsorolásához a szekvenciális inputfájl nevezetes felsorolását kell
használni. (Az x.First() és x.Next() helyett sx,dx,x:read, x.End()
helyett sx=norm, x.Current() helyett dx.) A megoldó program
ciklusfeltétele az sx=norm sy=norm helyett az sx=norm-ra
egyszerűsödhet, és ennélfogva egyszerűbbek lehetnek az elágazás
feltételei is.
z := <>
sx,dx,x:read; sy,dy,y:read
sx=norm
sy=abnorm sy=norm sy=norm
dx<dy dx>dy dx=dy
z:write(dx) SKIP SKIP
sx,dx,x:read sy,dy,y:read sx,dx,x:read;
sy,dy,y:read
240
9.4. Összefuttatás
241
9. Visszavezetés egyedi felsorolókkal
A= (x:enor(ℕ), u:outfile(Áru))
Ef = ( x = x' )
Uf = ( u f(a) )
a x'
a (t ' ) ha a azon (t ' ) a azon (m' )
f(a) f 2 (a) ha a azon (t ' ) a azon (m' )
f 3 (a) ha a azon (t ' ) a azon (m' )
a, a(t ' ).me a(m' ).me ha a(t ' ).me a(m' ).me 0
g(a)
a(t ' ) hiba ha a(t ' ).me a(m' ).me 0
242
9.4. Összefuttatás
u := <>
st, dt, t: read; sm, dm, m: read
st=norm sm=norm
sm=abnorm st=abnorm st=norm sm=norm
(sm=norm dt.azon=dm.azon
(st=norm dt.azon>
dt.azon < dm.azon)
dm.azon)
u:write(dt) dm.müv=
dm.müv=I I D U
u:write( H H S c :=
dm.azon, I I K dt.me+dm.me
dm.me) B B I
c<0
A A P
H dt.me:=c
I
B
A
u:write(dt)
st, dt, t: read sm, dm, m: read st, dt, t: read
sm, dm, m: read
243
9. Visszavezetés egyedi felsorolókkal
244
9.4. Összefuttatás
First()
i = 1 .. n
sf[i],df[i],f[i]:read
n
l, min := min df [i ]
i 1
sf [ i ] norm
Next()
i = 1 .. n
sf[i]=norm df[i]=min
sf[i],df[i],f[i]:read SKIP
n
l, min := min df [i ]
i 1
sf [ i ] norm
245
9. Visszavezetés egyedi felsorolókkal
y.First()
i = 1 .. n
sm[i],dm[i],m[i]:read
y.Next()
246
9.4. Összefuttatás
y.Next()
n
l, ind, min := min dm[i].azon
i 1
sm[i ] norm
l
dm.azon, dm.menny:=min, 0 SKIP
i = 1 .. n
sm[i]=norm dm[i]=min
dm.menny:= SKIP
dm.menny+dm[i].menny
sm[i],dm[i],m[i]:read
247
9. Visszavezetés egyedi felsorolókkal
u : =<>
st,dt,t:read; y.First();
st=norm y.End()
y.End() st=abnorm st=norm
(st=norm (st=norm y.End()
dt.azon< dt.azon> dt.azon=
y.Current().azon) y.Current().azon) y.Current().azon
dt.menny:=
u:write(dt) HIBA dt.menny+dm.menn
y
u:write(dt)
st,dt,t:read y.Next() st,dt,t:read; y.Next()
248
9.5. Rekurzív függvény feldolgozása
i [1.. x ] :
(r1 (i 1) xi , hamis ) ha xi ' '
r(i) (r1(i 1) xi , igaz ) ha xi ' ' r2(i 1)
(r(i 1)) ha xi ' ' r2(i 1)
r(0) ( , hamis )
Ezek után a feladat specifikációja igen egyszerű: számoljuk ki az
r rekurzív függvény utolsó értékét.
A = (x:infile( ), y:outfile( ))
Ef = ( x=x’ )
Uf = ( y r1 ( x' ) )
A feladat visszavezethető a rekurzív függvény helyettesítési
értékét kiszámoló programozási tételre, de a kapott algoritmussal van
egy kis bökkenő. Nem megengedett az x szekvenciális inputfájl i-dik
elemére történő közvetlen hivatkozás, ahhoz csak egy felsorolással
tudunk hozzáférni.
249
9. Visszavezetés egyedi felsorolókkal
y, l, i :=<>, hamis, 1
i x
xi ’ ’ xi =’ ’ l xi =’ ’ l
y:write(xi) y:write(xi) SKIP
l := hamis l := igaz
i := i+1
y, l :=<>, hamis
st, ch, x : read
st = norm
ch ’’ ch =’ ’ l ch =’ ’ l
y:write(ch) y:write(ch) SKIP
l := hamis l := igaz
st, ch, x : read
250
9.5. Rekurzív függvény feldolgozása
i [1.. x ] :
( xi , hamis ) ha xi ' '
r(i) ( xi , igaz ) ha xi ' ' r2(i 1)
( , r2 (i 1)) ha xi ' ' r2(i 1)
r (0) ( , hamis )
karakter szóköz volt-e vagy sem. A feladat leírásához ezért itt is egy
rekurzív függvényt kell bevezetnünk, amely természetesen hasonlít az
előző megoldásban használthoz. A lényeges különbség az, hogy most
az r:[0.. x ] * rekurzív függvény első komponense csak az
eredményhez hozzáfűzendő egy karakternyi vagy üres sorozatot állítja
elő, és nem a teljes eredményt.
A specifikáció pedig:
A = (x:infile( ), y:outfile( ))
Ef = ( x=x’ )
x'
Uf = ( y r1 (i ) )
i 1
A feladatot tehát a rekurzív függvény első komponense által adott
értékeinek az összefűzésével (összegzés) oldhatjuk meg. A soron
következő ilyen érték előállításához a szekvenciális fájl aktuális
karakterére és a megelőző karakterről információt adó logikai értékre
van szükség. Ugyanakkor nincs közvetlenül szükség arra az indexre,
amelyik a rekurzió lépéseit számolja. A rekurzív képlet általános
h:ℤ×Hk H függvényét most egy h: * alakú függvény
biztosítja, hiszen r(i)=h(x’i, r2(i–1)). Ha rendelkeznénk egy olyan
felsorolóval, amely a h kiszámolásához szükséges karakter-logikai
érték párokat a megfelelő sorrendben képes adagolni, akkor a feladat
megoldásával készen is lennénk.
Általánosságban is igaz az, hogy ha egy rekurzív függvény
egymás utáni értékeit kell előállítanunk egy feldolgozás számára, akkor
a rekurzív képlet h:ℤ×Hk H függvényét kell a számára szükséges k+1
darab argumentummal újra és újra kiszámolni, és ehhez ezen
argumentum-csoportokat kell egy alkalmas felsorolóval megadni.
Ezen gondolatmenet mentén a feladatunkat újraspecifikálhatjuk.
251
9. Visszavezetés egyedi felsorolókkal
252
9.5. Rekurzív függvény feldolgozása
y:=<>
l:=hamis st,ch,x:read
sx = norm
ch ’ ’ ch=’ ’ l ch=’ ’ l
y:write(’ ’) y:write(ch) SKIP
l:= ch=’ ’
st,ch,x:read
253
9. Visszavezetés egyedi felsorolókkal
db := 0
st,max,x:read
st,e,x:read
st = norm
e>max
db, max:=db+1, e SKIP
st,e,x:read
254
9.6. Felsoroló gyűjtemény nélkül
A = (n:ℕ, sum:ℕ)
Ef = ( n=n' n>0 )
n
Uf = ( Ef sum = i )
i 2
in prim(i)
A feladat közönséges összegzésként is megfogalmazható, ha
bevezetjük azt a felsorolót, amely közvetlenül az n szám prím osztóit
sorolja fel, és a feladatot ennek megfelelően újraspecifikáljuk.
A = (t:enor(ℕ), sum:ℕ)
Ef = ( t=t' )
Uf = ( sum = e )
e t'
Ezt visszavezethetjük az általános összegzésre úgy, hogy abban
az E=H=ℕ és minden e természetes számra f(e)= e.
sum := 0
t.First()
t.End()
sum := sum+t.Current()
t.Next()
255
9. Visszavezetés egyedi felsorolókkal
sum:=0;
d:=2;
d:=lko(n) d:=lko(n)
n>1 n>1
sum := sum + d d|n SKIP
d|n d:=d+1
n:=n/d
d:=lko(n)
256
9.7I.9.7. Feladatok
9.7. Feladatok
257
9. Visszavezetés egyedi felsorolókkal
258
9.7I.9.7. Feladatok
259
10. Feladatok megoldása
260
1. fejezet feladatainak megoldása
261
10. Feladatok megoldása
ha x > 0
< (x, y) (x,1) (x,x) (x–1,x) … (1, x!) >
ha x ≤ 0
< (x, y) (x,1) (x,x) (x–1,x) (x–1,x(x–1)) (x–2,x(x–1)) … >
Megoldja-e a fenti program azt a feladatot, amikor egy pozitív
egész számnak kell a faktoriálisát kiszámolni?
Válasz: Igen. Ehhez elég felírni a feladatot kezdőállapot-
célállapot párok formájában:
Állapottér: A = (n:ℤ, f:ℤ)
Kezdőállapotok: Azok az (x,y) egész szám párok, ahol az x
pozitív.
Célállapotok: Egy (x,y) kezdőállapothoz a (*,x!)
célállapot tartozik.
Vigyázat! Nem lenne helyes, ha a feladatot úgy határoznánk meg,
hogy őrizze meg a célállapotának első komponensében a bemenő
adatot, azaz az (x,y) kezdőállapothoz csak az (x,x!) célállapot
tartozzon. A program ugyanis „elrontja” az első komponens
értékét.
1.4. Tekintsük az A = (x:ℤ, y:ℤ) állapottéren az alábbi programot!
1. Legyen x értéke x–y
2. Legyen y értéke x+y
3. Legyen x értéke y–x
Írjuk fel e program néhány végrehajtását!
Válasz:
< (5,3) (2,3) (2,5) (3,5) >
< (1,1) (0,1) (0,1) (1,1) >
< (0,1) (–1,1) (–1,0) (1,0) >
< (-5,3) (–8,3) (–8,–5) (3,–5) >
Hogyan lehetne a végrehajtásokat általánosan jellemezni?
Válasz: < (u,v) (u–v,v) (u–v,u) (v,u) >
Megoldja-e a fenti program azt a feladatot, amikor két, egész
típusú változó értékét kell kicserélni?
262
1. fejezet feladatainak megoldása
263
10. Feladatok megoldása
264
1. fejezet feladatainak megoldása
265
10. Feladatok megoldása
266
2. fejezet feladatainak megoldása
267
10. Feladatok megoldása
268
2. fejezet feladatainak megoldása
A = ( n:ℕ, l: )
Ef = ( n=n’ )
Uf = ( Ef l = (n 1 k [2 .. p–1]: (k p) ) =
( Ef l=prím(n) )
2.9. Specifikálja: Adott egy sakktáblán egy királynő (vezér).
Helyezzünk el egy másik királynőt úgy, hogy a két királynő ne
üsse egymást!
Megoldás:
A = (x1:ℕ, y1:ℕ, x2:ℕ, y2:ℕ)
Ef = (x1=x1’ y1=y1’ x1, y1 [1..8] )
Uf = ( Ef x2, y2 [1..8] ( (x1 x2 y1= y2)
(x1= x2 y1 y2) ( x1 –x2 = y1– y2 )) )
2.10. Specifikálja: Adott egy sakktáblán két bástya. Helyezzünk el egy
harmadik bástyát úgy, hogy ez mindkettőnek az ütésében álljon!
Megoldás:
A = (x1:ℕ, y1:ℕ, x2:ℕ, y2:ℕ, l: , x:ℕ, y:ℕ)
Ef = (x1=x1’ y1= y1’ x2=x2’ y2=y2’ x1, y1, x2, y2 [1..8])
Uf = ( Ef l = ( (x1=x2 y1– y2 1) (y1= y2 x1– x2 1) )
l ( x, y [1..8]
(x1=x2) (x=x1 y1<y2 y1<y<y2 y1>y2 y1>y>y2)
(y1=y2) (y=y1 x1<x2 x1<x<x2 x1>x2 x1>x>x2 )
(x1 x2 y1 y2) (x=x1 y=y2 x=x2 y=y1) )
269
3. fejezet feladatainak megoldása
270
3. fejezet feladatainak megoldása
Végrehajtások
(7, 1) < (7, 1), (3, 2)>
(3, 1) < (3, 1), (3, 1), (3, 1) …>
Feladat:
A= (n:ℕ, m:ℕ)
Ef = ( n=n’ m=m’ n-5>0 )
Uf = ( Ef n=3 m= n–5 )
3.4. Adjunk meg olyan végrehajtási sorozatokat, amelyeket a (r:=p+q;
p:=r/q) szekvencia befuthat az A= (p:ℝ, q:ℝ, r:ℝ) állapottéren!
Adjunk meg olyan egyetlen értékadásból álló programot, amely
ekvivalens ezzel a szekvenciával!
Végrehajtások
(1,1,1) < (1,1,1), (1,1,2), (2,1,2) >
(3,0,1) < (3,0,1), (3,0,3), (3,0,3), (3,0,3)…>
(5,4,3) < (5,4,3), (5,4,9), (2.25,4,9) >
Értékadás:
p,r:=(p+q)/q, p+q
3.5. Igaz-e, hogy az alábbi három program ugyanazokat a feladatokat
oldja meg?
f1 f2 f3
S1 S2 S3
f1 f1
S1 SKIP f2
f2 f3
S2 SKIP S1 S2 S3 SKIP
f3
S3 SKIP
271
10. Feladatok megoldása
272
3. fejezet feladatainak megoldása
c
(a=0 (b 0 ( v = „Elsőfokú gyök” x1 )
b
(b=0 c=0) v = „Azonosság”
(b=0 c 0) v = „Ellentmondás” ) )
Algoritmus, amely az utófeltétel által sugallt többszörös elágazás lesz.
a 0
d : b2 4ac b 0 b=0 b=0
c=0 c 0
d<0 d=0 d>0
válasz:= válasz:= válasz:= válasz:= válasz válasz
Nincs Közös Két Elsőfokú := :=
valós valós valós gyök A E
gyök gyök gyök z l
x1 , x 2 : x1 , x 2 : c o l
x1
b b n e
b d
2a 2a o n
s t
s m
á o
g n
d
á
s
3.8. Értelmezze az alábbi feladatot! Adja meg néhány végrehajtási
sorozatát a megadott ciklusnak! Mutassa meg, hogy a feladatot
megoldja a program. (Segítségül megadtuk a ciklus egy invariáns
állítását és a hátralevő lépésszámra adható felső becslést.)
A = (x:ℤ)
Ef = ( igaz )
Uf = ( x = 0 )
x 0 legfeljebb abs(n) hátralevő lépés
x:=x – sgn(x) invariáns állítás: igaz
273
10. Feladatok megoldása
Bizonyítás:
A feladat előfeltételéből következik az invariáns állítás, hiszen
mindkettő az igaz állítás. Az invariáns állítás valóban invariáns,
hiszen a ciklusmag végrehajtása után is teljesülni fog az igaz
állítás. Ha egy állapotra az invariáns mellett a ciklusfeltétel
tagadottja is teljesül, akkor teljesül a feladat utófeltétele is, hiszen
mindkettő az x=0 állítás. Ezzel a haladási kritériumot igazoltuk.
A leállási kritériumhoz azt kell csak látni, hogy az abs(x) értéke
pozitív, ha a ciklusfeltétel igaz, és ilyenkor a ciklusmag eggyel
csökkenti az értékét. Így véges lépésen belül olyan állapotba
fogunk eljutni, amelyre a ciklusfeltétel hamis.
3.9. Értelmezze az alábbi feladatot! Adja meg néhány végrehajtási
sorozatát a megadott programnak! Mutassa meg, hogy a feladatot
megoldja a program. (Segítségül megadtuk a ciklus egy invariáns
állítását és a hátralevő lépésszámra adható felső becslést.)
A = (n:ℕ, f:ℕ)
Ef = ( n=n’)
Uf = ( f=n’! )
f:=1
n 0 legfeljebb n hátralevő lépés
f:=f n ivariáns állítás: f n!=n’!
n:=n–1
Bizonyítás:
A program egy értékadással indul, amely hatására egy (n’,1)
alakú állapotba jutunk. Ez után egy ciklus következik. Az (n’,1)
alakú állapotok megfelelő kiinduló állapotai a ciklusnak, mert
biztosan kielégítik a ciklus invariáns állítását ( 1 n’!=n’! ). Az
invariáns állítás valóban invariáns, hiszen a ciklusmag két
értékadása egy invariánst kielégítő (n0,f0) állapotból (f0 n0!=n’!)
az (n0–1, f0 n0) állapotba vezet, amelyre ugyancsak kielégíti az
invariánst: „f0 n0 (n0–1)!=n’!” Ha egy állapotra az invariáns
mellett a ciklusfeltétel tagadottja is teljesül, akkor teljesül a
feladat utófeltétele is (hiszen f n!=n’! n=0 f=n’!). Ezzel a
haladási kritériumot igazoltuk.
274
3. fejezet feladatainak megoldása
275
4. fejezet feladatainak megoldása
Összegzés:
m..n ~ 1..x
s ~ z
f(i) ~ y
Algoritmus:
z, i :=0, 1 z := 0
i x i:ℕ i = 1 .. x i:ℕ
z := z+y rövidebben z := z+y
i := i+1
4.2. Keressük meg egy természetes szám legkisebb páros valódi
osztóját!
Specifikáció:
A = ( n:ℕ, l: , d:ℕ)
Ef = ( n=n’ )
n/2
Uf = ( Ef l, d search(i n 2 i) )
i 2
Lineáris keresés:
m..n ~ 2 .. n div 2
ind ~ d
(i) ~ i|n 2|i
Algoritmus:
276
4. fejezet feladatainak megoldása
l, i:=hamis, 2 i:ℕ
l i n div 2
l, d:= i|n 2|i, i
i := i+1
4.3. Válogassuk ki egy egész számokat tartalmazó tömbből a páros
számokat!
Specifikáció:
A = ( x:ℤn, y:ℤn, k:ℕ)
Ef = ( x=x’ )
n
Uf = ( Ef y[1..k]= x[i ] ) ( az összefűzés jele)
i 1
2 x[ i ]
Összegzés:
m..n ~ 1..n
s ~ y[1..k]
f(i) ~ ha x[i] páros akkor <x[i]> különben <>
Algoritmus:
k, i:=0, 1 i:ℕ k := 0
i n i = 1 .. n i:ℕ
x[i] páros vagy x[i] páros
k := k+1 SKIP k := k+1 SKIP
y[k] := x[i] y[k] :=
x[i]
i := i+1
277
10. Feladatok megoldása
A = ( x:ℝ, l: , d:ℕ)
Ef = ( x=x’ )
n 1
Uf = ( Ef l, d search( x[i] 0 x[i 1] 0) )
i 1
Lineáris keresés:
m..n ~ 1..n-1
ind ~ d
(i) ~ x[i]=0 x[i+1]<0
Algoritmus:
l, i:=hamis, 1 i:ℕ
l i n-1
l, d:= x[i]=0 x[i+1]<0, i
i := i+1
4.4. Egy tömbben a tornaórán megjelent diákok magasságait tároljuk.
Keressük meg a legmagasabb diák magasságát!
Specifikáció:
A = (x:ℕn, max:ℕ)
Ef = ( x=x’ 1 n )
n
Uf = ( Ef max = max x[i] )
i 1
278
4. fejezet feladatainak megoldása
Specifikáció:
A = (m, n, a, b, c, d:ℤ, db:ℕ)
Ef = ( m=m’ n=n’ a=a’ b=b’ c=c’ d=d’ )
n
Uf = ( Ef db 1)
i m
f (i ) [ a..b] [c..d ]
Számlálás:
m..n ~ m..n
c ~ db
(i) ~ a f(i) b c f(i) d
Algoritmus:
db, i := 0, m i:ℤ db := 0
i n vagy i = m .. n i:ℤ
a f(i) b c f(i) d a f(i) b c f(i) d
db := db+1 SKIP db := SKIP
db+1
i := i + 1
4.6. Egy tömbben színeket tárolunk az színskála szerinti növekvő
sorrendben. Keressük meg a tömbben a világoskék színt!
Specifikáció:
A = (x:Színn, l: )
Ef = ( x=x’ x rendezett )
Uf = ( Ef l=( i [m..n]: x[i]=világoskék)
l (i [m..n] x[i]=világoskék) )
Logaritmikus keresés:
m..n ~ 1..n
(i) ~ x[i]=világoskék
Algoritmus:
279
10. Feladatok megoldása
280
4. fejezet feladatainak megoldása
A = ( x:ℤn, db:ℕ)
Ef = ( x=x’ )
n 1
Uf = ( Ef db 1)
i 1
x[i] 0 x[i 1] 0 ]
Számlálás:
m..n ~ 1..n-1
c ~ db
(i) ~ x[i]=0 x[i+1]<0
Algoritmus:
db := 0
i = 1 .. n-1 i:ℕ
x[i]=0 x[i+1]<0
db := db+1 SKIP
4.9. Egy n elemű tömbben tárolt egész számoknak az összegét egy
rekurzív függvénv n-edik helyen felvett értékével is megadhatjuk.
Definiáljuk ezt a rekurzív függvényt és oldjuk meg a feladatot a
rekurzív függvény helyettesítési értékét kiszámoló programozási
tétel segítségével!
Specifikáció:
A = (x:ℤn, s:ℤ)
Ef = ( x=x’ )
Uf = ( Ef s=f(n) )ahol f(0)=0 és i [1..n]: f(i)=f(i–1)+x[i]
Rekurzív függvény helyettesítési értéke:
k, m ~ 1, 1
y ~ s
em–1 ~ 0
h(i,f(i–1)) ~ f(i–1)+x[i]
Algoritmus:
s := 0
i = 1 .. n i:ℕ
s := s+x[i]
281
5. fejezet feladatainak megoldása
távolságának négyzete.)
Minimum kiválasztás:
m..n ~ 1..n
f(i) ~ x[i]2+y[i]2
max ~ min
282
6. fejezet feladatainak megoldása
m..n ~ 2..n
(i) ~ x[i] x[i–1]
Feltételes minimumkeresés:
m..n ~ 1..n
f(i) ~ x[i]
(i) ~ x[i] mod k =1
max ~ min
l := hamis
i = m .. n i: ℤ
x[i] mod k 1 l l
x[i] mod k =1 x[i] mod k =1
SKIP min< x[i] l, min, ind :=
min, ind:= SKIP igaz, x[i], i
x[i], i
5.4. Adottak az x és y vektorok, ahol az y elemei az x indexei közül
valók. Keressük meg az x vektornak az y-ban megjelölt elemei
közül a legnagyobbat!
Specifikáció:
283
10. Feladatok megoldása
Maximum kiválasztás:
m..n ~ 1..n
f(i) ~ x[y[i]]
284
6. fejezet feladatainak megoldása
Specifikáció:
A = (t:ℤ0..n-1×0..m-1, l: , ind:ℕ, jnd:ℕ)
Ef = ( t=t’ t sorfolytonosan növekedő )
Uf = ( Ef l= k [0..nm–1]:(t[k div m, k mod m]=h)
l (k [0..nm–1] ind=k div m jnd = k mod m
t[ind, jnd]=h) )
Logaritmikus keresés:
m..n ~ 0.. nm–1
i ~ k
(i) ~ t[k div m, k mod m]=h
Kiválasztás:
m ~ n
i ~ d
(i) ~ n|d m|d
285
10. Feladatok megoldása
d: = n
(n|d m|d)
d := d+1
5.8. Keressük meg két természetes szám legnagyobb közös osztóját!
Specifikáció:
A = (n:ℕ, m:ℕ, d:ℕ)
Ef = ( n=n’ n=m’ )
Uf = ( Ef d|n d|m i [d+1..n]: (i|n i|m) ) =
= ( Ef d= select (d n d m) )
d n
Kiválasztás:
m ~ n
i ~ d
(i) ~ n|d m|d
d := n
(d|n d|m)
d := d–1
286
6. fejezet feladatainak megoldása
l := i|n
i := i+1
5.10. Egy n elemű tömb egy b alapú számrendszerben felírt
természetes szám számjegyeinek értékeit tartalmazza úgy, hogy a
magasabb helyiértékek vannak elől. Módosítsuk a tömböt úgy,
hogy egy olyan természetes szám számjegyeit tartalmazza, amely
az eredetinél eggyel nagyobb, és jelezzük, ha ez a megnövelt
érték nem ábrázolható n darab helyiértéken!
Specifikáció:
A = (x:{0..9}n, c:{0,1})
Ef = ( x=x’ )
Uf = ( (x,c) = f(n) )
f:[0 .. n] {0..9}n×{0,1}
f(0) = (x’,1)
i [1..n–1]:
ha f(i)2=0 akkor f(i+1) = f(i)
különben f(i+1)1 = f(i)1f(i)1[n i ] ( f(i)1[n i ] 1) mod 10
f(i+1)2 = ( f(i)1[n i] 1) div 10
Rekurzív függvény helyettesítési értéke:
(Nem ez a leghatékonyabb megoldás.)
k, m ~ 1, 0
y ~ x, c
em–1 ~ x’, 1
y:=h(i,f(i–1)) ~ x[n–i], c:=(x[n–i]+1) mod 10, (x[n–i]+1) div
10
c := 1
i = 0 .. n i:ℕ
c=0
SKIP x[n–i], c :=
(x[n–i]+1) mod 10, (x[n–i]+1) div 10
287
10. Feladatok megoldása
b) Specifikáció:
288
6. fejezet feladatainak megoldása
A = (x:ℤn, k:ℕ, l: )
Ef = ( x=x’ k=k’ )
Uf = ( Ef l= i [2..n]:(x[i]>0 múlt(i)=k) )=
n
= ( Ef l search ( x[i ] 0 múlt(i) k) )
i 2
ahol múlt(1) = 0 és
múlt(i 1) 1 ha x[i 1] 0
múlt(i) =
0 ha x[i 1] 0
Lineáris keresésben rekurzív függvény kibontása:
l, i:= hamis, 2 i:ℕ l, i, m:= hamis, 2, 0
l i n l i n
l := x[i]>0 múlt(i)=k x[i–1]<0
i := i+1 m:ℕ m := m+1 m:=0
l := x[i]>0 m=k
i := i+1
6.2. Egymást követő napokon délben megmértük a levegő
hőmérsékletét. Állapítsuk meg, hogy melyik érték fordult elő
leggyakrabban!
A feladat megoldásakor azt a napot határozzuk meg, amelyiken
mért hőmérséklet a leggyakrabban fordult elő.
Specifikáció:
A = (x:ℤn, nap:ℕ)
Ef = ( x=x’ )
n
Uf = ( Ef max, nap= max hány(i) )
i 1
i 1
ahol hány:[1..n] ℕ és hány(i) = 1
j 1
x[ j ] x[i ]
Maximum kiválasztásba ágyazott számlálás:
289
10. Feladatok megoldása
290
6. fejezet feladatainak megoldása
j
ahol összeg:[1..n] ℝ és összeg(j) = t[i, j ] , és például
i 1
összeg(1) = t[1,1].
Maximum kiválasztásba ágyazott összegzés:
max, oszlop:= t[1,1], 1 s:=összeg(i)
j = 2 .. n j:ℕ s := 0
s := összeg(j) i = 1 .. j i:ℕ
s>max s := s+t[i,j]
max, oszlop:=s, j SKIP
6.6. Egy határállomáson feljegyezték az átlépő utasok útlevélszámát.
Melyik útlevélszámú utas fordult meg leghamarabb másodszor a
határon?
A feladat kétféleképpen is értelmezhető. Vagy azt az utast
keressük, akiről legelőször derül ki, hogy korábban már átlépett a
határon, vagy azt, akinek két egymást követő átlépése közt a
lehető legkevesebb másik utast találjuk.
a) Specifikáció:
A = (x:( *)n, l: , szám: *)
Ef = ( x=x’ )
291
10. Feladatok megoldása
l szám=x[ind] )
Lineáris keresésbe ágyazott lineáris keresés:
l,i:= hamis, 1 i:ℕ l := belső keresés(i)
l i n l,j := hamis, 1 j:ℕ
l := belső keresés(i) l j i–1
szám :=x[i] l := x[i]= x[j]
i := i+1 j := j+1
b) Specifikáció:
A = (x:( *)n, l: , i:ℕ)
Ef = ( x=x’ )
n
Uf = ( Ef l min ( k f 2(k)) )
k 1
f 1(k)
ahol f:[1..n] ×ℕ egy kétértékű függvény, azaz f1(k) egy
logikai érték, f2(k) pedig egy természetes szám.
1
k [1..n]: f(k) - keres ( x[k ] x[ j ])
j k 1
Feltételes minimum keresésbe ágyazott fordított lineáris keresés:
l := hamis
k := 1 .. n k:ℕ
ll, d := f(k) ll: , d:ℕ
ll l ll l ll
SKIP min>k–d l, min, i :=
min, i := k–d, k SKIP igaz, k–d, k
292
6. fejezet feladatainak megoldása
ll, d := f(k)
ll, j := hamis, k-1 j:ℕ
ll j 1
ll, d := x[k]=x[j], j
j := j–1
6.7. Egymást követő hétvégeken feljegyeztük, hogy a lóversenyen
mennyit nyertünk illetve veszítettünk (ez egy előjeles egész
szám). Hányadik héten fordult elő először, hogy az összesített
nyereségünk (az addig nyert illetve veszített pénzek összege)
negatív volt?
Specifikáció:
A = (x:ℤn, l: , i:ℕ)
Ef = ( x=x’ k=k’ )
n
Uf = ( Ef l, i search (nyereség ( i ) 0) )
i 1
i
ahol nyereség:[0..n] ℕ és nyereség(i) = x[ j ]
j 1
293
10. Feladatok megoldása
A = (t:ℕn×m, l: )
Ef = ( t=t’ )
n m
Uf = ( Ef l search ( search prím (t[i, j ])) )
i 1 j 1
a
ahol prím:ℕ és prím(a) = (a>1 search( (k a)) )
k 2
25
Mostantól kezdve nem tüntetjük fel külön a programok
segédváltozóit.
294
6. fejezet feladatainak megoldása
A = (t:ℕn×m, l: )
Ef = ( t=t’ )
n m
Uf = ( Ef l search ( search prím (t[i, j ])) )
i 1 j 1
a
ahol prím:ℕ és prím(a) = (a>1 search( (k a)) )
k 2
295
10. Feladatok megoldása
296
6. fejezet feladatainak megoldása
db := 0 l:=mind(i)
i = 1 .. n l, j := igaz, 1
mind(i) l j m
db := db+1 SKIP l := t[i,j]>0
j := j+1
297
7. fejezet feladatainak megoldása
298
8. fejezet feladatainak megoldása
299
10. Feladatok megoldása
7.5. Valósítsuk meg azt a zsák típust, amelyikről tudjuk, hogy csak az
1 és 100 közötti természetes szám kerülhet bele, de egy szám
többször is! Implementáljuk az új elem behelyezése, egy elem
kivétele és „egy elem hányszor van benne a zsákban”
műveleteket!
Megoldás: Először egy absztrakt típussal írjuk le a zsák fogalmát,
majd ezt egy olyan konrét típussal valósítjuk meg, ahol egy
zsákot egy 100 elemű természetes számokból álló tömbben
ábrázolunk úgy, hogy ennek e-edik eleme azt mutassa meg, hogy
az e szám hányszorosan van benn a zsákban. Jól látható, hogy a
konkrét típus sokkal hatékonyabb (tömörebb reprezentáció,
rövidebb implementáció) lesz, mint az absztrakt.
300
8. fejezet feladatainak megoldása
×
:2ℕ ℕ Zsák identitás I(h)={ (e,m) h e [1..100]}
h: 2ℕ×ℕ, e:ℕ, db:ℕ
1 és 100 közötti (e,m) h h:= h-{(e,m)}) {(e,m+1)}
egész szám ás
darabszám párok (e,m) h h:=h {(e,1)}
halmaza (e,m) h h:= h-{(e,m)}
2ℕ×ℕ
(e,m) h db:= m
(e,m) h db:= 0
N×N
:ℕ100 2 (v)={(e,v[e]) | e [1..100] v[e] 0}
v:ℕ100, e:ℕ, db:ℕ
ℕ100 v[e]:=v’[e]+1
v[e]:=0
db:= v[e]
301
10. Feladatok megoldása
: ℤ* Zsák identitás
s:ℤ*, e:ℤ, l:
ℤ* s:= s, e
s, e: = s2, … ,s s , s1
l:= s = 0
l:= s = 100
: ℤ100×ℕ×ℕ×ℕ ℤ*
(v,a,f,db) = v[a], … ,v[f] db=f–a+1 a,f [0..99]
100
I(v,a,f,db) = v:ℤ
a,f,db:ℕ, e:ℤ
ℤ100×ℕ×ℕ×ℕ db<100 f:=(f+1) mod 100
v[f]:=e
db:=db+1
db>0 e:=v[a]
a:=(a+1) mod 100
db:=db-1
l:= db=0
l:= db=100
302
8. fejezet feladatainak megoldása
:{0..9}* ℕ x
(x) = xi 10 i 1 , I(x) = x x 0
I: {0..9}* i 1
f(i) = (f1(i-1) ((xi+yi+f2 (i-1)) mod 10) , (xi+yi+ f2(i-1)) div 10)
303
10. Feladatok megoldása
f:[0.. x ] {0..9}*×{0..9}
f(0) = (<>,0)
f(i) = ( f1 (i-1) ((xi*c+f2 (i-1)) mod 10) ,
(xi*c+ f2 (i-1)) div 10 ) i [1..n]
304
8. fejezet feladatainak megoldása
Megoldás:
P A = (p:P, q:P, r:P)
r := p±q
A = (p:P, q:P, r:P)
r := p q
:ℝ* P (a) = a0+a1 x + … +a a x a , I(a) = a a 0
I:ℝ*
a p, q, r-t rendre az a,b,c :ℝ*reprezentálja
ℝ* k [0..max( a , b )]: c[k ] a[k ] b[k ] )
n
k [0.. a * b ]: c[k ] a[l ] b[k l]
l k n
l 0
305
10. Feladatok megoldása
i j e = x[i (i–1)/2+j]
i<j e=0
306
8. fejezet feladatainak megoldása
E ~ ℤ
H ~ ℤ*
+,0 ~ ,<>
f(e) ~ <e> ha e>0
<> különben
Algoritmus:
y :=<>
i = 1 .. n
x[i]>0
y :=y x[i] SKIP
Számoljuk meg egy halmazbeli szavak között, hogy hány ’a’ betűvel
kezdődő van!
Specifikáció:
307
10. Feladatok megoldása
308
8. fejezet feladatainak megoldása
Algoritmus:
l:=hamis; st,e,f:read
l st=norm
elem:= e
l:= e ≥ 0
st,e,f:read
8.3. Egy szekvenciális fájlban egy bank számlatulajdonosait tartjuk
nyilván (azonosító, összeg) párok formájában. Adjuk meg annak
az azonosítóját, akinek nincs tartozása, de a legkisebb a
számlaegyenlege!
Specifikáció:
A = (x:infile(Ügyfél), l: , a: *)
Ügyfél=rec(az: *, egyl:ℤ)
Ef = ( x=x’ )
Uf = ( l,min,elem = min e.egyl a=elem.az )
e x'
e.egyl 0
Feltételes minimum keresés az x szekvenciális inputfájl
nevezetes felsorolásával (st,e,x:read).
E ~ Ügyfél
H ~ ℤ
max ~ min
(e) ~ e.egyl≥0
f(e) ~ e.egyl
309
10. Feladatok megoldása
Algoritmus:
l := hamis
st,e,x:read
st = norm
e.egyl<0 l e.egyl 0 l e.egyl 0
SKIP min >e.egyl l, min, a :=
min, a:= SKIP igaz, e.egyl, e.az
e.egyl, e.az
st,e,x:read
8.4. Egy szekvenciális fájlban minden átutalási betétszámla
tulajdonosáról nyilvántartjuk a nevét, címét, azonosítóját, és
számlaegyenlegét (negatív, ha tartozik; pozitív, ha követel).
Készítsünk két listát: írjuk ki egy output fájlba a hátralékkal
rendelkezők, egy másikba a túlfizetéssel rendelkezők nevét!
Specifikáció:
A = (x:infile(Ügyfél), y:outfile( ), z:outfile( ))
Ügyfél = rec(név: *, cím: *, az: *, egyl:ℤ)
Ef = ( x=x’ )
Uf = ( y e.név z e.név )
e x' e x'
e.egyl 0 e.egyl 0
Két szekvenciális outputfájlt előállító feltételes összegzés
(szétválogatás) – amelyeket összevonunk –, az x szekvenciális
inputfájl nevezetes felsorolójával (st,e,x:read).
E ~ Ügyfél E ~ Ügyfél
* *
H ~ H ~
+,0 ~ ,<> +,0 ~ ,<>
f(e) ~ e.egyl ha e.egyl<0 f(e) ~ e.egyl ha e.egyl>0
Algoritmus:
310
8. fejezet feladatainak megoldása
311
10. Feladatok megoldása
Algoritmus:
st,e,x:read y:=<> z:=<> u:=<>
st = norm
e.virág=”piros”
y:write(e) SKIP
e.ős=”Mexikó”
z:write(e) SKIP
e.virág=”piros” e.ős=”Mexikó”
u:write(e) SKIP
st,e,x:read
312
8. fejezet feladatainak megoldása
Algoritmus:
st,e,x:read
max, min := e, e
st,e,x:read
st = norm
max <e min e max min>e
max:= e SKIP min:= e
st,e,x:read
max>0
m := max m := min
313
10. Feladatok megoldása
a ( e.bér )
(
/ 1 )
e x' e x'
e.tipus adm e.tipus adm
v ( e.bér )
(
/ 1 ))
e x' e x'
e.tipus vez e.tipus vez
Az eredmény kiszámolásához négy feltételes összegzés (ebből
egy kiválogatás) és három számlálás kell ugyanazon az x
szekvenciális inputfájl felsorolásával (st,e,x:read).
Algoritmus:
st,e,x:read
y,f,fdb,a,adb,v,vdb := <>,0,0,0,0,0,0
st = norm
e.típus=fiz e.túl>20 e.család>4
y:write(e) SKIP
e.típus=fiz
f, fdb := f+e.bér, fdb+1 SKIP
e.típus=adm
a, adb := a+e.bér, adb+1 SKIP
e.típus=vez
v, vdb := v+e.bér, vdb+1 SKIP
st,e,x:read
f , a, v := f/fdb, a/adb, v/vdb
314
8. fejezet feladatainak megoldása
315
10. Feladatok megoldása
A = (x:infile( ), y:outfile( ))
Ef = ( x=x’)
Uf = ( y távirat(ch ) )
ch x'
*
távirat:
" aa" ha ch " á"
" ee" ha ch " é"
" i" ha ch " í "
" oe" ha ch " ö" vagy ch " ő "
" ue" ha ch " ü" vagy ch " ű "
" o" ha ch " ó"
távirat (ch) " Aa" ha ch " Á"
" Ee" ha ch " É"
" I" ha ch " Í "
" Oe" ha ch " Ö" vagy ch " Ő"
"Ue" ha ch "Ü " vagy ch "Ű "
" O" ha ch " Ó"
ch különben
Algoritmus:
st,ch,x:read
y:= <>
st = norm
y: write(távirat(ch))
st,ch,x:read
316
9. fejezet feladatainak megoldása
317
10. Feladatok megoldása
318
9. fejezet feladatainak megoldása
Algoritmus:
s := 0
t.First()
t.End()
t.Current()>12
s := s+2 s := s+1
t.First()
319
10. Feladatok megoldása
df ' '
van_szó ( hossz , sf 2 , df 2 , f 2 1
df ( df 1 , f 1 )
sf , df , f select ( sf abnorm df ' ') ) )
df ( sf 2 , df 2 , f 2 )
t.First() t.Next()
sf, df, f : read van_szó:= sf=norm
sf = norm df=’ ’ van_szó
sf, df, f : read hossz:=0 SKIP
van_szó:= sf=norm sf = norm df ’ ’
t.Next() hossz:=hossz+
1
sf, df, f: read
sf = norm df=’ ’
sf, df, f: read
320
9. fejezet feladatainak megoldása
A = (t:enor(ℕ), g:ℕ*)
Ef = ( x=x' )
Uf = ( g=x' )
Algoritmus:
g:= <>
t.First()
t.End()
g:write(t.Current())
t.Next()
t.Fist() t.Next()
|f| 0 bit, hossz:= fi, 0
i, hossz:= 1, 0 SKIP i |f| bit = fi
hossz:=hossz+1
i:=i+1
321
10. Feladatok megoldása
322
9. fejezet feladatainak megoldása
Tároló Init()
Mark(szó)
l:=Full()
*
v: ( × )n, count:ℕ, szó: *
, l:
*
( × )n×ℕ i [1..n]: v[i].jel := hamis
count := 0
n
l , i : search (v[i ].szó szó )
i 1
l v[i].jel
v[i].jel := true SKIP
count:= count+1
l := count=n
323
10. Feladatok megoldása
x.First() x.Next()
u.First() u.Next()
vége:= u.End() vége:= u.End()
vége vége
p.ssz := 1; a.Init() p.ssz := p.ssz +1; a.Init()
u.End() S u.End() S
BekVég(u.Current()) K BekVég(u.Current()) K
a .Mark(u.Current()) I a .Mark(u.Current()) I
u.Next() P u.Next() P
p.van:= a.Full() p.van:= a.Full()
324
9. fejezet feladatainak megoldása
x.First() x.Next()
sf, df, f : read van_szakasz:= sf=norm
u.Next() van_szakasz
szakasz:=””
jel:=Jel(df) S
sf = norm Jel(df)=jel K
szakasz:=szak I
asz+df
sf, df, f: read P
325
10. Feladatok megoldása
hossz(szó)+1>free
g:write(sorvég) g:write(’ ’)
free:=60 free:=free-1
g:write(szó)
free:=free- hossz(szó)
326
9. fejezet feladatainak megoldása
e ha e { c' } e { f ' }
g( e ) ha e { c' } e { f ' }
ha e { c' } e { f ' }
ha e { c' } e { f ' }
h( e ) ha e { c' } e { f ' }
e ha e { c' } e { f ' }
Ez egy összefuttatásos (lásd 9.5. alfejezet) összegzés
szekvenciális inputfájlok felett.
Algoritmus:
327
10. Feladatok megoldása
A = (t:infile(Könyv), m:infile(Vált),
u:outfile(Könyv), h:outfile( *))
Könyv = rec(azon: *, szerző: *, cím: *, kiadó: *
,
év:ℕ, pld:ℕ, isbn: *)
Vált = rec(azon: *, forg:ℕ)
Ef = ( t = t' m = m' t azon m azon )
Uf = ( u f 1 (a)
a azon(t ') azon( m')
h f 2 (a) )
a azon(t ') azon( m')
328
9. fejezet feladatainak megoldása
u,h : =<>,<>
st,dt,t:read sm,dm,m:read
st=norm sm=norm
sm=abnorm st=abnorm st=norm
st=norm sm=norm sm=norm
dt.azon<dm.azon dt.azon>dm.azon dt.azon=dm.azon
a := dt.pld+dm.forg
a 0
u:hiext(dt) h:hiext(„hiba”) dt.pld := a HIBA
u:hiext(dt)
st,dt,t:read sm,dm,m:read st,dt,t:read
sm,dm,m:read
329
10. Feladatok megoldása
Specifikáció:
Legyen T=infile(DT) a törzsfájl típusa, ahol DT=rec(beo:ℕ,
az: *, bér:ℕ). Az U=infile(DT) új törzsfájl a T-vel megegyező
szerkezetű szekvenciális outputfájl. Legyen a módosító fájl típusa
M=infile(DM), ahol DM=rec(beo:ℕ, emel:ℝ).
Most is használjuk az előző feladat megoldásánál bevezetett
jelöléseket.
A= (t:T, m:M, u:U)
Ef = ( t = t' m = m' beo(t’) beo(m’) t (beo,az) m beo )
Képzeljük el azt a felsorolót, amely alapvetően a t fájl elemeit, a
dolgozókat járja be, de úgy, hogy minden dolgozónál végrehajtja
a rávonatkozó fizetésemelést is.
A= (x:enor(DT), u:U)
Ef= ( x = x' )
Uf= ( u e )
e x'
Algoritmus:
Ez a feladat a legegyszerűbb összegzésre, a másolásra vezethető
vissza.
A First() művelet beolvassa az első dolgozót és az első
fizetésemelést. A Next() művelet beolvassa a következő dolgozót,
és amennyiben a következő dolgozó beosztáskódja nagyobb
lenne, mint az aktuális fizetésemelés beosztáskódja, akkor a
következő fizetésemelést is. A beo(t’) beo(m’) előfeltétel
garantálja, hogy mindkét művelet végrehajtása után az aktuális
dolgozó beosztáskódja nem lehet nagyobb a fizetésemelés
beosztáskódjánál. A Current() művelet ha a fizetésemelés
beosztáskódja megegyezik a dolgozóéval, akkor azt a megemelt
fizetéssel, egyébként az eredeti fizetéssel adja vissza a dolgozót.
Az End() művelet akkor lesz igaz, ha a dolgozók felsorolása
véget ér.
330
9. fejezet feladatainak megoldása
Algoritmus:
u : =<>
st,dt,t:read; sm,dm,m:read
st=norm
sm=norm dt.beo=dm.beo
dt.bér:= dt.bér+ dt.bér* dm.emel SKIP
u:write(dt)
st,dt,t:read
st=norm sm=norm dt.beo>dm.beo
sm,dm,m:read SKIP
331
10. Feladatok megoldása
332
9. fejezet feladatainak megoldása
x.First() x.Next()
i=1..n sg[ind],dg[ind],g[ind]:read
sg[i],dg[i],g[i]:read l, ind, min :=
n
l, ind, min := dg[i].eha
n min
i 1
min dg[i].eha sg [i ] norm
i 1
sg [i ] norm
333
10. Feladatok megoldása
334
9. fejezet feladatainak megoldása
Algoritmus:
poz, neg, első:= hamis, hamis, 0
st,e,x:read
st=norm ( poz neg)
poz poz poz poz neg else
neg e>0 neg e>0 neg e<0 e<0
poz, első:= poz:= neg, első:= neg:= igaz SKIP
igaz, e igaz igaz, e
st,e,x:read
335
IRODALOM JEGYZÉK
336