Számítástechnika Középfokon

Szerzők:

Énekes Ferenc
Hanák D. Péter
Horváth Attila
Horváth Katalin
Hubert Tibor
Keczer Zoltán
Koltai Márta
Kőhegyi János
Németh Piroska
Sárkány Ernő
Zsakó László

Gulyásné Lőrincz Ilona
Környei László
Lőrentei Tamás
Orbán Anna
Pethő József
Szlávi Péter
Varga Balázs



Képző- és Iparművészeti Szakközépiskola, Budapest
Budapesti Műszaki Egyetem, Budapest
Zrínyi Miklós Gimnázium, Zalaegerszeg
Államigazgatási Főiskola, Budapest
Kvassay Jenő Ipari Szakközépiskola, Budapest
Apáczai Csere János Gimnázium, Pécs
Zrínyi Miklós Gimnázium, Budapest
Eötvös Lóránd Tudományegyetem, Budapest
Kvassay Jenő Ipari Szakközépiskola, Budapest
Katona József Gimnázium, Kecskemét
Eötvös Lóránd Tudományegyetem, Budapest

Ipari Szakközépiskola, Kaposvár
Hild József Építőipari Szakközépiskola, Győr
Lovassy László Gimnázium, Veszprém
Államigazgatási Főiskola, Budapest
Apáczai Csere János Gimnázium, Pécs
Eötvös Lóránd Tudományegyetem, Budapest
Eötvös József Gimnázium, Budapest

Országos Műszaki Információs Központ és Könyvtár, 1987
Tartalom

Előszó
Bevezetés

2. A számítástechnika története
2.1. Őstörténet
2.2. Mechanikus számolóautomaták
2.3. Automatikus vezérlésű gépek
2.4. Elektromechanikus gépek
2.5. Elektronikus számítógépek
2.6. Számítógép-generációk

3. Mi a számítógép?

4. A Feladatmegoldás lépései és módszerei
4.1.A feladat meghatározása
4.2. A feladatmegoldás lépései
4.3. Kódolási módszerek
4.4. Dokumentálás

5. Algoritmusleíró eszközök
5.1. Folyamatábra
5.2. Struktogram
5.3. Mondatszerű leírás

6. Adatszerkezetek
6.1. Elemi adattípusok
6.2. Összetett adattípusok

7. Alapvető algoritmustípusok
7.1. Egy sorozathoz egy érték hozzárendelése
7.2. Egy sorozathoz egy sorozat hozzárendelése
7.3. Sorozat elemeinek permutálása
7.4. Több sorozathoz egy sorozat hozzárendelése
7.5. Rekurzió
7.6. A visszalépéses keresés tétele (backtrack)

8. Programozási nyelvek
8.1. Emberközelség
8.2. Felhasználói kör
8.3. Számítási modell
8.4. Néhány nyelv rövid jellemzése
8.5. A programozási nyelvek rövid története

9. A program helyessége
9.1. Tesztelési módszerek
9.2. Hibakeresés
9.3. Programozási típushibák
9.4. Példák a program ellenőrzésére

10. Hatékonyságvizsgálat
10.1. A végrehajtási idő csökkentése
10.2. A helyfoglalás csökkentese
10.3. A bonyolultság csökkentése
10.4. Lokális hatékonyság

11. Gyakorló feladatok
11.1. Számok kiírása betűkkel
11.2. Szám átváltása más számrendszerbe
11.3. Római számok

12. Kis program, nagy program

13. A kódolás technikai elvei

14. Programozási nyelvek: utasítástípusok

15. Alacsonyszintű programozási nyelvekről
15.1. Előismeretek
15.2. Gépi kód
15.3. Assembler, assembly nyelv

16. Feladatok

Kódolási szabályok
Irodalomjegyzék

Előszó

Szokatlan vállalkozás eredményét tartja kezében az Olvasó. Néhány szakember (számítástechnikus, egyetemi oktató, középiskolái tanár összefogott, hogy megpróbáljon válaszolni a középiskolai oktatás néhány fontos kérdésére. Nehéz és hosszú megbeszélések, éjszakákba nyúló viták után kezdtek kibontakozni egy - többé-kevésbé egységesnek mondható - elképzelés körvonalai. Az eredetileg 12 főből álló csoport munkájába közben mások is bekapcsolódtak, s végül 18-ra nőtt a közreműködők száma. Fő célunk kezdettől fogva az volt, hogy konkrét segítséget adjunk a számítástechnika oktatásához. Ebben végig egyet is értettünk, a megvalósítás módját azonban nehezebb volt megtalálni. Bízunk benne, hogy Kollégáink megértéssel fogadják kezdeményezésünket és a saját gyakorlatukban is kipróbálják az általunk leírt elveket, eljárásokat, módszereket.
Könyvünket elsősorban azoknak a - számítástechnikai alapismeretekkel rendelkező - középiskolai tanároknak ajánljuk, akik valamilyen formában tanítanak számítástechnikát, de reméljük - haszonnal forgatják azok a kollégák is, akik saját szaktárgyukban akarják alkalmazni a számítógépet, valamint a számítástechnika iránt komolyabban érdeklődő diákok. Nem általános számítástechnikai ismereteket akarunk nyújtani, hanem azt szeretnénk bemutatni, hogy mit tartunk legfontosabbnak a programozás középiskolai tanításában, a számítógép lényegének megértetésében. Ezért könyvünk fő mondanivalója az algoritmuskészítés és a programírás technikája. Megpróbáltuk összefoglalni, hogy - véleményünk szerint - mennyi és milyen ismeret szükséges az eredményes tanításhoz (azaz mit kell tudni a tanárnak), abból mit célszerű megtanítani minden tanulónak, s mit az érdeklődőbbeknek. A követelmények állandó növekedése és a helyi adottságok különbözősége miatt nem vállalkozhattunk valami egységes, kőtelező tanterv kidolgozására, a könyvben foglaltak tehát ajánlások, lehetőségek. (Különösen vonatkozik ez a közölt tematikákra.) Végül megjegyezzük, hogy a programozással egyenrangúan fontosnak tartjuk a számítógép egyes tantárgyakban való felhasználását és egyéb iskolai alkalmazásait, ezek tárgyalása viszont meghaladja a könyv kereteit.

Bevezetés

A csupa nagybetűivel írt SZÁMÍTÁSTECHNIKAI KULTÚRÁT három részre szokás osztani: az alkalmazási, a programozási (szoftver) és a számítógépes műszaki (hardver) kultúrára. Mint az előszóban megállapítottuk, mi elsősorban a programozási kultúrával fogunk e könyvben foglalkozni. Ez az ún. programozási kultúra is jelentősen változott, kiszélesedett napjainkra és jól érezhetően két részre vált:

Ebből következik, hogy más módszerekre és eszközökre van szükség, mint az előző esetben, de hangsúlyozzuk, hogy módszerek és eszközök léteznek. Ezt azért is fontos kiemelni, mert néhány elterjedt, hibás nézetet szeretnénk cáfolni vele. Az egyik szerint a programozás művészet, minden feladat megoldása más és más eszközöket, módszereket kíván, s ezért lehetetlen tanítani. A másikat szakkönyvek és tanfolyamok terjesztik. Eszerint egy jó könyvből néhány óra alatt meg lehet tanulni programozni, egy néhány hetes tanfolyam a programozó szakemberekkel egyenrangúvá tehet minket, sőt olyan véleményt is hallottunk, hogy a TV-BASIC vizsga egyenértékű az egyetemi programozói végzettséggel. E vélemény alapján nincs értelme a programozás, a számítástechnika iskolai tanításának.
Véleményünk szerint mindkét nézet elfogadása súlyos hiba lenne. A programozás (általánosabban: a számítástechnika) helyét meghatározni, a szükséges ismereteket megtanítani az iskola feladata. Ebben a fejezetben azzal foglalkozunk, amit véleményünk szerint egy tanárnak tudnia kell erről a témakörről.
Még egy gondolatot kell felvetnünk. Ahogyan a rádióamatőrök, az amatőr csillagászok sem szakadhatnak el a megfelelő szakma hazai fejlődésétől, lehetőségeitől, úgy ezt a sokkal szélesebb körből kikerülő amatőr számítástechnikusok sem tehetik meg. Tehát nem hagyhatjuk figyelmen kívül a számítástechnika magyarországi állását, céljait, jelenségeit. Bár beszélhetünk amatőr és professzionális kultúráról, de szem előtt kell tartanunk, hogy az amatőr kultúra a professzionális eredményeiből táplálkozik, s ha elszakítanánk attól, akkor hamarosan öncélúvá, céltalan játékká válna és elsorvadna.

2. A számítástechnika története

2.1. Őstörténet
Az emberiség már a történelmi fejlődés kezdeti szakaszában az információk feldolgozására és továbbítására előállított eszközöket. A kutatások szerint az ősemberek első 'számolóeszközei' kavicsok, fadarabok, zsinórra kötött csomók és a barlang falára vagy fára, csontra vésett jelek voltak. Érdemes megjegyezni, hogy ezek a primitív számolóeszközök nemcsak kifejezték a mennyiségeket, hanem egyben meg is őrizték (tárolták) őket.
A számolástechnika történetének talán legjelentősebb lépése a számok fogalmának megalkotása, melynek kialakulása igen hosszú történelmi folyamat eredménye volt. Az emberi kultúra és a civilizáció talán legrégibb írásos emlékei Mezopotámiában maradtak ránk.
A számírás ékírásos számjelekkel történt. Négyezer éves számtanpéldák árulkodnak a babiloniak matematika tudásáról. Ismerték az "egyszeregy"-et, szorzótáblázataik voltak. Reciprok-táblázatokat készítettek az osztás megkönnyítésére. Az algebra apparátusát nem ismerték, mindent "algoritmikusan" írtak le.
A mennyiségek számokkal való kifejezése mellett az emberek kezdettől fogva törekedtek olyan eszközök előállítására, amelyek magát a számolást teszik könnyebbé és gyorsabbá. Valószínűleg a kavicsokkal való számolásból fejlődött ki az első számológép, az abakusz. Mintegy 2-3 ezer évvel ezelőtt kezdték használni Egyiptomban, Görögországban és több ázsiai országban. Egyes helyeken még ma is számolnak vele.
A VIII.-IX. században élt Muhammad ibn Músza al-Hvárizmi (kb.780-850). A kor legnagyobb arab matematikusa 820 körül írta meg a hindu számolást ismertető könyvét. A könyv elveszett, csak latin fordításban maradt fenn 'Liber Algoritmi de numero Indorum' címmel ('Algoritmus' könyve az indiai számokról). A könyvet egy angol szerzetes fordította latinra a XII. században. Ebből a könyvből és más arab forrásokból ismerték meg szélesebb körben Európában az újfajta számolást; ezért vált közkeletűvé az 'arab számok' elnevezés, amely teljesen elfeledtette a számjegyek indiai eredetét.
A számjegyek mai formájának kialakítása Albrecht Dürernek (1471-1528) köszönhető. E híres magyar származású német festőnek és grafikusnak a neve matematikatörténeti művekben is gyakran fordul elő.

2.2. Mechanikus számolóautomaták
1393-1449 között élt Jamshid ben Mas'ud Ghiath Ed-din Al-Kashi iráni csillagász és matematikus. Neki tulajdonítják a tizedes törtek első használatát és a pi értékének 16 jegy pontosságú meghatározását.
A XVI-XVII. század kiemelkedő matematikusa John Napier of Murschiston (1550-1617). Napier a matematika egyik nagy alakja, a logaritmusok rendszerének megalkotója. Számolóeszközök előállításával is foglalkozott. A pontos logaritmustáblázatok készítéséhez használt eszköze az úgynevezett 'Napier-csontok'. Találmányának segítségével - csont, illetve falécek mozgatásával - gépesítette a szorzást.
A következő jelentős személyiség Wilhelm Schickard, a tübingeni egyetem tanára. 1623-ban építette meg mechanikus számológépét, amely mind a négy alapművelet elvégzésére alkalmas volt. Gépének elkészítéséről levélben értesítette Keplert. Vázlatai alapján Kepler elkészítette a fogaslécekkel működő berendezést. Schickard számológépének alapja a tízállapotú forgókerék.
Blaise Pascal (1623-1662) híres tudós és filozófus 1642-ben megépítette számológépét. Egy óraszerkezetet alakított át számológéppé oly módon, hogy a számlapot mozgóvá, a mutatót pedig mozdulatlanná 'varázsolta'. Így lehetővé vált, hogy a forgó számlap különböző helyzeteit beállíthassa és rögzíthesse. Pascal gépe nem volt annyira fejlett, mint Schickardé, mivel csak két alapműveletet tudott. Pascal gépéből mintegy 50 példány ma is megtalálható.
1671-ben az akkori idők nagy német tudósa, Gottfried Wilhelm Leibniz (1646-1716) egy olyan logikai gép gondolatát vetette fel, amely szimbólumok rendszere révén tudna a tárgyak minőségére következtetni. Többek között mechanikus számológépek szerkesztésével is foglalkozott. Továbbfejlesztette a számkerék ötletét az ismételt összeadás alapvető lehetőségével. Az első, valódi négy alapműveletes gépet alkotta meg, kézi forgató meghajtással, mozgatható beállítóművel.
Az olasz Giovanni Polenus, valamint Antonius Braun a bordáskerekes (mozgatható fogaskerék) gép feltalálói. Ismét fél évszázad telt el, amíg az első igazán használható számológépeket 1774-1790 között Matthaus Hahn plébános elkészítette. Müller (hadmérnök, XVIII. sz.) tervezett egy olyan gépet, amely regiszterek közötti műveletvégzést alkalmazott és a túlcsordulást csengővel jelezte.
C. X. Thomas 1820-ban továbbfejlesztette Leibniz gépét és megépítette a négy alapművelet elvégzésére alkalmas 'Aritmometer' nevű gépét, amely a mai asztali számítógépek ősének tekinthető.

2.3. Automatikus vezérlésű gépek
A számítógépek fejlődésében a következő lépcsőfokot az AUTOMATIKUS VEZÉRLÉS megteremtése jelentette. Az első automata számítógép megépítésének gondolata Charles Babbage (1792-1871) nevéhez fűződik, aki megépítette a világ első, speciális célú, mechanikus működésű, digitális számítógépét, a 'DIFFERENCE ENGINE'-t. A gép elkészítését szükségessé tette az is, hogy a korabeli függvénytáblázatokban rengeteg hiba volt. A cél tehát olyan mechanikus szerkezet létrehozása volt, amely a véges differenciák módszerével folyamatosan számít függvényértékeket. Sajnos technológiai nehézségek miatt a gépet nem sikerült megépítenie.
1833-ban Babbage egy korszerűbb gép létrehozásán törte a fejét. Az 'ANALYTICAL ENGINE' kidolgozására vonatkozó elképzeléseiben jól használta fel a kora textiliparát forradalmasító francia J.M. Jacqard-nak, a szövés automatizálását lehetővé tevő találmányát, a lyukkártyavezérlésű szövőszéket. Az Analytical Engine egy mechanikus működésű, univerzális, külső programozású, digitális számítógép volt.
Ebben a korszakban nemcsak gépek konstruálásával foglalkoztak, hanem megjelentek a programok előhírnökei is. Lady Ada Lovelace (1815-1852) például jegyzeteiben számítógépes programra emlékeztető leírást közölt az Analytical Engine-re.
A lyukkártya olyan közeg, amelyben az információt szabványosított helyzetű lyukasztóval lehet rögzíteni. Ősalakjában, mint fatábla, már 1728 óta ismert. Falcon, a műszerész, lemezkéket használt szövőszék vezérlésére. Ennek felfedezésétől kezdve egy szövő több szövőszéket is tudott kezelni. A lyukkártya további alkalmazására döntő befolyással volt a német-amerikai származású dr. Hermann Hollerith (1860-1929) felfedezése, aki a lyukkártyát először alkalmazta információtárolóként és ezzel a gépi adatfeldolgozás megalapítójának tekinthető.
H. Hollerith doktori disszertációjaként dolgozta ki lyukkártyás rendszerét, majd később erre alapozva építette meg adatok statisztikai feldolgozására szolgáló gépét, amelyet az 1890-es amerikai népszámláláshoz már fel is használtak. Munkássága a Tabulating Machine Company létrehozásához vezetett, melyből 1924-ben alakult meg a világ első és ma is legnagyobb számítógépgyára, az IBM (Internatíonal Business Machines Corporation).

2.4. Elektromechanikus gépek
Az első világháború idején főleg a ballisztikai problémák megoldása került előtérbe, melyben nagy szerepet játszott F.R. Moulton és O. Verbelen, akik már nem egyedül, hanem tudós kollektívák élén tevékenykedtek. Az I. világháború végével világszerte nagy centrumok alakultak az elektromérnöki tudományok területén és ezzel párhuzamosan bevonult az elektrotechnika a számítógép konstrukciókba. Bush és Hazen analóg gépe 1930-ban épült meg, s a '30-as évek végén a Szovjetunióban és Németországban is építettek hasonló rendszerű, zömében elektromechanikus jellegű gépeket.
1938-ban Konrad Zuse, fiatal építészmérnök szerkesztett először jelfogós számítógépet. Programvezérelt számológépe megfelelt Babbage koncepciójának, azonban új ötleteket is tartalmazott: a számokat és műveleti utasításokat binárisan ábrázolta bistabil kapcsolóelemek alkalmazásával; lebegőpontos aritmetikát használt.
Zuse első gépe, a Z1 mechanikus kapcsolóelemeket és egy mechanikus tárolót tartalmazott. 1941-ben készült el a világ első, jól működő, igazi 'számítógépe' , a Z3, amely kb. 2600 jelfogóból állt. Tárkapacitása 64 sor (szó), egyenként 22 bináris számjeggyel (7 decimális számjegy). Programja még merev volt, nem tartalmazott feltételes utasításokat és egy 8 sávos mozifilmszalagra lyukasztották. Az egycímes gép igen tekintélyes műveleti sebességgel rendelkezett, 15-20 aritmetikai műveletet tudott másodpercenként elvégezni.
Kozma László magyar mérnök is tervezett a '30-as évek végén egy ilyen elektromechanikus számítógépet.
A II. világháború alatt a különböző államok elsősorban a műszaki, tudományos számítások elvégzésére alkalmas rendszerek fejlesztését szorgalmazták különböző munkacsoportok létrehozásával és a legújabb műszaki megoldások alkalmazásával. Így kezdték a viszonylag lassú reléket az igen gyors elektroncsövekkel felváltani.
Aiken és Watson irányításával az IBM Laboratóriumiban, 1944-ben elkészült az ASCC, más néven a MARK I. Ez még elektromechanikus (relés) működésű, külső vezérlésű gép volt.

2.5. Elektronikus számítógépek
Az első elektronikus számítógépek századunk '40-es éveinek közepe táján jelentek meg. 1946 elején elkészült I.P. Eckert és J.W. Mauchly irányításával az első elektronikus működésű (elektroncsöves) számítógép, az ENIAC. Ez még külső vezérlésű volt, hatalmas terem kellett az elhelyezéséhez, nagyon sok alkatrészből állt és kb. 150 KW volt az energiafelvétele.
Működésük által nyert tapasztalatok alapján dolgozta ki Neumann János (1903-1957) a tárolt programú digitális számítógépek felépítésének elveit, melyek lényegében véve ma is érvényesek (Neumann-elv). Ezen elvek értelmében egy elektronikus digitális számítógépnek a következőkből kell állnia:

A modern számítástechnika megjelenésében (nemcsak a gépek felépítésében) nagy szerepe volt Neumann Jánosnak. 1945 nyarán Neumann - az EDVAC kutatáshoz kapcsolódóan - elkészítette azt a tanulmányt, amelyet a modern számítástechnika megalapozásának tekinthetünk, újdonságot jelentett, hogy a programot - az adatokhoz hasonlóan - a számítógépben tárolják.
1949-ben Wilkes a Cambridge-i Egyetemen elkészítette a világ első, belső programvezérlésű, Neumann elven működő elektronikus számítógépét, az EDSAC-ot. Ez 44 bites, fixpontos számokkal dolgozó gép volt. Már csak 3000 elektroncsőből állt és csupán 15 kW teljesítményfelvétele volt. Viszonylag lassan működött, egy összeadást 1.5 ms, egy szorzást 6 ms alatt tudott elvégezni.
Az 1950-es évek táján meggyorsult a fejlődés. Eckert és Mauchly kifejlesztette a BINAC-ot, majd az UNIVAC-ot. Rövidesen 48 darab készült el belőle. 1000 darab 12 számjegyből álló szó tárolására volt alkalmas BCD kódban és már mágnesszalagos háttértárral is rendelkezett.
Az 50-es évek második felében kialakultak a világ legnagyobb számítógépgyártó cégei: az UNIVAC, az IBM, a CDC, a Honeywell, a Burroughs. Ebben az időszakban kezdtek a diszkrét félvezetők is (dióda, tranzisztor) robbanásszerűen elterjedni. Ez igen megnövelte az üzembiztos gépek tömeggyártását, viszonylag kis teljesítményfelvétel és méret mellett. Ekkor alakultak ki a ferrittárak is. Az új építőanyagokkal együtt több szervezési újdonság is megjelent: a megszakítás rendszer, az önállóan működő adatcsatornák, melyek segítségével a perifériás műveletek függetlenek lettek a processzortól. 1962-től elterjedtek a mágneslemezek.
Elektronikus számítógépekkel Magyarországon az 1950-es évek közepén kezdtek foglalkozni. A kezdeti kutatásokban nagy szerepe volt Kalmár Lászlónak, a szegedi József Attila Tudományegyetem professzorának. Jelentős szerepet játszott elméleti és gyakorlati tevékenységével Tarján Rezső is.
A 60-as évek elején az IBM bejelentette a 360-as sorozat indítását. Megjelent az ALGOL, a FORTRAN, a COBOL programozási nyelv.
Míg az első gépeknél a legfontosabb a hardver volt, itt a bonyolultság növekedésével szükség volt először az operációs rendszer, a programozási nyelvek, illetve azok fordítóprogramjai, később pedig programcsomagok, programkönyvtárak létrehozására.
E korszak jellegzetessége volt, hogy a számítógép 'eltávolodott' a felhasználótól. Teljesítőképességének kihasználása érdekében nem lehetett megengedni, hogy egyetlen felhasználó közvetlenül - a saját munkatempójához igazodva - használja a számítógépet. A jobb kihasználás miatt vezették be a kötegelt feldolgozást (batch) és a multiprogramozást (a ki- és bemeneti idő kihasználása érdekében). A programok fontosságának (prioritásának) figyelembevételével elérhető volt, hogy a rövid futási idejű programok gyorsan elkészüljenek (ütemezés).
1969-ben több szocialista ország (Bulgária, Csehszlovákia, Lengyelország, Magyarország, NDK, Szovjetunió) elkezdte kidolgozni az Egységes Számítástechnikai Rendszert (ESZR), amely az IBM 360/370-es rendszeréhez hasonló. Az egyes országok szakosodtak a különböző nagyságú gépek és egyéb berendezések gyártására. Magyarország a kisgépek gyártását kapta feladatul. A VIDEOTON Számítástechnikai gyár készíti az R10, majd később az R11 kisszámítógépet. Másik nagy számítógépgyártónk a Központi Fizikai Kutató Intézet, ahol a TPA sorozat gépeit gyártják. Ez utóbbi a DEC PDP 11-es sorozatával kompatibilis.
A 70-es évek elején üzembe helyezték az amerikai ARPANET-et, a világ első, széles körben (egyetemek, intézetek között) használt, csomagkapcsolt hálózatát. Részben a hálózatok, részben pedig a felhasználók egyéni számítógépigényeinek kielégítése miatt megnőtt a miniszámítógépek jelentősége, s ezzel új gyártók is élvonalba tudtak kerülni: DEC, HAWLETT-PACKARD, DATA GENERAL. A miniszámítógépek jellemzője az egyszerű felépítés, nagy sebesség, fejlett megszakítás-rendszer, kis tárkapacitás, kevés és olcsó háttértár, magas szintű ember-gép kapcsolat.
A miniszámítógépek fejlődésének hatására időszerűvé vált a szocialista országokban az Egységes Számítástechnika Rendszer (ESZR) mellett külön Mini Számítógép Rendszer (MSZR) létrehozása, amely a KFKI TPA-1140-eséhez hasonló gépekből áll.
AZ 1960-as évek végén, '70-es évek elején születtek meg azok a nagymértekben integrált (LSI) áramkörök, amelyek felhasználásával sikerült előállítani zsebszámológépeket. Néhány év alatt a világon nagyon sok vállalat készített ilyeneket, s ezek gyorsan el is terjedtek. Az integrált áramkörök megjelenése mellett meghatározóvá vált a mágneslemez háttértárként való alkalmazása, a tárak területén megjelentek a fém-oxid félvezető áramkörökből (MOS) felépített dinamikus RAM-tárak.
A nagyszámítógépek emberközelibbé tétele érdekében megjelent az időosztásos üzemmód, kialakultak a terminálhálózatok. Tovább nőtt a szoftver szerepe, új jelenség, hogy a még mindig egyeduralkodó IBM, a hagyományos amerikai (Burroughs, CDC, Honeywell-Bull) és európai (ICL, Siemens) gyártók mellett a számítógépek piacán megjelentek japán vállalatok is (Mitsubishi, Hitachi, Fujitsu, Nippon Electric). Hasonló fejlődés tapasztslható a miniszámítógépek gyártásában is. Új felhasználási területeket hódítottak meg (a korábbi ipari alkalmazások mellett az adatfeldolgozás, az oktatási alkalmazás egyes területeit).
1971-ben készült el az első mikroprocesszor, 1973-ban ennek egy fejlettebb, még több áramköri elemet tartalmazó változata. Rá 4 évre már piacra került a PET nevű személyi számítógép, amelyet azóta a különböző mikrogépek egész sorozata követett.
A technológia lényege: félvezető szilíciumból készült lemezre vékony felületi rétegek kialakításával, azok fotolitográfiai utón történő szelektív marásával és a kapott nyílásokon a tranzisztorhatást biztosító szennyező atomok diffúziójával sikerült elérni, hogy egy számítógép lényegében egy (néhány) áramköri lapon megvalósítható legyen.
1968-ban alakult meg az INTEL nevű kaliforniai cég, amely ezekben a fejlesztésekben az élen járt. A '70-es évek közepén kezdték emlegetni a Szilícium-völgyet. A San Francisco melletti 4 kisváros (Mountain View, Sunnyvale, Santa Clara, Cupertino) azóta is központja az új fejlesztéseknek. Bár az első mikroprocesszor megjelenése óta csak kb. 15 év telt el, máris beszélhetünk ezek generációiról.
Az első INTEL 8008 után hamarosan megjelent a második generáció (INTEL 8080, Motorola 6800, Z80), ahol a 8-bites processzorok címzési módja 16-bites lett, s így címezhetővé vált 64 Kbyte tár. Fő gyártok az INTEL, ZILOG, Motorola, National Semiconductor. Ezután az INTEL 8086-ossal megjelentek a 16 bites mikroprocesszorok, tovább bővült a címzési lehetőség (Mbyte nagyságrend), bonyolult megszakítási rendszerek alakultak ki. Újabban pedig már 32-bites mikroprocesszorokról beszélnek.

2.6. Számítógép-generációk
A számítógépek felépítése és működése alapján a számítógépek kővetkező generációit különböztetjük meg:

Szakmai folyóiratokban, sőt időnként napilapokban is, olvashatunk, az ötödik generációs számítógépekről. Ezek pontos jellemzőit a tervezők még nem teszik közzé, hiszen ezek a holnap gépei.

3. Mi a számítógép?

A számítógép jelen van mindennapjainkban, természetes hát, hogy különféle foglalkozású emberek akarják alkalmazni mindennapi munkájukban. A számítógépet alkalmazni kívánóknak egyre kevésbé kell ismerniük a gép működésének és programozásinak minden részletét, de arra képesnek kell lenniük, hogy a számítógépes szakember számára érthetően megfogalmazzák, mit is akarnak. Ehhez pedig meg kell érteniük a számítógépek működésének a lényegét.
Igen ám, de mi a lényeg? A számítógépekről szóló könyvek bemutatják a gép belső felépítését, beszélnek központi egységről, operatív tárról, háttértárról, perifériákról, ismertetnek különféle programozási nyelveket, operációs rendszereket stb. A kezelési utasítások részletesen elmondják, hogyan kell bekapcsolni a számítógépet, milyen billentyűket kell leütni különféle hatások elérésére, hogyan lehet - a gép grafikus lehetőségeit kihasználva - színes ábrákat rajzolni a képernyőre vagy éppen hangokat előállítani. Ezek természetesen mind fontos tudnivalók ahhoz, hogy megállapíthassuk, vajon az adott számítógép használható-e egyáltalán problémánk megoldásában. De problémamegoldásra általában a ma elterjedt, Neumann-elvű számítógépek nem alkalmasak: csak feladatot tudnak megoldani. Hogy mi a különbség? Az, hogy egy feladat megoldásának menetét, azaz a megoldás algoritmusát ismerjük és ismeri a számítógép is: van ilyen programja. Egy probléma megoldásának a menete viszont ismeretlen (legalábbis mi nem ismerjük, de lehet, hogy másoknak még programjuk is van a megoldására). A ma - és a közel jövő - számítógépe tehát csak feladatokat tud megoldani, olyanokat, amelyek megoldási algoritmusát a géppel program formájában közöljük. Algoritmusnak hívjuk azon instrukciók halmazát, melye egy feladat megoldásához kell. A számítógép különböző alkalmazásaira is gondolva tehát azt mondhatjuk, hogy a számítógép olyan (elektronikus) információtároló és -feldolgozó berendezés, amely a feladatok algoritmusának és a szükséges adatoknak az ismeretében előállítja a probléma megoldásához szükséges információt.
A számítógép működésének éppen ez a lényege: igen nagy sebességgel és roppant megbízhatóan tud végrehajtani algoritmusokat. A számítógéppel problémát megoldani akaró ember dolga, hogy megtalálja a megoldás algoritmusát. Hanem ezt az algoritmust nagyon pontosan kell megfogalmazni: a számítógép nem viseli el a kétértelműséget. Egy számítógépnek ugyanis nincsenek tapasztalatai, a közhiedelemmel ellentétben (hogy ti. gondolkodó gép lenne) nem gondolkodik; csak azt tudja végrehajtani, amit megmondanak neki. Ha a végrehajtandó programban pontatlanságok vannak, a gép valahogy dönteni fog, ám az eredmény rendszerint egészen más lesz, mint amit elképzeltünk. Jó esetben csak nem tudunk mit kezdeni ezzel az 'eredménnyel', rossz esetben (pl. valamit vezérlő rendszerek esetén) a pontatlanság katasztrófához vezethet!
A problémát megfogalmazó és a megoldás algoritmusát kidolgozó ember - nagyobb munkák esetén: emberek csoportja - nem feltétlenül ugyanaz (és a számítógépek nagymértékű elterjedésével egyre kevésbé lesz ugyanaz). Kettőjük közös feladata, hogy az algoritmus első megfogalmazásából kiindulva azt részalgoritmusok sorozatára bontsák, s ezeket egyre pontosabban fogalmazzák meg. Ezt a pontosítást, más szóval konkretizálást addig kell folytatniuk, amíg az éppen használt programozási nyelv szintjét el nem érik. A programfejlesztésnek ezt a folyamatát nevezzük módszeres (strukturált) programozásnak.
Annak, aki számítógépet valamilyen feladat megoldására akar alkalmazni, nem kell többet tennie, mint megvásárolni a gépet és a kívánt feladatot elvégző programot, és meg kell tanulnia ezek használatát. Ez nem sokkal nehezebb, mint a mai háztartási gépek, járművek, elektronikus berendezések stb. kezelése.
Egészen mást kell elsajátítania annak, aki alkotó módon, azaz problémamegoldásra akarja használni számítógépet: algoritmizálni kell tudnia. Arra kell képesnek lennie, hogy a megoldás algoritmusát addig pontosítsa, amíg az a számítógépes szakember számára érthetővé nem válik. A további pontosítás - az éppen használt programozási nyelv szintjéig - már a szakember dolga.
Egyre több szakterületen lesz szükség erre a képességre. Ezért amikor számítástechnikát tanítunk, akkor elsősorban nem egy-egy programozási nyelvet (pl. BASIC-et), vagy a számítógép részeinek működését kell megtanítanunk, hanem az algoritmizálási képességet kell kifejlesztenünk a tanulókban. A tapasztalatok azt bizonyítják, hogy ezt megtanítani és megtanulni sem olyan egyszerű.
Mindez, persze, nem egészen új. A számítástechnikával foglalkozók jól tudják: a '60-as évek végén, a '70-es évek elején a számítástechnikusok között világszerte élénk vita folyt az ún. strukturált programozásról. A vita eredményeképpen számos fontos módszertani kérdés tisztázódott, új programozási nyelvek születtek, amelyek - legalább részben - megvalósítják ezeket az elveket. Ennek ellenére ma is nagyon kevés olyan magyar nyelvű könyv van, amely algoritmusok tervezésével és készítésével, adatszerkezetekkel, programozási módszerekkel foglalkozna; s ezek sem a számítástechnikával épp hogy ismerkedők számára készültek.
A számítógép legfontosabb tulajdonsága az alkalmazó szempontjából - tehát az, hogy program formájában megadott algoritmusokat igen nagy sebességgel és megbízhatóan tud végrehajtani. Problémák számítógépes megoldásához tehát el kell készítenünk a megoldás algoritmusát. Hogyan is gondoljunk a számítógépre az algoritmus kidolgozása közben?
Többé-kevésbé közismert, hogy minden számítógép központi feldolgozó egységből (CPU), operatív tárból, billentyűzetből, valamilyen - ma általában televíziószerű - kiíró egységből (az utóbbi kettőt együtt szokás manapság konzolnak, terminálnak nevezni), háttértárakból és esetleg több más ki- és beviteli egységből áll.
A fénykép ugyan hű tükörképe a számítógépnek, s ha arra vagyunk kíváncsiak, hogyan illik majd a gép környezetébe, akkor pont a fényképre van szükségünk. De amikor a számítógépet valamire használni akarjuk, akkor kedvezőbb, ha a lényeget jobban kifejező modelljéből indulunk ki.
A számitógép-tervezőket főleg az érdekli, hogy milyen fő részei vannak a számítógépnek és milyen kapcsolatok vannak a részek között. Ezért ők rendszerint így ábrázolják a gépet:

A programozó szempontjából a részegységek és kapcsolataik másodlagosak, számára sokkal fontosabb, hogy milyen mértékben kell pontosítania a részalgoritmusokat. Erre a célra a számítógép egy másik modellje alkalmasabb:

Vagyis célszerű úgy gondolni a számítógépre, mint ún. virtuális vagy absztrakt számítógépek sorozatára.
A számítógép magját a gépi eszközök alkotják. Ezek mindent tudnak, amit a számítógép egyáltalán tud, de működtetésük nagyon kényelmetlen, mert minden eszköz a többitől eltérő tulajdonságokkal rendelkezik, s ezeket a program írásánál - amelyet természetesen gépi kódban keli elkészíteni - figyelembe kell venni. Vagyis minden program megírásánál rengeteg részletkérdéssel kell foglalkozni. Régen tudjuk, hogy így szinte lehetetlen nagyobb programot készíteni.
A következő szintet a - szűkebb értelemben vett - operációs, vagyis működtető rendszer jelenti. (Tágabb értelemben az operációs rendszerbe tartozónak tekintik a programkönyvtárakat, a fordító- és a segédprogramokat is.) Kisebb számítógépek kevesebbet tudó operációs rendszerét monitornak, azaz felügyelőprogramnak nevezik, de témánk szempontjából a lényeg ugyanaz. Egyik legfontosabb feladata, hogy a gépi eszközök egymástól eltérő tulajdonságait eltakarja, használatukat egységesítse a felsőbb szintek számára: az operációs rendszer különféle rutinjai a fizikai eszközökből ún. logikai eszközöket hoznak létre. Ezek a logikai eszközök virtuálisak, azaz látszólagosak abban az értelemben, hogy egy gépi eszköz és valamilyen kiszolgáló program együttese alkotja őket. A logikai eszközöket azért is könnyebb kezelni, mert utasításkészletük rendszerint jobban illeszkedik a megoldandó problémához, használatukhoz kevesebb részletkérdést kell ismerni a fizikai eszköz működéséből. Ez persze nem azt jelenti, hogy a logikai eszköz többet tud a fizikai eszköznél! A dolog épp fordítva áll. A logikai eszköz intelligensebb ('kevesebb szóból is ért'), programozása könnyebb, de ezekért az előnyökért cserébe korlátozza a fizikai eszköz használatát.
A további szinteket a programkönyvtárak, a fordító- és segédprogramok, az alkalmazási programcsomagok és végül a felhasználói programok alkotják. Az eddigiek alapján világos, hogy minden újabb szint az előzőnél összetettebb, intelligensebb utasításokat valósít meg, de ugyanakkor korlátokat is emel: a létrejövő absztrakt gépek egyre speciálisabb célt szolgálnak! A legkülső szinten megjelenő programok általános célú számítógépünket már egyetlen fel adat(típus) elvégzésére való célszámítógéppé teszik: sakkozógéppé, bérelszámológéppé, írógéppé stb.
Egy feladat megoldásához tehát egy már kész célszámítógépet hozunk működésbe. A problémamegoldás viszont éppen egy ilyen célszámítógép létrehozását jelenti. A programozás egyik alapkérdése tehát az, hogy miként csináljunk absztrakt számi tógépet.
Mint a műszaki élet annyi mis területén, itt is két alapvető megközelítési módszer kínálkozik: haladhatunk felülről lefelé vagy alulról felfelé. A megoldandó problémák ugyanis rendszerint túl nagyok ahhoz, hogy egyszerre minden részletet átlássunk. Ezért az adott pillanatban fontos dolgokat el kell választani a részletektől.

Probléma szintje
(felső szint)
felülről lefelé
rendelkezésre álló absztrakt számítógép
(alsó szint)
alulról felfelé

A számítógépes rendszerek létrehozását a hídveréshez hasonlíthatjuk:

A megoldandó probléma (pl. egy közlekedési csomópont irányítása) és az erre a célra alkalmazandó számítógép (amely a kettes számrendszerbeli számok nyelvén ért) közötti szakadék áthidalása a programozás feladata.

4. A Feladatmegoldás lépései és módszerei
(frontális, felülről lefelé haladó, alulról felfelé haladó, kritikus részek kiemelésének módszere)

A tanulás kezdeti szakaszában, elemi feladatok számítógépre vitelekor a feladat megoldása annak egy-két mondatos megfogalmazása után a program adott nyelven, adott gépre történő kódolásával folytatódik, majd az esetleges hibák kijavítása után a 'kész' program rögzítésével be is fejeződik. Közben följegyezzük a program nevét és a magnó számlálójának állását. Már ebben az embrionális szakaszban is fellelhetők a feladatmegoldás egyes lépései, úgymint:

Később, néhány hét, hónap múlva a számítástechnikai helyzet bonyolódik! Jönnek az újabb ismeretek, velük újabb feladatok, megszületnek az újabb 'kész' programok. Mindez csak úgy önmagáért, hiszen tanulunk! Úgy fél év múlva a helyzet egyre elviselhetetlenebb! Hol is van ez a csodálatos program? Mit csinál voltaképpen? Hogyan működik? Milyen adatokat vár, milyen sorrendben? Ugyanezt kérdezhetjük eredményeiről is! És egyre csak jönnek az újabb feladatok! Mintha ezt már megcsináltam volna. Vagy mégsem ez volt, csak hasonló? Bemutatkozunk a nyilvánosság előtt, de - igaza van Murphy-nek - legfőbb büszkeségünk épp ott hagy cserben bennünket. Soroljuk tovább?
Előbb-utóbb eljutunk abba az állapotba amikor rendet kell teremtenünk! Vigasztaljon bennünket az a tudat, hogy a ma profi programozói is átestek a fejlődés felsorolt nehézségein és keserű tapasztalataikat örök okulásul PROGRAMOZÁSI ELVEK néven rögzítették. Fogadjuk meg és alkalmazzuk takácsaikat már a kezdet kezdetén! Ebben a fejezetben a feladatmegoldás első három lépését tárgyaljuk.

4.1.A feladat meghatározása
A feladat megfogalmazását, meghatározását általában néhány leírt, kimondott mondattal elintézettnek tekintjük. Pedig éppen a hiányos, pongyola feladatmeghatározás következménye lehet az, hogy az elkészült program nem azt a feladatot, vagy nem úgy oldja meg, ahogy azt annak megfogalmazója - gondolatban - kívánta.
A feladat megfogalmazása mindig legyen egyértelmű, pontos, teljes; rövid, tömör, formalizált, szemléletes, érthető, tagolt formájú. Mindezeket úgy valósítsa meg, hogy abból a program készítője egyértelműen és pontosan azt a feladatot és ügy oldja meg, ahogy azt a feladat kitűzője elvárta. A további viták elkerülése végett nem árt, ha a feladat kitűzése írásban rögzített! Példaként nézzük meg egy részfeladat kitűzését, megfogalmazását.

A feladat:
Már ismerjük adott számú felvételiző elért pontszámait és az elérhető maximális pontszámot. Határozzuk meg és listázzuk ki (képernyőre) a P pontot elért felvételizők sorszámát és nevét.

Már ismert adatok:

A részprogram bemenő adata:

A részprogram eredménye a képernyőn megjelenő lista, mely a P pontot elért felvételizők nevét és sorszámát tartalmazza. Legyen előre-hátra lapozható (E,H), ENTER-re fejeződjön be a részfeladat!
Egyéb követelmény: A már ismert adatok értéke változatlan maradjon!

Ugye elég pontosnak, rövidnek, tagoltnak tűnik a feladat megfogalmazása? Pedig ha belegondolunk, akkor hamarosan kiderül, hogy nem egyértelmű a P megadási módja, azaz adott-e már a program előző részében, vagy most kérjük be billentyűzetről. MAX értéke vajon lehet 0 és 120, vagy nem? A meghatározás egyértelműen rendelkezik a részfeladat befejezését jelentő billentyűről, viszont az előre-hátra lapozást kiváltó billentyűket legfeljebb sugallja a szövegben szereplő nagy E és H betű. Ha mindezeket tisztáztuk a feladat kitűzőjével, még akkor is hátra van a 'listázzuk ki' és 'lapozható' kifejezések értelmezése. Ugyanis elég nagy a szabadságunk!
Mit tartalmazzon a lista egy képernyőn belül? Csak egy nevet és sorszámot, esetleg az aktuális pontszámot is? Vagy annyi felvételiző adatait jelenítsük meg egy képernyőn amennyi csak elfér, esetleg ne legyen zsúfolt a kép? Csupa lényeges kérdés! Egyrészt sokkal könnyebb megírni az egy nevet megjelenítő lapozható algoritmust, mint ha pl. maximum tíz tanuló adatait tartalmazza egy-egy előre-hátra lapozható képernyő. Másrészt pedig, ha például 100 tanuló érte el az adott pontszámot, akkor a felhasználó szempontjából egyáltalán nem mindegy, hogy egy-egy futtatásnál 100 vagy csak 10 beavatkozással nézheti át a számára oly fontos névsort. Az ilyen szabadsági fokok nagyon veszélyesek! Kényelmesebb programozó gyakran a számára egyszerűbb megoldást választja, aminek következtében előbb-utóbb leszoknak róla és programjairól a megrendelők.
Az elv: a feladat megfogalmazásából eredő választási lehetőségeinket úgy használjuk ki, hogy megoldásunk az egyéb követelmények betartása mellett a felhasználó szempontjából a lehető legkényelmesebb legyen! A programot mi egyszer írjuk meg és reméljük többször használják!

A FRONTÁLIS feladatmegoldás 'módszerét' ismeri meg először minden programozó (sajnos). Mint a neve is mutatja, a feladatot egy egységként kezeli, teljes arcvonalán támad, azt egyszerre akarja megoldani minden előzetes felmérés, részekre bontás, átgondolás nélkül. Kis, tanulói feladatok megoldására még eredményesen alkalmazható. Ahogy egyre nagyobbak, bonyolultabbak a feladatok: annál több probléma jelentkezik e módszer használatakor, de ha eddig bevált és más módszert nem ismerünk, akkor... Lehet, hogy emiatt mondják sokan: 'a programozás valami nagyon bonyolult dolog?
Legjellemzőbb hibái: a kész programnak nincs szerkezete, csupa trükk az egész, módosítani, javítani, fejleszteni szinte lehetetlen, a tesztelése véget nem érő, dokumentációja nincs, használata bizonytalan, csak idő kérdése, hogy működését senki se értse. Kezdetben csak a készítőjével együtt használható, később már vele sem. Előnye tehát nincs, hiszen amit szabadságnak vélünk, az nem más, mint anarchia.

4.2. A feladatmegoldás lépései
Gyakorlottabb amatőr és szakember egyaránt a feladat FELÜLRŐL LEFELÉ haladó megoldását, lebontását alkalmazza legtöbbször. Hangsúlyoznunk kell, hogy a feladat megoldásának ebben a szakaszában nem programot, hanem ALGORITMUST készítünk. Nem törődünk azzal, hogy később a program milyen nyelven, milyen gépre készül el. A feladat ilyen szintű megoldása, annak rögzítése óriási előnyökkel jár. A majdani aktuális nyelv és gép sajátosságait figyelmen kívül hagyhatjuk, csak a feladat logikájára, a megoldás ebből adódó szerkezetére, az egyes részek kapcsolódására, a szükséges adatszerkezetekre, adatokra, mindezek rögzítésére koncentrálhatunk. A feladat algoritmikus megoldása után választhatjuk ki a megoldásra legmegfelelőbb nyelvet, sőt esetleg gépet is.
A megoldás nyelv- és gépfüggetlenségének előnyeit - a hordozhatóságot - csak az értékeli igazán, akinek volt már szerencséje egy hosszabb programot annak listájából átírni egy másik gépre, netán nyelvre. Szükségképpen merül föl az a kérdés, milyen nyelven írjuk le a születő, a feladatot megoldó algoritmust, ha egyszer nem kódolunk, azaz nem törődünk egyetlen programozási nyelvvel, nyelvjárással sem? Erre a kérdésre könyvünk következő fejezete ad választ.
Fordítsuk hát figyelmünket a felülről lefelé haladó módszer részleteire. A kitűzött feladat többszöri figyelmes végigolvasása, -gondolása után foghatunk hozzá annak megoldásához. Alapvető STRATÉGIAI ELVÜNK meglehetősen régi: OSZD MEG ÉS URALKODJ! A programozók ezt az elvet a LÉPÉSENKÉNTI FINOMÍTÁS elvének nevezik. Mondanivalója: oszd részekre a feladatot, mert így az egyes részeket egymástól függetlenül (természetesen azokat egymáshoz szigorúan illesztve) megoldhatod és így uralkodhatsz az egész feladat felett. Első közelítésben szinte minden feladat a következő három részre osztható:

Ez a felosztás sajnos ma még nem elegendő, az egyes részeket tovább kell finomítanunk. (Ne gondoljuk azonban, hogy mindig a második rész a legbonyolultabb!) A felosztáskor nyilvánvalóan ki kell jelölnünk azt, hogy az illető részfeladat milyen adatokat vár, azokkal mit csinál és milyen eredményeket szolgáltat. A megoldás hogyanjáról most nem döntünk! Az első - és minden további - szint részfeladatai közötti kapcsolatot, harmóniát is biztosítanunk, rögzítenünk kell. Az egyes részfeladatok közötti kapcsolatot azok be- és kimeneti adatainak illesztésével biztosíthatjuk.
Feladatunkat tehát az első szinten néhány jól körülhatárolt részfeladatra osztjuk és ezek egymás közötti kapcsolatát is meghatározzuk. A következő szinteken pedig addig folytatjuk az előző szint részfeladatainak további részekre bontását és azok ismételt egymáshoz illesztését, amíg olyan elemi részfeladatokig nem jutunk, melyek kódolása már nem okoz problémát egy kezdőnek sem, mert arra nagyon egyszerű szabály adható meg. Reméljük sikerült érzékeltetni a lépésenkénti jelzőt. A módszer leírása, megértése egyszerű, következetes betartása és alkalmazása viszont nagyon fegyelmezett gondolkodást, tervszerű munkát igényel!

Milyen további tanácsokkal, elvekkel szolgálhatunk a lépésenkénti finomítás STRATÉGIAI elvének gyakorlati alkalmazásához? Lássuk a TAKTIKAI elveket!

A megoldás lépésenkénti finomításával előbb-utóbb eljuthatunk egy olyan szintre, amelyen az adott nyelven rendelkezésünkre álló utasításokból már felépíthetjük, létrehozhatjuk az éppen szükséges eljárásokat. Akár így is kezdhettük volna: a meglévő eljárásokból létrehozunk olyan magasabb szintű eljárásokat, amelyeket szükségesnek gondolunk, ezekből még magasabb szintű eljárásokat állítunk össze stb. Ezt alulról föl-felé haladó módszernek nevezzük. A kétféle módszer a gyakorlatban kiegészíti egymást, de a felülről lefelé haladóé az elsőbbség. A számítógépes problémamegoldásnál ugyanis eleinte felülről lefelé haladunk, s csak később, egyes részletek kidolgozásakor építkezünk alulról fölfelé.
A megoldás ALULRÓL FELFELÉ haladó felépítése óriási előrelátást, gyakorlatot igényel. Sikerrel csak igazán kiváló képességű szakemberek alkalmazhatják. Kisebb, nem túl bonyolult feladatok megoldásira ajánlott, vagy akkor, ha pontosan definiálhatók azok: az elemi eljárások, amelyeket a megoldás során használnunk: kell. Sikeres alkalmazásához első lépésként alaposan végig kell gondolni a feladatot felülről lefelé. Először a legelemibb eljárásokat, azok algoritmusát készítjük el, majd ezekből - és néhány elemi utasításból bonyolultabbakat hozunk létre, melyek egy kisebb részfeladat megoldását adják. Munkánkat addig folytatjuk: újabb és újabb részfeladatok összefogásával, amíg meg nem kapjuk a teljes feladat megoldását.
KRITIKUS RÉSZEK KIEMELÉSÉNEK módszerét ugyancsak nagy gyakorlattal rendelkező programozóiknak ajánljuk. Tulajdonképpen itt is felülről lefelé haladunk, de nem dolgozunk ki részletesen (tovább bontva) minden részfeladatot, nem írunk rá részletes algoritmust, mert akkora gyakorlattal rendelkezünk már, hogy egy-egy nem túl bonyolult részfeladat megfogalmazása, illesztése után képesek vagyunk annak hibátlan kódolására. Ilyen feladat lehet pl. a 4.1. fejezetben megfogalmazott felvételizős példa. Részletes algoritmust csak a feladat legbonyolultabb, kritikus részeiről készítünk. Tulajdonképpen a feladatot több részfeladatra osztjuk, azokat elő- és utófeltételekkel látjuk el, illesztjük őket egymáshoz, de viszonylag részletes algoritmust csak azokról a részfeladatokról készítünk, melyek azonnali kódolásával nem tudunk megbirkózni.
Hogyan is végezzük el a feladat részfeladatokra bontását? A kérdés megválaszolásához a mindennapi életből kell kiindulnunk. Egy bonyolult tevékenységet elemibbekből háromféle módon építhetünk fel. Lehet több elemi tevékenységet egymás után elvégezni (számítástechnikai szakkifejezés: szekvencia, felsorolás), lehet egy feltételtől függőén egyik vagy másik tevékenységet végezni (elágazás, választás). A legbonyolultabb esetben egy elemi tevékenységet végzünk el sokszor (ciklus, ismétlés).

Az algoritmusainkat tehát háromféle módon építhetjük fel elemibb algoritmusokból. Hogyan tudjuk eldönteni, hogy mikor melyiket alkalmazzuk? Ahogyan az algoritmusok felépítésére vannak eszközök, úgy az összetett adatok felépítésére is vannak. Egy összetett adat állhat elemibb adatok felsorolásából (felsorolás), egy feltételtől függően vagy ilyen vagy olyan szerkezetű lehet (alternatív szerkezet), illetve állhat elemi adatok sokaságából (sorozat, halmaz). Az algoritmusok és az adatszerkezetek között igen szoros kapcsolat van. Egy felsorolást általában szekvenciával dolgozunk fel, egy alternatív szerkezetet választással, egy sorozatot pedig ismétléssel. Az adatszerkezet tehát segítségünkre lehet abban, hogy mikor melyik algoritmikus struktúrát alkalmazzuk, de semmit nem mond arról, hogyan alkalmazzuk. Erre a kérdésre adnak majd választ a programozási tételek.

Algoritmus
Az algoritmus legáltalánosabb értelemben nem más, mint tervszerűség. Ha egy elvégzendő cselekvéssorozatot lépésről-lépésre átgondoljuk, megtervezzük, úgy is mondhatjuk, hogy algoritmust adunk egy bizonyos cél elérésére.
A számítógépek az algoritmusok alkalmazhatóságát sokszorosára növelték. Olyan méretű feladatoknál, melyek a számítógépek megjelenése előtt megoldhatók voltak, a teljes gépesítés nem okvetlenül volt előnyös, hiszen az algoritmus "lefuttatását", a gépies számítási munkát is embernek kellett végeznie, és jelentősen növelhette a hatékonyságot, ha ez az ember is ügyeskedhetett, kihasz-nálhatta menet közben az előre nem látható egyszerűsítési lehetőségeket. A gépek megjelenése megváltoztatta a helyzetet: sokkal nagyobb, bonyolultabb számítási, adatfeldolgozási feladatokat tudnak megoldani, mint az ember magában, de ehhez pontosan, egyértelműen megfogalmazott programra, algoritmusra van szükségük. Ezek az algoritmusok a gépek nélkül gyakorlatilag használhatatlanok, ezért korábban a megfelelő feladatok fel sem vetődtek. A gép így aztán olyan munkákat is átvállalhatott az embertől, melyekről az úgy érezte, hogy intelligenciája, nemformális ítélőképessége legjavát követelik tőle (pl. a piaci döntéseket).

Egy tetszőleges algoritmus felépíthető a következő elemekből:

Az iteráció nem feltétlenül szükséges elem, hiszen az előállítható szekvenciákból, feltételből és ugrásból.
1966-ban két olasz matematikus, Corrado Böhm és Giuseppe Jacopini mutatja be azokat a kutatási eredményeket, amelyeket azóta az algoritmusok strukturált leírásának egyik alaptételeként használunk. A tételt Böhm-Jacopini-tételnek nevezik: Bármely algoritmust leírhatunk három alapstruktúra segítségével: szekvenciával, iterációval és szelekcióval.
A csak szekvenciákból, szelekciókból és iterációkból építkező programot strukturált programnak nevezzük. A strukturált programozásban ismeretlen a feltétel nélküli vezérlésátadás fogalma, így többek között egy ciklusból sem ugorhatunk ki. Ebből következik, hogy a program minden szekvenciájának - és így az egész programnak is - egyetlen belépési és egyetlen kilépési pontja van.

4.3. Kódolási módszerek
Az algoritmus elkészítése után a kódolás munkája következik a programkészítés folyamatában. Az IS-BASIC nyelv definíciója mellett a függelékben megtalálhatók néhány nyelv kódolási szabályai is az országban leginkább elterjedt géptípusokra, nyelvekre, nyelvjárásokra. Néhány példánál megadjuk a Turbo Pascal 3.xx változatot is, összehasonlítási lehetőség céljából. Kérjük az Olvasót, hogy a leírt szabályokat a gyakorlatban viszonylag szabadon alkalmazza, ne tekintse azokat merev dogmáknak.
Az algoritmusírásban legelterjedtebb felülről lefelé haladó módszer következtében kódoláskor is ezt az utat követjük legtöbbször. Programunk. így meglehetősen sok, egymásba skatulyázott eljáráshívást tartalmaz. Egy bonyolultabb rutint néhány egyszerűbb hívásával és egy pár elemi utasítás összeépítésével megoldottnak tekintünk, holott a hívott eljárások még nem is léteznek.
Sok nyelv (pl.: BASIC) főleg a tanulás kezdeten szinte sugallja ezt a módszert. Meglehetősen hosszú idő, sok program megírása után azonban előbb-utóbb kialakítjuk magunknak azt a szubrutinkönyvtárat, mely több egyszerű téglából, néhány bonyolultabb, de kellően általános és szinte mindenütt használható panelból áll, melyeket készen beépíthetünk egy-egy nagyobb műbe. Aki próbálta, az tudja, hogy ez a feladat még fejlesztői segédprogram alkalmazásával sem egyszerű dolog.
A kész algoritmust alulról felfelé is haladva is kódolhatjuk. Létezik a programozási nyelveknek egy másik csoportja (pl.: LOGO, FORTH stb.), amelyek szinte kínálják az alulról felfele haladó kódolást. Először a legelemibb feladatokat megoldó eljárásokat készítjük el, vagy a már készeket (a szubrutinkönyvtárban lévő, névvel ellátottakat), pontosabban a nyelvben már meglévőket - hiszen létrehozásuk, névvel való jelölésük óta a nyelvnek szerves részei, szerepelnek annak azonnal végrehajtható szótárában - egyszerűen felhasználjuk. A bonyolultabb - most készített - eljárásnak is nevet adunk, melynek hatására ez a szó is a nyelv szerves részévé válik, míg végül kész programunk is csak a nyelv egy új szava lesz.

4.4. Dokumentálás
Kétféle dokumentáció létezik: felhasználói és fejlesztői. Részletezésük nélkül röviden: a FELHASZNÁLÓI DOKUMENTÁCIÓ önálló, a kész programmal együtt átadandó szöveg, mely megad minden, a program használatához szükséges információt. Tartalmazza:

A FEJLESZTŐI DOKUMENTÁCIÓ nekünk szól és a program fejlesztésével párhuzamosan készül. Részei:

5. Algoritmusleíró eszközök

Az előző fejezetben, a feladatmegoldás lépései között már találkoztunk az algoritmuskészítés fogalmával. Most az algoritmus leírásának eszközei közül mutatunk be néhányat. Ezeknek az algoritmusleíró eszközöknek célja a megoldás menetinek géptől független, szemléletes, a logikai gondolatmenetet, a szerkezeti egységeket világosan tükröző leírása.
Előnyei:

5.1. Folyamatábra
A folyamatábra a feladat megoldási lépéseinek sorrendjét - utasítástípusonként különböző geometriai alakzatok felhasználásával - szemléltető ábra. A felhasznált szimbólumok és jelentésük a következő:

ún. határszimbólumok, a program elejét és végét jelzik;
beolvasó és kiíró utasítás;
értékadó utasítás, műveletvégrehajtás, aritmetikai kifejezés kiértékelése stb;
elágazás. A feladatvégrehajtás egy, a rombuszba írt feltétel alapján egyik vagy másik irányban folytatódik. A rombusznak két kimenete van, amelyek igen és nem (l,N) jelzéssel vannak ellátva.
számlálásos ciklus

A folyamatábrában a haladás irányát nyilakkal jelöljük. Ha a nyilakat elhagyjuk, a folyamatábrát felülről lefelé, illetve balról jobbra haladva követjük.
Fenti szimbólumok segítségével utasítássorozatok (szekvencia), elágazások, ciklusok, eljárások szervezhetők.
Most nézzük az előbbi példánk folyamatábráját:

A folyamatábra hátránya, hogy elemei nem felelnek meg az algoritmuskészítés során felhasználható struktúráknak (szekvencia, elágazás, ciklus). Használatukkal igen könnyen előállíthatok olyan bonyolult szerkezetek is, amelyek megértése azután nagyon nagy problémát jelent.
Megadunk néhány elvet a folyamatábra használatához:

5.2. Struktogram
A második fajta algoritmusleíró nyelv az ún. struktogram. Ez valójában a mondatszerű leírás és a folyamatábra egyféle keveréke. Magában hordozza a mondatszerű leírásból a struktúrára jellemző bekezdéses ábrázolás bizonyos jegyeit, de megtalálhatók benne a folyamatábrára emlékeztető geometriai elemek, elágazások is.
Magát az algoritmust egy téglalapba írjuk. A feladatmegoldás struktúrájának megfelelően ebbe a téglalapba további téglalapokat illesztünk- és a végrehajtandó utasításokat ezekbe írjuk bele. Egymás utáni végrehajtás esetén a téglalapot két (több) téglalapra osztjuk:

Elágazás esetén a téglalapot kettévágjuk és a megoldást a feltételeknek megfelelően folytatjuk.

A ciklusutasítást egy másfajta téglalappal adjuk meg:

Befejezésképpen nézzük meg a jól ismert feladat struktogramját. N valós szám összege:

5.3. Mondatszerű leírás
Amint azt a név is mutatja, az algoritmus egymást követő lépéseit mondatokkal vagy mondatszerű szerkezetek egymásutánjával próbáljuk leírni. A mondatszerű leírás két fajtája különböztethető meg.

Beolvasó és kiíró utasítás

Be: (változók felsorolása) [az adatokkal szemben támasztott követelmények]
Ki: (kifejezések felsorolása) [a kiírás formájára vonatkozó követelmények]

Értékadó utasítás

változó:=kifejezés

Az utasítás hatására a változó felveszi az egyenlőségjel jobb oldalán álló kifejezés aktuális értékét.

Elágazások (feltételes utasítások)

Ha (feltétel) akkor
   utasítások
elágazás vége

Jelentése:
Ha az adott feltétel teljesül, akkor az utasítás(ok) kerül(nek) végrehajtásra, és a feladat megoldása az elágazás vége után folytatódik. Ha a feltétel nem teljesül, a megoldás egyből az elágazás vége után folytatódik.

Ha (feltétel) akkor
   utasítások 1.
különben
   utasítások 2.

elágazás vége

Jelentése:
Ha a feltétel teljesül, akkor az utasítások 1. kerül végrehajtásra, különben pedig az utasítások 2. A feladat megoldása mindkét esetben az elágazás vége után folytatódik. Megjegyzés: ha az elágazás ágain egyetlen utasítás van, akkor az 'elágazás vége' szöveget nem kell kiírni.

Elágazás
   feltétel 1 esetén
      utasítások 1
   feltétel 2 esetén
      utasítások 2
   ...
   feltétel n esetén
      utasítások n
   egyéb esetben
      utasítások n+1
Elágazás vége

Jelentése:
Ha az i. feltétel teljesül (i=1,2,... n), akkor a neki megfelelő utasítás(oka)t kell végrehajtani, majd a feladat megoldása az Elágazás végé után folytatódik. Ha egyik feltétel sem teljesül, akkor az egyéb esetben megadott utasításokat kell végrehajtani, illetve ha ezt nem adjuk meg, akkor az Elágazás vége után folytatódik a végrehajtás.

Ciklusszervező utasítások

Ciklus (ciklusváltozó kezdőérték)-től (végérték)-ig (lépésköz)-ösével
   ciklusmag utasításai
Ciklus vége

Jelentése:
A ciklusmag utasításai a ciklusváltozó kezdő- és végértékének, valamint a lépésköznek megfelelő számszor kerülnek végrehajtásra (számlálásos ciklusutasítás). (A lépésköz 1 esetén elhagyható.)

Ciklus amíg (feltétel)
   ciklusmag utasításai
Ciklus vége

Jelentése:
A ciklusmag utasításait addig kell végrehajtani , amíg a feltétel igaz. Ha a feltétel hamis logikai értékű, a végrehajtás a Ciklus vége után folytatódik (elöl tesztelő ciklus).

Ciklus
   ciklusmag utasításai
amíg (feltétel)
Ciklus vége

Jelentése:
Az előzőhöz hasonló ciklusutasítás, azzal a különbséggel, hogy a ciklusmag utasításait egyszer mindenképpen végre kell hajtani (hátul tesztelő ciklus).

Eljárások
Bonyolultabb, összetett feladat esetén a teljes algoritmust a feladat struktúrájának megfelelően többszörös mélységben készítjük el. Az egyes feladatmegoldási szinteken a következő szint algoritmusrészeire eljáráshívásokkal hivatkozunk.

Eljárásnév (paraméterek):
   az eljárás utasításai
Eljárás vége

A főprogramot a következőképpen írjuk:

Program:
   utasítások
Program vége.

Az eljárásokat paraméter nélkül is használhatjuk, ekkor az eljárás neve mögötti zárójeleket sem kell kiírni. Az eljárás hívása egyszerűen a nevének leírásával történik.
A fenti utasítástípusokkal utasítássorozatok, elágazások, ciklusok, eljárások szervezhetők, velük tetszőleges algoritmus megfogalmazható.

Egyéb jelölések
Ha egy sorba több utasítást írunk, akkor közéjük kettőspontot kell tenni.
Az algoritmusleírásba bárhova elhelyezhetünk megjegyzéseket, a kódoláshoz szükséges magyarázatokat szögletes zárójelek közé zárva.

Most nézzük az előbbi egyszerű példa leírását a fenti módszerrel:

Program:
   Be: N [N>0, egész]
   S:=0
   Ciklus I=1-től N-ig
      
Be: A
      S:=S+A
   Ciklus vége
   Ki: S
Program vége.

Ezzel a fajta algoritmusleírással azért foglalkoztunk részletesebben, mert megtanítását, használatát bármely iskolatípusban javasoljuk. Előnye: a hétköznapi nyelvhez közel álló, szerkezetet tekintve szemléletes, könnyén megtanulható algoritmusleíró nyelv. Jól átgondolt használatával a feladatmegoldás két részre bontható: a megoldás megfogalmazására és az elkészült algoritmus kódolására.
Természetesen az általunk választott szavaknak lehetnek más változatai, melyek semmivel sem rosszabbak ezeknél. Felsorolunk példaként néhány lehetőséget:

Be - Olvas, Ki - Ír, Elágazás - Választás, Ha - Amennyiben, különben - egyébként, Ciklus - Ismétlés, amíg - mialatt

Az algoritmusleíró nyelv használatához felsorolunk néhány TECHNOLÓGIAI ELVET. Ezek a nyelv használatának 'hogyanját' adják meg:

6. Adatszerkezetek

Térjünk rá az adatokra! Az adattípus fogalmát a következőképpen definiálhatjuk: az adattípus megadása a típus értékkészletének, a rajta végzett műveleteknek, az értékek jelölésének és a tárban való ábrázolásának a rögzítését jelenti. Az adattípusaink kétfélék lehetnek: elemiek, amelyeknek felhasználói szempontból nincs belső szerkezetük, valamint összetettek, amelyek elemiekből épülnek fel; ezek az adatszerkezetek .
A 4.2. fejezetben megállapítottuk, hogy a program által feldolgozandó adatok finomításakor (az összetett adat részekre bontásában) többféle szerkezetet használhatunk: a felsorolást, az alternatív szerkezetet, a sorozatot és a halmazt. Most összetett adatszerkezetek megadásával, ábrázolásával, a rajtuk végzett műveletek megvalósításával foglalkozunk.
Az alapvető kérdés természetesen az, hogy mit tekintünk elemi adatnak és mit összetettnek? Az elemi adatnak a program szempontjából nincs szerkezete, nem tudjuk egyes részeit külön kezelni, az összetett adatoknál erre van lehetőség. E definíció alapján a kérdésre nem tudunk egyértelműen válaszolni. A válasz elsősorban a használt programozási nyelvtől függ. A BASIC esetén egy valós szám már elemi adatnak számít, hiszen használatakor nem törődünk a szerkezetével, nem akarjuk egyes részeit külön kezelni (sőt nem is tudjuk). Ha gépi kódot használunk, akkor a valós szám elemi típusként nem létezik, a Z80 gépi kód csak 1 és 2 byte-os számokra ad néhány aritmetikai műveletet. Itt tehát a valós számokat nekünk kell megvalósítani, elemibb adatokból (byte) felépíteni, így a gépi kódban a valós szám nem elemi adattípus.
Másik kérdés az lehet, hogy miért kell foglalkozni az adatszerkezetekkel, az adatszerkezetek ábrázolásával, a rajtuk végzett műveletek megvalósításával? A kérdésre tulajdonképpen már megadtuk a válasz első részét: azért, mert az egyes nyelvekben nem létezik minden, számunkra szükséges adatszerkezet. A válasz másik része az adatszerkezeteket a programozási tételekhez (algoritmustípusokhoz) hasonlítja. Legtöbbször ugyanis nem akármilyen adatszerkezetet kell használnunk, hanem valamilyen nevezetes, gyakran használt típust (egész szám, valós szám, tömb, verem, fa, stb.). így az adatszerkezetek körében is elvégezhetjük a tipizálást.
Az adatszerkezeteket most mégis elemi és összetett adatokra bontjuk, s ezt a magasszintű nyelveknél szokásos felosztás alapján végezzük.

6.1. Elemi adattípusok

6.1.1. Egész szám
Egész számokra az egyes nyelvek sokféle műveletet adnak. Van olyan nyelv, amely megkülönbözteti az egész számokon végezhető műveleteket a valós számokon végezhetődtől. Ilyen esetben az egész osztás egész hányadost ad eredményül, s rendszerint van egész eredményt adó maradékképzés is. Más nyelvek (pl. a BASIC) az egészeket is valós számként tárolják. Ilyenkor természetesen előfordulhat, hogy egész számokkal végzett műveletek nem egész eredményt adnak (pl. osztás, gyökvonás).
Egész számok használatakor nem árt ismerni az ábrázolásukat. Legtöbbször 2 byte-on ábrázolják őket, kettes komplemens kódban. Ez a negatív számok miatt érdekes. Az ábrázolás megadja a számítógépben így tárolható egész számok korlátját: -32768 és +32767 közöttiek lehetnek. Ennek komoly következményei vannak: a matematikával ellentétben a számítógépes egész számok köre nem zárt az alapműveletekre, azaz lehetséges, hogy két egész szám összege nem számítható ki. Ezt nevezzük túlcsordulásnak.
Gépi kódban kicsit más a helyzet. Itt általában nem létezik az egész (a 2 byte-os) számokra az összes alapművelet. Például a Z80 csak az összeadás és a kivonás műveletét ismeri, a szorzást, a hányados- és maradékképzést nekünk kell megvalósítanunk. Ezt megtehetjük ismételt összeadással, illetve kivonással.

6.1.2. Valós szám
Valós számokra (ábrázolásukból következően) kétféle korlátot adhatunk. Létezik egy nagyságrendi korlát és egy pontossági korlát. Első megjegyzésünk, hogy a számítógépben ábrázolható valós számok igazából nem valósak, hanem 2-es vagy 10-es számrendszerben véges sok számjeggyel leírható racionális számok. Megadásuk egy 0 és 1 közötti számmal (mantissza) és (2-es vagy 10-es) hatványkitevővel történik. Ezt hívjuk lebegőpontos számábrázolásnak. A tízes számrendszerben felírhatjuk a számokat normalizált formában: a tizedesvesszőt eltoljuk, és a tíznek megfelelő hatványával szorozzuk a számot, hogy a számjegyek a tizedesvesszőtől jobbra helyezkedjenek el, és a tizedes első számjegye ne legyen 0. Például:

 364,7896 = 0,3647896 x 10^3
-0,005674 = -0,5674 x 10^-2

Valós számokra a műveletek sokasága létezik, csupán gépi kódban okoz gondot a kezelésük. Általában célszerű a BASIC értelmezőben már meglevő szubrutinokat használni valós számok kezelésére.

6.1.3. Logikai érték
Egyes nyelvek ismerik a logikai típust és a rá vonatkozó műveleteket (pl. Pascal), a BASIC-ben logikai típus nincs, műveletek viszont vannak (AND, OR, NOT). Itt meg kell oldani a logikai IGAZ és HAMIS értékek tárolását. Ezt a legtöbb BASIC úgy csinálja, hogy a hamis értéknek a 0-t, az igaznak pedig a -1-et vagy az 1-et felelteti meg (az IS-BASIC a -1-et adja). A logikai értékek ezután egész típusú változókban tárolhatók. Megjegyezzük, hogy a BASIC az egész típusú számokon bitenként hajtja végre a logikai műveleteket.
Turbo Pascal-ban a logikai változó tárolása 1 byte-on történik. bár mindössze egy bit (a legalsó) tartalmazza a szükséges információt (FALSE=0, TRUE=1).

6.1.4. Karakter
Ha egy nyelvben ilyen típus létezik, akkor egy ilyen változóban (1 db) tetszőleges karaktert tárolhatunk. A karakterek kódolására legtöbbször az ASCII kódrendszert használják, nagygépeken az EBCDIC is előfordul. Karakterekre az összehasonlítás, a kódmegadás, a következő, illetve az előző karakter képzése műveleteket szokták megvalósítani.

6.2. Összetett adattípusok
Az összetett adatok nem összefüggéstelen halmazai az adatelemeknek, hanem valamilyen sorrendi, szerkezeti összefüggés van köztük.
Háromféle összetételi módot ismerünk:

Az összetett adattípusok többsége azonos típusú elemek valamilyen sorozata (tömb, szöveg, verem, sor, lista, szekvenciális állomány, direkt állomány és indexelt állomány), melyeket a velük végezhető műveletek alapján különböztethetünk meg. A lehetséges műveletek a következők:

Az adatszerkezetek elemeinek a tárbeli sorrendje és az adatelemek valódi sorrendje eltérő lehet. Az előbbit a fizikai, az utóbbit a logikai sorrendnek nevezzük. Az adatszerkezet ábrázolásánál arra kell törekednünk, hogy az elemekkel végzett műveletek során könnyen felhasználhatók legyenek a köztük fennálló szerkezeti összefüggések. Az adatszerkezeteket tehát úgy kell elhelyezni a tárban, hogy ne csak az adatelemeket, hanem a szerkezeti összefüggéseket is ábrázoljuk.

6.2.1.Tömb
A legismertebb összetételi eszközt akkor használjuk, amikor azonos típusú elemibb adatok sorozatát akarjuk kezelni. A legegyszerűbb ilyen szerkezet a tömb. A tömböt a többi sorozat jellegű adatszerkezettől a rajta végzett műveletek különböztetik meg. A tömb egy olyan sorozat, amelynek elemszáma rögzített és bármelyik elemére egy indexszel (sorszámmal, sor-, illetve oszlopszámmal, stb.) hivatkozhatunk. (Ez az indexelés vagy kijelölés művelete.) Ez olyan alapvető szerkezet, hogy egy-két kivételtől eltekintve (LOGO, FORTH) minden magasszintű nyelvben megtalálható.
Ha a megvalósításával foglalkozunk (például gépi kódban), akkor gondoskodnunk kell annyi hely lefoglalásáról, ahány tömbelemünk van, majd pedig az indexelés megvalósításáról. Ez utóbbi a kezdőcím tárolását jelenti, majd az index értékéből ki kell számítani, hogy az adott tömbelem mennyivel található a kezdőcím mögött.

6.2.2. Szöveg
A szövegtípus hasonlít a tömbhöz. Elemei csak karakterek lehetnek, viszont az elemek számát (a szöveg hosszát) több nyelv nem tartja állandónak. Tehát ez egy olyan sorozat, amelynek az elemszáma változhat. Másik különbözőség, hogy egyszerre nem csak egy elemmel lehet dolgozni, hanem többel, akár az összessel is. Azaz a szövegtípusra létezik az egymás után írás művelete, illetve a részképzés. Ez utóbbit néha függvényekkel valósítják meg (baloldali valahány karakter, jobboldali valahány karakter, tetszőleges részből valahány karakter). Vegyük észre, hogy a szövegtípust elemi típusnak tekintjük, amikor a típushoz tartozó teljes adaton és nem csak egy részén végzünk műveletet. Egyes nyelvek kifejezetten támogatják az ilyen ún. adatabsztrakciót, s lehetővé teszik, hogy a programozó a saját összetett adatait kezelő műveleteket is létrehozza; ettől kezdve ezeket az összetett adatokat eleminek vehetjük. Ahol szövegtípus van, ott gyakran nincs karaktertípus, mert a karakter azonos az egy karakterből álló szöveggel (ilyen a BASIC is).
Ha egy szövegtípusú változó hossza (karakterszáma) futás közben változhat, akkor a tárolása kicsit bonyolulttá válik. Meg kell adni minden esetben, hogy hol található egy ilyen változó (kezdőcím), valamint azt, hogy aktuálisan hány karakterből áll. Ezt a két adatot a programnyelv elrejti előlünk, s csak speciális függvényeken keresztül teszi elérhetővé (pl. LEN). Csak nagyon ritkán van szükség arra, hogy az ábrázolással részletesen is foglalkozzunk.

6.2.3. Verem
Ez az a gyakran használt struktúra, amely a gépi kód kivételével nagyon kevés nyelvben fordul elő, tehát ha szükségünk van rá, akkor nekünk kell megvalósítani. A verem adatok sorozatát tartalmazza, de csak speciális műveleteket engedünk meg vele kapcsolatban. Ezek a következők:

PUSH(X) - egy X értéket a verem tetejére (a sorozat végére) helyez,
POP(X) - a verem tetején (a sorozat végén) levő értéket az X változóba teszi, majd a veremből elhagyja.

A verem tehát olyan sorozat, amelynek csak az egyik végét tudjuk kezelni, oda tehetünk be új elemet és onnan vehetünk ki elemet.

Hogyan lehet egy vermet megvalósítani? Két feladatunk van: a verem ábrázolásának és a műveletek elkészítésének megválasztása.
Ábrázolás: használjunk egy VEREM(N) vektort a verembe kerülő elemek tá-rolására! Ebből persze következik, hogy N elemnél többet nem helyezhetünk el a veremben (a PUSH műveletnél figyelni kell erre). Szükségünk van arra is, hogy megmondjuk, meddig van kitöltve ez a vektor, azaz kell egy mutató, amely például az első szabad helyre mutat. Ebből viszont az következik, hogy a verem használata előtt ennek a változónak kezdőértéket kell adni (1), tehát a műveletek körét szélesíteni kell. Jelöljük ezt a mutatót VM-mel.

Műveletek:

! Inicializálás
LET N=10 ! verem mérete
LET VM=1 ! veremmutató
NUMERIC VEREM(1 TO N)

DEF PUSH(X)
  IF VM>N THEN
    PRINT "HIBA! Betelt a verem!"
  ELSE
    LET VEREM(VM)=X:LET VM=VM+1
  END IF
END DEF

DEF POP(REF X)
  IF VM=1 THEN
    PRINT "HIBA! Üres a verem!"
  ELSE
    LET VM=VM-1:LET X=VEREM(VM)
  END IF
END DEF

A veremszerkezetnek számos alkalmazása van. Ilyen például az eljárások hívásának szervezése. Ha egy A eljárás meghívja a B eljárást, akkor tárolni kell azt a címet, amelyre a B eljárás végrehajtása után vissza kell ugrani. Ha B eljárás még egy C eljárást is hív, akkor a B-beli folytatás címét szintén tárolni kell. A verem alkalmazásival ez egyszerien megoldható. Minden eljáráshívásnál a verembe tesszük azt a címet, ahol folytatni kell az eljárás befejezése útin a vég-rehajtást, az eljárás végen pedig ezt a címet ki kell venni a veremből, majd ezen a címen kell folytatni a végrehajtást.

6.2.4. Sor
A sor kicsit hasonlít a veremre. Ez olyan sorozat, amelynek az egyik végére lehet tenni új elemeket, a másik végéről pedig el lehet venni őket (azaz mindíg a legelsőnek betett elemet lehet kivenni). Így a műveletei:

SORBA(X) - berakja a sor végére az X elemet,
SORBOL(X) - kivesz a sor elejéről egy értéket X-be.

Ábrázolás:
A legegyszerűbb megvalósítása szintén egy vektorral történik (SOR(N)), de itt két mutatóra van szükség: tudni kell, hogy hova lehet tenni új elemet (HOVA), illetve honnan lehet kivenni (HONNAN). Itt is szükség lesz egy új műveletre, a kezdőérték adásra, valamint vizsgálni kell, hogy a vektor végére értünk-e, illetve hogy kiürült-e a sor.

! Inicializálás
LET N=10 ! sor mérete
LET HOVA=1:LET HONNAN=1 ! mutatók
NUMERIC SOR(1 TO N)

DEF SORBA(X)
  IF HOVA>N THEN
    PRINT "HIBA! Betelt a sor!"
  ELSE
    LET SOR(HOVA)=X:LET HOVA=HOVA+1
  END IF
END DEF

DEF SORBOL(REF X)
  IF HONNAN=HOVA THEN
    PRINT "HIBA! Üres a sor!"
  ELSE
    LET X=SOR(HONNAN):LET HONNAN=HONNAN+1
  END IF
END DEF

Ez így nagyon gazdaságtalan megoldás, hiszen, ha a sorban egyszerre soha nincs 2-3 elemnél több, akkor is előbb-utóbb a vektor végére érünk, s így a feldolgozásunk leáll. Csináljuk ilyenkor azt, hogy a vektor elején folytatjuk az elhelyezést (ez a SOR ciklikus tárolása)! Ezt a tárolást ciklikus tárolásnak nevezzük. Használjunk egy DB nevű változót a sorban levő elemek számlálására!

! Inicializálás
LET N=10 ! sor mérete
LET HOVA=1:LET HONNAN=1:LET DB=0 ! mutatók
NUMERIC SOR(1 TO N)

DEF SORBA(X)
  IF DB=N THEN
    PRINT "HIBA! Betelt a sor!"
  ELSE
    LET SOR(HOVA)=X:LET HOVA=HOVA+1:LET DB=DB+1
    IF HOVA>N THEN LET HOVA=1
  END IF
END DEF

DEF SORBOL(REF X)
  IF DB=0 THEN
    PRINT "HIBA! Üres a sor!"
  ELSE
    LET X=SOR(HONNAN):LET HONNAN=HONNAN+1:LET DB=DB-1
    IF HONNAN>N THEN LET HONNAN=1
  END IF
END DEF

A SOR kezelése megoldható lenne a DB változó nélkül is, akkor azonban az algoritmusok kicsit bonyolultabbak lennének.
Nézzük most meg a sor egy lehetséges megvalósításának Turbo Pascal programját:

Program Sor_Demo;
const max=10;
type telem=byte;
     tsor=array[1..max] of telem;
var sor:tsor;
     elem:telem;
     db,elso:integer;

Function Tele:boolean;
begin
  tele:=db=max
end;

Function Ures:boolean;
begin
  ures:=db=0
end;

Procedure Sorba(x:telem);
var hova:integer;
begin
  if not Tele then begin
    hova:=elso+db;
    if hova>max then hova:=hova-max;
    sor[hova]:=x;db:=db+1
  end
end;

Procedure Sorbol(var x:telem);
begin
  if not Ures then begin
    x:=sor[elso];elso:=elso+1;
    if elso>max then elso:=1;
    db:=db-1
  end
end;

Procedure SorLista;
var m,i:byte;
begin
  m:=Elso;
  for i:=1 to db do begin
    Write(sor[m]:4);
    m:=m+1;
    if m>max then m:=m-1
  end;
  Writeln
end;

begin
  ClrScr;
  Randomize;
  db:=0;elso:=1;
  while not tele do begin
    Sorba(Random(256));
    Delay(500);
    Sorlista
  end;
  while not ures do begin
    Sorbol(elem);
    Delay(500);
    Sorlista
  end
end.

6.2.5. Lista
Sokszor előfordul, hogy az adatokra nem olyan sorrendben van szükség, ahogyan megkaptuk őket. Sőt időnként ilyen sorrend lenne a jó, időnként meg másmilyen. Ekkor persze megoldás lenne, hogy minden ilyen esetben átrendezzük a sorozat elemeit a kívánt sorrendbe, ez azonban rengeteg időt venne igénybe. A lista egy olyan szerkezet, amely megmondja, hogy egy adott adatelem után melyik a (logikailag) következő. (Nevezik ezt az ábrázolási módot láncolt ábrázolásnak is.)
Egy adat mellé több ilyen mutatóértéket is elhelyezhetünk, és így több logikai sorrendet tárolhatunk. Természetesen külön meg kell adnunk, hogy az adott sorrendben melyik elemet tartjuk elsőnek. Ez lesz a listafej. Meg kell még oldani az utolsó elem felismerését: ez az az elem, amely útán nem következik senki sem. Ezt például egy speciális, egyébként elő nem forduló mutatóértékkel jelezhetjük.
Ez a megoldás akkor is előnyös, amikor két adatelem közé egy újabbat kell felvenni vagy pedig az adatsor közepéről kell kitörölni elemet. A láncolt adatszerkezetek tehát így ábrizolhatók:

Ebből eddig az látszik, hogy a láncolt ábrázolásnál az adatszerkezet helyfoglalása megnövekszik. A láncolt ábrázolás előnyei az adatszerkezet módosításakor mutatkoznak meg. Egyszerű a listába új elemet beilleszteni, pl. a K. és a (K+1). közé (a K-adik elem mutatóját át kell állítani!):

A K. elem törlése csak a (K-1) elem mutatójának megváltoztatását jelenti:

Kétirányú lista esetén az adatelemekhez még egy mezőt illesztünk, amely az őt megelőző elem címét adja meg.
Ha a listát úgy módosítjuk, hogy az utolsó elem után újra az első következzen, akkor GYŰRŰről beszélünk.

6.2.6. Rekord
Lényege, hogy az összetett változónak: (rekord) adunk egy közös nevet, s az egyes, rendszerint különböző típusú részeinek (mezőinek) szintén. Így lehetővé válik a rekord elemeinek önálló, külön kezelése és a részek együttes feldolgozása is. Ezután például egy adatnyilvántartűsban egy ember személyi adatai összességére így hivatkozhatunk:

adat,

az illető nevére:

adat.név,

a születési évére:

adat.születés.idő.év

Tehát előre írjuk a közös nevet, majd egy pont után a rész nevét, s ha ez további összetétel, akkor jön a következő pont és utána a rész részének a neve. Ennek a műveletnek kiválasztás (szelekció) a neve. A Pascal nyelv lehetőséget biztosit ilyen adatok kezelésére, a BASIC nem, így ott ezeket az adatokat csak különböző nevű változókban vagy tömbökben tarolhatjuk.

6.2.7. Alternatív szerkezet
Ezután ismerkedjünk meg az alternatív szerkezettel, mely abban különbözik a rekordtól, hogy az összetételében változhatnak a részek is, a részek tartalmától függően.
Személyi adatnyilvintartásra gondolva természetes, hogy mindenféle adatot (leánykori név, katonakönyv száma) nem kell mindenkiről tárolni. Így szükségünk lehet arra, hogy egy összetett adatszerkezetet (rekordot) többféle, alternatív szerkezetben valósítsunk meg. Ez a többféleség pedig a rekord valamely mezőinek (részeinek) értékétől függ. (Pl. leánykori név akkor kell, ha az illető nő.) Ha egy nyelv nem adja meg az ilyen adatok tárolásinak lehetőségét, akkor mindenkiről minden adatot nyilván kell tartani, azokat is, amelyeknek az adott személyre nincs értelme.

A kővetkező három részben háttértárakhoz (kazetta, lemez) kapcsolódó adatszerkezetekkel foglalkozunk. Ezek az adatállományok. Az állomány elemek (rekordok) sorozata, amelyre az állomány típusától, szervezési módjától függően különböző műveleteket definiálunk.

6.2.8. Szekvenciális állomány
Szekvenciális bemeneti, illetve kimeneti állományról beszélhetünk. Az elsőből csak olvasni lehet, a másodikba pedig csak írhatunk. Megengedett műveletek:

A műveletek a SOR szerkezet műveleteire hasonlítanak: a bemeneti állomány olyan sor, amelyből csak kivehetünk elemeket, a kimeneti állomány pedig olyan, amelybe csak betehetünk. Amikor az ACCESS INPUT / ACCESS OUTPUT utasításával megnyitunk egy állományt, az IS-BASIC pontosan így kezeli azokat.

6.2.9. Direkt állomány
A direkt állományba írhatunk és olvashatunk is belőle. Fő jellegzetessége azonban az, hogy bármikor bármelyik rekordja elérhető, módosítható. Természetesen a rekordokat ilyenkor valamilyen azonosítóval kell ellátni (ez célszerűen egy sorszám, de néha fizikai lemezcím is lehet). Megengedett műveletek:

A direkt állomány tehát abban különbözik a tömbtől (azon kívül, hogy a háttértárban megmaradnak az adatok), hogy az elemszáma - általában - növelhető.

6.2.9. Indexelt állomány
Sok esetben jó lenne a rekordokat nem sorszámmal (címmel) azonosítani, hanem valamilyen jellemző adatukkal. Például egy személyi nyilvántartásban jó lenne az egyes embereket a személyi számukkal azonosítani, valamint szükség esetén eszerint előkeresni. Az indexelt állományok ezt a lehetőséget biztosítják számunkra. Ekkor az állományhoz tartozik egy táblázat (ez az indextábla), amely a kívánt adatot (kulcsmező), valamint egy rekordra mutató értéket tartalmaz. Az indextábla általában a kulcsmező értékei szerint rendezett. Ha az indextábla elemeit csak egymás után (sorosan) érhetjük el, akkor INDEXSZEKVENCIÁLIS állományról beszélünk.
Megengedett műveletek:

6.2.11. Bináris fa
A számítástechnikáiban fontos szerepet játszanak azok az adatszerkezetek, amelyeknek elemei között a szerkezeti összefüggések fával ábrázolhatok. Nézzük az alábbi egyszerű aritmetikai kifejezést: a*b+c
Ennek kiszámítási szabályit bináris fával ábrázolhatjuk:

A fa olyan hierarchikus adatszerkezet, mely véges számú csomópontból áll, és igazak a következők:

Azok a fák, melyeknél egy elágazásból legfeljebb két él indul, bináris fák. Gyökérelemnek nevezzük azt az elemet, amelybe nem fut be él.

A fa bejárása
A fa csomópontjaiban tárolt adatokat természetesen valamilyen szisztéma szerint el szeretnénk érni. Kereshetünk például egy adott tulajdonsággal rendelkező adatot, vagy a fa összes adatát ki szeretnénk listázni. Egy általános fa esetében a bejárási stratégiák lényegében a következők lehetnek:

Bináris fa esetén a szülő egyértelműen a gyerekek között helyezkedik el. Ezért itt a gyökérközepű bejárásnak is van értelme. Pl.: bal részfa, gyökér, jobb részfa.

6.2.12. Gráf
A gráf olyan hálós adatszerkezet, amely csúcsokból (adatelemek), valamint azokat összekötő élekből (kapcsolatok) áll. Bármely két csomópont kapcsolatban állhat egymással Speciális esetként a fa, sőt a bináris fa egy gráf, amelynek nagyon egyszerű a szerkezete. Elképzelhető az is, hogy a gráf egyes éleihez valamilyen számértéket rendelünk, amely a kapcsolat jellemzésére szolgál. Gráffal adható meg például egy vasúthálózat, ahol az út hosszát rendeljük az élekhez:

Egy gráfot többféleképpen ábrázol hatunk. Szokásos a csúcsmátrixszal való ábrázolás. Ekkor egy N csúcsot tartalmazó gráfhoz fel kell venni egy N*N-es mátrixot. A mátrix i. sora j. oszlopába 0-át teszünk, ha e két csúcs között nincs él, 1-et (vagy az élhez rendelt számértéket), ha van. Az előbbi példa így leírva:

 
Budapest
Hatvan
Újszász
Szolnok
Cegléd
Kecskemét
Budapest
0
67
84
0
73
0
Hatvan
67
0
52
0
0
0
Újszász
84
52
0
17
0
0
Szolnok
0
0
17
0
27
0
Cegléd
73
0
0
27
0
33
Kecskemét
0
0
0
0
33
0

Másik lehetőség az élmátrixszal történő ábrázolás, ahol az élekben szereplő csúcspárokat adjuk meg (valamint esetleg az élekhez rendelt számértéket). A fenti példa élmátrixa:

Budapest, Hatvan, 67
Budapest, Újszász, 84
Budapest, Cegléd, 73
Hatvan, Újszász, 52
Újszász, Szolnok, 17
Szolnok, Cegléd, 27
Cegléd, Kecskemét, 33

Ebben a példában az utóbbi tárolás a gazdaságosabb, ezzel szemben viszont az előbbiben lényegesen gyorsabban meg lehet vizsgálni, hogy van-e két város között közvetlen összeköttetés.

6.2.13. Halmaz
A halmaz olyan sorozat, ahol az elemeknek nem definiált a sorrendje, azaz nincs értelme a következő elemet kérni semmilyen szempontból sem. Használhatunk viszont halmazműveleteket: egyesítést (uniót), metszetet, halmazkülönbséget.

Ábrázolás:
A legegyszerűbb halmazábrázolást úgy valósíthatjuk meg, ha egy vektorban felsoroljuk az elemeit, valamint külön megadjuk az elemek számát. Ekkor a halmazműveletek a kővetkező fejezetben szereplő eldöntés, egyesítés, metszet stb. tételek algoritmusaival adhatok meg.

7. Alapvető algoritmustípusok
(programozási tételek)

A feladatmegoldás lépéseinek vizsgálatakor megállapítottuk, hogy a megoldás elemi lépésekre bontásakor mikor, melyik algoritmikus struktúrát használjuk. Eddig azonban nem beszéltünk arról, hogy melyikét, hogyan kell használni. Erre a kérdésre ad választ ez a fejezet.
Aki már több algoritmust készített különböző témában, bizonyára tapasztalta, hogy bizonyos részfeladatok tipizálhatók, megoldásukhoz lényegében ugyanaz az algoritmus szükséges, csak éppen az algoritmusban szereplő konstansok, változók neve, jelentése más és más. Ebben a fejezetben most néhány ilyen, ún. típusalgoritmust mutatunk be, melyeket PROGRAMOZÁSI TÉTELEK-nek is nevezhetünk. Ez az elnevezés a matematikai tételekkel kapcsolatos hasonlóságból származik. Ezek a tételek azt mondják ki, hogy a megadott programok helyes megoldásai a hozzájuk tartozó feladatoknak. A tételek bizonyítását a közölt programok helyességének bizonyítása jelenti. (Ezzel mi nem foglalkozunk).
A programozási tételek ismeretében már a legtöbb feladat megoldása során nincs más dolgunk, mint a kifejtés adott szintjén meghatározni, hogy milyen feladatról van szó, s utána alkalmazni a megfelelő algoritmust. Csak néha-néha van szükség új tételek kimondására, alkalmazására. Az ilyen típusú programkészítés nyilvánvalóan biztosítja, hogy ha a feladatot jól értettük meg, akkor helyes algoritmust írunk megoldására. Megjegyzendő azonban, hogy a tételek gépies alkalmazásával nem mindig a lehető legkedvezőbb programot kapjuk. A helyes megoldás hatékonyabbra való átírása azonban már külön tevékenység, s általában erősen feladatfüggő.
Feladataink jól meghatározott osztályokba sorolhatók kiindulási adataik és az általuk szolgáltatott eredmény alapján.
A legegyszerűbbek EGY ADATBÓL EGY ADATOT számolnak ki. Kicsit bonyolultabbak azok, amelyek EGY ADATBÓL EGY SOROZATOT adnak. (Pl. adjuk meg az X első elemű, L növekményű számtani sorozat első N tagját!).
Számítástechnikai szempontból bonyolultabbak az olyan feladatok, - mi ilyenekkel fogunk foglalkozni - amelyekben

Mindegyik feladatosztályt két csoportra oszthatjuk. Olyan feladatokra, amelyekben egyszerre csak a sorozat egyetlen elemének vizsgálatára van szükség, illetve olyanokra, amelyeknél egyszerre több elemet is figyelembe kell venni. Az EGY SOROZATHOZ EGY ÉRTÉKET rendelő feladatosztályt még két csoportra oszthatjuk. Az egyikben a sorozat elemeiből új értékeket kell kiszámolni (pl. darabszám), a másikban az eredeti sorozat valamilyen elemének sorszámát kell előállítani.
Most tehát a fenti csoportosítás szerint nézzük meg a programozási tételeket. Az egyes típusalgoritmusoknál mindig megadjuk

7.1. Egy sorozathoz egy érték hozzárendelése
(Elemenkénti feldolgozás)

T1. Az összegzés tétele
Általános feladat: Adott egy N elemű számsorozat. Számoljuk ki az elemek összegét! A sorozatot most és a továbbiakban is az N elemű A(N) vektorban tároljuk.
Megjegyzés: A későbbi feladatok során előfordulhat, hogy a vizsgált sorozat szöveges típusú változókat tartalmaz.

Algoritmus:

Eljárás:
  S:=0
  Ciklus I=1-től N-ig
    S:=S+A(I)
  Ciklus vége
Eljárás vége.

IS-BASIC:

NUMERIC A(1 TO N)
...
LET S=0
FOR I=1 TO N
  LET S=S+A(I)
NEXT

Ugyanez Turbo Pascal-ban:

const n=10;
var a:array[1..n] of integer;
    s,i:integer;
  ...
begin
  ...
  s:=0;
  for i:=1 to n do
    s:=s+a[i];
  ...
end.

F7.1. feladat:
N napon keresztül, naponta egy alkalommal megmértük a hőmérsékletet. Adjuk meg az N napos időszak átlaghőmérsékletét!
Megfeleltétés: sorozat A(N)

NUMERIC A(1 TO N)
...
PRINT "Átlaghőmérséklet: ";ATLAG;" fok."
...
DEF ATLAG
  LET S=0
  FOR I=1 TO N
    LET S=S+A(I)
  NEXT
  LET ATLAG=S/N
END DEF

Ugyanez Turbo Pascal-ban:

const n=10;
var a:array[1..n] of integer;
    s,i:integer;

Function Atlag:real;
var s:real;
    i:integer;
begin
  s:=0;
  for i:=1 to n do
    s:=s+a[i];
  Atlag:=s/n
end;
...

begin
  ...
  writeln ('Atlag= ',atlag)
end.

T2. Az eldöntés tétele
Általános feladat: adott egy N elemű sorozat és egy, a sorozat elemein értelmezett T tulajdonság. Az algoritmus eredménye: annak eldöntése, hogy van-e a sorozatban legalább egy T tulajdonsággal rendelkező elem. Az általános algoritmus így írhatjuk le:

Eljárás:
  I:=1
  Ciklus amíg I<=N és A(I) nem T tulajdonságú
    I:=I+1
  Ciklus vége
  VAN:=I<=N
Eljárás vége.

A 'VAN:=I<=N' kifejezés a következőt jelenti: a VAN egy logikai változó, amely akkor és csak akkor igaz értékű, ha I<=N.
IS-BASIC-ben:

NUMERIC A(1 TO N)
NUMERIC T
...
LET I=1
DO WHILE I<=N AND A(I)<>T
  LET I=I+1
LOOP
LET VAN=I<=N
IF VAN THEN PRINT "Van ilyen elem!"

Ugyanez Turbo Pascal-ban:

const n=10;
var a:array[1..n] of integer;
    t,i:integer;
    van:boolean;
...

begin
  ...
  i:=1;
  while (i<=n) and (a[i]<>t) do
    i:=i+1;
  van:=i<=n;
  if van then Writeln ('Van ilyen elem!')
end.

A VAN=I<=N kifejezés a következőt jelenti: a VAN egy logikai változó, amely akkor és csak akkor igaz értékű, ha I<=N. Könyvünk további feladataiban is találkozunk ehhez hasonlójelöléseket, melyek értelmezése a most leírtaknak megfelelően történik.

F7.2. feladat:
N napon keresztül, naponta egy alkalommal megmértük a hőmérsékletet. Adjuk meg, hogy volt-e olyan nap, amikor fagyott!
Mefeleltetés: sorozat: - A(N), tulajdonság - A(I)<0

NUMERIC A(1 TO N)
...
IF FAGYOTT THEN PRINT "Volt olyan nap, amikor fagyott!"
...
DEF FAGYOTT
  LET I=1
  DO WHILE I<=N AND A(I)>=0
    LET I=I+1
  LOOP
  LET FAGYOTT=I<=N
END DEF

F7.3. feladat:
Állapítsuk meg, hogy az N elemű A() sorozat növekvő sorrendben rendezett-e.
Itt azt kell eldöntenünk, hogy a sorozatban van-e olyan elem, amely kisebb, mint a sorozat előző eleme. Ha van, a sorozat nem rendezett.

NUMERIC A(1 TO N)
...
LET I=2
DO WHILE I<=N AND A(I)>=A(I-1)
  LET I=I+1
LOOP
LET RENDEZETT=I>N
...

T3. A kiválasztás tétele
Adott egy N elemű sorozat, egy, a sorozat elemein értelmezett T tulajdonság, valamint azt is tudjuk, hogy a sorozatban van legalább egy T tulajdonságú elem. A feladat ezen elem sorszámának meghatározása.
A megoldás az előző példa alapján nagyon egyszerű. Csupán annyi az eltérés, hogy azt a többletismeretet, hogy biztosan van T tulajdonságú elem, au eljárásban lévő ciklusfeltétel egyszerűsítésére használjuk.
Algoritmus:

Eljárás:
  I:=1
  Ciklus amíg A(I) nem T tulajdonságú
    I:=I+1
  Ciklus vége
  SORSZ:=I
Eljárás vége.

IS-BASIC:

NUMERIC A(1 TO N)
NUMERIC T
...
LET I=1
DO WHILE A(I)<>T
  LET I=I+1
LOOP
LET SORSZ=I

Ugyanez Turbo Pascal-ban:

var a:array[1..10] of integer;
    i,t,sorsz:integer;
...

begin
  ...
  i:=1;
  while a[i]<>t do
    i:=i+1;
  sorsz:=i;
  ...
end.

T4. A keresés tételei
E feladatcsoportban a sorozat elemei között egy adott tulajdonságú elemet keresünk. Az algoritmus eldönti, hogy van-e ilyen elem, és hányadik a sorozatban (1-től számolva).

T4/a. A lineáris keresés tétele
Rendelkezésre áll egy N elemű sorozat, egy, a sorozat elemein értelmezett T tulajdonság. Olyan algoritmust kell írni, amely eldönti, hogy van-e T tulajdonságú elem a sorozatban, és ha van, megadja a sorszámát. (Ez a feladat az előző kettő összefoglalása.)
Algoritmus:

Eljárás:
  I:=1
  Ciklus amíg I<=N és A(I) nem T tulajdonságú
    I:=I+1
  Ciklus vége
  VAN:=I<=N
  Ha VAN akkor SORSZ:=I
Eljárás vége.

IS-BASIC:

NUMERIC A(1 TO N)
NUMERIC T
...
LET I=1
DO WHILE I<=N AND A(I)<>T
  LET I=I+1
LOOP
LET VAN=I<=N
IF VAN THEN SORSZ=I

Ugyanez Turbo Pascal-ban:

const n=10;
var a:array[1..10] of integer;
    i,t,sorsz:integer;
    van:boolean;
...

begin
  ...
  i:=1;
  while (i<=n) and (a[i]<>t) do
    i:=i+1;
  van:=i<=n;
  if van then sorsz:=i;
  ...
end.

T4/b. A logaritmikus keresés tétele
Általános feladat: Adott egy N elemű RENDEZETT sorozat és egy keresett elem (X). Olyan algoritmus készítése a feladat, amely megadja, hogy szerepel-e a keresett elem a sorozatban, s ha igen, akkor megadja a sorszámát. Ez hasonló az előbbi keresési feladathoz. Most kihasználjuk, hogy a vizsgált sorozat rendezett. Ez alapján bármely elemről el tudjuk dönteni, hogy a keresett elem előtte vagy utána van-e, vagy esetleg éppen megtaláltuk. Működése a következő:

Algoritmus:

Eljárás:
  AH:=1: FH:=N
  Ciklus
    K:=INT((A+F)/2)
    Ha A(K)<X akkor AH:=K+1
    Ha A(K)>X akkor FH:=K-1
  amíg AH<=FH és A(K)<>X
  Ciklus vége
  VAN:=AH<=FH
  Ha VAN akkor SORSZ:=K
Eljárás vége.

IS-BASIC:

NUMERIC A(1 TO N)
LET SORSZ=0
...
LET AH=1:LET FH=N
DO
  LET K=INT((AH+FH)/2)
  IF A(K)<X THEN LET AH=K+1
  IF A(K)>X THEN LET FH=K-1
LOOP WHILE AH<=FH AND A(K)<>X
LET VAN=AH<=FH
IF VAN THEN LET SORSZ=K

Valamivel gyorsabb megoldás:
(A függvény paramétere a keresett érték.)

DEF KERESES(X)
  LET AH=1:LET FH=N:LET KERESES=0
  DO
    LET K=INT((AH+FH)/2)
    SELECT CASE A(K)
    CASE IS<X
      LET AH=K+1
    CASE IS>X
      LET FH=K-1
    CASE ELSE
      LET KERESES=K
  END SELECT
  LOOP UNTIL AH>FH OR A(K)=X
END DEF

Megjegyzések:
A 'logaritmikus' elnevezés onnan származik, hogy e módszerrel az elem megtalálásához szükséges lépések száma kb. log N.
Általában igaz az, hogy a kiinduló sorozat tulajdonságait felhasználva az egyszerű (lineáris) keresésnél sokkal hatékonyabb algoritmus készíthető: Egy 65536 elemből álló rendezett tömb esetében, lineáris kereséssel átlagosan 32768 elemet kell megvizsgálnunk, míg logaritmikus kereséssel 15-öt.
Ha rendezett sorozaton mégis az elemi keresési módszert alkalmazzuk, akkor a kiválasztott elem speciális tulajdonsággal is rendelkezni fog (ez lesz a legkisebb, illetve a legnagyobb adott tulajdonságú elem).

F7.5. feladat
Ismerjük egy osztály tanulóiak névsorát. Adjuk meg a "Nagy" vezetéknevű tanuló teljes nevét!
Megfeleltetés:
N - osztálylétszám,
sorozat Nevsor(N,2) [vezetéknév, keresztnév]
tulajdonság - A(I,1)="Nagy"

STRING NEVSOR$(1 TO N,1 TO 2)*20
...
LET A$="Nagy"
LET SORSZ=KERES(A$)
IF SORSZ>0 THEN PRINT NEVSOR$(SORSZ,2)
IF SORSZ=0 THEN PRINT "Nincs ilyen tanuló!"
...
DEF KERES(X$)
  LET AL=1:LET FE=N
  LET KERES=0:LET HOSSZ=LEN(X$)
  DO
    LET K=INT((AL+FE)/2)
    IF NEVSOR$(K,1)(1:HOSSZ)<X$ THEN LET AL=K+1
    IF NEVSOR$(K,1)(1:HOSSZ)>X$ THEN LET FE=K-1
  LOOP WHILE AL<=FE AND NEVSOR$(K,1)<>X$
  LET VAN=AL<=FE
  IF VAN THEN LET KERES=K
END DEF

A KERES eljárás a keresett név sorszámát adja vissza, ha van ilyen név. Ha nincs ilyen tanuló, 0 értéket ad vissza.

T5. A megszámlálás tétele
Rendelkezésre áll egy N elemű sorozat és egy sorozat elemein értelmezett T tulajdonság. Most a T tulajdonsággal rendelkező elemek megszámlálása a feladat.
Algoritmus:

Eljárás:
  S:=0
  Ciklus I=1-től N-ig
    Ha A(I) T tulajdonságú akkor S:=S+1
  Ciklus vége
Eljárás vége.

IS-BASIC:

NUMERIC A(1 TO N)
...
LET S=0
FOR I=1 TO N
  IF A(I)=T THEN LET S=S+1
NEXT

Ugyanez Turbo Pascal-ban:

const n=10;
var a:array[1..10] of integer;
    i,t,s:integer;
...
begin
  ...
  s:=0;
  for i:=1 to n do
    if a[i]=t then s:=s+1;
  ...
end.

F7.6 feladat
Ismerjük egy osztály tanulóinak névsorát. Adjuk meg a "Nagy" vezetéknevűek számát!
Megfeleltetés:
sorozat - A(N,2) [vezetéknév, keresztnév]
tulajdonság - A(I,1)="Nagy"

STRING NEVSOR$(1 TO N,1 TO 2)*20
...
LET A$="Nagy"
PRINT "Az osztályban ";SZAMLAL(A$);"fő";A$;" nevű tanuló van."
...
DEF SZAMLAL(X$)
  LET S=0
  FOR I=1 TO N
    IF NEVSOR$(I,1)=X$ THEN LET S=S+1
  NEXT
  LET SZAMLAL=S
END DEF

F7.6 /2 feladat
Ismerjük N ember személyi számát. Számoljuk meg, hogy hány féri és nő adatait tartalmazza sorozatunk! A férfiakat a FFI, a nőket a NO változóban számláljuk.
Megfeleltetés:
N - emberek száma
SZEMSZAM(N) - sorozat
tulajdonság: SZEMSZAM(I) első karaktere ="1" vagy "3"

NUMERIC SZEMSZAM(1 TO N)
...
LET FFI=0
FOR I=1 TO N
  IF STR$(SZEMSZAM(I))(1:1)="1" OR STR$(SZEMSZAM(I))(1:1)="3" THEN LET FFI=FFI+1
NEXT
LET NO=N-FFI

Az eddigi tételeknél (típusfeladatoknál) egyszerre a kiinduló sorozat egyetlen elemét kellett vizsgálni. Most olyanok következnek, ahol egyszerre több elemre is szükségünk lehet. Ezek közül sok átfogalmazható a korábbi feladatoknak megfelelőre.

Például :
Feladat: döntsük el, hogy egy sorozat monoton növekvő-e!

  1. variáció: döntsük el, hogy egy sorozat minden eleme nagyobb vagy egyenlő-e, mint az azt megelőző! (Itt egyszerre mindig két elemet kell vizsgálni.)
  2. variáció: végezzük el a következő megfeleltetést:
       elemszám: N-1
       sorozat: (1. elem,2.elem) , (2.elem,3.elem) , . . .
       tulajdonság - az I. elempár 1. tagja kisebb a 2.-nál.
    Így már egy egyszerű eldöntési feladatot kaptunk.

Ebből a csoportból egyetlen feladattípussal ismerkedünk meg, amely nem vezethető vissza az előzőekre: ez a legnagyobb, illetve a legkisebb elem kiválasztása.

T6. A maximumkiválasztás tétele
Általános feladat: Ebben a feladatban egy sorozat legnagyobb elemét kell megtalálni. Lényeges nehézséget okoz a korábbiakkal szemben az, hogy most egyszerre nem elég a sorozat egyetlen elemét vizsgálni, hiszen a legnagyobb az, amelyik mindegyiknél nagyobb, azaz mindegyikkel össze kell hasonlítani. A feladat megoldását úgy kapjuk, hogy visszavezetjük elemenkénti feldolgozásra: egy elem maximumát mindig tudjuk. Ha ismerjük K elem közül a legnagyobbat és veszünk hozzá egy új elemet, akkor a maximum vagy az eddigi, vagy pedig az új elem lesz.
Algoritmus:

Eljárás:
  INDEX:=1
  Ciklus I=2-től N-ig
    Ha A(INDEX)<A(I) akkor INDEX:=I
  Ciklus vége
  MAXIMUM:=INDEX
Eljárás vége.

IS-BASIC:

NUMERIC A(1 TO N)
...
LET INDEX=1
FOR I=2 TO N
  IF A(INDEX)<A(I) THEN LET INDEX=I
NEXT
LET MAXIMUM=INDEX

Megjegyzés: Minimumkiválasztásnál csak a feltételes utasítás feltétele fordul meg (< helyett > lesz).
Ugyanez Turbo Pascal-ban:

const n=10;
var a:array[1..10] of integer;
    i,index,maximum:integer;
...

begin
  ...
  index:=1;
  for i:=2 to n do
    if a[index]<a[i] then index:=i;
  maximum:=index;
  ...
end.

Ha a kérdést úgy tesszük fel, hogy mennyi a legnagyobb érték, akkor egy másik megoldást kapunk:

NUMERIC A(1 TO N)
...
LET ERTEK=A(1)
FOR I=2 TO N
  IF ERTEK<A(I) THEN LET ERTEK=A(I)
NEXT
LET MAXERTEK=ERTEK

Ugyanez Turbo Pascal-ban:

const n=10;
var a:array[1..10] of integer;
    i,ertek,maxertek:integer;
...
begin
  ...
  ertek:=a[1];
  for i:=2 to n do
  if ertek<a[i] then ertek:=a[i];
  maxertek:=ertek;
  ...
end.

F7.7 feladat
Készítsünk algoritmust, amely N ember magasságának ismeretében megadja a legmagasabb magasságát. Feltételezve, hogy minden ember különböző magasságú.
Megfeleltetés: sorozat - magasság1, máagasság2, . (A(N))

STRING NEVSOR$(1 TO N)*20
NUMERIC A(1 TO N)
...
LET INDEX=LEGMAGASABB
PRINT "A legmagasabb: ";NEVSOR$(INDEX),A(INDEX);"cm"
...
DEF LEGMAGASABB
  LET INDEX=1:LET ERTEK=A(1)
  FOR I=2 TO N
    IF ERTEK<A(I) THEN LET ERTEK=A(I):LET INDEX=I
  NEXT
  LET LEGMAGASABB=INDEX
END DEF

7.2. Egy sorozathoz egy sorozat hozzárendelése
A következőkben áttérünk arra az esetre, amikor az eredmény is egy sorozat lesz. Nem foglalkozunk olyan egyszerű példákkal amikor a sorozat minden elemén (egymástól függetlenül) egy függvény értékét kell kiszámítani. Ide tartozik az összes következő típusú feladat:
A(I)=f(A(I)=B(I)) [I=1..N]

T7. Kiválogatás tétele
Általános feladat: Ebben a feladatban egy N elemű sorozat összes T tulajdonsággal rendelkező elemét kell meghatározni. Gyűjtsük a kiválogatott elemek számait a B() vektorban! Az eredménysorozat rövidebb, vagy ugyanakkora lesz, mint a bemenő sorozat.
Algoritmus:

Eljárás:
  INDEX:=0
  Ciklus I=1-től N-ig
    Ha A(I) T tulajdonságú akkor
      INDEX:=INDEX+1: B(INDEX):=I
  Ciklus vége
Eljárás vége.

IS-BASIC:

NUMERIC A(1 TO N)
NUMERIC B(1 TO N)
...
LET INDEX=0
FOR I=1 TO N
  IF A(I)=T THEN LET INDEX=INDEX+1:LET B(INDEX)=I
NEXT

F7.8 feladat
Készítsünk algoritmust, amely N ember magasságának ismeretében megadja az X magasságúakat!
Megfeleltetés:
sorozat: magasság1, magasság2, ... (A(N))
tulajdonság: A(I)=X

STRING NEVSOR$(1 TO N)*20
NUMERIC A(1 TO N)
NUMERIC B(0 TO N)
...
CALL VIZSGAL(T)
CALL KI
...
DEF VIZSGAL(X)
  LET INDEX=0
  FOR I=1 TO N
    IF A(I)=X THEN LET INDEX=INDEX+1:LET B(INDEX)=I
  NEXT
LET B(0)=INDEX ! Kiválogatott elemek száma B(0)-ba
END DEF
...
DEF KI
  IF B(0)=0 THEN
    PRINT "Nincs ilyen magasságú ember!"
  ELSE
    FOR I=1 TO B(0)
      PRINT NEVSOR$(B(I)),A(B(I));"cm"
    NEXT
  END IF
END DEF

F7.9 feladat
Tökéletesnek nevezzük azokat a természetes számokat, amelyek osztóinak összege - az 1-et beleértve, de az adott számot nem - kiadja magát a számot. Készítsünk algoritmust, amely meghatározza 2-től N-ig a tökéletes számokat!
A kiválasztás tételét kell alkalmaznunk, hiszen meg kell határoznunk minden szám osztóinak összegét, majd ki kell választanunk azokat a számokat, amelyeknél ez az összeg az adott számmal egyenlő. N-et - a futásidőre tekintettel - célszerű 8128-ban maximalizálni, és a keresést csak a páros számokra korlátozni.

Megfeleltetés:
sorozat: 2, 4, ..., N
tulajdonság: S=I (ahol S az I osztóinak összege)

FOR I=2 TO N STEP 2
  LET S=1:LET J=2:LET L=SQR(I)
  DO WHILE J<L
    IF MOD(I,J)=0 THEN LET S=S+J+I/J
    LET J=J+1
  LOOP
  IF J*J=I THEN LET S=S+J
  IF S=I THEN PRINT I
NEXT

Ugyanez Turbo Pascal-ban:

function Tokeletes(num:integer):boolean;
var sum,i,l:integer;
begin
  sum:=1;i:=2;l:=Round(Sqrt(num));
  repeat
    if (num mod i=0) then
      sum:=sum+i+(num div i);
    i:=i+2
  until i>l;
  Tokeletes:=(sum=num)
end;

var a:integer;
begin
  ...
  for a:=2 to n do
    if Tokeletes(a) then
      Writeln (a:5)
end.

7.3. Sorozat elemeinek permutálása
Ezután olyan algoritmusokkal foglalkozunk, amelyek a sorozat elemeinek valamilyen permutálását végzik. Ilyen permutáció készítése a feladata például a RENDEZÉSEKnek. Lényegük: a kapott adatokat növekvő, vagy csökkenő sorrendbe kell állítani.
Igen sokféle rendezési eljárás létezik. Ennek a sokféleségnek több oka is van. Egyik maga az a tény, hogy a rendezés olyan általános probléma, amely számítógépes programjaink jelentős részében megtalálható. Másik ok, hogy rendezni sokszor nem számokat, hanem szövegeket, esetenként hosszú rekordokat kell. Ez pedig sok szempont együttes figyelembevételét igényli. Azt, hogy egy konkrét feladat esetén melyik algoritmust valósítjuk meg, igen sok körülmény határozhatja meg.
A megfelelő eljárás kiválasztásakor fontos tényező lehet a módszer tárigénye, a végrehajtási idő, az eljárás során végrehajtott összehasonlítások, illetve mozgatások, cserék száma és természetesen az adott gépi környezet. Hosszú rekordok rendezése esetén például az összehasonlítás, a rekordok cseréje igen időigényes művelet. Számok rendezésekor ez lényegesen gyorsabban megy. Nagy adathalmaz esetén takarékoskodnunk kell a tárral, sőt van olyan eset, amikor a teljes feldolgozandó adatmennyisig el sem fér egyszerre a tárban. Minden feladat megoldásakor meg kell találnunk az adott körülmények között számunkra valamilyen szempontból optimálisnak tűnő eljárást. Abszolút értelemben vett, minden igényt maradéktalanul kielégítő, tökéletes rendezési eljárás nem létezik. Nekünk kell eldöntenünk, hogy az adott probléma megoldásához a rendelkezésünkre álló lehetőségek közül melyiket részesítjük előnyben a többivel szemben.
Most a fentiek illusztrálására bemutatunk néhány algoritmust és mindegyikhez megadjuk az un. hatékonysági mutatókat is, melyek segíthetnek a választásban. Előbb azonban pontosítanunk kell értelmezésüket.
Az első vizsgált mennyiség az algoritmus TÁRIGÉNYE lesz. Ezt a rendezendő adatok számával fejezzük ki. (Természetesen minden algoritmusban szükség van még a rendezés során néhány munkaváltozóra, de ezeket itt most nem vesszük figyelembe.) A következő lesz a végrehajtáshoz szükséges ÖSSZEHASONLÍTÁSOK és MOZGATÁSOK SZÁMA, ahol összehasonlításon olyan <, >, =, <= , >=, <> vizsgálatokat értünk, melynek legalább az egyik oldalán rendezendő adat áll. Mozgatáson pedig olyan értékadó utasítást, amelyben legalább az egyik oldalon rendezendő adat szerepel. A VÉGREHAJTÁSI IDŐ az algoritmusok egyik legfontosabb hatékonysági mutatója. Az időértékeket 4 MHz-s és 6 MHz-s gépre valamint a BASIC és a ZZZIP-pel lefordított változatra külön-külön megadjuk. Minden esetben ugyanazt a számsorozattot rendeztük.
Végül megjegyezzük, hogy valamennyi algoritmus az ún. belső rendezésre mutat példát, ami azt jelenti, hogy minden adat az eljárás során végig bent van a számítógép főtárában.

T8. Rendezési tételek

T8/a. Rendezés közvetlen kiválasztással
A módszer lényege: A rendezendő számok legyenek az A vektor elemei. Az első menetben kiválasztjuk a vektor legkisebb elemét úgy, hogy az A(1)-et összehasonlítjuk A (2) , ..., A (N) mindegyikével. Ha A(1)-nél kisebb elemet találunk, felcseréljük őket, vagyis ezt a kisebbet tesszük A(l)-be. így a menet végére A(1) biztosan a vektor legkisebb elemét tartalmazza majd. Az eljárást A(2)-vel folytatjuk, ezt hasonlítjuk össze az A(3), ..., A(N) elemekkel. És így tovább, menetenként a soron következő legkisebb elem kiválasztásával N-1 menet után a vektor rendezett lesz.
A módszer működését véletlenszerűen kiválasztott 16 szám esetén a következő táblázatmutatja:

A rendezés algoritmusa:

NUMERIC A(N)
...
FOR I=1 TO N-1
  FOR J=I+1 TO N
    IF A(J)<A(I) THEN LET SW=A(J):LET A(J)=A(I):LET A(I)=SW
  NEXT
NEXT

Ugyanez Turbo Pascal-ban:

const n=26;
var a:array[1..n] of integer;
    i,j,sw:integer;
...
begin
  ...
  for i:=1 to n-1 do
    for j:=i+1 to n do
      if a[j]<a[i] then begin
        sw:=a[j];a[j]:=a[i];a[i]:=sw
      end;
end.

A hatékonysági mutatók alakulása:
Tárigény: N+1
Összehasonlítások száma maximum: N*(N-1)/2
A mozgatások száma függ az elemek előrendezettségétől. Ha a rendezendő elemek eredetileg monoton növő sorozatot alkotnak - nevezzük ezt a továbbiakban legjobb esetnek - akkor 0, eredetileg monoton csökkenő előrendezettség esetén (legrosszabb eset): 3*N*(N-1)/2

A végrehajtási idő véletlenszerű elrendezettség és N=500 elem esetén:

 
BASIC
ZZZIP
Pascal
4 MHz (memóriavárakozással)
2959 s
62 s
24 s
6 MHz (memóriavárakozás nélkül)
1607 s
33 s
13 s

Megjegyzés: Az algoritmus figyelmes tanulmányozásakor látható, hogy minden menetben igen sok felesleges csere történik. Ez pedig a végrehajtási idő szempontjából komoly többletet jelent. A módszer a felesleges cserék kiküszöbölésével javítható. Nézzük meg az így keletkezett algoritmust!

T8/b. Rendezés minimumkiválasztással
A módszer lényege: A felesleges cserék kiküszöbölése érdekében két segédváltozó bevezetésére van szükségünk. A MIN nevű változó tartalmazza az adott menetben addig megtalált legkisebb elemet, INDEX pedig annak vektorbeli sorszámát, indexét. Az A vektor elemeit mindig MIN változó tartalmával hasonlítjuk össze. Ha MIN-nél kisebb elemet találunk, azt betesszük az ERTEK nevű változóba és az INDEX-ben megjegyezzük a szóbanforgó elem indexét (bár elég lenne csak az elem indexét tárolni, a tömbelem keresése és az azzal összehasonlítás lassabb.). A menet végére a MIN a vektor soron következő legkisebb elemet tartalmazza, az INDEX pedig azt a sorszámot, ahol ezt az elemet találtuk. Csak a menet utolsó lépésében van szükségünk cserére, ami kor a MIN-ben lévő legkisebb elemet a helyére tesszük.
Most nézzük meg, mit jelent ez az előbbi 16 szám esetén:

A rendezés algoritmusa:

NUMERIC A(N)
...
FOR I=1 TO N-1
  LET MIN=A(I):LET INDEX=I
  FOR J=I+1 TO N
    IF MIN>A(J) THEN LET MIN=A(J):LET INDEX=J
  NEXT
  LET A(INDEX)=A(I):LET A(I)=MIN
NEXT

Ugyanez Turbo Pascal-ban:

const n=26;
var a:array[1..n] of integer;
    i,j,index,min:integer;
...
begin
  ...
  for i:=1 to n-1 do begin
    min:=a[i];index:=i;
    for j:=i+1 to n do
      if min>a[j] then begin
        min:=a[j];index:=j
      end;
    a[index]:=a[i];a[i]:=min
  end;
  ...
end.

A hatékonysági mutatók alakulása:
Tárigény: N+1
Összehasonlítások száma: N*(N-1)/2
A mozgatások száma legjobb esetben 3*(N-1), legrosszabb 3*(N-1)+[N*N/4]
Az előző változattal összehasonlítva láthatjuk, hogy a két módszer tárigénye, valamint az összehasonlítások száma megegyezik. A mozgatások száma, és ennek eredményeképpen természetesen a végrehajtási idő is ez utóbbi eljárás esetén azonban lényegesen csökken.
A végrehajtási idő véletlenszerű elrendezettség és N=500 elem esetén:

 
BASIC
ZZZIP
PASCAL
4 MHz (memóriavárakozással)
1281 s
32 s
17 s
6 MHz (memóriavárakozás nélkül)
696 s
17 s
9 s

Megjegyzés: Vegyük észre, hogy algoritmusunkban a korábban említett minimumkiválasztási tételt alkalmaztuk N-1-szer!

Az előbbi két esetben menetenként a legkisebb elem kiválasztása volt a a módszer legjellemzőbb tulajdonsága. Most nézzünk meg néhány, elvileg más alapon készült rendezést!

T8/c. Buborékos rendezés
A módszer lényege: A buborékos rendezés alapgondolata a szomszédos elemek cseréje. Az első menetben a rendezendő A vektor végéről indulva minden elemet összehasonlítunk az előtte levővel. Amennyiben rossz sorrendben vannak, felcseréljük őket. Az első menet végére a legkisebb elem biztosan a helyére kerül. Minden további menetben ismét a vektor végéből indulunk, de egyre kevesebb összehasonlításra van szükségünk, hiszen a vektor eleje fokozatosan rendezetté válik.
Végeredményben a teljes vektor rendezéséhez N-1 menetre van szükségünk.
Nézzük meg az A vektor alakulását az ismert 16 számra:

A rendezés algoritmusa:

NUMERIC A(N)
...
FOR I=2 TO N
  FOR J=N TO I STEP-1
    IF A(J-1)>A(J) THEN LET SW=A(J-1):LET A(J-1)=A(J):LET A(J)=SW
  NEXT
NEXT

Ugyanez Turbo Pascal-ban:

const n=26;
var a:array[1..n] of integer;
    i,j,sw:integer;
...
begin
  ...
  for i:=2 to n do
    for j:=n downto i do
      if a[j-1]>a[j] then begin
        sw:=a[j-1];a[j-1]:=a[j];a[j]:=sw
      end;
  ...
end.

A hatékonysági mutatók alakulása:
A módszer tárigénye: N+1
Az összehasonlítások száma független az A vektor előrendezettségétől, minden esetben N*(N-1)/2.
A mozgatások száma legjobb esetben 0, legrosszabb esetben 3*N*(N-1)/2
A végrehajtási idő véletlenszerű elrendezettség és N=500 elem esetén:

 
BASIC
ZZZIP
PASCAL
4 MHz (memóriavárakozással)
3582 s
73 s
37 s
6 MHz (memóriavárakozás nélkül)
1946 s
39 s
20 s

Az algoritmus - az előrendezettségtől függően - esetleg gyorsítható, ha egy jelzőt vezetünk be, mely figyeli, hogy a cikluson belől volt-e csere, amennyiben nem volt, vége az eljárásnak, a sor többi része már rendezett.

NUMERIC A(N)
...
FOR I=2 TO N
  LET VEGE=-1
  FOR J=N TO I STEP-1
    IF A(J-1)>A(J) THEN
      LET SW=A(J-1):LET A(J-1)=A(J):LET A(J)=SW
      LET VEGE=0
    END IF
  NEXT
  IF VEGE THEN EXIT FOR
NEXT

T8/c/2. Kétirányú buborékos rendezés (Koktélrendezés) (kiegészítés)
A módszer lényege: A rossz a hatékonysági mutatóval rendelkező buborék rendezés javítása. Egy menetben a legkisebb és legnagyobb elemet is a helyre tesszük, így felváltva mozognak a kis elemek a tömb eleje, a nagyok pedig a tömb vége felé.

A rendezés algoritmusa:

NUMERIC A(N)
...
LET AH=0:LET FH=N+1
DO WHILE AH<FH
  LET AH=AH+1:LET FH=FH-1:LET VEGE=-1
  FOR J=AH TO FH-1
    IF A(J)>A(J+1) THEN
      LET SW=A(J):LET A(J)=A(J+1):LET A(J+1)=SW
      LET VEGE=0
    END IF
  NEXT
  IF VEGE THEN EXIT DO
  LET VEGE=-1
  FOR J=FH-1 TO AH STEP-1
    IF A(J)>A(J+1) THEN
      LET SW=A(J):LET A(J)=A(J+1):LET A(J+1)=SW
      LET VEGE=0
    END IF
  NEXT
IF VEGE THEN EXIT DO
LOOP

Sajnos, mivel a cserék száma számottevően nem csökken, a hatékonyság javulása minimális:

 
BASIC
ZZZIP
4 MHz (memóriavárakozással)
3383 s
62 s
6 MHz (memóriavárakozás nélkül)
1840 s
33 s

A két (lefelé- és felfelé rendező) ciklus összevonható:

NUMERIC A(N)
...
LET ST=AH+1:LET EN=FH:LET D,CH=1
DO
  FOR J=ST TO EN STEP D
    IF A(J-1)>A(J) THEN LET T=A(J-1):LET A(J-1)=A(J):LET A(J)=T:LET CH=J
  NEXT
  LET EN=ST:LET ST=CH-D:LET D=-1*D
LOOP UNTIL EN*D<ST*D

 

T8/d. Egyszerű beillesztéses rendezés
A módszer lényege: Úgy végezzük a rendezést, mintha kártyáznánk és kezünkbe egyesével vennénk fel az asztalról a kiosztott lapokat. Az éppen felvett lapnak megkeressük a kezünkben lévő, már rendezett sorozatban a helyét úgy, hogy közben a nála nagyobbakat egy hellyel elcsúsztatjuk, végül beillesztjük a felvett lapot a neki megfelelő helyre. N elem esetén a végső sorrend kialakításához N-1 menetre van szükségünk.
Nézzük meg az A vektor alakulását az ismert 16 számra:

A rendezés algoritmusa:

NUMERIC A(N)
...
FOR J=2 TO N
  LET I=J-1:LET SW=A(J)
  DO WHILE I>0 AND SW<A(I)
    LET A(I+1)=A(I):LET I=I-1
  LOOP
  LET A(I+1)=SW
NEXT

Ugyanez Turbo Pascal-ban:

const n=26;
var a:array[1..n] of integer;
    i,j,sw:integer;
...
begin
  ...
  for j:=2 to n do begin
    i:=j-1;sw:=a[j];
    while (i>0) and (sw<a[i]) do begin
      a[i+1]:=a[i];i:=i-1
    end;
    a[i+1]:=sw
  end;
  ...
end.

A hatékonysági mutatók alakulása:
A módszer tárigénye: N+1
Az összehasonlítások száma függ az elemek előrendezettségétől . Legjobb esetben N-1, legrosszabb esetben pedig N*(N+1)/2-1.
A mozgatások száma is függ az előrendezettségtől. Legjobb esetben 2*(N-1), legrosszabb esetben pedig 2*(N-1)+N*(N-1)/2.
A végrehajtási idő véletlenszerű elrendezettség és N=500 elem esetén:

 
BASIC
ZZZIP
PASCAL
4 MHz (memóriavárakozással)
1800 s
33 s
20 s
6 MHz (memóriavárakozás nélkül)
978 s
18 s
11 s

A most bemutatott módszer nagy hátránya, hogy benne - éppen a beillesztés miatt - elég sok mozgatásra van szükség. Az elemeknek a megfelelő helyre való beillesztését megoldhatjuk másképpen is, az ún. listaszerkezet alkalmazásival. Most következő algoritmusunk erre mutat példát.

Az eddig tárgyalt módszerek közös tulajdonságát úgy foglalhatjuk össze, hogy valamennyien úgy működtek, hogy lépesenként egyre hosszabb rendezett sorozatot állítottak elő, s ahhoz, hogy egy újabb elem beletartozzon ebbe a sorozatba, össze kellett hasonlítani azt a többi vagy még nem rendezett elemmel, vagy a már rendezett elemekkel, s ez, minél több elemünk volt, annál több összehasonlítást és mozgatást jelentett. E negatívum mellett meg kell jegyeznünk, hogy valamennyi módszer algoritmusa igen egyszerű volt.
A most következő három módszer lényegesen különbözik a fentiektől. Igaz ugyan, hogy algoritmusuk jóval bonyolultabb az eddigieknél, viszont hatékonysági mutatóik az elemszám függvényében igen kedvező képet mutatnak.

T8/e. Fésűs rendezés (Comb Sort) (kiegészítés)
A Fésűs rendezés a Buborék rendezés javítása. A buborék a leglassabb rendezési algoritmus, azonban egy egyszerű módosítással annyira javítható, hogy vetekszik a később bemutatandó Gyorsrendezéssel. Az eredeti fésűs rendezést Stephen Lacey és Richard Box fejlesztette, és a Byte Magazin publikálta 1991-ben. A változtatás a buborékhoz képest nem nagy: az alapötlet az, hogy a sorozat végén levő kicsi értékekre találjunk rá minél hamarabb, mert ezek lassítják jelentősen a buborékot. (A sorozat elején levő nagy értékek nem annyira lassítanak, mert ezekre hamar rátalálunk). A gap beállításával először a távollevő elemeket rendezzük. Ezután a gap csökken, míg végül egy lesz. Lacey és Richard Box megmutatták, hogy a gap minden lépésben 1.3-mal osztandó.

A rendezés algoritmusa:

NUMERIC A(N)
...
LET GAP=N:LET SW=1
DO WHILE GAP>1 OR SW
  LET GAP=MAX(INT(GAP/1.3),1)
  LET SW=0
  FOR I=1 TO N-GAP
    IF A(I)>A(I+GAP) THEN
      LET T=A(I):LET A(I)=A(I+GAP):LET A(I+GAP)=T
      LET SW=1
    END IF
  NEXT
LOOP

Ugyanez Turbo Pascal-ban:

const n=26;
var a:array[1..n] of integer;
    i,t,gap:integer;
    sw:boolean;
...
begin
  ...
  gap:=n;sw:=true;
  while (gap>1) or sw do begin
    gap:=Trunc(gap/1.3);
    if (gap<1) then gap:=1;
    sw:=false;
    for i:=1 to n-gap do
      if a[i]>a[i+gap] then begin
        t:=a[i];a[i]:=a[i+gap];a[i+gap]:=t;
        sw:=true
      end
  end;
  ...
end.

 
BASIC
PASCAL
4 MHz (memóriavárakozással)
207 s
3 s
6 MHz (memóriavárakozás nélkül)
112 s
2 s

T8/f. Shell-módszer beszúrással
A módszer lényege: A Shell-módszer nem foglalkozik egyszerre minden rendezendő elemmel, csak az egymástól adott távolságra lévőkkel. A rendezés most is több menetben történik. Minden menet elején meghatározunk egy ún. lépésközt (D), amely azt jelenti, hogy az adott menetben a vektor egymástól D távolságra lévő elemeit rendezzük. (Adott meneten belül a rendezés több módszer szerint történhet. Mi most a beszúrást választottuk.) Az utolsó menetben, D=1 esetén a vektor rendezetté válik. Az induló lépésköz meghatározása úgy történik, hogy a rendezéshez szükséges menetek száma körülbelül log2 N legyen. A további lépésközöket felezéssel kapjuk.
A módszer előnye az, hogy viszonylag kevés művelettel az eredeti vektor 'nagyjából' rendezetté válik. A kisebb elemek körülbelül egyszerre haladnak a vektor elejére, végleges helyük felé, míg a nagyobbak a vektor vége felé. A lépésköz csökkentésével ebben a nagyjából rendezett vektorban már csak kisebb korrekciókat kell végrehajtunk.
Most nézzük meg, hogy rendezi a Shell-módszer választott 16 számunkat! Az induló lépésköz D=15, ezt 7, 3, végül 1 követi. A táblázat az egyes menetek utáni állapotot mutatja.

A rendezés algoritmusa:

NUMERIC A(N)
...
LET D=2^INT(LOG(N)/LOG(2))-1
DO
  LET I=1
  DO WHILE I<=D AND I+D<=N
    FOR J=I+D TO N STEP D
      LET AH=A(J):LET BH=J-D
      DO WHILE BH>0 AND AH<A(BH)
        LET A(BH+D)=A(BH):LET BH=BH-D
      LOOP
      LET A(BH+D)=AH
    NEXT
    LET I=I+1
  LOOP
  LET D=INT(D/2)
LOOP WHILE D>0

A hatékonysági mutatók alakulása:
A módszer tárigénye: N+1
Az összehasonlítások és mozgatások száma függ az A vektor előrendezettségétől. Monoton növekvő és csökkenő esetben az összehasonlítások száma N*log N nagyságrendű. A mozgatások száma monoton növekvő előrendezettség eseten 0, monoton csökkenő esetben nagyságrendben megegyezik az összehasonlítások számával.
Véletlenszerű előrendezettség esetén az összehasonlítások ész a mozgatások száma a fentieknél valamivel nagyobb.
A végrehajtási idő véletlenszerű elrendezettség és N=500 elem esetén:

 
BASIC
ZZZIP
4 MHz (memóriavárakozással)
215 s
4 s
6 MHz (memóriavárakozás nélkül)
117 s
3 s

A fenti algoritmus ebben a formában a Pascal nyelv korlátai miatt nem valósítható meg egyszerűen Turbo Pascal-ban, ezért az algoritmust némileg módosítani kell, de az 500 elemű tömb rendezésével így is másfél másodperc alatt végez.

const n=26;
var a:array[1..n] of integer;
    i,j,step,tmp:Integer;
...
begin
  ...
  step:=n div 2;
  while step>0 do begin
    for i:=step to n do begin
      tmp:=a[i];j:=i;
      while (j>step) and (a[j-step]>tmp) do begin
        a[j]:=a[j-step];j:=j-step;
      end;
      a[j]:=tmp;
    end;
    step:=step div 2;
  end;
end;

T8/g. Gyorsrendezés (Quicksort)
A máig is leggyorsabb rendezési eljárást Sir Charles Antony Richard Hoare (Tony Hoare) dolgozta ki 1962-ben.
A módszer lényege: Igen gyors és hatékony rendezésről van szó, amelynek alapja az, hogy most egymástól távol lévő elemeket hasonlítunk össze egymással és szükség esetén felcseréljük azokat. Az algoritmus a rendezendő számok listáját először két részre bontja. A felbontáshoz kiválaszt egy támpontnak nevezett elemet (más néven pivot, főelem vagy vezérelem), és particionálja a listát: a támpontnál kisebb elemeket eléje, a nagyobbakat mögéje mozgatja. Az így keletkezett tömbrészeket ismételten szétosztva végül 1 elemű résztömbök keletkeznek, és így a teljes tömb rendezett lesz.
Egyszerűbb, ha az algoritmus működését az ismert 16 szám segítségével mutatjuk be. Válasszuk ki az A vektor első elemét es vegyük ki a vektorból, a helye üres marad!

főelem
A(1)-A(16)
 
64
56
8
42
5
12
16
40
3
31
47
22
24
33
7
46
64
X
56
8
42
5
12
16
40
3
31
47
22
24
33
7
46

A vektor végéről indulva keresünk egy ennél a kiválasztottnál kisebb elemet. Ha találunk, azt betesszük az előbb felszabadult helyre. Most a "lyuk" ott keletkezik, ahonnan ezt az elemet elvettük. Ide a vektor elejéről keresünk egy, a kiválasztott elemnél nagyobb elemet. Ha találunk, beillesztjük, ha nem, az azt jelenti, hogy oda éppen a kiválasztott elem illik.

főelem
A(1)-A(16)
64
46
56
8
42
5
12
16
40
3
31
47
22
24
33
7
X
 
46
56
8
42
5
12
16
40
3
31
47
22
24
33
7
64

A konkrét példában a vektort most nem sikerült két részre vágni, mert a 64 éppen a legnagyobb elem, ezért menjünk egy lépéssel tovább. Most a 46-ot emeljük ki a vektor elejéről és hátulról haladva keressünk nála kisebb elemet. És így tovább. A vektor alakulását a rajzon szemléltetjük.

főelem
A(1)-A(16)
46
X
56
8
42
5
12
16
40
3
31
47
22
24
33
7
64
46
7
56
8
42
5
12
16
40
3
31
47
22
24
33
X
64
46
7
X
8
42
5
12
16
40
3
31
47
22
24
33
56
64
46
7
33
8
42
5
12
16
40
3
31
47
22
24
X
56
4
46
7
33
8
42
5
12
16
40
3
31
X
22
24
47
56
64
46
7
33
8
42
5
12
16
40
3
31
24
22
X
47
56
64
 
7
33
8
42
5
12
16
40
3
31
24
22
46
47
56
64

A 46 most a végleges helyére került. Tőle "balra" nála kisebb, tőle "jobbra" nála nagyobb elemek helyezkednek el. Az eljárást az így kettévágott vektor egyik részének elemeivel a fent leírt módon - vagyis az alábbi algoritmus alapján - folytatjuk tovább.

Quick(AH,FH):
  Szétválogat(AH,FH,E)
  Ha AH<E-1 akkor Quick(AH,E-1)
  Ha E+1<FH akkor Quick(E+1,FH)
Eljárás vége.

A szétválogató eljárás a vektor elemeit úgy rendezi át, hogy az E-edik elem elé kerülnek a nála kisebbek, mögé pedig a nagyobbak.

A rendezés algoritmusa:

NUMERIC A(1 TO N)
...
CALL QSORT(1,N)
...
DEF QSORT(AH,FH)
  NUMERIC E
  LET E=AH:LET U=FH:LET K=A(E)
  DO UNTIL E=U
    DO UNTIL E=U OR A(U)<K
      LET U=U-1
    LOOP
    IF E<U THEN
      LET A(E)=A(U):LET E=E+1
      DO UNTIL E=U OR A(E)>K
        LET E=E+1
      LOOP
      IF E<U THEN LET A(U)=A(E):LET U=U-1
    END IF
  LOOP
  LET A(E)=K
  IF AH<E-1 THEN CALL QSORT(AH,E-1)
  IF E+1<FH THEN CALL QSORT(E+1,FH)
END DEF

Ugyanez Turbo Pascal-ban:

{$A-}
const n=26;
var a:array[1..n] of integer;
...
Procedure QSort(ah,fh:integer);
var e,k,u:integer;
begin
  e:=ah;u:=fh;k:=a[e];
  while e<>u do begin
    while (e<>u) and (a[u]>=k) do
      u:=u-1;
    if e<u then begin
      a[e]:=a[u];e:=e+1;
      while (e<>u) and (a[e]<=k) do
        e:=e+1;
      if e<u then begin
        a[u]:=a[e];u:=u-1
      end
    end
  end;
  a[e]:=k;
  if ah<e-1 then QSort(ah,e-1);
  if e+1<fh then QSort(e+1,fh)
end;
begin
  ...
  QSort(1,n);
  ...
end.

A hatékonysági mutatók alakulása:
A módszer tárigénye N+1, további az N elemű A vektorhoz 2*N méretű vermet kell biztosítanunk.
Az összehasonlítások száma monoton növő, illetve csökkenő előrendezettség esetén egyaránt N*(N+1)/2-1. Véletlenszerű előrendezettség esetén azonban már csak N*log N nagyságrendű. A mozgatások száma monoton növekvő előrendezettségnél 2*(N-1), monoton csökkenő esetben 2*N+(N-4)/2. Véletlenszerű előrendezettség mellett pedig az összehasonlítások számának körülbelül a fele.
A végrehajtási idő véletlenszerű elrendezettség és N=500 elem esetén:

 
BASIC
PASCAL
4 MHz (memóriavárakozással)
139 s
2 s
6 MHz (memóriavárakozás nélkül)
76 s
1 s

A végrehajtási idő véletlenszerű elrendezettség és N=5000 elem esetén:

 
BASIC
PASCAL
4 MHz (memóriavárakozással)
1942 s
20 s
6 MHz (memóriavárakozás nélkül)
1020 s
12 s

Az interpteretes és a compileres programozási nyelvek közötti különbséget jól szemlélteti, hogy míg BASIC-ben az előbb bemutatott megoldás a gyorsabb, PASCAL-ban az alábbi megoldás gyorsabb 25 százalékkal:

{$A-}
const n=26;
var a:array[1..n] of integer;
...
Procedure QSort(bal,jobb:integer);
var i,j,pivot,x:integer;
begin
  i:=bal;j:=jobb;
  pivot:=a[(i+j) div 2];
  while i<= j do begin
    while a[i]<pivot do i:=i+1;
    while a[j]>pivot do j:=j-1;
    if i<=j then begin
      x:=a[i];a[i]:=a[j];a[j]:=x;
      i:=i+1;j:=j-1
    end
  end;
  if bal<j then QSort(bal,j);
  if i<jobb then QSort(i,jobb)
end;
begin
  ...
  QSort(1,n);
  ...
end.

Ezzel be is fejeztük a legfontosabbnak vélt vagy talán legjellemzőbbnek ítélt rendezési algoritmusok ismertetését. Ezeken kívül persze még igen sok érdekes és alapjaiban különböző rendezési eljárás létezik. Most pedig folytassuk a programozási tételeket egy, az előbb leírt gyorsrendezés alapgondolatát alkotó tétel ismertetésével.

T9. A szétválogatás tétele
Általános feladat: Rendelkezésre áll egy N elemű sorozat (A(N)), valamit egy kiemelt eleme (X=A(1)). Cseréljük fel úgy a sorozat elemeit, hogy az X-nél kisebbek X előtt legyenek, a nála nagyobbak pedig utána.

Algoritmus:

NUMERIC A(1 TO N)
...
LET X=A(1)
LET E=1:LET U=N
DO WHILE E<U
  DO WHILE E<U AND A(U)>=X
    LET U=U-1
  LOOP
  IF E<U THEN
    LET A(E)=A(U):LET E=E+1
    DO WHILE E<U AND A(E)<=X
      LET E=E+1
    LOOP
    IF E<U THEN LET A(U)=A(E):LET U=U-1
  END IF
LOOP
LET A(E)=X

T10. Permutáció rekurcióval
Az eddigi példákban egy sorozat önkényesen kiválasztott egyetlen permutációját adtuk meg (általában a növekvő sorrendben rendezettet). Az utolsó feladatban soroljuk fel egy N elemű sorozat összes permutációját!
Könnyű belátni, hogy a következő sorozat első elemének n különböző értéket választhatunk, a másodiknak a megmaradt n-1, a harmadiknak az n-2, az n. értéknek pedig az utolsó megmaradt érték közül választhatunk. Egy n-elemű halmaz permutációinak száma tehát n! (faktoriális). Ebben az a nehézség, hogy már egy 70 elemű sorozat permutációinak száma is meghaladja a gogol (egy számjegy és száz darab nulla) értéket. Ennyi elem felsorolása reménytelenül sok időbe telik. Reálisan maximum 8 elemű sorozat esetében kapjuk meg elfogadható időn belül az összes permutációt (40320 sorozatot).

NUMERIC T(1 TO N)
LET S=0
...
CALL PERM(N)
PRINT S;" sorozat"
END
...
DEF PERM(I)
  NUMERIC J,X
  IF I=1 THEN
    FOR X=1 TO N
      PRINT T(X);
    NEXT
    PRINT :LET S=S+1
  ELSE
    CALL PERM(I-1)
    FOR J=1 TO I-1
      LET C=T(J):LET T(J)=T(I):LET T(I)=C
      CALL PERM(I-1)
      LET C=T(J):LET T(J)=T(I):LET T(I)=C
    NEXT
  END IF
END DEF

Ugyanez Turbo Pascal-ban:

{$A-}
const n=5;
var t:array[1..8] of byte;
    s:integer;
...

Procedure Perm(i:integer);
var j,x,c:integer;
begin
  if i=1 then begin
    for x:=1 to n do
      Write(t[x],' ');
    Writeln;s:=s+1
  end
  else begin
    Perm(i-1);
    for j:=1 to i-1 do begin
      c:=t[j];t[j]:=t[i];t[i]:=c;
      Perm(i-1);
      c:=t[j];t[j]:=t[i];t[i]:=c;
    end;
  end;
end;

begin
  ...
  s:=0;
  Perm(n);
  Writeln(s,' sorozat')
end.

7.4. Több sorozathoz egy sorozat hozzárendelése
Most pedig egy olyan feladatosztályra térünk át, ahol több sorozatból kell készíteni egy újabb sorozatot. Ezek általában visszavezethetők korábbi feladatokra, néhánnyal mégis érdemes külön is foglalkozni. A legegyszerűbbek közé tartoznak például olyanok, amelyek két sorozatból indulnak ki, ezeket halmazoknak tekintik, s valamilyen halmazműveletet végeznek rajtuk (egyesítés, metszet,...). Ezek általában kiválogatási, eldöntési feladatokra vezethetők vissza.

T10. A metszetképzés tétele
Rendelkezésünkre áll egy N és egy M elemei halmaz az A(N) és a B(M) vektorban ábrázolva. Készítsük el a két halmaz metszetét a C() vektorba! (Két halmaz metszetébe azok az elemek tartoznak, amelyek mindkettőben szerepelnek. C maximális elemszáma N és M közül a kisebbik.)

Algoritmus:

Eljárás:
  CN:=0
  Ciklus I=1-től N-ig
    J:=1
    Ciklus amíg J<=M és A(I)<>B(J)
      J:=J+1
    Ciklus vége
    Ha J<=M akkor CN:=CN+1: C(CN):=A(I)
  Ciklus vége
Eljárás vége.

IS-BASIC:

NUMERIC A(1 TO N)
NUMERIC B(1 TO M)
NUMERIC C(0 TO MIN(M,N))
..
LET CN=0
FOR I=1 TO N
  LET J=1
  DO WHILE J<=M AND A(J)<>B(I)
    LET J=J+1
  LOOP
  IF J<=M THEN LET CN=CN+1:LET C(CN)=A(J)
NEXT
LET C(0)=CN ! C(0)-ba a metszet elemeinek száma

T11. Az egyesítés (unióképzés) tétele
Általános feladat: Rendelkezésünkre áll egy N és egy M elemű halmaz az A(N) és a B(M) vektorban ábrázolva. Készítsük el a két halmaz egyesítését a C() vektorba! (Két halmaz egyesítésébe azok az elemek tartoznak, amelyek legalább az egyikben szerepelnek. Így C halmaz elemszáma legfeljebb N+M.)

Algoritmus:

Eljárás:
  Ciklus I=1-től N-ig
    C(I):=A(I)
  Ciklus vége
  CN:=N
  Ciklus J=1-től M-ig
    I:=1
    Ciklus amíg I<=N és A(I)<>B(J)
      I:=I+1
    Ciklus vége
    Ha I>N akkor CN:=CN+1: C(CN):=B(J)
  Ciklus vége
Eljárás vége.

IS-BASIC:

NUMERIC A(1 TO N)
NUMERIC B(1 TO M)
NUMERIC C(0 TO N+M)
...
FOR I=1 TO N
  LET C(I)=A(I)
NEXT
LET CN=N
FOR J=1 TO M
  LET I=1
  DO WHILE I<=N AND A(I)<>B(J)
    LET I=I+1
  LOOP
  IF I>N THEN LET CN=CN+1:LET C(CN)=B(J)
NEXT
LET C(0)=CN ! C(0)-ba az egyesítés elemeinek száma

T12. Az összefuttatás tétele
Általános feladat: Rendelkezésre állnak két rendezett sorozat elemei. Állítsunk elő belőlük egy sorozatot úgy, hogy az eredeti sorozatok minden eleme szerepeljen benne, és ez a sorozat is rendezett legyen! (Pl. növekvő sorrendű sorozatokat vizsgálunk.)
A feladat tulajdonképpen az unió tétel speciális esete: uniót kell előállítani úgy, hogy a rendezettség megmaradjon! A két sorozat: A(N), B(M). Az eredmény: C(N+M). A megoldásban INF jelöli a számítógépen ábrázolható legnagyobb értéket. Ezt alkalmazzuk végjelként, a megoldás egyszerűsítése érdekében.

Algoritmus:

Eljárás:
  I:=1: J:=1: K:=0
  A(N+1):=+végtelen: B(M+1):=+végtelen
  Ciklus amíg I<N+1 vagy J<M+1
    K:=K+1
    Elágazás
      A(I)<B(J) esetén C(K):=A(I): I:=I+1
      A(I)>B(J) esetén C(K):=B(J): J:=J+1
      A(I)=B(J) esetén C(K):=A(I): I:=I+1: J:=J+1
    Elágazás vége
  Ciklus vége
Eljárás vége.

IS-BASIC:

NUMERIC A(1 TO N+1)
NUMERIC B(1 TO M+1)
NUMERIC C(0 TO N+M)
...
LET I,J=1:LET K=0
LET A(N+1),B(M+1)=INF
DO WHILE I<(N+1) OR J<(M+1)
  LET K=K+1
  SELECT CASE A(I)
  CASE IS<B(J)
    LET C(K)=A(I):LET I=I+1
  CASE IS>B(J)
    LET C(K)=B(J):LET J=J+1
  CASE ELSE
    LET C(K)=A(I):LET I=I+1:LET J=J+1
  END SELECT
LOOP
LET C(0)=K ! C(0)-ba a vektor elemeinek száma

Megjegyzés: az összefuttatás az alapgondolata az ún. külső rendezéseknek, amelyeknél a teljes rendezendő adatmennyiség nem fér el egyszerre az operatív tárban.

7.5. Rekurzió (kiegészítés)
A rekurzió - melyet érintőlegesen már többször említettünk - , a matematikában, valamint a számítógép-tudományban egy olyan művelet, mely végrehajtáskor a saját maga által definiált műveletet, vagy műveletsort hajtja végre, ezáltal önmagát ismétli. Bár a legtöbb feladat iterációval is megoldható, és a rekurzió sok esetben lassítja a programvégrehajtást és a vermet is intenzíven használja, a rekurzív megoldás a tiszta logikai szerkezettel és rövid programkódokkal bőven ad kárpótlást. Egy feladat rekurzív, ha a megoldáshoz vezető lépések során

E módszer az indukció elvén alapszik. A feladatot mindig visszavezetjük egy előző feladatra, melynek megoldása egy fokkal egyszerűbb. Véges lépésben elérjük a legegyszerűbb esetet, és így a feladatot megoldottuk. Egy függvényt vagy eljárást akkor nevezünk rekurzívnak, ha meghívja saját magát. Ebből a szempontból kétféle módszert különböztetünk meg:

Egy eljárás vagy függvény hívásakor a veremre kerülnek a rutin lokális változói, paraméterei, valamint a visszatérési cím. Mindezek helye akkor szabadul fel, ha a vezérlés a rutin befejezésére kerül, vagyis a rutin befejezte a feladatát. Amikor a rutint másodszor hívjuk meg, anélkül, hogy a futását befejezte volna, újabb adatok kerülnek a veremre. A második hívás adatai tehát nem azonosak az első hívás adataival. Az adatok minden esetben az aktuális hívás lokális adatai. Amikor a második futást sikerül befejezni, akkor az első futásnak pontosan arra a pontjára érünk vissza, ahol annak végrehajtását felfüggesztettük.
Ahhoz, hogy egy rekurzív folyamat be tudjon fejeződni, figyelni kell arra, hogy legyen valami, ami megállítja a további rekurzív hívást, és az elkezdett rutinok sorra befejeződhessenek. A rekurzív rutinban minden esetben szerepelnie kell egy küszöbfeltételnek, vagy leállító feltételnek, mely alapján eldől, lesz-e további rekurzív hívás, vagy sem.

Fibonacci-számok
A Fibonacci-számok a matematikában az egyik legismertebb másodrendben rekurzív sorozat elemei, ezért a programozásban a rekurzió legegyszerűbb példájaként tartják számon. A sorozat első két eleme 0 és 1, a további elemeket az előző kettő összegeként kapjuk:
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, ...

Határozzuk meg a sorozat első N elemét!

FOR I=1 TO N
  PRINT FIB(I);
NEXT
...
DEF FIB(K)
  IF K<3 THEN
    LET FIB=1
  ELSE
    LET FIB=FIB(K-2)+FIB(K-1)
  END IF
END DEF

Ugyanez Turbo Pascal-ban:

{$A-}
const n:byte=23;
var i:integer;

Function Fib(k:byte):integer;
begin
  if k<3 then
    Fib:=1
  else
    Fib:=Fib(k-2)+Fib(k-1)
end;

begin
  for i:=1 to n do
    write(Fib(i),' ')
end.

Megjegyzés: Bár a rekurzív implementáció a legegyszerűbb, de közvetlenül nem alkalmas nagy Fibonacci-számok kiszámítására, mert a korábbi Fibonacci-számokat sokszor ki kell számítani hozzá, amitől a futásidő exponenciálisan nő. Lineáris futásidő érhető el viszont ciklussal és két segédváltozó használatával, amelyek kezdetben 0 és 1 értékeket kapnak, majd az elsőt minden lépésben felülírjuk a másodikkal, a másodikat pedig a kettő összegével:

FOR I=1 TO N
  PRINT FIB(I)
NEXT
...
DEF FIB(X)
  LET F=0:LET PREV=1
  FOR Z=2 TO X
    LET NXT=F+PREV
    LET PREV=F
    LET F=NXT
  NEXT
  LET FIB=F
END DEF

Ugyanez Turbo Pascal-ban:

Program Fib2;
var i:integer;

Function Fib(x:integer):integer;
var z,f,nxt,prev:integer;
begin
  f:=0;prev:=1;
  for z:=2 to x do begin
    nxt:=f+prev;
    prev:=f;
    f:=nxt
  end;
  Fib:=f
end;

begin
  for i:=1 to 24 do
    Write(Fib(i),' ')
end.

Fraktálok
A rekurzió leglátványosabb és legszemléletesebb alkalmazása a fraktálok rajzolása. A fraktálok "önhasonló", végtelenül komplex matematikai alakzatok, melyek változatos formáiban legalább egy felismerhető (tehát matematikai eszközökkel leírható) ismétlődés tapasztalható.
Az egyik első és egyben legismertebb fraktál a Helge von Koch svéd matematikus által 1904-ben leírt Koch-görbe. A görbét úgy állíthatjuk elő, hogy egy szabályos háromszög oldalait elharmadoljuk, majd a középső harmadára ismét egy szabályos háromszöget rajzolunk. Ezen háromszögek oldalait szintén harmadoljuk, és háromszöget rajzolunk rájuk. Ezt elvileg a végtelenségig folytatjuk, gyakorlatilag ilyen irányú törekvéseinknek gátat szab a számítógép grafikai felbontásának határa.

Algoritmus:

OPTION ANGLE RADIANS
CALL KOCH(50,200,0,1200)
...
DEF KOCH(X,Y,A,D)
  IF D>16 THEN
    LET D=D/3:LET PI3=PI/3
    CALL KOCH(X,Y,A,D)
    CALL KOCH(X+D*COS(A),Y+D*SIN(A),A+PI3,D)
    CALL KOCH(X+D*COS(A)+D*COS(A+PI3),Y+D*SIN(A)+D*SIN(A+PI3),A-PI3,D)
    CALL KOCH(X+2*D*COS(A),Y+2*D*SIN(A),A,D)
  ELSE
    PLOT X,Y;X+D*COS(A),Y+D*SIN(A)
  END IF
END DEF

Az algoritmus minden egyes szakasz kezdő és végpontját kiszámítja. Az IS-BASIC azonban ismeri a LOGO programozási nyelvből származó Teknőc grafikát, melynek segítségével jelentősen egyszerűsíthetjük (és gyorsíthatjuk) az algoritmust:

OPTION ANGLE DEGREES
PLOT 50,200;ANGLE 0;
CALL KOCH(0,1200)
...
DEF KOCH(A,D)
  IF D>16 THEN
    LET D=D/3
    CALL KOCH(A,D)
    CALL KOCH(60,D)
    CALL KOCH(-120,D)
    CALL KOCH(60,D)
  ELSE
    PLOT LEFT A;FORWARD D;
  END IF
END DEF

Itt a leállító feltétel az oldalhosszúság (D), melyet minden eljáráshívásban harmadolunk, a küszöbérték pedig a 16, ha az oldalhosszúság ez alá csökken, nem hívjuk meg az eljárást újra.
Ha nem csak egy szakaszt akarunk kirajzolni, hanem a Koch-hópehely néven is ismert teljes, önmagába záródó görbét, akkor sincs sokkal nehezebb dolgunk, hiszen csak ezt a görbét kell a háromszög mindhárom oldalára "ráilleszteni":

OPTION ANGLE DEGREES
PLOT 330,700;ANGLE 0;
FOR I=1 TO 3
  CALL KOCH(0,1000)
  PLOT LEFT 120;
NEXT
...

Ugyanezzel az eljárással rajzoljunk Cesaro-görbét, hiszen az a Koch-görbe variánsa, ahol az elfordulási szög 60 fok és 90 fok között változtatható (a példában 80).

OPTION ANGLE DEGREES
PLOT 16,640;ANGLE 0;
CALL CESARO(0,4800)
...
DEF CESARO(A,D)
  IF D>32 THEN
    LET D=D/3
    CALL CESARO(A,D)
    CALL CESARO(80,D)
    CALL CESARO(-160,D)
    CALL CESARO(80,D)
  ELSE
    PLOT RIGHT A;FORWARD D;
  END IF
END DEF

Igen egyszerűen megrajzolható a szintén közismert fraktál fa, melyen minden csomópontban tetszőleges szögben kétfelé ágaznak a fa ágai.

OPTION ANGLE DEGREES
PLOT 640,10;ANGLE 90;
CALL TREE(200)
...
DEF TREE(N)
  IF N<24 THEN EXIT DEF
  PLOT FORWARD N;RIGHT 25;
  CALL TREE(N*.75)
  PLOT LEFT 50;
  CALL TREE(N*.75)
  PLOT RIGHT 25,BACK N,
END DEF

Ha a fa ágai háromfelé ágaznak, 90 vagy 60 fokban, szintén látványos "fát" kapunk.

A Turbo Pascal CP/M változatához nem készülhetett egységes grafikus rutingyűjtemény, hisz a grafikus képernyő paraméterei hardware függőek. Ha nem használunk teknőc-grafikát minden vonal kezdő és végpontját szögfüggvényekkel kell meghatározni.
A teljes program Turbo-Pascal-ban (lássunk példát az incluide-file-ok használatára is):

Program FractalTree;
{$A-}
{$I Grafcs.tpu}
const dfi=0.436;
      c=0.75;
      mind=32;
Procedure Ag(ang,d,x0,y0:real);
var x1,y1:real;
begin
  x1:=x0+d*Cos(ang);
  y1:=y0+d*Sin(ang);
  Draw(101,Round(x0),Round(y0),Round(x1),Round(y1));
  if d>mind then begin
    Ag(ang+dfi,d*c,x1,y1);
    Ag(ang-dfi,d*c,x1,y1)
  end
end;
begin
  Graf_ON(101,1,0,40,22);
  Display(101,1,1,22);
  Palette(101,0,170,0,0,0,0,0,0);
  Ag(Pi/2,200,640,10);
  repeat until KeyPressed;
  Graf_OFF(101)
end.

A korabeli BASIC nyelvek általában nem ismerik sem az eljárásokat (és így a paraméterátadást sem), sem a teknőcgrafikát. Az amúgy kényelmes Spectrum BASIC-ben az alábbi módon lehet megvalósítani a fenti algoritmust, "manuális veremkezeléssel":

1 REM *** Tree ***
5 BORDER 6: CLS
10 DIM w(10)
30 LET s=1
40 PLOT 128,0
50 LET w(s)=48
60 LET d=0
70 GO SUB 100
80 STOP
100 IF w(s)<6 THEN GO TO 200
110 DRAW w(s)*SIN d,w(s)*COS d
120 LET w(s+1)=w(s)*0.75
130 LET d=d+0.4
140 LET s=s+1: GO SUB 100
150 LET w(s+1)=w(s)*0.75
160 LET d=d-0.8
170 LET s=s+1: GO SUB 100
180 LET d=d+0.4
190 DRAW -w(s)*SIN d,-w(s)*COS d
200 LET s=s-1
210 RETURN

Aperiodikus csempézés alatt a síknak véges sokféle csempével (síkidommal) való, átfedés- és hézagmentes lefedését értjük úgy, hogy nincs olyan része a síknak, aminek ismételt eltolásával a végtelen sík mintázata megkapható lenne (azaz nincs két, a síkon értelmezett nem párhuzamos eltolási szimmetria). A Penrose-féle csempézés az aperiodikus csempehalmazok egy olyan csoportja, amit Roger Penrose (és tőle függetlenül Robert Ammann) fedezett fel. A Penrose-csempék ugyan nem ismétlődő, nem periodikus alakzatokat hoznak létre, a mintának mégis vannak bizonyos periodikusság látszatát nyújtó jellegzetességei, egyfajta rendezettsége. Erre mutat látványos példát a Penta Plexity.

OPTION ANGLE DEGREES
...
PLOT 260,210;ANGLE 90;
LET X=((SQR(5)+1)/2)^2
FOR I=1 TO 5
  CALL PENTA(582,3)
  PLOT RIGHT 72;
NEXT
...
DEF PENTA(D,LEV)
  IF LEV=0 THEN
    PLOT FORWARD D;
    EXIT DEF
  END IF
  CALL PENTA(D/X,LEV-1)
  PLOT RIGHT 72;
  CALL PENTA(D/X,LEV-1)
  PLOT RIGHT 72;
  CALL PENTA(D/X,LEV-1)
  PLOT RIGHT 180,
  CALL PENTA(D/X,LEV-1)
  PLOT LEFT 36;
  CALL PENTA(D/X,LEV-1)
  PLOT RIGHT 72;
  CALL PENTA(D/X,LEV-1)
END DEF

A Pitagorasz-fa néven ismert fraktál természetesen nem azért kapta a nevét, mintha Szamoszi Püthagorasz írta volna le. Nem kevés köze van viszont a fraktálnak a Pitagorasz-tételhez: négyzetekből épül fel, melyek derékszögű háromszögeket fognak közre. A kellő mélységig megrajzolt fraktál a brokkoli fejéhez hasonlít, ezért brokkoli-fraktálnak is nevezik.

OPTION ANGLE DEGREES
LET SQ2=SQR(2)
PLOT 580,20;ANGLE 90;
CALL BROCCOLI(225,15)
...
DEF BROCCOLI(X,Y)
  IF X<Y THEN EXIT DEF
  CALL SQUARE(X)
  PLOT FORWARD X,LEFT 45,
  CALL BROCCOLI(X/SQ2,Y)
  PLOT RIGHT 90,FORWARD X/SQ2,
  CALL BROCCOLI(X/SQ2,Y)
  PLOT BACK X/SQ2,LEFT 45,BACK X,
END DEF
DEF SQUARE(X)
  FOR I=1 TO 4
    PLOT FORWARD X;RIGHT 90;
  NEXT
END DEF

A Sierpinski-háromszög Waclaw Sierpinski lengyel matematikus által megtalált fraktál, amely úgy áll elő, hogy egy szabályos háromszögből elhagyjuk az oldalfelező pontok összekötésével nyert belső háromszöget, majd az így maradt három háromszögre rekurzívan alkalmazzuk ugyanezt az eljárást. Minden lépésben a keletkező kis háromszögek oldalhossza megfeleződik, és területük a negyedére csökken.

CALL SIERP(896,180,50)
...
DEF SIERP(W,X,Y)
  IF W>28 THEN
    CALL SIERP(W/2,X,Y)
    CALL SIERP(W/2,X+W/4,Y+W/2)
    CALL SIERP(W/2,X+W/2,Y)
  ELSE
    PLOT X,Y;X+W/2,Y+W;X+W,Y;X,Y
  END IF
END DEF

Még látványosabb a végeredmény, ha a megrajzolt háromszögeket ki is színezzük. Ebben az esetben a rajzoló utasítás így néz ki:

    PLOT X,Y;X+W/2,Y+W;X+W,Y;X,Y,X+4,Y+4,PAINT

A teljes program Turbo-Pascal-ban:

Program Haromsz2
{$A-}
{$I grafcs.tpu};
Procedure Sierp(w,x,y:integer);
begin
  if w>28 then begin
    Sierp(w div 2,x,y);
    Sierp(w div 2,x+w div 4,y-w div 2);
    Sierp(w div 2,x+w div 2,y)
  end
  else begin
    Plot(101,x,y);Beam(101,1);
    Plot(101,x+w div 2,y-w);
    Plot(101,x+w,y);Plot(101,x,y);
    MoveTo(101,x+4,y-4);Fill(101)
  end
end;
begin
  Graf_ON(101,1,0,40,27);
  Palette(101,32,142,0,0,0,0,0,0);
  Display(101,1,1,27);
  Sierp(896,180,950);
  while not KeyPressed do;
  Graf_OFF(101)
end.

A Spectrum BASIC-ben, a fenti algoritmust így lehet megvalósítani (a kifestést nem ismeri a Spectrum, azzal szintén trükközni kell):

1 REM *** Sierpinski ***
5 BORDER 6: PAPER 1: INK 5: CLS
10 DIM w(5): DIM x(5): DIM y(5)
20 LET s=1
50 LET w(s)=160
60 LET x(s)=48
70 LET y(s)=8
80 GO SUB 100
90 STOP
100 IF w(s)=10 THEN GO TO 250
110 LET w(s+1)=w(s)/2
120 LET x(s+1)=x(s)
130 LET y(s+1)=y(s)
140 LET s=s+1: GO SUB 100
150 LET w(s+1)=w(s)/2
160 LET x(s+1)=x(s)+w(s)/4
170 LET y(s+1)=y(s)+w(s)/2
180 LET s=s+1: GO SUB 100
190 LET w(s+1)=w(s)/2
200 LET x(s+1)=x(s)+w(s)/2
210 LET y(s+1)=y(s)
220 LET s=s+1: GO SUB 100
230 GO TO 290
250 PLOT x(s),y(s)
260 DRAW w(s)/2,w(s)
270 DRAW w(s)/2,-w(s)
280 DRAW -w(s),0
285 GO SUB 500
290 LET s=s-1
300 RETURN
500 REM * PAINT *
510 DIM a(w(s))
520 LET t=1
530 LET a(t)=w(s)-1
540 GO SUB 600
550 RETURN
600 IF a(t)<1 THEN GO TO 660
610 DRAW a(t)/2,a(t)
620 DRAW a(t)/2,-a(t)+1
630 DRAW -a(t),0
640 LET a(t+1)=a(t)-2
650 LET t=t+1: GO SUB 600
660 LET t=t-1
670 RETURN

További fraktál rajzoló rutinokat találunk a példaprogramok között!

7.6. A visszalépéses keresés tétele (backtrack)
Az utolsó feladattal a problémamegoldás egy igen széles területén alkalmazható algoritmust mutatunk be, amelynek lényege, a feladat megoldásának megközelítése rendszeres próbálkozásokkal. Sok esetben ennél jobb módszert nem is követhetünk.
Általános feladat: Adott N sorozat, amelyek rendre M(1),M(2),... elemszámúak. Ki kell választani mindegyikből egy-egy elemet úgy, hogy az egyes sorozatokból való választások más választásokat befolyásolnak (pl. nem lehet két sorozatból azonos sorszámú elemet választani). Tulajdonképpen ez egy bonyolult keresési feladat: egy adott tulajdonsággal rendelkező szám N-est kell keresni. A megoldást úgy készítjük el, hogy ne kelljen az összes lehetőséget végignézni!
Először megpróbálunk az első sorozatból választani egy elemet, ezután a következőből, s ezt mindaddig csináljuk, amíg a választás lehetséges. Amikor áttérünk a következő sorozatra, akkor jeleznünk kell, hogy ebből még nem próbáltunk elemet választani. X(I) jelöli az I. sorozat kiválasztott eleminek sorszámát, ha még nem választottunk, akkor értéke 0 lesz. Ha nincs jó választás, akkor visszalépünk az előző sorozathoz, s megpróbálunk abból egy másik elemet választani. Ez az egész eljárás vagy úgy ér véget, hogy minden sorozatból sikerült választani (ekkor megkaptuk a megoldást), vagy pedig úgy, hogy a visszalépések sokasága után már az első sorozatból sem lehet újabb elemet választani (ekkor a feladatnak nincs megoldása).
A megoldás - mint a korábbi tételeknél láttuk - egyszerűbbé válik, ha tudjuk, hogy van megfelelő tulajdonságú elemsorozat. Most azonban kövessük az általános eset megoldását!
Algoritmus:

I:=1
Ciklus amíg I>=1 és I<=N
  Ha VAN_JÓ_ESET(i) akkor
    I:=I+1 : X(I)=0
  különben
    I:=I-1
  Elágazás vége
Ciklus vége
VAN:=I>N

Az I. sorozatból úgy választunk elemet, hogy próbálunk mindaddig új elemet venni, amíg egyáltalában van további elem és az éppen vizsgáltat nem lehet választani. Ha a keresgélés közben a sorozat elemei nem fogytak el, akkor az előző szintnek válaszolhatjuk azt, hogy sikeres volt a választás. Ha pedig az utolsó sem felelt meg, akkor azt, hogy vissza kell lépni az előző sorozathoz.

A visszalépéses keresés klasszikus példafeladata a 8 vezér-probléma, amely tulajdonképpen egy sakkfeladvány. Általánosabb megfogalmazásban "n vezér problémáról" beszélhetünk, ami azt a kérdést veti fel, hányféleképpen lehet lerakni n darab királynőt egy n x n-es táblán. A megoldáshoz - a vezér lépési lehetőségeinek ismeretében - az szükséges, hogy egynél több bábu ne legyen azonos sorban, azonos oszlopban, illetve átlóban.
A megoldás nehezen számítható, mivel 8x8-as sakktáblán a bábuknak összesen 4426165368 különböző lerakása létezik, de ebből csak 92 felel meg a 8-vezér probléma feltételeinek. Ez igen nagy számítási időt jelent kimerítő keresést alkalmazva. Az összes lehetséges lerakások száma, és ezáltal a számításhoz szükséges idő csökkenthető azáltal, hogy bevezetünk egy olyan egyszerű és magától értetődő szabályt, miszerint minden sorban (vagy oszlopban) csak egy-egy bábu állhat. Így a vizsgálandó lerakások száma 8^8 = 16777216-ra redukálódik. Ez 16884-szer kevesebb, mint az első esetben, kimerítő keresést feltételezve. Ugyan még ebben az esetben is kimerítő keresést alkalmazunk, bizonyos lehetőségeket kihagyva, de n = 8 királynő esetén, egy 8 x 8-as sakktáblán már kezelhető lépésszámhoz jutunk. Ugyanakkor nagy "n" esetén, például n = 1000-re továbbra is megengedhetetlenül nagy a lépésszám. A "próbálgatáson" alapuló kimerítő keresésnél intelligensebb keresési algoritmusra van szükségünk a probléma hatékony megoldásához.

Wirth algoritmusa
Az algoritmus egy "trükkös" adatszerkezetet használ, amely 3 logikai (szám) típusú egy dimenziós tömbből áll. Ezek a tömbök tartják nyilván a sakktábla mezők státuszát a királynők szempontjából. A logika "igaz" tömbelem azt jelenti, hogy az adott sorban vagy átlóban nem található királynő (VAN_JÓ_ESET). A logikai "hamis" érték pedig azt jelenti, hogy az adott sorban vagy átlóban már van vezér. Az algoritmus futásának kezdetén minden tömbelem "igaz" logikai értékre van inicializálva (ezt végzi el az INIC eljárás). Az A() "sor" tömb elemei a sakktábla egy-egy sorának felelnek meg, a tömbelemek 1-től 8-ig számozódnak (8x8-as méretű sakktáblát feltételezve). Ha egy királynőt helyezünk az n-edik sorba, akkor ennek a tömbnek az n-edik eleme "hamis"-ra változik. A másik tömb a C() "oszlop-sor" tömb. Ennek az elemei -7-től 7-ig számozódnak és megfelelnek az egyes oszlop és sor indexek különbségének. Végül a harmadik tömb a B() "oszlop+sor" tömb. Ennek az elemei 2-től 16-ig számozódnak és megfelelnek az egyes oszlop és sor indexek összegének. A soron következő megoldást az X() tömbbe gyűjtjük ki, a kész megoldást a KI eljárás jeleníti meg.
N = tábla mérete, vezérek száma.

NUMERIC A(1 TO N),X(1 TO N)
NUMERIC B(2 TO 2*N),C(-N+1 TO N-1)
LET MEGOLDAS=0
CALL TOLT(A):CALL TOLT(B):CALL TOLT(C)
CALL PROBAL(1)
PRINT MEGOLDAS;"db megoldas"
END
...
DEF PROBAL(I)
  NUMERIC J
  FOR J=1 TO N
    IF A(J) AND B(I+J) AND C(I-J) THEN
      LET X(I)=J
      LET A(J),B(I+J),C(I-J)=0
      IF I<N THEN
        CALL PROBAL(I+1)
      ELSE
        CALL KI
      END IF
      LET A(J),B(I+J),C(I-J)=1
    END IF
  NEXT
END DEF

DEF KI
  LET S$=""
  LET MEGOLDAS=MEGOLDAS+1
  FOR K=1 TO N
    LET S$=S$&CHR$(64+K)&STR$(X(K))&" "
  NEXT
  PRINT S$
END DEF

DEF TOLT(REF T)
  FOR I=LBOUND(T) TO UBOUND(T)
    LET T(I)=1
  NEXT
END DEF

Ugyanez Turbo-Pascalban (max. 12-es táblaméretet feltételezve):

Program Vezerek;
{$A-}
var n,megoldas:integer;
    a:array[1..12] of boolean;
    b:array[2..24] of boolean;
    c:array[-11..11] of boolean;
    x:array[1..12] of integer;

Procedure Inic;
var i:integer;
begin
  for i:=1 to 12 do
    a[i]:=true;
  for i:=1 to 24 do
    b[i]:=true;
  for i:=-11 to 11 do
    c[i]:=true;
  megoldas:=0
end;

Procedure Ki;
var k,j:integer;
begin
  megoldas:=megoldas+1;
  for k:=1 to n do
    write(chr(64+k),x[k],' ');
  writeln
end;

Procedure Probal(i:integer);
var j:integer;
begin
  for j:=1 to n do begin
    if (a[j] and b[i+j] and c[i-j]) then begin
      x[i]:=j;
      a[j]:=false;b[i+j]:=false;c[i-j]:=false;
      if i<n then
        Probal(i+1)
      else
        Ki;
      a[j]:=true;b[i+j]:=true;c[i-j]:=true
    end
  end
end;

begin
  Inic;
  repeat
    write('Mekkora tabla? (2-12) ');readln(n);
  until ((n>1) and (n<13));
  probal(1);
  writeln(megoldas,' db megoldas')
end.

A BASIC változat 255 másodperc alatt adja meg a 8x8-as táblára a 92 megoldást, a Turbo Pascal változat 7 másodperc alatt.

A visszalépéses algoritmusra alapozva a keresési feladatokhoz hasonlóan el lehet készíteni eldöntési, kiválasztási, megszámolási, kiválogatási feladatok megoldását, sőt még a valamilyen szempontból legjobb megoldás megkeresését is.

8. Programozási nyelvek

A programozási nyelveket az alábbi szempontok szerint csoportosíthatjuk:

8.1. Emberközelség
Az EMBERKÖZELSÉG szerinti felosztásban annál magasabb szintűnek tekintünk egy programozási nyelvet, minél közelebb áll szintaxisa a beszélt emberi (angol) nyelvhez, jelölésrendszere pedig a szokásos szakmai (legtöbbször matematikai) jelölésekhez. E felosztás szerint beszélhetünk alacsony- és magasszintű nyelvekről. Az irodalomban elterjedt még a nagyon magas szintű elnevezés is, ez az elnevezés azonban nem illik bele ebbe a csoportosításba, mert ezek a nyelvek más szempont szerint tartoznak külön osztályba (számítási modell).

Az ALACSONYSZINTŰ nyelvek csak a számítógép 'huzalozott', 'beégetett' utasításait, a GÉPI KÓDOT ismerik. Kezdetben ezeket a kódokat is kettes számrendszerben kellett a programozónak bevinnie az adatokkal együtt. Gépi kód annyi van, ahány géptípus, pontosabban ma már processzorcsalád létezik. Igaz, hogy a mai vásárló nem üres, buta gépet kap, de azokat a programokat, melyektől a megvásárolt gép olyan okos lesz, gépi kódban írták meg. (Ez a megállapítás ugyan nem mindig igaz, de ennek részletei számítástechnikai szakemberekre tartoznak, mi ezzel nem foglalkozunk.) Ha eltekintünk a mai, modern fejlesztési eszközöktől, akkor minden új gépcsalád kifejlesztésekor a kezdet kezdetén legalább egy programot nullák és egyesek véges sorozataként kell(ett) megírni, amitől a gép már elfogadta a tízes (decimális), vagy a gyakoribb tizenhatos (hexadecimális) számrendszerben megírt utasításkódokat és adatokat. Ma egy gépi kódú program decimális, vagy hexadecimális számok véges sorozata. Ezt általában a gépbe beégetett monitorprogram teszi lehetővé, amely képes ilyen számoltat fogadni és azokat adott tárcímre elhelyezni, s az után az így beírt programot végrehajtani.
Az ASSEMBLY nyelveket az az igény teremtette meg, hogy az ember számára idegen számok, helyett a gépi utasításokat funkciójuk angol nevéből álló rövidítésekkel, úgynevezett mnemonikokkal, emlékeztetőkkel helyettesítsük. Ezzel párhuzamosan megteremtik annak lehetőségét, hogy tárcímek helyett szimbolikus neveket használjunk. Ezért megírták gépi kódban azt a programot (assemblert), amely az így megírt programot gépi kódra fordította. A mai assemblerek, a leírt ősnél lényegesen többet tudnak (címkék, direktívák, makrók kezelése; a forrásprogram listázása, javítása, mentese, fordítása, hibajegyzék készítése; a tárgyprogram futtatása, mentése stb.). Az assemblerek szolgál-tatásait figyelembe véve ma már sokkal gyorsabban, hatékonyabban programozhatunk. Ugyanakkor ezen a szinten még maximálisan kihasznál hatjuk a géptípus, a processzor sajátosságait. A magas szintű nyelvek fordító, értelmező programjait és az egyéb, úgynevezett rendszerprogramokat sokszor ezeken a nyelveken írják.
Akár gépi kódban, akár assembly nyelven programozunk is, a nyelv utasításainak ismerete mellett elengedhetetlenül szükséges az adott géptípus belső felépítésének, szerkezetének, már meglévő 'huzalozott', 'beégetett' képességeinek, társzerkezetének, rendszerváltozóinak, perifériaszervezésének stb. biztos tudása is.

A MAGASSZINTŰ nyelveket a számítástechnika térhódításával párhuzamosan fejlesztették ki az egyes szakirányú feladatok kényelmes megoldására. Míg az assembly nyelvű programot író szakembernek a nyelven kívül szinte mindent tudnia teli magáról a gépről is, addig a magasszintű nyelven programozónak csak a nyelvet kell ismernie, a gépről már alig kell tudni a valamit.
Az első magasszintű nyelvek közül a COBOL-t adat-feldolgozásra, a FORTRAN-t és az ALGOL-t tudományos számítási feladatok elvégzésére fejlesztették ki. Ma a különböző magasszintű nyelvek száma sok száz. Napjainkban terjedő nyelv a C, a Modula-2 és az Ada. A nagygépekhez kapcsolt felhasználói terminálok, illetve a személyi számítógépek megjelenésével jogos igénnyé vált a párbeszédes üzemmód, az interaktivitás. Széles körben ismert magasszintű nyelvek a BASIC különböző változatai, a Pascal, a LOGO, a FORTH stb. Enterprise-on az IS-BASIC mellett többek között a Turbo Pascal 1, 2, 3-as változatai, a HiSoft Pascal, IS-FORTH, fig-FORTH, IS-LISP, C-BASIC használható.

8.2. Felhasználói kör
A FELHASZNÁLÓI KÖR szerinti felosztáskor amatőr és professzionális nyelvekről beszélünk. Jellemzőik között általában nem húzható éles határvonal.

Az AMATŐR nyelvekre jellemző az interaktivitás, vagyis a párbeszédes üzemmód. Az egyes nyelvek fejlődése gyors, ezért nehezen szabványosíthatok vagy egyáltalán nem is szabványosították őket. Rengeteg egymással nem kompatibilis megvalósításuk, nyelvjárásuk van, melyek az egyes géptípusok speciális tulajdonságait is kihasználják. Mivel nem egy jól meghatározott feladatkőr megoldására, hanem általános célokra készültek, ezért nagyon sok bennük az egyszerű nyelvi elem, viszont többnyire nem tartalmaznak bonyolult struktúrákat kezelő utasí-tásokat. Ennek következménye, hogy az ilyen nyelveken megírt program is egyszerű szerkezetű, de terjedelmes. Ezek a nyelvek a számítástechnika nem hivatásos használói számára készültek.

A PROFESSZIONÁLIS nyelvel rendszerint moduláris szerkezetűek (azaz különállóan fordítható, un. modulokból építhetők benne a programok). Egy-egy fejlettebb változatuk mindig felülről kompatibilis az előzővel: annak szigorú bővítése, ezért a kész programok hordozhatósága biztosított. ÁItalában kevesebb nyelvi elemet tartalmaznak, de akad közöttük bonyolult struktúrákat kezelő is. Kialakításuknál az a cél, hogy minél jobban kezelhető eszközöket adjanak a programozó kezébe, amelyek segítségével bonyolult feladatok is megoldhatók. Mindig van fordítóprogramjuk. A fentiek következménye, hogy egy-egy program szerkezete bonyolult lehet. Ezek a nyelvek kifejezetten programozó szakemberek számára készültek, így ezekkel könyvünkben nem foglalkozunk.

8.3. Számítási modell
A SZÁMÍTÁSI MODELL szerinti felosztás abból indul ki, hogy a nyelv mögé milyen számítógépet képzelünk, milyennek képzeljük el a programot, a program végrehajtását.

A NEUMANN-ELVŰ nyelvek 'számítógépének' van tára és a program, illetve az adatok is abban helyezkednek el. Ezért a program végrehajtását tárállapotok sorozataként írhatjuk le. Az ilyen rendszerű nyelvekben van változó, értékadás, ciklus, elágazás. A be- és kiviteli műveletek tulajdonképpen tárban történő másolást jelentenek. Mivel a jelenlegi számítógépek Neumann-elvűek, ezért a legtöbb nyelv is ilyen szerkezetű, felépítésű.

Az AUTOMATA ELVŰ nyelvekben az adatok állapotok, illetve bemenetek, bemeneti jelek. A program elkülönül az állapotoktól, végrehajtása egyszerű állapotok sorozata. Jellemzőjük a tevékenységorientáltság. Az előzőek következményeként az ilyen nyelvekben változó, értékadás nincs, csak: primitív állapot- vagy paraméterfüggő ciklusok, elágazások vannak. Az utasítások paraméterezhetők, a beolvasás tulajdonképpen paraméterezés, a kiírás az állapotváltozás nyoma. Ilyen nyelvek pl. a LOGO grafikai része és az ipari robotok nyelvei.

A FUNKCIONÁLIS nyelvek szerint a számítógépnek nincs hagyományos értelemben vett tára. A program egy függvény, végrehajtása pedig a függvény kiértékelését jelenti. Az elképzelések következménye, hogy ezekben a nyelvekben változó, értékadás nincs. Ciklus helyett rekurzív függvények vannak, léteznek feltételes függvények az elágazások végrehajtására. Természetesen függvényargumentum is van! A beolvasás egy speciális függvény, a kiírás pedig a függvény eredménye, értéke. Biztosított új függvények (utasítások) létrehozása. Ilyen nyelvek pl. a LOGO szövegkezelő része és a FORTH (a program a különböző szótárakban, az adatok pedig a végrehajtási és a vezérlési veremben vannak).

A LOGIKAI nyelvek szerint a program egy logikai formula, melynek végrehajtása annak kiértékelését jelenti. A formulában szerepelhetnek paraméterek. A program és az adatok nem különülnek el, hiszen minden adat egy-egy azonosan igaz logikai formula. Jellemzőjük az erős matematikai kidolgozottság. A fentiekből következik, hogy ezekben a nyelvekben sincs változó és értékadás. Ciklus helyett rekurzív formulák vannak, s léteznek feltételes formulák is. Elemi utasítás a mintaillesztés, ilyenek a be- és kiviteli műveletek is. A programozó létrehozhat új formulákat (utasításokat). Ilyen nyelv például a magyar szakemberek: által kifejlesztett MPROLOG.

8.4. Néhány nyelv rövid jellemzése
Ebben a fejezetben röviden véleményt mondunk néhány, az iskolában számításba jövő nyelvről. Ez a pillanatnyi saját véleményünk, ami természetesen változhat. Az mindenesetre látható belőle, hogy nem egyetlen nyelvet képzelünk el, és egyetlen nyelvet sem zárunk ki.

8.5. A programozási nyelvek rövid története
A programozási nyelvek kialakulásuk óta jelentős átalakuláson mentek keresztül. Ahogyan beszélhetünk számítógépek generációiról, úgy beszélhetünk a programozási nyelvek generációiról is. Ezt a fejlődést a Neumann-elvű nyelveken követjük végig.

9. A program helyessége

A kész algoritmus, a megírt program tesztelésekor csak annyit mondhatunk ki, hogy az hibás, vagy hogy hiba a tesztelés során nem került elő. Ez utóbbi még nem jelenti azt, hogy a program feltétlenül jó, hibamentes. Egy program jóságáról megnyugtatóan csak programhelyesség-bizonyítással győződhetünk meg. A bizonyítás szigorú matematikai, logikai bizonyítást jelent.
A bizonyítás során az algoritmust bemeneti (elő) és kimeneti (utó-) feltételekkel egészítjük ki, vagyis megfogalmazzuk a bemeneti adatokkal (kezdeti állapottal) és az eredményekkel (végállapottal) kapcsolatos elvárásainkat, feltételeinket. Ezt követően a program különböző részeinél oda illő elemi állításokat helyezünk el, majd ezen elemi állításokból, logikai műveletekkel és a programváltozók különböző értékeivel összetett logikai állításokat, következtetéseket mondunk ki a következő elemi állításra; melyeknek igazaknak kell lenniük, ha a két elemi állítás közötti programrész helyesen működik. Így lépésről lépésre bizonyíthatjuk a program (algoritmus) helyességét annak minden egyes szintjén.
Az egyes programrészek működésére már kimondott axiómák, bizonyított szabályok léteznek. Ilyenek az értékadás és az üres utasítás axiómái, vagy a szekvencia, az elágazás, a ciklus, a következmény, a befejeződő ciklus következtetési szabályai.
A feladat meglehetősen bonyolult, ezért szokás a program (algoritmus) helyességének bizonyítását részfeladatokra bontani, annak befejeződését, részleges (parciális) és teljes helyességét külön lépésben bizonyítani. A program befejeződése azt jelenti, hogy annak végrehajtása minden érvényes és érvénytelen adatra befejeződik valamilyen módon. A parciális helyesség fogalma azt jelenti, hogy minden olyan bemeneti adatra, amelyre a program megáll, az eredmény is helyes lesz. Vigyázat! Itt szó sincs arról, hogy minden érvényes bemeneti adatra megállna a program! A teljes helyesség már nyilvánvaló: a program minden érvényes bemeneti adatra megáll és az eredmény is helyes lesz.
Mivel ez az eljárás nehéz, nagy programokra nem végezhető el, más megoldást kelé keresni. Ez lesz a tesztelés. A tesztelés nem fogja garantálni a program hibamentességét, csupán valószínűsíti azt.
Egy programot csak akkor fogadhatunk el jónak, ha meggyőződtünk helyességéről. Ebben a fejezetben azzal foglalkozunk, hogy ezt hogyan valószínűsíthetjük. Először meg kell vizsgálnunk, hogy a program azt teszi-e, amit várunk tőle: ezt nevezzük TESZTELÉSnek. Ha a tesztelés eredményeként azt kapjuk, hogy a program hibásan működik, akkor meg kell keresnünk a hibát: ez a HIBAKERESÉS. Végül, ha megtaláltuk a hibát, akkor azt ki kell javítani: ez a HIBAJAVÍTÁS. A hiba kijavítása után ez a folyamat újra kezdődik, hiszen meg kell győződnünk róla, hogy a javítás sikeres volt, illetve arról is, hagy nem keletkezett miatta más hiba.

9.1. Tesztelési módszerek
A programok tesztelésinek két, logikailag eltérő módszere van. Az egyikben a program szövegét vizsgáljuk, ezt nevezzük STATIKUS tesztelésnek. A másikban a program végrehajtását vizsgáljuk: ez a DINAMIKUS tesztelés. Egy program ellenőrzését célszerű mindig statikus teszteléssel kezdeni, mert a tapasztalat azt mutatja, hogy a hibák jelentős része már így kiszűrhető, s ehhez nincs szükség a program sok időbe kerülő futtatásához.

9.1.1. Statikus tesztelés
A KÓDELLENŐRZÉS során a program szöveget hasonlítjuk össze az algoritmussal. Célszerű lehet, ha ezt a munkát nem a program írója végzi, hiszen még a közmondás is azt mondja: más szemében á szálkát...
A FORMAI ELLENŐRZÉSt legtöbbször a fordító- vagy értelmező programra bízhatjuk, csupán a BASIC egyes gépi megvalósításai olyanok, hogy a formai hibák is csak futáskor derülnek ki. Jól használhatok a fordítóprogramok által gyakran adott egyéb információk is. Például kigyűjthetik a programban használt változókat, megmondhatják, hogy melyiket hol használtuk, értékét hol változtatjuk meg stb.
A TARTALMI ELLENŐRZÉS, ellentmondás-keresés sokkal nehezebb feladat. Ilyen tartalmi hiba, ha egy változónak nem adunk értéket és mégis használjuk, vagy ha értéket adunk neki, de ezt semmire sem használjuk. Ebbe a csoportba tartoznak a vezérléssel kapcsolatos hibák: a végtelen ciklus, illetve amikor egy utasítást sohasem hajthatunk végre. Az ilyen hibák sokszor nyilvánvalóan látszanak, máskor nagyon nehéz észrevenni őket.

9.1.2. Dinamikus tesztelés
Lényegük, hogy a programot különböző tesztadatokkal ki-próbáljuk, majd az eredményekből következtetünk a program helyességére. Elvileg elérhető lenne, hogy így garantáltan meggyőződjünk a program helyességéről. Erre két út is kínálkozik. Az egyik szerint hajtsuk végre a programot az összes lehetséges bemenő adattal, majd vizsgáljuk az eredményt! A másik azt mondja, hogy a programot hajtsuk végre utasításai összes lehetséges sorrendjében! Gyakorlatilag sajnos mindkét ötlet kivitelezhetetlen. Ha csak egy egész számot olvas be a program, akkor is annyiszor kellene kipróbálni az első elv szerint, ahány egész szám lehetséges. Már ez nagyon sok. Ha két egész szám van, akkor már az előző szám négyzete a kipróbálások száma. A második elv szerint, ha a programban egy ciklus található, akkor ki kell próbálni úgy, hogy a ciklusmag egyszer sem fut, egyszer fut, kétszer fut... Ez szintén járhatatlan út. Mégis e két elv határozza meg a dinamikus tesztelés két fő osztályát: a FEKETE és a FEHÉR DOBOZ módszereket.

Fekete doboz módszerek
Ebben az esetben a program adatait vizsgáljuk, s ez alapján próbálunk tesztadatokat készíteni, s magát a programot, mintegy fekete doboznak tekintjük. Éppen ezért nevezik adatvezérelt tesztelésnek is. Itt tulajdonképpen arról van szó, ha a program két bemenő adatra egyformán működik, akkor elég az egyikkel kipróbálni. Ez alapján a bemenő adatok csoportosíthatók, osztályokba sorolhatók. A tesztelés lényege ezen osztályok meghatározása.
Az EKVIVALENCIA-OSZTÁLYOK KERESÉSE erre épít. A bemenő adatokat soroljuk osztályokba a következő elv szerint: Ha az osztály egyetlen tagjával kipróbálva a programot, jó eredményt kapunk, akkor várhatóan a többi elemre is jó eredményt kapunk! Ha a program az osztály egy tagjára hibásan működik, akkor a többire is működjön hibásan! Ezeket az osztályokat a feladat elemzése alapján állapíthatjuk meg. Az érvényes bemenő adatokra is kell létrehozni osztályokat és az érvénytelenekre is! Például, ha a feladatunk egy maximum 40 karakteres szöveg magánhangzóinak megszámolása, akkor a következő ekvivalencia-osztályokat vehetjük fel:

Ha választottunk ekvivalencia-osztályokat, akkor el kell döntenünk, hogy mikor melyikből választunk kipróbálandó adatot. Ezt megtehetnénk úgy is, hogy olyan bemenő adatokat választunk, amelyek egyszerre pontosan egy ekvivalencia-osztályba tartoznak, ennél azonban van jobb stratégia is. Az előbbi feladatra gondolva, azt a programot várhatóan felesleges úgy kipróbálni, hogy egyszer csak A betű van a szövegben, egyszer csak á, ... Először válasszunk olyan bemenő adatot, amely minél több érvényes ekvivalencia-osztályt fed le! Ha az érvényes osztályokkal végeztünk, akkor vehetjük egyenként az érvényteleneket. Ezeket mindenképpen külön kell vizsgálnunk, hiszen egy hibás adat miatt elképzelhető, hogy a következőt nem vizsgáljuk meg.
Ha az osztályok sorrendjét eldöntöttük, akkor az marad hátra, hogy hogyan válasszunk belőlük adatokat. Lehet tetszőlegeset választani vagy van valami értelmes stratégia? Erre ad választ a HATÁRESET-ELEMZÉS módszere. E módszer szerint az egyes osztályokból határon levő elemeket válasszunk! Az előbbi példára gondolva, vizsgáljunk 41 betűs szöveget, 40 betűset, 1 betűset, ... !

Fehér doboz módszerek
Most elsődlegesnek a program szerkezetét, logikáját tekintjük, ezért szokás ezt a módszert logikavezérelt tesztelésnek is nevezni. Itt az utasítások összes lehetséges végrehajtási sorrendjénél szeretnénk valami okosabbat kitalálni.

9.2. Hibakeresés
Hibakeresésről akkor beszélünk, ha már tudjuk, hogy van hiba a programban, csak még nem tudjuk, hogy hol. A hibakeresés célja a hiba helyének meghatározása. A hiba okozóját különböző módszerekkel kereshetjük.

9.2.1. Hibakeresési módszerek
Az INDUKCIÓS módszer szerint próbáljuk rendszerezni a rendelkezésünkre álló tesztadatokat! Ebből próbáljunk valamilyen feltételezést tenni a hiba okára vonatkozóan! Ha ezt a feltevést igazolni tudjuk, akkor a hibát megtaláltuk, következhet a kijavítása, ha nem, akkor új feltevéssel kell próbálkozni.
Például, ha egy program jól működik a 4, 8, 20 bemenő adatokra és hibásan a -1, -7-re, akkor tételezzük fel először, hogy a pozitívara jól működik, a negatívokra pedig nem. Ha ezt sikerül igazolni, akkor készen vagyunk, ha nem, akkor vizsgáljuk meg azt a feltevést, hegy a pirosakra műkö-dik jól és a páratlanokra hibásan! Ha ez sem sikerül, akkor még mindig feltehetjük, hogy az abszolút értekben prímszámokra működik hibásan. A példából egy fontos dolog kiderült: a hipotézisek felállításához nincs szükség a program ismeretire, az csak a hipotézis igazolásához kell.
A DEDUKCIÓS módszer lényege a hiba lehetséges okai körének szűkítése. Először minden lehetséges okot feltételezünk, majd ezek közül ki kell küszöbölni azokat, amelyek nem okozhatnak hibát.
Vizsgáljuk meg így az előző példát! Első feltevésünk az, hogy negatív, vagy páratlan, vagy prím abszolút értékű, vagy 2-vel nem osztható, vagy ... adatokra a program hibásan működik. Várhatóan ennyi hiba nincs a programban, ezért ezt a kört szűkíteni kell mindaddig, amíg meg nem találjuk a hibát.
A VISSZALÉPÉSES módszer a hiba előfordulásának helyétől (kiírás vagy futási hibaüzenet) indul ki, s követi visszafelé a program végrehajtását mindaddig, amíg az adatok hibásak. Amint egy olyan ponthoz érünk, amikor még nincs hiba, akkor megtaláltuk a hiba helyét.
Mindhárom módszert segíthetjük TESZTELÉSSEL, csak ilyenkor a tesztelés célja nem új hiba felfedése, hanem egy meglevő lokalizálása. Így tehát olyan adatokkal kell kipróbálni a programot, amelyek közelebb visznek a hiba felfedéséhez.

9.2.2. Hibakeresési eszközök
A hibák megkereséséhez a legtöbb számítógép, a legtöbb programozási nyelv biztosit valamilyen segédeszközt. Ha egy eszköz az adott esetben nem elérhető, általában akkor is van mód elkészítésükre. Ezek között találhatunk egyszerű eszközöket és bonyolultakat is.
A lehető legegyszerűbb eszköz a KIÍRÁS. A program alkalmas pontjain elhelyezett kiíró utasításokkal sok hasznos információt nyerhetünk programunkról. Arra kell csupán vigyázni, hogy ha kiírást ciklus belsejébe teszünk, akkor annyi adatot kaphatunk, amelyet képtelenség feldolgozni, ráadásul felesleges is.

Bármelyik hibakeresési eszközt is használjuk, ha a program szövegébe valamilyen utasítást beépítettünk, akkor azt a hiba kijavítása után el is kell onnan távolítani, Igen ám, de ha újabb hibát találunk, akkor valószínűleg újra be kell írni őket. Ezért az a jó rendszer, ahol ezeket nem kell kitörölni, hanem a fordítás/végrehajtás előtt megmondhatjuk, hogy kellenek-e vagy sem. Ha erre nincs lehetőségünk, akkor is célszerűbb ilyenkor megjegyzés sorokba tenni őket, mint kitörölni.
Lezárásként egy megjegyzést kell fűznünk a hibakeresési eszközök használatához. Ezeket csak végső eszközként használjuk, ha a hibakeresési módszerekkel nem jutottunk eredményre! Használatukkal ugyanis általában sokkal tovább tart a hibakeresés, mint a megfelelő módszerek alkalmazásával.

9.3. Programozási típushibák
Programkészítés során sokféle hibát elkövethetünk. Az elkövetett hibák megkeresése a hibakeresésnek hívott tevékenység feladata. Egy korábbi fejezetben már foglalkoztunk hibakeresési módszerekkel, most ugyanezt egy más nézőpontból vizsgáljuk. Abból indulunk ki, hogy ha egy programban hibát kell keresni, akkor először keressünk olyan hibákat, amelyeket a korábbi gyakorlatunk során szoktunk elkövetni. Ez azért jó módszer, mert általában a hibák sem tetszőleges fajtájúak (kivéve a gépelési hibákat), hanem jól meghatározott csoportokra oszthatók. Ebben a fejezetben a tipikus programozási hibákat soroljuk fel. Ezen hibák egy része nem minden programozási nyelv, illetve nyelvjárás esetén tényleges hiba, de elkerülésük még ott is hasznos lehet, ahol nem okoznak hibát.

9.4. Példák a program ellenőrzésére

Fehér doboz módszerek
A statikus módszerekre - úgy érezzük - nem kell példákat mondanunk, nézzük először a tesztelés fehér doboz módszereit! A programozási tételeknél megismert általános algoritmusokat vizsgálunk.

Példa:
Nézzünk először egy maximumkiválasztásos feladatot: olvassunk be N számot, majd adjunk meg a legnagyobb sorszámát (ha több egyforma is van, akkor az egyiket)!

Program:
  Be: N [N>0]
  Be: A() [a teljes tömb beolvasása]
  INDEX:=1
  Ciklus I=2-től N-ig
    Ha A(I)>A(INDEX) akkor INDEX:=I
  Ciklus vége
  Ki: INDEX
Program vége.

Az utasítások egyszeri lefedésinek elve alapján olyan tesztadat kell, amellyel a program minden utasítását legalább egyszer végrehajtjuk. Ilyen bemenő adat:

N   = 2 (a ciklus miatt kell a két elem)
A() = 1, 2 (az elágazás miatt A(1)>A(2) kell)

A döntéslefedés elve azt mondta ki, hogy a programban szereplő összes feltétel lehessen igaz és hamis érték is. Itt szintén elég egyetlen próba:

N   = 3  
A() = 1, 2, 1 (az elágazás feltétele igaz is lesz, hamis is lesz)

Milyen hibákat fedezhetünk fel így a programban? Nézzük külön a két módszert! Mindegyiknél megadjuk előbb a vizsgált utasítást (helyesen), majd azt a hibás formát, amelyet a próba kimutat.

1. helyes: hibás:
  Be: N Be: M
  INDEX:=1 INDEX:=2
  INDEX:=I INDEX:=1
  Ki: INDEX Ki: I

2. További eset:

A(I)>A(INDEX) vizsgálat felfedezhető

Példa:
Rendelkezésünkre áll egy N és egy M elemű halmaz az A() és a B() vektorban ábrázolva. Készítsük el a két halmaz metszetét a C() vektorba!

Program:
  Be: N,M [N,M>=0]
  Ha N<M akkor L:=N különben L:=M
  Tömb A(N),B(M),C(L)
  Be A(),B() [a két tömb beolvasása]
  CN:=0
  Ciklus I=1-től N-ig
    J:=1
    Ciklus amíg J<=M és A(I)<>B(J)
      J:=J+1
    Ciklus vége
    Ha J<=M akkor CN:=CN+1: C(CN):=A(I)
  Ciklus vége
  Ki: CN
  Ciklus I=1-től CN-ig
    Ki: C(I)
  Ciklus vége
Program vége.

Az utasításlefedés alapján a következőket kell meggondolni: a külső ciklusba belépéshez N>=1 kell. A belső ciklusba beléphetünk, ha M>=1 és A(1)<>/B(1). A belső ciklus utáni elágazásba akkor lephetünk be, ha J<=M maradt, azaz M>=2 és például B(2)=A(1). A legelső elágazás mindkét ágát egyetlen tesztadattal nem járhatjuk be. Így kell egy N<M eset és egy N>=M eset. Tehát a tesztadatok:

N   = 1
M   = 2
A() = 5
B() = 4, 5

illetve

N   = 1
M   = 1
A() = 5
B() = 5

A döntéslefedés alapján ezt egy helyen kell módosítani: a belső ciklus utáni feltétel lehessen hamis is, azaz legyen olyna A()-beli elem, amely nem szerepel B()-ben! Így például változtassuk meg a második tesztadatsort!

N   = 2
M   = 1
A() = 4, 5
B() = 5

Ezekkel a kővetkező hibákat fedezhetjük fel:

1. helyes: hibás:
  C(CN):=A(I) C(CN):=A(J)
  J<=M J<=N
  J<=M J<M

Továbbá: CN:=CN+1 hiánya

1. helyes: hibás:
  CN-ig N-ig

Továbbá: J<=M feltétel hiánya mindkét helyen

Érdemes elgondolkodni azon is, hogy vajon milyen hibákat nem lehet kimutatni ezekkel a tesztadatokkal. Sőt van olyan hiba is (N<M helyett N>M vizsgálata), amelyet semmilyen tesztadattal sem lehet kimutatni.

Fekete doboz módszerek
A fekete doboz módszerek alkalmazásánál ugyanazokat a példákat nézzük meg, mint a fehér doboz módszereknél.

Példa:
Olvassunk be N számot, majd adjunk meg a legnagyobb sorszámát (ha több egyforma is van, akkor az egyiket)!

Az ekvivalenciaosztályok módszerével olyan tesztadatokat kell választani, hogy az egy osztályba kerülőkre várhatóan egyformán működjön a program! Választani kell érvényes és érvénytelen ekvivalenciaosztályokat is! Ezek a következők lesznek:

N=0
N=1
N>1 és az első elem a maximális
N>1 és az utolsó elem a maximális
N>2 és egy középső elem a maximális
N>1 és minden elem egyenlő

A határesetvizsgálat módszerét is figyelembe véve, ezek alapján a következő tesztadatokat választhatjuk:

N=0
N=1, A()=5
N=2, A()=3,2
N=2, A()=2,3
N=3, A()=2,3,2
N=2, A()=3,3

Így a fehér doboz módszerekhez képest még néhány hibát felfedezhetünk (itt is azt adjuk meg, hogy mit rontunk el mire):

  helyes: hibás:
  A(I)>A(INDEX) A(I)=A(INDEX)
  N-ig N-1-ig
  INDEX:=I INDEX:=A(I)
  INDEX:=I elmaradása

Példa:
Rendelkezésünkre áll egy N és egy M elemű halmaz az A() és a B() vektorban ábrázolva. Készítsük el a két halmaz metszetét a C() vektorba!

Itt egy kicsit bonyolultabb a helyzet. Vegyük fel a következő ekvivalenciaosztályokat:

N<0
M<0
N>=0 és M>=0
és a metszet üres
N>=0 és M>=0 és minden A()-beli a metszetben van
N>=0 és M>=0 és nem minden A()-beli van a metszetben
N>=0 és M>=0 és minden B()-beli a metszetben van
N>=0 és M>=0 és nem minden B()-belí van a metszetben

Újra a határesetvizsgálat figyelembevételével kapjuk a választott tesztadatokat:

  1. N=-1
  2. M=-1
  3. N=0, M=1, B()=5
  4. N=1, M=0, A()=5
  5. N=1, M=1, A()=2, B()=3
  6. N=1, M=1, A()=2, B()=2
  7. N=2, M=3, A()=2,3, B()=3,1,4

Ezekkel a tesztadatokkal további hibákat találhatunk meg a programban:

  helyes: hibás:
  A(I)<>B(J) A(I)<B(J)
  A(I)<>B(J) A(J)<>B(I)
  J<=M J<=N
  J:=1 J:=I
  C(CN):=A(I) C(N):=A(I)
  CN-ig N-ig, M-ig
  0-szor lefutó ciklus hiánya

Hibakeresés
Most sorra vesszük a hibakeresési módszereket. Mindegyikhez ugyanazt a programot használjuk, amelyet ugyanúgy rontunk el. Ez az előbbi metszetszámító program lesz.

Hibás algoritmus:

Program:
  Be: N,M [N,M>=0]
  Ha N<M akkor L:=N különben L:=M
  Be A(),B() [a két tömb beolvasása]
  CN:=0
  Ciklus I=1-től N-ig
    J:=1
    Ciklus amíg J<=M és A(I)>B(J)  [itt a hiba]
      J:=J+1
    Ciklus vége
    Ha J<=M akkor CN:=CN+1: C(CN):=A(I)
  Ciklus vége
  Ki: CN
  Ciklus I=1-től CN-ig
    Ki: C(I)
  Ciklus vége
Program vége.

Próbáljuk ki az így elrontott algoritmusból készített programot az ekvivalenciaosztályok módszerével megadott tesztadatokra! A (7), illetve az (5) kivételével a többi esetben helyes eredményt kapunk. A (7) esetben a metszetbe kerül a 2 és a 3, illetve az (5) esetén a 2. Nézzük az egyes hibakeresési módszereket!

Indukciós módszer
Próbáljuk szélesíteni a hibás adatok körét! Hipotézis:

Ha a program szövegét megnézzük, az A() alapján előbb eldöntjük, hogy fel kell-e venni egy elemet, mintsem a következő A()-belit vizsgálnánk, s A()-ban soha nem lépünk vissza. Így ezt a feltevést el kell vetnünk. Próbálkozzunk mással:

Ha most ilyen tesztadatokat készítünk, akkor azt tapasztaljuk , hogy feltevésünk jogos volt. Próbáljuk tovább szélesíteni a hibát okozó adatok körét:

Futtatással vagy az algoritmus elemzésével meggyőződhetünk arról, hogy ez is igaz. Próbáljuk még szélesíteni a hibát okozó adatok körét:

Ezt azonban könnyen cáfolhatjuk, ugyanis egy közbülső feltevés igazolásakor beláthattuk, hogy nem igaz. A hibát okozd adatok körét nem tudjuk tovább bővíteni, így arra a megálla-pításra kell jutnunk, hogy rossz vizsgálat alapján döntjük el, hogy bekerüljön-e A()-beli a metszetbe. Nem azt nézzük, hogy van-e vele egyenlő B()-beli, hanem azt, hogy van-e nála nagyobb vagy vele egyenlő. És ezzel meg is találtuk a hibás A(I)>B(J) ciklusfeltételt.

Dedukciós módszer
Itt először mindenféle hibát feltételezünk, majd megpróbáljuk szűkíteni a hibát okozó adatok körét. Induló hipotézisünk az, hogy A() összes eleme belekerül a metszetbe. Ezt próbáljuk alesetekre bontani!

Nézzük az egyes hipotéziseket! Most egy hipotézist akkor vetünk el, ha van olyan elem, amelyre a feltevésünk nem igaz és a program mégis rosszul működik.
Az első hipotézis akkor hamis, ha lehet A()-ból olyan M-nél nagyobb sorszámú elemet választani, amelyre a program hibásan működik. A teszteseteink között ilyen lehetőség nem fordult elő, ezért például új tesztelést kell végeznünk:

N=2, M=1, A()=2,1, B()=3 (az 5. tesztesetet bővítjük)

Most a program az A(2)=1-et is felveszi a metszetbe, tehát az első hipotézis hamis.
A második akkor hibás, ha van olyan A()-beli, amelynél nincs kisebb metszetbeli, s mégis felvesszük. Ilyen volt az 5. teszteset.
A harmadikkal akkor van baj, ha A() és B() elemeinek maximumát is felvennénk, amikor nem kellene. Az (5. teszteset, illetve abban A() és B() szerepének felcserélésével meggyőződhetünk arról, hogy ezt az elemet nem vesszük fel, azaz a hipotézisünk helyes.
Próbáljuk szűkíteni a hibás adatok halmazát! Új hipotéziseink:

Az első hipotézist az 5. teszteset alapján elvethetjük, hiszen ott az egyetlen A()-belinél nem volt A()-ban nagyobb, s a program mégis rosszul működött. Ugyanezért a harmadik sem igaz.
A másodikra nem tudunk ellenpéldát találni, további szűkíteni sem tudjuk tovább a hibás adatok körét. Tehát ha egy tetszőleges B()-belinél kisebb vagy egyenlő elemet találunk A()-ban, akkor azt felvesszük - hibásan - a metszetbe. Azaz egy összehasonlítás feltételét rontottuk el.

Visszalépéses hibakeresés
Ebben az esetben a hiba helyétől indulunk ki, s a programban visszafelé lépünk mindaddig, amíg nem találjuk meg a hiba okozóját. Most az 5. tesztesetből indulunk ki.

Hibakiírás használata
A hibakeresési eszközök használatával is lehet hibát felfedezni a programban. Helyezzünk el kiírást a megfelelő helyen! A hiba a CN kiírásánál tűnt fel, tehát valahol előbb kellene elhelyezni újabb kiírást.

Hibakiírás: I,CN,C(CN)

Ekkor a következő kiírást kapjuk az utolsó teszteset hatására:

I, CN, C(CN) = 1, 1, 2
I, CN, C(CN) = 2, 2, 3

Ebből azt vehetjük észre, hogy az A() vektor első elemét megvizsgálása után felvesszük, pedig nem kellene.

J, M = 1, 3
I, CN, C(CN) = 1, 1, 2
J, M = 1, 3
I, CN, C(CN) = 2, 2, 3

Tehát B() első elemének vizsgálata után úgy döntünk, hogy az A()-beli elem szerepel B()-ben. Mivel A(1)<>A(2), ezért ez biztosan nem lehetséges. J=1-ből következik, hogy nem a J<=M hamissága miatt léptünk ki a ciklusból, tehát a másik feltételnek kell hibásnak lennie.

10. Hatékonyságvizsgálat

A hatékonysággal kapcsolatos kérdésekkel szemben az első érv az szokott lenni, hogy ez a professzionális programozásban érdekes dolog, de nekünk lényegében semmi dolgunk vele. Ez nem így van. A programozási tételek, algoritmustípusok alkalmazása ugyanis csak a feladatok megoldhatóságára adnak receptet, de ettől még nagyon rossz megoldást eredményezhetnek. Nézzük meg azt a programot, amely az összegzést alkalmazza az első N szám összegének kiszámítására!

PRINT OSSZEG(N)
...
DEF OSSZEG(X)
  LET S=0
  FOR I=1 TO X
    LET S=S+I
  NEXT
  LET OSSZEG=S
END DEF

Ezt a feladatot sokkal egyszerűbben is meg lehet oldani, némi matematikai ismeret birtokában:

PRINT OSSZEG(N)
...
DEF OSSZEG(X)=X*(X+1)/2

Ez a példa nem egyedi eset, sok hasonló található még. Miattuk van szükség elsősorban a hatékonyság vizsgálatára. Másrészt természetesen könnyű olyan programot írni, ahol egyébként is gondot okozhat a kevésbé hatékony megoldás. Hatékonyabbra íráshoz legtöbbször valamilyen trükköket szoktak emlegetni, holott ez egyáltalán nincs így. Léteznek módszerek, amelyek alkalmazásával a programot hatékonyabbra írhatjuk.
Mielőtt belekezdenénk a módszerek tárgyalásába, meg kellene állapítanunk, hogy micsoda valójában a hatékonyság, mit mérünk, amikor hatékonyságot mérünk. Három dolog jön számításba: a VÉGREHAJTÁSI IDŐ, a HELYFOGLALÁS (programszöveg és adatok), valamint a BONYOLULTSÁG (elkészítési / megértési idő, szükséges tudás).
Más osztályozásra jutunk, ha a vizsgálandóból indulunk ki. GLOBÁLIS hatékonyságról beszélünk, ha az algoritmusleíró nyelven írt algoritmust vizsgáljuk (esetleg kódolási szempontokat is figyelembe véve), LOKÁLIS hatékonyságról pedig akkor, ha a program szövegét. Az elsőhöz, érteni kell a program működését, a másodiknál az adott részlet szerkezetét kell csak ismerni, de a program globális működését nem. Mi először a globális hatékonysággal foglalkozunk.

10.1. A végrehajtási idő csökkentése
A program végrehajtási idejét elsősorban a ciklusok befolyásolják. Ha egy utasítást ugyanis cikluson kívül hajtunk végre, az a végrehajtási idő nagyon-nagyon kis százalékát jelenti csupán. Nyilvánvaló tehát, hogy a ciklusokkal kell valamit tennünk. A végrehajtási idő csökkentésére szolgáló módszerek egy része a ciklusok végrehajtási számát próbálja csökkenteni, más része pedig a ciklusmag egy végrehajtásának idejét.

10.1.1. Ciklusok végrehajtási számának csökkentése
Ha lényegesen csökkenteni tudjuk egy ciklusmag végrehajtási számát, az a program végrehajtásiban jelentős előnyöket hozhat. Erre különböző módszereket találhatunk.
A legjelentősebb módszerek közé tartozik az ADATOK SPECIÁLIS TULAJDONSÁGÁNAK KIHASZNÁLÁSA. Ha ugyanis rendelkezünk valamilyen tudással a feldolgozandó adatokról, akkor ha ez kihasználható a program elkészítésében, nagy futási idő nyereséget érhetünk el.
Mi lehet ez a speciális tulajdonság? Például lehet a rendelkezésre álló adatok rendezettsége. A programozási tételek között két ilyen tulajdonságú feladat is szerepelt. Az egyikben egy rendezett sorozatban egy adott értéket kellett keresni, ez volt a logaritmikus keresés. A másikban két rendezett sorozat unióját kellett megadni, ez volt az összefuttatás. Mindkét algoritmussal jóval kevesebb lépéssel lehetett megoldani az adott feladatot, mint a rendezettség figyelembevétele nélküli keresési, illetve unió tétellel.
A második módszer a MATEMATIKAI ISMERETEK KIHASZNÁLÁSÁra épül. Nagyon sokszor előfordul az, hogy egy valamilyen szempontból vizsgálandó sorozat helyett elég a sorozat valamely részsorozatait vizsgálni az adott feladat szempontjából. Például ez a helyzet, ha egy számról el kell dönteni, hogy prímszám-e. A megoldás alapváltozata azt mondja, hogy N akkor prímszám, ha 2 és N-1 között nincs osztója. A matematikai ismeretek felhasználásival viszont azt állíthatjuk, hogy egy szám akkor prím, ha 2 és saját négyzetgyöke között nincs osztója.

IF PRIM(N) THEN PRINT N;"prím szám!'
...
DEF PRIM(N)
  IF N<=1 OR INT(N)<>N THEN
    LET PRIM=0
  ELSE IF N=2 THEN
    LET PRIM=-1
  ELSE
    LET PRIM=-1
    FOR I=2 TO CEIL(SQR(N))
      IF MOD(N,I)=0 THEN
        LET PRIM=0
        EXIT FOR
      END IF
    NEXT
  END IF
END DEF

Ugyanez Turbo-Pascalban:

var i,m:integer;

Function Prim(n:integer):boolean;
var i:integer;
begin;
  if n<=1 then Prim:=false
  else if n=2 then
    Prim:=true
  else begin
    Prim:=true;
    for i:=2 to round(Sqrt(n)) do
    begin
      if n mod i=0 then begin
        Prim:=false;
        exit
      end
    end
  end
end;

begin
  ...
  if Prim(i) then Write(i,' prim szam!');
  ...
end.

Ezzel az algoritmussal szemléletesen összemérhetjük az interpreteres BASIC és a lefordított Pascal program sebességét, ha 1000-ig megvizsgáljuk a számokat (6Mhz-n mérve):

 
BASIC
PASCAL
6 MHz (memóriavárakozás nélkül)
258 s
14 s

Az alábbi megoldás valamelyest lassabb, de az agyonstrukturált Pascal-ban elegánsabb:

PROGRAM "Prim2.bas"
FOR X=1 TO 1000 STEP 2
  IF PRIM(X) THEN PRINT X;
NEXT
DEF PRIM(SZ)
  LET PRIM=0:LET Z=SQR(SZ):LET O=1
  DO
    LET O=O+1
  LOOP UNTIL MOD(SZ,O)=0 OR O>=Z
  IF (MOD(SZ,O)<>0 AND SZ<>1) OR SZ=2 THEN LET PRIM=-1
END DEF

A Turbo-Pascal változat:

Program Prim2;
var i:integer;

Function Prim(sz:integer):boolean;
var z:real;
    o:integer;
begin
  Prim:=false;
  z:=Sqrt(sz);o:=1;
  repeat
    o:=o+1;
  until (sz mod o=0) or (o>=z);
  if (sz mod o<>0) and (sz<>1) or (sz=2) then
    Prim:=true
end;

begin
  for i:=1 to 1000 do
    if Prim(i) then Write(i,' ');
  repeat until KeyPressed
end.

Ilyen jellegű tudást nagyon sok feladatban felhasználhatunk (pl. a legnagyobb osztó = N/legkisebb osztó, legkisebb osztó=legkisebb prímosztó stb.). Az az érdekes, hogy ezt a tudást sokszor úgy használjuk, hogy nem is vesszük észre, pl. a következő programban:

PRINT LNKO(A,B)
..
DEF LNKO(A,B)
  DO WHILE A<>B
    IF A<B THEN
      LET B=B-A
    ELSE
      LET A=A-B
    END IF
  LOOP
  LET LNKO=A
END DEF

Itt a legnagyobb közös osztót határozzuk meg. (A-nak és B-nek pozitív egész számnak kell lennie.) Azt használjuk ki, hogy A és B közös osztói osztói A-B-nek is, ha A>B. Aki ezzel a matematikai ismerettel nem rendelkezik, az a feladatot így képtelen megoldani, holott ez az egyik leghatékonyabb megoldás (amely ráadásul gépi kódban is megvalósítható, hiszen csak összehasonlítást és kivonást tartalmaz).

Ennél is sokkal hatékonyabb eljárás az euklideszi algoritmus. Az algoritmus első lépésében maradékosan osztjuk A-t B-vel, majd az előbbi maradékot az új maradékkal, és így tovább, mindig az osztót a maradékkal. A maradék véges sok lépés után nulla lesz, hiszen amíg nem nulla, addig minden lépésben legalább eggyel csökkenni fog. A keresett legnagyobb közös osztó az utolsó nem nulla maradék.

PRINT LNKO(A,B)
..
DEF LNKO(A,B)
  
DO WHILE B>0
    LET T=B
    LET B=MOD(A,B)
    LET A=T
  LOOP
  LET LNKO=A
END DEF

Ugyanez Turbo Pascal-ban:

Function Lnko(a,b:integer):integer;
var t:integer;
  begin
  while b>0 do begin
    t:=b;
    b:=a mod b;
    a:=t
  end;
  Lnko:=a
end;

...
begin
  Writeln Lnko(a,b)
end.

Ugyanez rekurzív algoritmussal:

DEF LNKO(A,B)
  IF MOD(A,B)<>0 THEN
    LET LNKO=LNKO(B,MOD(A,B))
  ELSE
    LET LNKO=B
  END IF
END DEF

Ugyanez Turbo Pascal-ban:

Function Lnko(a,b:integer):integer;
begin
  if a mod b<>0 then
    Lnko:=Lnko(b,a mod b)
  else
    Lnko:=b
end;

Ha már megvan két szám legnagyobb közös osztója, "lendületből" meghatározhatjuk a legkisebb közös többszörösüket is! Ugyanis két szám szorzata egyenlő legnagyobb közös osztójuk, és legkisebb közös többszörösük szorzatával. Ez hatékony módszert ad a legkisebb közös többszörös meghatározására, mivel elég az euklidészi algoritmussal meghatározni a legnagyobb közös osztót, összeszorozni a két számot, majd a szorzatot elosztani a legnagyobb közös osztóval.

DEF LKKT(A,B)=(A*B)/LNKO(A,B)

Ugyanez Turbo Pascal-ban:

Function Lkkt(a,b:integer):integer;
begin
  Lkkt:=(a*b) Div Lnko(a,b)
end;

Programunkat tehát így érdemes kiegészíteni:

IF VIZSGAL(A,B) THEN
  PRINT A;B,"Legnagyobb közös osztó: ";LNKO(A,B)
  PRINT A;B,"Legkisebb közös többszörös: ";LKKT(A,B)
ELSE
  PRINT "Pozitív egész számokat kérek!"
END IF
...
DEF LNKO(A,B)
  DO WHILE B>0
    LET T=B
    LET B=MOD(A,B)
    LET A=T
  LOOP
  LET LNKO=A
END DEF
DEF LKKT(A,B)=(A*B)/LNKO(A,B)
DEF VIZSGAL(A,B)
  LET VIZSGAL=-1
  IF A<1 OR B<1 OR FP(A)<>0 OR FP(B)<>0 THEN LET VIZSGAL=0
END DEF

Ha megvan az LNKO a relatív prímek vizsgálatát elvégző függvény elkészítésével is gyorsan fogunk végezni: Két, vagy több egész szám relatív prím, ha az 1-en és a -1- en kívül nincs más közös osztójuk. Ilyenkor a legnagyobb közös osztójuk az 1, vagyis:

DEF RPRIM(A,B)
  LET RPRIM=0
  IF LNKO(A,B)=1 THEN LET RPRIM=-1
END DEF

10.1.2. Egy ciklus végrehajtási idejének csökkentése
A másik lehetőségünk, hogy a ciklusmag végrehajtási idejét csökkentjük. Ez azért lehet jelentős, mert ha a ciklusmagot sokszor hajtjuk végre, akkor a teljes futási idő is lényegesen csökkenhet.
Az első módszer az ELÁGAZÁSOK TRANSZFORMÁLÁSÁRA épít. Azt használja ki, hogy egy elágazás feltételének vizsgálata helyett általában egyszerűbb egy indexes változó indexelése. Például, ha meg kell számolni, hogy egy szövegben az angol ABC egyes nagybetűi hányszor fordulnak elő, akkor a következő két megoldás közül a második a rövidebb végrehajtási idejű:

1. változat:

NUMERIC BETU(65 TO 90)
...
FOR I=65 TO 90
  LET BETU(I)=0
NEXT
...
FOR I=1 TO LEN(A$)
  SELECT CASE A$(I:I)
  CASE "A"
    LET BETU(ORD("A"))=BETU(ORD("A"))+1
  CASE "B"
    LET BETU(ORD("B"))=BETU(ORD("B"))+1
...
  CASE ELSE
  END SELECT
NEXT

2. változat:

NUMERIC BETU(65 TO 90)
...
FOR I=65 TO 90
  LET BETU(I)=0
NEXT
...
FOR I=1 TO LEN(A$)
  LET X=ORD(A$(I:I))
  IF X>64 AND X<91 THEN
    LET BETU(X)=BETU(X)+1
  END IF
NEXT

Másik módszer a CIKLUSOK TRANSZFORMÁLÁSA az adatszerkezet-választás alapján. Itt általában adatábrázolás-választással érhetjük el, hogy egy ciklus helyett egyetlen műveletet kell elvégeznünk. Itt tehát tulajdonképpen egyes összetett adattípusok létező műveleteit használjuk a végrehajtási idő csökkentésére. Gondoljunk arra a példára, amikor a programozási tételeknél a halmazok metszetének, illetve uniójának elkészítését vizsgáltuk. Mindkét esetben két, egymásba ágyazott ciklust használtunk. Ugyanakkor ezen feladatok megoldását a halmazok jól megválasztott ábrázolásával lényegesen meggyorsíthatjuk.

Sokszor a kivételes esetek vizsgálata lassítja a programot, ezért sebességnövekedést érhetünk el a KIVÉTELES ESET KIKÜSZÖBÖLÉSÉvel. Gondoljunk egy olyan feladatra, amikor egy számsorozatban kell egy adott tulajdonságú elemet keresni (N elemű A() vektort használunk):

NUMERIC A(1 TO N)
...
PRINT KERES(X)
...
DEF KERES(X)
  LET I=1:LET KERES=0
  DO WHILE I<=N AND A(I)<>X
    LET I=I+1
  LOOP
  IF I<=N THEN LET KERES=I
END DEF

Itt a kivételes eset az, hogy a vektorban nincs benne a keresett elem. Emiatt van szükség az I<=N feltétel vizsgálatára. Ha tudnánk, hogy biztosan van ilyen elem, akkor ezt az ellenőrzést kihagyhatnánk, amitől a ciklus egyszeri lefutásának ideje kisebb lenne. A kivételes esetet úgy szüntethetjük meg, hogy a vektor végére egy olyan elemet helyezünk, mint amilyet keresünk. Ha a keresés során ezt találjuk meg, akkor nem volt ilyen elem, különben pedig volt.

NUMERIC A(1 TO N+1)
...
PRINT KERES(X)
...
DEF KERES(X)
  LET A(N+1)=X
  LET I=1:LET KERES=0
  DO WHILE A(I)<>X
    LET I=I+1
  LOOP
  IF I<=N THEN LET KERES=I
END DEF

A negyedik módszer az ADATOK SPECIÁLIS TULAJDONSÁGÁNAK KIHASZNÁLÁSÁra épít. Már láttuk, hogy ennek alapján a ciklusok végrehajtási számát csökkenthetjük. Ez a módszer néha egy futás végrehajtási idejét is csökkentheti. Például, ha egy táblázatban csak A és B betűk vannak és meg kell számolni, hogy melyikből mennyi, akkor elég az A-k számát megszámolni, mert a B-k száma az összes helyek számából levonva az A-k száma.
Sokszor érhetünk el futási idő csökkenést az ADATOK ELÖFELDOLGOZÁSÁval is. Ez azt jelenti, hogy ha egy kifejezést többször kel kiszámítani, akkor ezt tegyük meg egyszer, majd később csak használjuk a kiszámított értéket!
Gyakran a konkrét adatmozgatással veszítünk rengeteg időt. Az adatmozgatást elkerülhetjük, ha listákat, mutatókat használunk az adatok sorrendjének, kapcsolatainak leírására.

10.2. A helyfoglalás csökkentese
A helyfoglalással is kétféle szempontból érdemes foglalkozni. Egyrészt csökkenthetjük a program által használt adatok helyfoglalását, másrészt magának a programszövegnek a helyfoglalását. Az egyes módszerek ezek közül valamelyikkel foglakoznak.

10.2.1. Az adatok mennyiségének csökkentése
A legtöbb nyereséget hozó módszer az INDEXES VÁLTOZÓK KIKÜSZÖBÖLÉSE. Sokszor használunk tömböt az adatok tárolására akkor is, amikor valójában nincs rá szükségünk. Például a - már bemutatott - N. Fibonacci-féle számot megadó programra ez tűnik a legegyszerűbb megoldásnak:

PRINT FIB(N)
...
DEF FIB(X)
  NUMERIC F(1 TO X+1)
  LET F(1)=0:LET F(2)=1
  FOR I=3 TO X
    LET F(I)=F(I-1)+F(I-2)
  NEXT
  LET FIB=F(X)
END DEF

Így szükségünk van egy N+1 elemű vektorra, melyben tároljuk a sorozat elemeit. Pedig minden új érték kiszámításihoz csupán az előző kettő elemre van szükségünk. A korábban bemutatott megoldásban ezért csak két segédváltozót használtunk fel.
Az indexes változók kiküszöbölésére gyakran jó lehetőség van a CIKLUSOK ÖSSZEOLVASZTÁSÁval. Ez azt mondja ki, hogy ha egy kiszámítandó vektor minden elemére csupán egyszer van szükség, akkor a vektor helyett inkább a szükséges helyen számítsuk ki - egyszer - a megfelelő értéket!
Ha egy indexes változót nem szüntethetünk meg, akkor is hozhat eredményt a VÁLTOZÓ TRANSZFORMÁLÁSA. Ha például egy mátrixnak csak a diagonálisában vannak nem nulla elemek, akkor felesleges a többi helyen levő nullákat tárolni, helyette egy elem megadását célszerű módosítani.
Hasonlít az előző módszerre az ADATPREZENTÁCIÓ MEGVÁLASZTÁSA. Itt arról van szó, hogy az adatainkat úgy ábrázoljuk, hogy minél kisebb helyet foglaljanak! Ez egyszerű esetben azt jelenti, hogy valós típusú változó helyett használjunk egész típusút (pl. PASCAL-ban), ha csak egész számokra van szükségünk. Ha egy vektor elemei csak a 0 és az 1 értéket vehetik fel, akkor egy egész típusú változóban több elemet is tárolhatunk.

A Pascal-háromszög a matematikában a binomiális együtthatók háromszög alakban való elrendezése. A nyugati világ nagy részén Blaise Pascalról nevezték el, noha indiai, perzsa, kínai és itáliai matematikusok már évszázadokkal Pascal előtt tanulmányozták. A háromszögben a sorok számozása zérótól kezdődik, és a páratlan és páros sorokban a számok el vannak csúsztatva egymáshoz képest. A háromszöget a következő egyszerű módon lehet megszerkeszteni: A nulladik sorba csak be kell írni az 1-est. A következő sorok szerkesztésénél a szabály a következő: az új számot úgy kapjuk meg, ha összeadjuk a felette balra és felette jobbra található két számot. Ha az összeg valamelyik tagja hiányzik (sor széle), akkor nullának kell tekinteni.
Természetesen semmi akadálya, hogy energiát és tárhelyet nem kímélve egy nagyméretű kétdimenziós tömbben tároljuk az egyes sorokban szereplő értékeket, a következő sor elemeit pedig az előző sorból számítsuk. Némi matematikai ismeret birtokában azonban összesen három változó (ebből kettő ciklusváltozó) felhasználásával is megoldható a feladat. Még a kiírás formázására kell figyelni, hogy valóban háromszög alakban jelenjen meg a háromszög.

PROGRAM "Pascal.bas"
TEXT 80
LET SOR=12
FOR I=0 TO SOR
  LET C=1
  PRINT TAB(37-I*3);
  FOR K=0 TO I
    PRINT USING " ££££ ":C;
    LET C=C*(I-K)/(K+1)
  NEXT
  PRINT
NEXT

Ugyanez Turbo Pascal-ban:

Program Pascal;
const sor=12;
var c,i,k:integer;
begin
  ClrScr;
  for i:=0 to sor do begin
    GotoXY(37-i*3,i+1);
    c:=1;
    for k:=0 to i do begin
      Write(c:6);
      c:=c*(i-k) Div (k+1)
    end;
    Writeln
  end;
  repeat until KeyPressed
end.

10.2.2. A programszöveg méretének csökkentése
Az első módszer tulajdonképpen a végrehajtási idő csökkentés egy módszerének megismétlése: az ADATOK ELŐFELDOLGOZÁSA. Ha ezt megtesszük akkor a feldolgozó kódrészt nem kell sokszor megismételni, így a programszöveg is rövidülhet.
A második módszer is a többször előforduló részek egyszeri leírásán alapul, ez az AZONOS FUNKCIÓK ELJÁRÁSBA FOGLALÁSA. Lényege, hogy a programban több helyen is szereplő azonos / hasonló részeket önálló programegységekbe foglaljuk, s csak egyszer írjuk le! Erre a legegyszerűbb példa - ami sokszor elő is fordul a programokban - amikor egy billentyű megnyomására kell várakozni.

CALL WK
...
CALL WK
...
DEF WK
  DO
  LOOP WHILE INKEY$=""
END DEF

10.3. A bonyolultság csökkentése
Ez a jellemző az, amelyik a legnehezebben megfogható, hiszen nincs az előző kettőhöz hasonló mérőszáma. Mégis érdemes vele foglalkozni, mert az egyszerűség jelentősen csökkentheti a program megértésének idejét, ami a hibát keresők / módosítók számára igen nagy előny.
Itt is segítséget nyújthat a KIVÉTELES ESET KIKÜSZÖBÖLÉSÉnek elve, hiszen a kivételes eset kezelése nemcsak a futási időit növeli, hanem bonyolultságot is okoz.
A kivételes eset sokszor amiatt fordul elő, mert egy ciklus lefutásakor az első esetben mást kell csinálni, mint a többiben, ráadásul ez azért fordul elő, mert egy változónak valamilyen kezdőértéket kell adni. Ekkor segít a FIKTÍV KEZDŐÉRTÉKADÁS elve, amely azt mondja ki, hogy adjunk a kérdéses változónak olyan kezdőértéket, amelyet a program a ciklus első lefutásakor biztosan módosít, s így nem kell külön figyelni az első lefutás esetét.
Bonyolultságot szokott okozni az is, ha egyszerre túlságosan sokat akarunk megoldani (a közmondás szerint: aki sokat markol, az keveset fog). Ezen segít a FUNKCIÓK SZÉTVÁLASZTÁSÁnak elve. Ez azt jelenti, hogy a feladatot több, apróbb feladatra bontjuk le.

10.4. Lokális hatékonyság
Most a program teljes megértése nélküli módszerek következnek. Erről csak röviden emlékezünk meg, mert általában kevésbé jelentősek, mint az eddig ismertetett módszerek. Ezek háromfélék lehetnek (vegyesen adjuk a futási idővel, a helyfoglalással és a bonyolultsággal kapcsolatosakat).

10.4.1. Elvi tanácsok
Itt egy felsorolást adunk:

10.4.2. Programtranszformációk
Ezek a módszerek a programszerkezetek formális jegyei alapján dolgoznak. Megadják, hogy milyen szerkezetű programot milyen feltételek esetén lehet más szerkezetűvé alakítani. Felsorolunk közülük néhányat és megvilágítjuk egy-egy algoritmus segítségével.

A ciklustól független utasítások kiemelése

FOR H=H0 TO 0 STEP-1
  LET EH=M*G*H
  LET EM=M*G*H0-M*G*H
  PRINT EH,EM
NEXT

Hatékonyabb:

LET MG=M*G:LET E0=MG*H0
FOR H=H0 TO 0 STEP-1
  LET EH=MG*H
  LET EM=E0-EH
  PRINT EH,EM
NEXT

Ciklusok összevonása
Ha két ciklus azonos lépésszámú, végrehajtása egymástól független, akkor összevonhatók.

LET MIN=A(1)
FOR I=2 TO N
  IF MIN>A(I) THEN MIN=A(I)
NEXT
LET MAX=A(1)
FOR I=2 TO N
  IF MAX<A(I) THEN MAX=A(I)
NEXT

Hatékonyabb:

LET MIN,MAX=A(1)
FOR I=2 TO N
  IF MIN>A(I) THEN MIN=A(I)
  IF MAX<A(I) THEN MAX=A(I)
NEXT

Elágazások összevonása
Ha egymás után két elágazás található, amelyeknek ugyanaz a feltétele, s a végrehajtás alatt ugyanúgy értékelődnek ki, akkor összevonhatók.

IF A<B THEN
  MIN=A
ELSE
  MIN=B
END IF
IF A>B THEN
  MAX=A
ELSE
  MAX=B
END IF

Hatékonyabb:

IF A<B THEN
  LET MIN=A: MAX=B
ELSE
  LET MIN=B:LET MAX=A
END IF

Elágazások felesleges feltételeinek elhagyása
Ha 2- vagy több irányú elágazást használunk, és különösen, ha az utolsó ág feltétele egyenértékű 'minden más' esettel, akkor a feltételrendszer egyszerűsíthető.

IF X>0 THEN PRINT "pozitív"
IF X=0 THEN PRINT "nulla"
IF X<0 THEN PRINT "negatív"

Hatékonyabb:

SELECT CASE X
CASE IS>0
  PRINT "pozitív"
CASE 0
  PRINT "nulla"
CASE ELSE
  PRINT "negativ"
END SELECT

Elágazás ágainak kiemelése
Ha az elágazás mindkét ága egyformán indul és a közös rész nem változtatja meg a feltétel kiértékelését, akkor ez a közös rész kiemelhető az elágazás elé. Ha az elágazások vége azonos, akkor ez mindentől függetlenül kiemelhető az elágazás mögé. Mindkét átalakítás a programszöveg hosszát csökkenti.

IF A<B THEN
  LET MIN=A
  PRINT MIN
ELSE
  LET MIN=B
  PRINT MIN
END IF

Rövidebb:

IF A<B THEN
  LET MIN=A
ELSE
  LET MIN=B
END IF
PRINT MIN

11. Gyakorló feladatok (kiegészítés)

11.1. Számok kiírása betűkkel
Most nézzünk pár összetettebb feladatot! Írjuk ki a megadott számot betűkkel!
A módszer lényege: az algoritmus a számokat három karakteres csoportokra bontja. Ebből először kiolvassa a "százasokat", "tízeseket" és az "egyeseket", majd hozzáfűzzi az ezreseket és egy kötőjelet. Ezt mindaddig folytatja, amíg el nem fogynak az "ezresek". A legutolsó három karakterhez már nem fűz "ezreseket":
.-xyzmillió-xyzezer-xyz.

Hogy a számokat el tudja "olvasni", két tömbre lesz szükség:

Ennek a két tömbnek a feltöltését végi el a TOLT eljárás. Ezen kívül még egy tömbre szükségünk lesz, ugyanis a nagy számok felvetik azt a problémát, hogy "leírva" hosszabbak lesznek, mint az egy szöveges változóban tárolható 254 karakter. Az MT változó fogja számolni, hogy a tömb hányadik eleménél tartunk a beírásban. A leírt számot a SZAM tömbben fogjuk tárolni. Ennek kiírását végzi el a KIIR eljárás.
A kiírandó számot az SZ változóban adjuk át a SZÁMBETU eljárásnak, mégpedig paraméterként, hogy ezt ne rontsa el az eljárás, az X változó lesz a munkaváltozó. Az eljárás - szükség esetén - először kiegészíti a "számot" (amely string-ként van kezelve) hárommal osztható karakterszámra, vagyis az elejére egy vagy két nullát fűz. A H változó számolja az ezreseket. A BEIR eljárás fűzi hozzá a számhoz a százasokat-tízeseket-egyeseket, melyet fel kell készíteni a magyar nyelv két kivételére: a tíz / tizen... és húsz / huszon... eltérésre. Az ezresek beírása után csökkenti a H értékét és levágja az X változó elejéről az "elolvasott" karaktereket.
Végezetül levágjuk az utolsó kötőjelet a szám végéről, és megvizsgáljuk nem maradt-e üres a SZAM változó, ez ugyanis azt jelentené, hogy nullát adtunk meg számnak, így ezt még be kell írni.

STRING JEGY$(0 TO 9,1 TO 2)*10
STRING ERTEK$(2 TO 22)*12
STRING SZAM$(1 TO 5)*254
STRING SZ$*77
CALL TOLT
...
CALL SZAMBETU(SZ$)
CALL KIIR
...
DEF SZAMBETU(X$)
  LET H=LEN(X$):LET MT=1
  DO UNTIL FP(H/3)=0
    LET X$="0"&X$:LET H=H+1
  LOOP
  LET H=H/3
  DO UNTIL H=1
    CALL BEIR
    IF X$(1:3)<>"000" THEN LET SZAM$(MT)=SZAM$(MT)&ERTEK$(H)&" - "
    LET X$=X$(4:):LET H=H-1
    IF LEN(SZAM$(MT))>195 THEN LET MT=MT+1:LET SZAM$(MT)=""
  LOOP
  CALL BEIR
  LET HOSSZ=LEN(SZAM$(MT))
  IF SZAM$(MT)(HOSSZ-1:)="- " THEN LET SZAM$(MT)=SZAM$(MT)(1:HOSSZ-3)
  IF SZAM$(1)="" THEN LET SZAM$(1)="nulla"
  DEF BEIR
    LET SZAM$(MT)=SZAM$(MT)&JEGY$(VAL(X$(1:1)),1)
    IF X$(1:1)<>"0" THEN LET SZAM$(MT)=SZAM$(MT)&"száz"
    SELECT CASE X$(2:3)
    CASE "10"
      LET SZAM$(MT)=SZAM$(MT)&"tíz"
    CASE "20"
      LET SZAM$(MT)=SZAM$(MT)&"húsz"
    CASE ELSE
      LET SZAM$(MT)=SZAM$(MT)&JEGY$(VAL(X$(2:2)),2)
    END SELECT
    LET SZAM$(MT)=SZAM$(MT)&JEGY$(VAL(X$(3:3)),1)
  END DEF
END DEF

DEF KIIR
  FOR I=1 TO MT
    PRINT SZAM$(I);
  NEXT
END DEF

DEF TOLT
  FOR I=1 TO 2
    FOR J=0 TO 9
      READ JEGY$(J,I)
    NEXT
  NEXT
  FOR I=2 TO 26
    READ ERTEK$(I)
  NEXT
END DEF
...
DATA "","egy","kettő","három","négy","öt","hat","hét","nyolc","kilenc"
DATA "","tizen","huszon","harminc","negyven"
DATA "ötven","hatvan","hetven","nyolcvan","kilencven"
DATA "ezer","millió","milliárd","billió","billiárd","trillió"
DATA "trilliárd","kvadrillió","kvadrilliárd","kvintillió"
DATA "kvintilliárd","szextillió","szextilliárd","szeptillió"
DATA "szeptilliárd","oktillió","oktilliárd""nonillió"
DATA "nonilliárd","decillió","decilliárd","undecillió","undecilliárd"
DATA "bidecillió","bidecilliárd"

11.2. Szám átváltása más számrendszerbe
Egy "a" alapú számrendszerből egy "b" alapú számrendszerbe lehet konvertálni számokat a következő algoritmussal: a számot "b"-vel osztva "a" maradék adja a keresett utolsó számjegyet, a hányados ismételt osztásával pedig a további számjegyeket nyerhetjük jobbról balra haladva. Például 11 hármas számrendszerbeli alakja 102, mivel:

Mint látható, az osztásokat addig folytatjuk, amíg hányadosként nullát nem kapunk. Ha a 0..9 számjegyek mellett az angol abc 26 betűjét használjuk számjegyek jelölésére, akkor a számokat 2..36 közötti alapú számrendszerbe válthatjuk át.
Az algoritmus felhasználásával írjunk programot Turbo Pascal-ban, amely tízes számrendszerbeli számokat tetszőleges számrendszerbe vált át!
A Num eljárásban az "a" az osztandó szám, "b" az új alap. A "szamjegy" tömb egy 36 elemű karakter, amiben a 0..9, A..Z karaktereket tároljuk (Inic eljárás). Az eljárás rekurzívan működik, az első kiíratás az utolsó, legbelső eljáráshívásból történik, majd visszafelé, az első hívásig folytatódik. Így a számjegyek a helyes sorrendben balról-jobbra írjuk ki.

Program Konverzio;
{$A-}
var szamjegy:array[0..35] of char;
    szr,nr:integer;
Procedure Inic;
var i:integer;
begin
  for i:=0 to 9 do
    szamjegy[i]:=chr(48+i);
  for i:=10 to 35 do
    szamjegy[i]:=chr(55+i)
end;

Procedure Num(a,b:integer);
begin
  if a>=b then Num(a div b,b);
  Write(szamjegy[a mod b]);
end;
...

begin
  Inic;
  ...
  Writeln;Write('Szam: ');Readln(nr);
  Write('Szamrendszer: ');Readln(szr);
  Write(nr,' alakja a ',szr,'-es szamrendszerben = ');Num(nr,szr);
  ...
end.

11.3. Római számok
Ezután már különösebb kommentár nélkül írjunk ki arab számot római számmal!

NUMERIC ARABIC(1 TO 13)
STRING ROMAN$(1 TO 13)*2
CALL INIC
...
PRINT TOROMAN$(SZAM)
...
DEF TOROMAN$(X)
  IF X>4999 THEN
    LET TOROMAN$="Túl nagy!"
    EXIT DEF
  END IF
  LET SUM$=""
  FOR I=1 TO 13
    DO WHILE X>=ARABIC(I)
      LET SUM$=SUM$&ROMAN$(I)
      LET X=X-ARABIC(I)
    LOOP
  NEXT
  LET TOROMAN$=SUM$
END DEF

DEF INIC
  FOR I=1 TO 13
    READ ARABIC(I),ROMAN$(I)
  NEXT
END DEF
DATA 1000,"M",900,"CM",500,"D",400,"CD",100,"C",90,"XC"
DATA 50,"L",40,"XL",10,"X",9,"IX",5,"V",4,"IV",1,"I"

Ugyanez Turbo Pascal-ban:

Program Roman;
type numtype=string[20];
const arabic:array[1..13] of integer=(1000,900,500,400,100,
                                      90,50,40,10,9,5,4,1);
      roman:array[1..13] of string[2]=('M','CM','D','CD',
                  'C','XC','L','XL','X','IX','V','IV','I');
var sz:integer;

Function toRoman(x:integer):numtype;
var result:string[30];
    i:byte;
begin
  if x>4999 then
    toRoman:='Tul nagy!'
  else begin
    result:='';
    for i:=1 to 13 do begin
      while x>=arabic[i] do begin
        result:=result+roman[i];
        x:=x-arabic[i]
      end
    end;
    toRoman:=result;
  end
end;

begin
  ...
  Writeln(toRoman(sz));
  ...
end.

12. Kis program, nagy program

A program készítőjének felkészültségétől, ismereteitől függően számára egy 2-300 utasításból álló program is nagy lehet. Éles határvonal ugyan nincs, de nagy programnak a néhány ezertől több tízezer utasításig terjedő programokat nevezzük.
A kis programot többnyire egy ember írja valamilyen, a munkájával kapcsolatos probléma megoldására. A program viszonylag rövid, szerkezete egyszerű, általában valamilyen interaktivitást biztosító nyelven készül. Rövid életű, meglehetősen szűk körben használt. Megjelenése, barátságossága, bolondbiztossága kívánnivalókat hagy maga után. Dokumentációja nincs, vagy ha van, akkor hiányos. Nehezen fejleszthető, nem hordozható, egy géptípusra készül.
Az előző bekezdés tálán sértőnek, lekicsinylőnek tűnhet a kedves olvasó számára, hiszen ő is ilyen programokat ír. Sietünk megnyugtatni mindenkit, hogy mi - a szerzők - is ilyen programokat írunk. Néhány kivételtől eltekintve amatőrök vagyunk valamennyien. Egy amatőr is írhat azonban színvonalas, programot!
A nagy programokat általában szakemberek írják, születésük csapatmunka eredménye, készítésével megbízásnak tesznek eleget. Készítése 'mérnöki munka', 'ipari folyamat', eredménye egy termék. Már a feladat megfogalmazása, pontosítása többfordulós tárgyalássorozatot kíván, melynek végére elkészül a feladat pontos megfogalmazása, egyben a fejlesztői és felhasználói dokumentáció első része, ami tartalmazhatja a szükséges gépi környezetet és programnyelvet is. Utóbbi esetben a készítők keze meglehetősen kötött!
A fejlesztés második lépéseként a programtervezők kapják meg a feladatot, akik valamilyen algoritmusleíró nyelven elkészítik az algoritmust és egyben dokumentálják is azt. Ha még nem történt meg a gép- és nyelvválasztás, akkor ez a következő lépés. Fontos gépi jellemzők: az operatív tár nagysága, műveleti sebessége, a háttértár milyensége (lemez, szalag) kapacitása és az ott őrzött adatok átlagos elérési ideje. A nyelvvel szemben támasztott követelmények közül elsődleges a hatékonysága. Vannak-e hatékony algoritmikus elemei, lehet-e fordítani, mennyire moduláris, támogatja-e a csapatmunkát, van-e széles programkönyvtára. Fontos szempont még az is, hogy milyen a nyelv ismertsége, dokumentáltsága, állandósága, hordozhatósága.
A következő lépés a programozóké. Az algoritmus alapján ők végzik a program kódolását, egy másik csapat pedig már teszteli is a kész modulokat. Közben folyik az elkészült munkák dokumentálása is. A részfeladatokra-bontásban, azok elkészítésében több szempont érvényesülhet. Haladhatunk a végrehajtás menete szerint (ez tesztelésnél kényelmes), végezhetjük az elkészítést és az összeépítést alulról felfelé vagy felülről lefelé. Minden egyes szint megoldásakor feloszthatjuk a munkát a feladat jellege alapján (pl. egy emberé a felhasználóval való kapcsolattartás, másiké az adatbázis kezelés) vagy úgy, hogy egy-egy ember az azonos adatszerkezetekkel dolgozó összes modult írja meg.
Mint említettük a modulonkénti tesztelést, hibakeresést, javítást az eddig elkészült dokumentáció alapján egy másik munkacsoport a kódolással párhuzamosan végezheti. Munkájukat ők is dokumentálják. A kódolás és a modulonkénti tesztelés befejezésével a modulok összeépítése és az összeépítési teszt következik. Az esetleges hibák felderítése, kiküszöbölése után kapjuk a már teljes, működő, úgynevezett HELYES programot.
A következő fázis a hatékonyság-, minőségvizsgálat és javítás. Ebbe a munkába általában bevonják a feladatot kitűző vállalat, intézmény képviselőjét is. Ekkor a már helyes programot futtatják néhányszor a majdani tényleges használatnak megfelelő módon és adatokkal. Az eredményeket természetesen összehasonlítják a más (kézi) úton meghatározottakkal. A túl lassú, szükségtelenül nagy helyigényű, esetleg szépséghibás modulokat a programból kiemelik, a megoldó algoritmust kicserélik, javítják, újra kódolják, tesztelik, majd visszaillesztik a teljes programba és ismét vizsgálják annak hatékonyságát. A műveletsor vége az úgynevezett Jó program.
A program érvényesítése felhasználói környezetben történik tényleges - régebbi és más úton már kiszámított - be- és kimeneti, elég nagy tömegű adatok futtatásával. Közben folyik az eddigi (fejlesztői) dokumentáció rendszerezése, kiegészítésé, a felhasználói dokumentáció részletes elkészítése. A program érvényesítését követően megkezdődik hitelesítése, melyet a fejlesztők képviselőinek irányításával, segítségével a program leendő kezelői végeznek már új, éles bemeneti adatokkal, egyben megtanulják annak használatát. A program által végzett feladatot közben hagyományos módon is megoldják, a két megoldási mód eredményeit rendszeresen összehasonlítják. A leírt folyamat fél-egy évig tart. Közben az utolsó fázis tapasztalatainak figyelembevételével elkészül a részletes fejlesztői és felhasználói dokumentáció. Utolsó lépés a program és a felhasználói dokumentáció átadása, azok tényleges használatba vétele.
A folyamatot itt nagyjából befejezettnek: is tekinthetnénk, ha a készítők nem akarnák programjukat más megrendelőknek is értékesíteni, más gépre, nyelvre átírni, szolgáltatásait fejleszteni, bővíteni, az egész befektetett munkát jobban hasznosítani, a folyamatot rentábilissá tenni, terméküket minél szélesebb körben reklámozni, értékesíteni.
Az előző bekezdésben felsorolt feladatok, valamint a leadott, kész program rendszeres használata során előbb-utóbb felszínre kerülő hibák (Murphy-nek mindig igaza van) megkövetelik a program karbantartását. A karbantartási munkák a már üzemszerű használatba vett programi hibáinak javítását; időközben végzett fejlesztéseinek, kisebb módosításainak az átadott példányra történő rávezetését, dokumentálását jelentik.
Az ilyen munkák elvégzését általában a megkötött szerződés is rögzíti.
Ugye nem is olyan egyszerű egy nagy program elkészítése? Pedig a mi kis 'amatőr' programjaink is mennyi fejtörést okoznak, munkát igényelnek! Ha jobban utánagondolunk, akkor csírájában, néha csak tervekben, bennük is fellelhetők a nagy programok készítésének fázisai.

13. A kódolás technikai elvei

Minden számítástechnikával foglalkozónak meg kell ismerkedni a programkészítés lépésével! Ennek során be kell tartania az algoritmuskészítésre vonatkozó elveket! Ugyancsak nagyon fontos, hogy az elkészülő program jól használható legyen, és - az iskolára gondolva - a programkészítés pontos, rendszerezett, minőségi munkára neveljen! Ezért követelményeket kell állítanunk a készülő programok vizsgálatához is, ezek lesznek a kódolás technikai elvei.
A feladat pontos megfogalmazását követően a stratégiai, taktikai és technológiai elveket figyelembe véve készül a megoldó algoritmus. Az algoritmus elkészítését követi a program kódolása. A kódolással, a kész programmal szemben támasztott TECHNIKAI, minőségi követelményeket részletezzük ebben a fejezetben. Úgy gondoljuk, ezek azok az elvek, amelyeket az amatőr programozóknak is maradéktalanul be kell tartania. A kódolást segítik a kódolási szabályok, amelyek megmondják, hogy az algoritmusból hogyan kell előállítani az adott nyelvű programot.
A kódolási szabályok mechanikus alkalmazásával készült program (amely a feladat logikai szempontjából tökéletes megoldás) csak HELYES, de nem Jó. Saját (interaktív) felhasználását nem segíti elő, nem gondol a felhasználó esetleges tévedéseire, azok kiküszöbölésére, szakmai járatlanságára sem. Az utóbbi szempontokat is figyelembe vevő és kielégítő programot mondjuk csak Jónak.
A kódolás TECHNIKAI ELVEIVEL, a jó program technikai követelményeivel foglalkozunk a továbbiakban.

A BARÁTSÁGOS, udvarias program már betöltése alatt tájékoztatja a felhasználót annak várható idejéről (ha az túl hosszú) és a betöltés tényéről. Esetleg automatikusan indul és azonnal bemutatkozik. Tudatja felhasználójával feladatát, képességeit, szolgáltatásait, használatának mikéntjét, hibajelzéseit, a hibák kiküszöbölésének módját, a háttértárral kapcsolatos műveletek teendőit, funkcióbillentyűit. stb. Alapvető követelmény, hogy a futás során feltett kérdések egyszerűek, világosak, a várható felhasználó ismeretszintjének megfelelők legyenek. Például az 'Add meg a lineáris egyenletrendszer mátrixa fődiagonálisának első elemét!' szöveg helyett inkább a 'Kérem az első egyenlet első együtthatóját!' mondatot írassuk ki. A válaszok egyszerűen megadhatók legyenek, ne kérjünk be olyan adatokat, melyek az előzőekből már származtathatók. Egyáltalán, a felhasználói beavatkozások számát csökkentsük minimumra saját jól felfogott érdekünkben is, hisz ahány beavatkozás, annyi hibalehetőség! Hosszabb ideig tartó műveletek alatt tájékoztassuk a felhasználót a program tevékenységéről, annak: várható idejéről. A háttértárral kapcsolatos műveleteket mindig ellenőrizzük le, annak hibátlan voltáról tájékoztassuk a felhasználót, hiba eseten adjunk tanácsot és biztosítsunk lehetőséget annak kiküszöbölésére.

A BOLONDBIZTOS, biztonságos program mindent kibír! A szándékosan rossz, vagy véletlenül hibás felhasználói beavatkozások sem terelhetik ellenőrizhetetlen vágányokra, azaz nem fordulhat elő, hogy működését, futását nem az általunk eltervezett valamelyik módon fejezi be, 'elszáll', illetve egy, a felhasználónak semmit sem mondó angol nyelvű hibaüzenettel leáll, vagy 'eszméletlen' eredményekét szolgáltat amellett, hogy algoritmusa helyes.
A biztonságosság szempontjából kritikus pontok a felhasználó beavatkozásai. Ezeket a részeket nagy gonddal írjuk meg! Ellenőrizzük, hogy a bevitt adat típusa, értéktartománya megfelelő-e. A kért adat vart mértékegységét annak kérésekor mindig adjuk meg. Kerüljük a különböző típusú, sőt az azonos típusú, de logikailag nem összetartozó adatok egyszerre, egy utasításban történő bevitelét is! Hibás, érvénytelen adatbevitelkor adjunk saját hibajelzést és biztosítsuk a javítás lehetőségét! Ha jól meggondoljuk, akkor a technikai elvek közül a biztonságosság betartása a legnehezebb feladat.

A JÓL OLVASHATÓ program saját, további fejlesztői, módosítói munkánkban jelent óriási előnyt. Az ilyen program felépítése, szerkezete listájából is jól követhető, felismerhető. A lista olvashatóságát, gyors megértését leginkább az oly sűrűn és szívesen alkalmazott feltétel nélküli (oda-vissza) ugró utasítások nehezítik. Elvben minden program megírható ilyen utasítások alkalmazása nélkül is, lehetőleg kerüljük használatát! Sok nyelv esetén mégis szükség van a GOTO utasítás használatára, de az ENTERPRISE IS-BASIC nem tartozik ezek közé... Ilyenkor arra ügyeljünk, hogy csak az algoritmikus struktúrák megvalósítására, kivételes esetek kezelésére használjuk!
A jó olvashatóságot szolgálják az algoritmusleíró nyelv kifejtésénél már leírt technológiai elvek (bekezdéses leírás, összetett struktúrák zárójelezése) is. Ezek az elvek néhány szóköz, megjegyzés-sor beiktatásával a programlistában is meg valósíthatók.
A megjegyzések szerepe lényegesen nagyobb az eddig említettnél. Kódoláskor ugyanis az algoritmust nagymértékben jellemző sok tulajdonság elveszne a programozási nyelv kötött-ségei miatt, ha azokat nem rögzítenénk egy-egy jól megfogalmazott, a kód megfelelő helyén beszúrt megjegyzésben. Nem az a jó megjegyzés amely a kódot ismétli, hanem az amelyik az algoritmusról közöl információt!

Sokszor a rendelkezésre álló tárkapacitásának szűkös volta miatt nincs lehetőségünk arra, hogy a fenti elveket maradéktalanul betartsuk, azaz működő, helyes programunk még elfér, de az udvariasság, bolondbiztonság, jó olvashatóság követelményeinek eleget tevő, kibővített, jó programunk már nem fér el a rendelkezésünkre álló tárban. Ilyenkor, ha feltétlenül ragaszkodunk az egy file - egy program elvhez, akkor más - alternatív - megoldások mellett legalább az udvariasság és a biztonságosság követelményeit elégítsük ki feltétlenül, hisz feltételeik teljesítése szorosan hozzátartozik a program használhatóságához. A jó olvashatóság hiánya csak: bennünket zavar fejlesztéskor.

A KÓDOLÁS MINŐSÉGI, esztétikai, ergonómiai elvei tulajdonképpen a már ismertetett udvariasságra és biztonságosságra vonatkozó elvek további finomítását, részletezését nyújtják. Mondanivalójuk lényege, hogy különösen nagy gondot kell fordítani a felhasználóval való párbeszéd módjára, a képernyőn, nyomtatón megjelenő információk tartalmára, külalakjára, a program továbblépésének, a hibák jelzésének és javításának módjára.

A LAPKEZELÉSI TECHNIKA azt jelenti, hogy a képernyőre (nyomtatóra) kerülő szövegek, adatok logikai egységekre bontva, tartalmukra, jelentésükre utaló megjegyzésekkel ellátva kerüljenek kijelzésre, jól különüljenek el egymástól. Számszerű adatok mellett mindig jelenjen meg azok neve, mértékegysége, értéktartománya. A képernyőn, papíron levő információ egy pillantással átfogható legyen, ezért sosem lehet zsúfolt. A lap kitöltése mindig legyen arányos, tagolását előre tervezzük, megéri a fáradságot! Képernyőnél ke-rüljük a betűnkénti lassított kiírást, végképp ne használjunk minden betű mellé hangjelzést! Az ilyen megvalósítás zavaró, idegesítő. Ne kényszerítsük rá a felhasználóra bizarr elképzeléseinket; programozói tudásunkat, technikai ismereteinket máshol csillogtassuk.
A lapkezelés sarkalatos kérdése a továbblépés is. Egy lap olvasási idejéről, a továbblépésről mindig a felhasználó döntsön! A lapozás módját természetesen mi adjuk meg, de az legyen ott a képernyőn. Általában is igaz, hogy ha a felhasználó érvényesen beavatkozott, akkor azt AZONNAL tudassuk vele! Legegyszerűbb, ha ténykedése következményét rögtön látja a képernyőn, mert az megváltozott. Érvénytelen beavatkozáskor vagy hibajelzést adunk (pl. adatbevitelnél) vagy tudomást sem veszünk róla, legfeljebb hanggal jelezzük a hibát (pl. menütechnikánál). Nagy adatmennyiség vagy hosszú szöveg megjelenésekor biztosítsuk a visszafelé lapozás, illetve a lapozásból történő kilépés azonnali lehetőségét is. Hatásos, ha egy lap lényeges információit kiemeljük (villogtatás, más szín, fényerő, aláhúzott, inverz, vagy dupla széles kiírás), azonban mértékkel és következetesen alkalmazzuk a felsorolt lehetőségeket. Például egy itt-ott villogó, más fényerejű, hatszínű kiírást tartalmazó képernyő csak zavaró lehet!

A MENÜTECHNIKA a lapkezeléssel szorosan összefüggő módszer, mely a felhasználóval való párbeszéd gyors, elegáns megvalósítására alkalmas. A képernyőn megjelenő menüben felsorolt tevékenységek közül - mint egy étlapról - választ a felhasználó. Ezzel a választással egyidejűleg kizár egy sor olyan kérdést is, melyet már fel sem kell tenni. Több lépcsős mélységben is alkalmazható, általában bonyolult, sok szolgáltatással rendelkező programoknál használják.
A menütechnikát alkalmazó programok általában első, úgynevezett főmenüjükkel jelentkeznek be és a választott részfeladat végrehajtása után is ide térnek vissza. Ezért szinte kötelező, hogy a főmenü mindig tartalmazzon egy 'program vége' választást is, és az esetleges almenüknek legyen egy 'vissza a főmenüre' pontja. A választott részfunkciók tényleges végrehajtásinak megkezdése előtt (főleg, ha sok beavatkozást tartalmaznak, már meglévő adatokat írhatnak át vagy végrehajtásuk hosszú időt igényel, illetve végrehajtásuk után a program futásának előző állapota nem, vagy csak nehezen állítható vissza), akkor mindenképpen biztosítsuk a választást megelőző utolsó menüre való, a részfunkció tényleges végrehajtása nélküli visszatérést. Ne kötelezzük a felhasználót az érvényes, ám téves választását követő kényszerpálya bejárására, készítsünk neki vészkijáratot! A vázolt problémák megvalósíthatók egy biztonsági (I/N) kérdéssel, vagy a részfunkció végrehajtásának befejezését jelentő, úgynevezett végjei bevitelével. Tanácsos, ha a program vége, vissza az előző menüre, vészkijárat funkciókat csak két billentyű egyidejű lenyomásával válthatja ki a felhasználó (ne lehessen 'véletlenül' befejezni).
Gyakran előfordul, hogy a menü egyes funkciói végrehajtásának csak akkor van értelme, ha választása előtt a menü más pontjait futtattuk már. Az előzetes feltételek teljesülését kapcsolókkal figyelhetjük. Nem megfelelő állásukkor adjunk hibajelzést, magyarázatot, majd állítsuk vissza a menüt. A menütechnikát kis programoknál is alkalmazhatjuk, mert például udvariasnak tekinthető-e az a program, amely ugyan bemutatkozik, sőt több oldalon keresztül ismerteti felhasználási módját, de még az ötvenedik futtatásnál is arra kényszerít, hogy mindezt elolvassam, mert nem tartalmaz menüt.

Az ADATOK BEVITELÉVEL kapcsolatban szóltunk már a tájékoztató szöveg, a mértékegység, az értéktartomány megjelenítésének szükségességéről, a bevitt adatok típusának, értékének ellenőrzéséről, a lényegesek kiemeléséről, a tagolás fontosságáról. Beszéljük meg a bevitt adatok áttekintésének, javításának szükségességét, lehetőségeit. Hosszabb futási idejű, sok beavatkozást igénylő programoknál feltétlenül nézze át a felhasználó a billentyűzetről bevitt adatait még feldolgozásuk megkezdése előtt! Kevés adatot igénylő programnál is előfordulhat egy-egy melléütés miatt elrontott, hibás, egyébként megfelelő típusú, értéktartományú adat. Több száz adatot pedig szinte lehetetlen elírás nélkül bevinni. Hibás adatból pedig ritkán születik helyes eredmény!
A bevitt adatok ellenőrzése, javítása egy előre-hátra lapozható, a javítandó adatok behatárolását, a javítást biztosító és elvégző képernyőlistával megvalósítható. A javítás megtörténtét megnyugtatóan igazolhatjuk, ha az illető adat javítás előtti és utáni értékét is megjelenítjük ugyanazon a képernyőn.
A megvalósított adatbeviteli és vezérlési technika a felhasználó szemszögéből nézve legyen egységes, következetes. Például a vezérlési beavatkozásokat mindig lezárás nélkül, az adatokat mindig <ENTER> lezárással kérjük. Ettől még fogadhatjuk és ellenőrizhetjük az utóbbiakat is karakterenként.

Az EREDMÉNYEK mellett esetleg választhatóan jelenítsük meg a hozzájuk tartozó bemenő adatokat is. A program eredményei képernyőre, nyomtatóra, háttértárra kerülhetnek. A képernyőre említett arányos kitöltés, tagoltság, esztétikus megjelenés, lényegkiemelés a nyomtatott képre is érvényes. Még valami! A tördelés, elválasztás mindkét periférián a helyesírás szabályainak megfelelő legyen! Egy többjegyű szám sem kerülhet két sorba! Képernyőn, nyomtatón egyaránt kerüljük a távirati stílust (AA=Á, OE=Ö, stb.), zavaró, nehezen olvasható. Ha lehet, használjunk mindkét helyen ékezetes ábécét. Azt már említeni is alig merjük, hogy például az ékezetes betűket sem ismerő program ne vállalkozzon helyesírás oktatására! A nyomtatott eredmény készítésénél arra is gondoljunk, hogy ez valamilyen dokumentum lesz, amin minden szükséges információnak szerepelnie kell.
Ha a program eredményei háttértáron megőrzésre kerülnek, akkor elkerülhetetlen a kivitel körültekintő megszervezése, a kivitt adatok helyességének ellenőrzése. Ha kazettára dolgozunk, akkor különös jelentősége van a névválasztásnak. A felhasználó mindig adhasson legalább egy nevet az adatoknak és ezt a nevet mentsük is ki az állomány elején! Újabb futtatáskor a (rész)eredményeket háttértárról beolvasva furcsa dolgok történnek, ha nem a várt adatok kerülnek a gépbe! Ezt a kellemetlenséget kiküszöbölhetjük a névadással, ha beolvasáskor először csak a file nevét olvassuk be és a felhasználóra bízzuk a döntést, hogy tovább olvassunk-e, vagy inkább megkeresi a tényleges adatokat. A biztonságot növelhetjük azzal, ha a felhasználó által adott név mellé illesztjük a mindig változó dátumot, verziószámot.

A HIBAJELZÉS a felhasználó figyelmének felkeltését szolgálja, ezért legyen mindig hatásos, de ne legyen ijesztő. A vele kapcsolatos legfontosabb elvárások a következők:

14. Programozási nyelvek: utasítástípusok

Bármelyik nyelvet is választjuk elsőnek tanítandó programozási nyelvnek, tanításakor ugyanazokkal az utasítástípusokkal kell foglalkoznunk. Ezen utasítástípusok szükségességére az algoritmuskészítés, az algoritmusleíró nyelv alapján következtethetünk. Éppen ezért ebben a fejezetben általános utasítástípusaival foglalkozunk. Figyelembe vettük azonban, hogy a ma legelterjedtebb nyelv a BASIC, ezért az utasításfajták tárgyalását ezen nyelvre alapozzuk (hangsúlyozzuk azonban, hogy a BASIC helyén más nyelv is állhatna).
Emlékeztetésül előrebocsátjuk, hogy a magasszintű, Neumann-elvű nyelvek szerint a számítógép egy véges méretű tárral (memóriával) rendelkező eszköz, melyben a feladatot megoldó program és a szükséges adatok is a memóriában vannak. A program végrehajtásának különböző állapotait, fázisait egymástól jól elkülöníthető memóriaállapotok véges sorozataként foghatjuk fel. A program végrehajtása utasításról-utasításra, szekvenciálisán történik.
A gépi elképzelésekből következően ezekben a nyelvekben van változó, értékadás, ciklus, elágazás, be- és kiviteli műveletek, utasítások. Az előzőekhez természetesen hozzátartozik még az indítás és a megállás problémája, utasításai, parancsai. A fenti utasítástípusokkal elvben az összes feladat megoldható, minden további megvalósított utasítástípus (függvény, eljárás stb.) már csak a programozó kényelmét szolgálja, de a gyakorlatban nem elhanyagolható tényező. Tekintettel arra, hogy ma csaknem minden gép Neumann-elvű, ezért a legtöbb megvalósított magasszintű nyelv is ilyen típusú. Közülük a legismertebb, személyi számítógépeken a legelterjedtebb, oktatási célokra kifejlesztett és arra jól is alkalmazható a BASIC.
A BASIC éppen gyors nyelvi fejlődése, az újabb gépekhez jobb, többet tudó változat kifejlesztése miatt gyakorlatilag sohasem került szabványosításra, bár történtek erre kísérletek (létezik minimál-BASIC szabvány, illetve BASIC szabványtervezet). Egyes nyelvjárásai legtöbbször nem kompatibilisek egymással még felülről és akkor sem, ha ugyanazon gépcsalád fejlettebb tagjainak képességeit igyekeznek kiszolgálni. Ma legfeljebb az a törekvés érvényesül, hogy a fejlettebb gép egy külön üzemmódban fogadja el a régi testvér nyelvét, programjait. A felsorolt problémákon segíthet a BASIC nyelv különböző nyelvjárásaira is létező, szabványosított operációs rendszerek használata, mint a CP/M. Ugyanis a legnagyobb probléma, a hordozhatóság akadálya éppen az, hogy az egyes BASIC nyelvjárások messzemenően kihasználják az adott gép lehetőségeit. Ezen igyekszik segíteni az operációs rendszer, mely könnyebbé teszi a felhasználó, programozó munkáját azáltal, hogy a géppel való kapcsolattartást szabványosítja, az egyes gépi lehetőségeket is figyelembe vevő megvalósításokat implementációiban magára vállalja, ezáltal biztosítja a szabványainak eleget tevő programok géptípusok közötti hordozhatóságát, széles körű alkalmazhatóságát.
A BASIC különböző implementációi, megvalósításai éppen általános céljuk miatt meglehetősén szegényesek az egyes utasítástípusok részletezésében, kínálatában. Vegyük hát sorra az egyes nyelvjárások közös tulajdonságait, előnyeit, hátrányait. A továbbiak a hazánkban leginkább elterjedt géptípusokra, azok BASIC értelmezőire, azok tulajdonságaira, szolgáltatásaira vonatkoznak.

ÉRTÉKADÁS, VÁLTOZÓ: a Változókkal szemben leggyakrabban hangoztatott bírálat, kifogás azok lehetséges névválasztásainak, ezzel számuknak korlátozott volta miatt hangzik el. A legtöbb nyelvjárás csak két karakteres változóneveket enged meg, a korlátozásokat is figyelembe véve egy programon belüli számuk maximálisan, típusonként 962 lehet. A rövid név miatt a programlistában nem szerepeltethetünk beszédes azonosítókat, számuk korlátozása a legjellemzőbb feladatok megoldása szempontjából nem jelent akadályt. Az IS-BASIC 31 karakter hosszú változóneveket fogad el, ez már több is, mint a maximálisan célszerű változónév hossza.
A sokkal lényegesebb típuskorlátok éppen más nyelvek ismeretének hiánya, az abban megvalósított változótípusok ismeretlensége miatt fel sem merülnek. Mert mit is nyújt a BASIC? Az általunk definiált elemi változók értékei különböző, elvben végtelen, gyakorlatban - az ábrázolhatóság, pontosság miatt - véges számosságú számhalmazok (egész, valós, netán dupla pontosságú) elemei, vagy tetszőleges, de nagyon is véges hosszúságú szövegek lehetnek. Az egyes elemi változók típusára az azonosító után tett, tehető megkülönböztető karakter utal. Összetettebb adatstruktúrák ábrázolására csak az egy- vagy többdimenziós tömbök állnak rendelkezésünkre.
Az elemi adattípusok közül hiányzik például a logikai típus - bár egyes számértékeknek minden implementáció megfeleltet igaz vagy hamis logikai értékeket; az elemi logikai műveletek AND, OR, NOT éppen emiatt működnek. Az egyes elemi változótípusokhoz szorosan hozzátartozik a velük kapcsolatos műveletek megléte is. Például nem sokat ér a komplex szám vagy mátrix, mint elemi adattípus (és vele kapcsolatban legfeljebb az értékadás definíciója), ha nem biztosítjuk a nyelvben az új adattípusokkal végezhető egyszerű műveletek elvégezhetőségét nyelvi, utasítás szinten.
A BASIC-ből leginkább hiányolt elemi adattípusok: logikai változó és értékei, komplex típusú változó és műveletei, mutató, halmaz, részhalmaz típusú változó és elemi műveletei.
Az összetettebb adatszerkezetek közül pedig éppen, mert a gyakorlati feladatok megoldásakor sokszor előfordulnak, hiányoljuk legalább a verem és a sorszerkezet elemi megvalósítását a velük kapcsolatos műveletek elemi, utasításszintű létrehozását azok esetleges hibajelzéseivel együtt. Ugyanígy a legtöbb BASIC változatban nem találhatjuk meg a mátrixszal való műveletek utasításszintű megvalósítását sem.
Az adatkezeléssel kapcsolatos feladatokban pedig elengedhetetlen az oda-vissza bejárható lista ismerete, megvalósítása, műveleteinek - létrehozás, törlés, felülírás, beszúrás, bővítés, mentés, beolvasás, összefűzés, rendezés, keresés, válogatás - létrehozása, alkalmazása. Hasonlóan hiányzik az adatfeldolgozási feladatokat könnyebben megoldhatóvá tevő rekord- (Pascal), illetve file-fogalom (Pascal, COMAL).
Az adatokkal, adatszerkezetekkel, az azokhoz tartozó műveletekkel kapcsolatban felsorolt és meg sem említett hiányosságok természetesen pótolhatók az egyes BASIC nyelvjárások megvalósított utasításaival is, így oktatási szempontból - a jobb megértés miatt - nem is baj ha hiányoznak, pusztán arra szerettük volna felhívni az olvasók figyelmét, hogy nem a BASIC a feladatmegoldás egyedül üdvözítő nyelve, mert más nyelvekben esetleg olyan, a feladatmegoldás szempontjából lényeges elemeket is készen találunk és alkalmazhatunk, melyeket BASIC-ben csak fáradságos munkával valósíthatunk meg. Gondoljunk a programozási tételek között felsorolt unió tételre, illetve az unió Pascal megvalósítására: C:=A+B! Még nem is beszéltünk az értékadás fel nem vázolt lehetőségeiről, pl. a többszörös értékadásról (A=B=C).
A változókkal kapcsolatban még meg sem említettük azok hatáskörét, formális, vagy aktuális voltát stb. Pedig a BASIC egyik legfontosabb hiánya, hogy változói között nem tesz ilyen megkülönböztetést, definiálható felhasználói- függvényeiben sem teszi lehetővé valódi formális-aktuális paraméter-átadást. Csak globális változói vannak, így meglehetősen nagy figyelmet kíván az adatok egyes programrészek közötti illesztése. A nyelv egyáltalán nem támogatja a több logikai szintből álló programozást, struktúrakiépítést. Az IS-BASIC-re ez a megállapítás már nem igaz, az teljes mértékben támogatja a strukturált programozást, így az adatok elszigetelésének elvét is!
Egy személyi számítógépre írt program adatokat magából a programból is kaphat a READ, DATA, RESTORE utasítások segítségével, azonban ezt a megoldást általában csak olyan adatokra (pl. zene) használjuk, melyek nem változnak a futtatások során.

BE- ÉS KIVITEL: A nagygépek nem interaktív, magas- szintű nyelveiben a programok futtatásakor az adatok bevitele valamilyen tárolóról (lyukszalag, lyukkártya, adatlap, mágnesszalag, lemez) történik és az eredmények is háttértárra kerülnek. A programozó, felhasználó sokszor nem is találkozik a géppel. A programot és az adatokat tartalmazó hordozót a számítóközpont diszpécserének adja le, az eredményeket is tőle kapja. A futtatást az operátor végzi, a géppel folytatott párbeszéde az operátori terminálon keresztül valósul meg. A program futtatásához szükséges információkat, nevét, nyelvét, a szükséges be- és kimeneti perifériákat, háttértárolókat, annak első szegmense, az úgynevezett munka- (job) szegmens tartalmazza és azokat az operációs rendszer dolgozza fel.
Így a nagygépek nyelveinek be- és kiviteli utasításai meglehetősen egyszerűek, általában egy író és olvasó utasítást tartalmaznak, ahol az utasítás egységszám formájában tartalmazza az aktuális perifériát is. A be- és kivitel formátuma az, ami szigorúan kötött, a B/K utasításokhoz gyakran tartozik egy, a külalakot meghatározó, úgynevezett formátumutasítás.
A személyi számítógépekre jellemző, hogy az adatbevitel legtöbbször billentyűzetről, néha háttértárról történik, a kivitel leggyakoribb eszköze pedig a tv-képernyő vagy a monitor, csak ezután következik a nyomtató, illetve háttértár. Az egyes perifériákra vonatkozó B/K műveletek elvégzésére általában itt is egységszámmal hivatkozunk azzal a könnyítéssel, hogy az elsődleges B/K perifériák (billentyűzet, képernyő) egységszámait nem kell megadnunk.
A bemeneti/kimeneti utasítások legbonyolultabb része a gép és a háttértár közötti adatcsere. A háttértárra rögzíthető adatállományok több típusa (szekvenciális, direkt, indexelt stb.) ismert. Közönséges mágnesszalagon, kazettán csak a szekvenciális (soros) állomány hozható létre (ezért az IS-BASIC is csak soros állománykezelést valósít meg). A vele végezhető műveletek: kazettán csak az állomány írása, olvasása, lemezen bővítése is megengedett. Az állomány adatait valamilyen elválasztójel - pl. CR - különíti el egymástól, végét végjel zárja. Az adatok típusa tetszőleges, hossza változó, ügyeljünk arra, hogy az adatok írásának és olvasásinak sorrendje azonos legyen! Az állomány adatainak törlése, felülírása, új adatok beszúrása, átrendezése csak a tárban lehetséges úgy, hogy a régi állományt végig beolvassuk, azt a tárban módosítjuk, majd az újat ismét rögzítjük.
Direkt, véletlen elérésű állomány csak lemezen valósítható meg. A direkt állomány rekordokra, a rekordok mezőkre oszthatók fel. Egy rekord például egy ember adatait adhatja meg úgy, hogy ezen belül a mezők az ember nevét, születési helyét, személyi számát, anyja nevét, lakhelyét stb. tartalmazhatják. Egy állományon belül legtöbbször minden rekord tetszőleges, de egyenlő hosszúságú és azonos szerkezetű, vagyis egy-egy rekordon belül a mezők száma és egy-egy megfelelő mező típusa, hossza megegyezik. A mezők összhossza adja a rekord hosszát. A mezőket nem határolja semmiféle elválasztójel, olvasásuk, írásuk, módosításuk pozicionálással magában a háttértárban valósul meg. A pozicionálásról a programozó gondoskodik, egy téves pozíció megadásának következményei beláthatatlanok.
A változó rekordhosszúságú állományok szerkezetére semmiféle megkötés nincs, arról a feladat kívánalmainak megfelelően a program írója dönt, egy-egy állomány hosszának csak a lemez kapacitása szab határt. A megkötések hiánya miatt nagyon sokféle file valósítható meg, használatuk azonban nagy gyakorlatot, körültekintő munkát igényel.
A kiíró utasítások körét a személyi számítógépek jelentősen kibővítették. Egyik ilyen alapvető utasítás segítségével a képernyőn pozícionálhatunk. További lépést jelentenek a rajzoló utasítások. Legelemibb változatukban a képernyő egy pontjának kigyújtására, illetve kioltásira van lehetőség. A bonyolultabb grafikával rendelkező gépek lehetőséget adnak egyenes, körív, téglalap stb. rajzolására, színezésére. A harmadik terület, ahol új utasításokkal találkozhatunk, a hang- és zenekészítés.

A CIKLUS: Az utasítások ismétlése rendkívül fontos, lehetőség. A BASIC legtöbb nyelvjárásiban csak az úgynevezett számlálásos ciklust valósították meg utasításszinten, ahol a ciklusváltozó egy kezdőértéktől halad a végértékig meghatározott lépésközzel. A ciklus magja egyes nyelvjárásokban egyszer mindenképpen lefut, ha a vezérlés a ciklus kezdő utasítására került, ugyanis a ciklusváltozó értékét a ciklus végén változtatja meg és teszteli a megvalósító algoritmus, másoknál az elején vizsgál, s így elképzelhető, hogy a ciklus egyszer sem fut le. A legtöbb gépen a számábrázolás pontatlanságából adódóan egyes esetekben előfordulhat, hogy az utolsó még megengedett értékre már nem fut le a ciklus. A ciklusból kilépve a ciklusváltozó értéke (az esetek többségében) az szám lesz, amelyre már nem futott le a ciklus!
Az általános ciklusfogalom azt jelenti, hogy a ciklus lefutása egy logikai feltételtől függ. A ciklus mindaddig ismétlődik, amíg a logikai kifejezés igaz (vagy hamis). A cikluskezdet, logikai kifejezés, ciklusmag, ciklusvég felépítési ciklust elöl tesztelőnek, míg a cikluskezdet, ciklusmag, logikai kifejezés, ciklusvég szerkezetűt hátul tesztelőnek nevezzük. Mindkettőnél igaz, hogy a ciklus írásakor nem tudjuk előre megmondani, hogy hányszor fut majd le. Előbbi lehet, hogy egyszer sem, utóbbi egyszer biztosan lefut. A PASCAL és az IS-BASIC nyelvben az említett ciklusok utasítás szinten vannak megvalósítva. Egy-egy feladat megoldásakor segíthet az a ciklus is, ahol a ciklusváltozó lehetséges értékei szabálytalan, felsorolással megadott véges számsorozatot alkotnak. Még általánosabb az a ciklus, ahol a ciklusváltozó (rész)halmaz szöveg típusú is lehet. A BASIC-ben meg nem valósított típusú ciklusokat létrehozhatjuk egy-egy néhány soros programrészlettel, GOTO, GOSUB használatával.
A ciklussal szembeni alapvető követelmény, hogy a cikluskezdet ciklusvég-utasítások egyáltalán létezzenek (pl. a Pascal-bán nincs ciklusvég-utasítás), s egyértelműen zárják le a ciklusutasítást.

Az ELÁGAZÁS, VÁLASZTÁS teszi lehetővé egyes programrészletek feltételtől függő végrehajtását. A BASIC-ben oly előszeretettel és sokszor feleslegesen alkalmazott GOTO utasítás nem elágazás, hanem feltétel nélküli vezérlésátadás! Csak indokolt helyzetben használjuk de IS-BASIC-ben teljesen elhagyható a GOTO / GOSUB használata. Az elemi elágazások mindig megfogalmazhatók

Ha (a) logikai feltétel (igaz)
  akkor    Utasítások1
  különben Utasítások2
Elégazás vége

alakban. Egyszerűbb esetekben a különben ág elmaradhat. Amennyiben az adott BASIC nyelvjárásban van ELSE ág, és az Utasítások1, illetve Utasítások2 mindössze néhány rövid utasítást jelent, akkor az elágazás megoldható GOTO nélkül.
Többirányú elágazást biztosít az ON utasítás, mely jól alkalmazható például a menü válaszainak - fogadására. Használatkor a legtöbb gondot a feltételek és az ON utasítás változója értékeinek egymáshoz illesztése, transzformációja jelenti. Az IS-BASC-ben az ON GOTO / ON GOSUB helyett a CASE szerkezet használata javasolt. A többi BASIC nyelv utasításszinten nem valósítja meg a legáltalánosabb több irányú elágazást, a CASE szerzetet, amely

Elágazás
  feltétel1 esetén Utasítások1
  feltétel2 esetén Utasítások2
  ...
  feltételN esetén UtasításokN
  egyéb esetben Utasítások
Elágazás vége

alakú (ilyen általános szerkezet meg a Pascal-ban sincs, az IS-BASIC-ben van). A szerkezet lényeges eleme, hogy ha az i. feltétel igaz, akkor az i. utasításcsoport végrehajtása után a vezérlés az elágazás végére kerül.

BELSŐ FÜGGVÉNYEK: Az egyes nyelvek által megvalósított belső matematikai és szövegkezelő függvények köre, minimális száma ma már kialakult, az egyes nyelvek, nyelvjárások között csak kisebb eltérések mutatkoznak. A matematikai célú nyelvekben a létrehozott matematikai függvények köre szélesebb. A szövegkezelő és konverziós függvények nagyjából kielégítik az igényeket, jól használhatók. Az ilyen függvények épp az első generációs magasszintű nyelvekből hiányoznak legtöbbször.

ELJÁRÁSOK, FÜGGVÉNYDEFINÍCIÓK a magasszintű programozási nyelvek fontos strukturális elemei. Elvben alkalmazásuk nélkül is megoldható lenne minden feladat, azonban hiányuk nagyon megnehezítené a programozó dolgát és megnövelné a program szövegének terjedelmét. Általános alkalmazásukhoz, igazi megvalósításukhoz nélkülözhetetlen a globális-lokális változók, a formális-aktuális paraméterek megléte és utóbbiak cseréjének lehetősége. Az IS-BASIC ezen követelményeket maximálisan teljesíti, a többi BASIC-ből viszont a felsorolt feltételek nagy része hiányzik, ezért ezen eszközök alkalmazása nehézkes. A FORTRAN-ban névvel, formális be- és kimeneti paraméterekkel láthatjuk el a definiált szubrutint, önálló programszegmenst, pl.: MASOD(A,B,C,X1,X2). A felsorolt paraméterek nemcsak formálisak, hanem lokálisak is. Hívásakor a formális paraméterek helyére az aktuálisak lépnek, a bemeneti paraméterek akár tömbelemek, skalár változók, vagy konstansok lehetnek, pl.: CALL MASOD(D,-2.,F,T,Z). Az elmondottak a függvény definiálásakor a is érvényesek. Függvény definiálásakor a legtöbb BASIC változat például csak egy paramétert engedélyez.
Több nyelv ismeretének előnyei az elmondottakból már kiszűrhetők. Megismerhetünk olyan szerkezeteket, struktúrákat, függvényeket, eljárásokat, melyek az általunk eredetileg ismert nyelvben nincsenek meg, de egy másikban utasításszinten vannak megvalósítva. Működésük, szerkezetük pontos ismeretének birtokában ezeket egy feladat megoldásakor alkalmazhatjuk, felépíthetjük olyan nyelvben is, amelyben nincsenek megvalósítva. Az ismert fogalmak köre is bővülhet.
Lényeges lesz, hogy ezek után a feladat ismerete alapján megválaszthatjuk azt a nyelvet, amelyen a megoldást a legegyszerűbben, leggyorsabban, leggazdaságosabban készíthetjük el.

15. Alacsonyszintű programozási nyelvekről

Az első nyelv után sokszor a gépi kóddal, az assembly nyelvvel való foglalkozás következik. Ezt egyrészt az érdeklődés, másrészt a BASIC-ben megoldhatatlan vagy nagyon nehezen megoldható feladatok léte magyarázza. Ezek azok a nyelvek, amelyek erősen kötődnek az adott mikroprocesszor típusához. Használatukhoz mindenképpen szükség van az adott gép belső szerkezetének, 'lelkivilágának' ismeretére, Így tanulását, alkalmazását csak haladóknak ajánlhatjuk.
Ebben a fejezetben néhány szóval áttekintjük az itthon Elterjedt személyi számítógépek processzorait, azok gépi kódját és assembly szinti programozását. A SPECTRUM, HT, PRIMO, TVC, ENTERPRISE stb. gépek Z80, a COMMODORE család tagjai pedig 6502 vagy 6510 típusú processzorra épülnek. A szintén elterjedt, elterjedő IBM személyi számítógépek processzorai az INTEL 8086, 8088, 80286, 80386 típusúak.
A gépi kódú programoknak két nagy előnye van a magasszintű nyelven megírtakkal szemben. Ugyanazt a feladatot megoldó programok gépi kódban megírva rendszerint gyorsabban futnak, másrészt kisebb tárkapacitást igényelnek. Az eleve gépi kódban írt programok lényegesen hatékonyabbak, gyorsabbak és rövidebbek a magas szintről gépi kódra fordítottaknál. Maximálisan kihasználhatjuk a gép nyújtotta lehetőségeket. Egy alacsonyszintű program hatékonysága sokkal jobban függ a programozó ismereteitől, gyakorlottságától, mint egy magasszintűé.
Ezt a sok előnyt egy jelentős hátrány ellensúlyozza: a gépi kódú program megírása sokszor nagyságrendekkel nehezebb, mint a megfelelő magasszintű nyelvű program megírása. Így arra a kérdésre, hogy mikor írjunk gépi kódú programot, a válaszunk: amikor muszáj!

15.1. Előismeretek
ELŐISMERETEK nélkül nem megy a gépi kódú programozás. Az, aki alacsony, gépi szinten kíván programozni, előbb alaposan ismerje meg a bináris, decimális, hexadecimális számrendszereket, az átszámításokat, alapműveleteket! Tudja a processzor felépítését, regisztereit, az állapotregiszter bitjeinek jelentését, használatát, a lehetséges címzési módokat, megszakításokat! Magasabb szinthez tanulmányozza a ROM rutinokat, RAM vektorokat! Elengedhetetlen a tár felosztásának ismerete is.

A Z80 REGISZTEREI: Az általános célú regiszterek nyolc bitesek, de a felsorolás szerint páronként összekapcsolhatok, rendre A,F; B,C; D,E; H,L a szokásos jelölésük. Közülük kiemelt szerepe A-nak és F-nek van. Az A az akkumulátor, az F a processzor állapotát jelző biteket (flag) tartalmazó állapotregiszter. Az ugyanezen, de vesszős nevekkel (A párja A'...) ellátott másik nyolc regiszter funkciója azonos az előzőekkel, de a két regiszterkészlet közül egyszerre csak az egyik használható. A 16-bites regiszterek közül a két indexregiszter jele IX és IY, címek tárolására kiválóan alkalmas (16 biten 64K címezhető). Az SF jelű veremmutatóval a processzor által használt verem (stack) alját adhatjuk meg, jelölhetjük ki. A 64k tárterület címzéséhez elengedhetetlen, hogy a programszámláló, PC is 16-bites legyen. Tartalma mindig a következő gépi utasítás tárbeli címét adja meg. Az eddigieken kívül a 8-bites R regisztert a dinamikus RAM frissítésére használja a processzor, az ugyancsak 8-bites I regiszterre pedig a megszakítások kezeléséhez van szüksége.

A 65XX REGISZTEREI: Számuk lényegesen kevesebb a Z80 regisztereinek számánál. Az akkumulátor jele itt is A, amely ugyanúgy 8-bites, mint a két, X és Y jelű indexregiszter. A veremmutató, SP azért lehet 8-bites, mert a verem helye fix, mindig az első lapon található. A Z80 F regiszterének megfelelő, ugyancsak 8-bites az SR jelű állapotregiszter, mely a processzor állapotára utaló biteket tartalmazza. Egyedül a PC jelű utasítísszámláló kétbyte-os a 64K-nyi címtartomány átfogására. Szorosan véve a processzornak több regisztere nincs is, de a tár nulladik és első byte-jait is használja.

Az olvasó bizonyára ismeri már a tárlapozás fogalmát. A fogalom azt takarja, hogy egyes gépekbe (80K-S SPECTRUM, bővített C64, Enterprise) 64K-nál nagyobb tárat építettek be, holott processzoruk csak 64K-t címezhet. A fölös memóriatartományt csak úgy kezelhetjük, ha ugyanazokon a címeken egymás 'mögött', 'alatt' több tárrész is létezik. Ezek ki/bekapcsolását végzi C64-en a processzor, vagy a programozó az első két byte tártálmának megváltoztatásával. Az ENTERPRISE-ban a memórialapozásról külön vezérlőchip és az operációs rendszer gondoskodik, vagy a programozó is elvégezheti ezt a feladatot.

15.2. Gépi kód
A GÉPI KÓDÚ programokat nyugodtan beilleszthetjük a BASIC szövegébe és onnan meg is hívhatjuk, futtathatjuk azokat. Erre több módszer is kínálkozik géptípustól függően. A gépi kód alkalmazása, az utasításkódok és operandusok, adatot: akár tízes, akár tizenhatos számrendszerben történő bevitele fárasztó, nehézkes, sok hibával jár. Egy ilyen program fejlesztése, tesztelése hosszú folyamat, éppen ezért a gépi kódot csak rövid, néhány utasításból álló programok fejlesztésekor alkalmazzuk: közvetlenül. A szakirodalomban gyakran látható, viszonylag hosszabb ilyen programrészek valamilyen assemblerrel készülnek és a listák egy külön, a gépi kódot pl. DATA sorokba író program nyomtatott termékei. Megjelenésük azért indokolt, hogy a gépi kódú, assembly szintű programozásban járatlan fejlesztő is alkalmazhasson gépi betéteket, eljárásokat BASIC programjaiban.

15.3. Assembler, assembly nyelv
Az ASSEMBLEREK olyan fordítóprogramok, amelyek az assembly nyelven megírt programokat fordítják le gépi kódra, továbbá személyi számítógépeken biztosítják azok dokumentálását, háttértárba történő mentését, onnan való betöltését, futtatását, tesztelését, általában megkönnyítik a fejlesztést (ezen lehetőségek egy része nem is assembler funkció, mégis beépítik az assemblerbe). Hiba esetén hibajelzést adnak, javítási lehetőséget biztosítanak. Segítik az adatterületek kijelölését, feltöltését. Fejlettebb változataik lehetővé teszik makrók definiálását, használatát.
Az ASSEMBLY SZINTŰ NYELV alkalmazása mindig együtt jár valamilyen assembler használatával. Ahány assembler, annyi assembly szintű nyelvjárás van. Mint minden nyelv, ez is meghatározott szintaktikájú utasításokból és parancsokból áll. Az assembly utasítások, általában a következő alakúak:

<sorszám> <címke> <mnemonik> <operandus> <megjegyzés>

A sorszámot legtöbbször az assembler generálja, vagy egyáltalán nincs is. Érvényes sorban a sorszám mellett legalább vagy mnemonik, vagy megjegyzés áll. A megjegyzés nem kötelező. A mnemoniktól függően kötelező az operandus. A program szerkezete határozza meg a címke meglétét vagy hiányát. Egy utasítás legtöbbször egy gépi utasításnak felel meg (kivétel a makrók és a direktívák).
A sorszám csak a program sorainak azonosítására szolgál fejlesztéskor, más szerepe nincs. A címke a program szerkezetéből adódó elágazások, ugrások szimbolikus címe, neve; értéke fordításkor konkretizálódik. A mnemonik egy gépi kódú utasítás általában kettő vagy három betűs - annak angol nevéből származó - emlékeztetője, vagy az assemblernek a program kezdőcímére, helyfoglalására, adataikra stb. utaló úgynevezett direktívája, pszeudóutasítása. Az operandus értelmezése a mnemoniktól függ, cím vagy adat lehet. A megjegyzés csak a program olvasójának szóló tetszőleges szöveg, szerepe azonban lényegesen nagyabb, mint BASIC-beli megfelelőjének. Itt tényleg az algoritmusra irányuljon, ne a kódot ismételje.
Az eddigiekből is kiderül, hogy egy sor - egy utasítás szerkezetűek az assembly szintű nyelvek. Soron belül az egyes mezőket általában legalább egy szóköz választja el egymástól, kivéve a megjegyzést, melyet legtöbbször pontosvessző előz meg és egyben választ el a sor többi részétől. Ajánlott az egyes mezőket mindig ugyanabban az oszlopban kezdeni.
A személyi számítógépek assembleremet parancsai a megírt forrásprogram képernyőre, nyomtatóra való listázását, javítását, mentését, betöltését, módosítását, fordítását szolgálják. Biztosítják a lefordított tárgyprogram mentesét, betöltését, más címre történő áthelyezését, futtatását is.
A mnemonikok, gépi utasítások részletes ismertetésére nem vállalkozunk, csak csoportosítjuk őket. Az első csoportot az úgynevezett adatmozgató utasítások alkotják. Beszélhetünk 16- vagy 8-bites adatmozgatásról, megkülönböztethetjük ezeket a forrás és a cél helye szerint is. Azaz léteznek az adatot regiszterből regiszterbe, regiszterből tárba, tárból regiszterbe, memóriából memóriába mozgató, töltő utasítások. Külön szót érdemelnek a tömbmozgatást, adatcserét végző utasítások. A gépi kódú programozás gerincét jelentik a vezérlésátadást, szubrutinszervezést biztosító utasítások. Az eltolások, ciklikus léptetések valósítják meg az oly fontos bitműveleteket. Az aritmetikai és logikai utasítások csoportja biztosítja a szokásos műveletvégzéseket. Az ún. összehasonlító utasítások segítségével vizsgálhatók a állapotregiszter bitjei. Nagyon fontosak még a beolvasó-, kiíró utasítások: egyes processzortípusoknál ezek a műveletek ugyanolyanok, mint a tárműveletek, s így nincs külön bemeneti/kimeneti utasításuk. Ezekkel az utasításokkal oldható meg a számítógép és a külvilág közötti információcsere is. Utoljára hagytuk a veremkezelő utasításokat, a megszakításkezelést, melyek erősen kötődnek a gépi kódú programozáshoz.
Hosszabb, bonyolultabb feladatot megoldó program fejlesztése még így is nagyon sok körültekintést, gyakorlatot igényel. A fejlesztőnek mindig minden lehetséges esetre, elágazásra gondolnia kell, azokat kezelnie szükséges, hisz a gépi kódú programokra BASIC nyelvű társaiknál sokkal jobban érvényes, hogy működésüket csak az előre eltervezett módon fejezhetik be! A megoldás során nagyon sok olyan részfeladatot old meg a programozó, amit nála képzettebb szakemberek már régen megoldottak, sőt rendelkezésére is bocsátottak, ott van a gépben.
Az interpreter rutinjaira vagy az ENTERPRISE esetében az operációs rendszer funkcióhívásaira is gondolunk. Haladó szintű gépi-, assembly programoknál alkalmazásuk elengedhetetlen! Használatukhoz ismernünk kell belépési címüket, a futásukhoz szükséges előfeltételeket, a környezetet - a regiszterek, jelzőbitek tartalmát, az előzetesen meghívandó rutinokat - végül hatásukat, az eredmények tárolásának helyét, módját, futásuk után a processzor állapotát. A témáról az olvasó részletes ismertetést talál az illető gép gépi kódú programozásával, a ROM rutinokat leíró és a RAM vektorok leírásával foglalkozó szakkönyvekben.

16. Feladatok

1. Írjunk programot, amely kiszámolja a kör területet és kerületét!
2. Írjunk háromszög, négyzet, téglalap, trapéz, szabályos n oldalú sokszög, kör területét, kerületét számító programot.
3. Számítsuk ki hasáb, téglatest, kocka, henger, kúp, gömb térfogatát!
4. Írjunk programot mérték átszámítására - 1 angol mérföld = 1609,34m.
5. Írjunk programot, amely kiszámolja y=2*x+5 értékeit, -2- től 5-ig!
6. Írjunk programot, amely kiszámolja egy szám faktoriálisát (1*2*...*n)

Ciklus

7. Készítsünk 1*1 szorzótáblázatot 10-es számrendszerben!
8. Készítsünk 1*1 szorzótáblázatot 8-as számrendszerben!
9. Készítsünk 1*1 szorzótáblázatot 16-os számrendszerben!
10. Készítsünk adott ideig várakozó programot!
11. Készítsünk emlékezet tesztprogramot amelyben a gép kiír egy ideig a képernyőre 5 számot és visszakérdezi!
12. Írjunk programot, amely 100-tól 500-ig kiírja a 3-mal, 7-tel osztható számokat!
13. Írjunk programot, amely 100-tól 500-ig kiírja az 5-tel osztható, de 25-tel nem osztható számokat!
14. Írjunk programot, amely kiírja azokat a természetes számokat, amelyekre igaz a 6*x+8*y<40 egyenlőtlenség!
15. Írjunk programot, amely egy adott számtani (vagy mértani) sorozat elemeit generálja!

IF-THEN, RND

16. Írjunk programot, amely LNKO-t számol!
17. Írjunk programot, amely LKKT-t számol!
18. Írjunk programot, amely kétismeretlenes egyenlet gyökeit keresi képlet alapján, ügyelve arra, mikor hány megoldás van!
19. Írjunk programot, amely másodfokú egyenlet gyökeit keresi képlet alapján, ügyelve arra, mikor hány megoldás van!
20. Írjunk programot amely a születési dátum ismeretében eldönti, megnézhetem-e a korhatáros filmet!
21. Írjunk programot, amely a koordináták ismeretében eldönti, melyik negyedben van a pont!
22. Írjunk programot, amely eldönti egy adott évről, hogy szökőév-e!
23. Írjunk programot nem ismétlődő lottószám generálásra!

READ-DATA

24. Írjunk programot, amely bekér egy számot és kiírja azt betűvel.

Grafika

25. Rajzoljunk ki sakktáblát a képernyőre!
26. Rajzoljunk ki koordinátarendszert a képernyőre!
27. Rajzoljunk ki egy kockát a képernyőre!
28. Rajzoljunk ki egy függvényt a képernyőre!
29. Egy pont fusson a képernyőn!
30. Véletlen esőt generáljon a program!

Egyéb

31. Pithagoraszi számhármasokat írjon ki a program
  • a*a+b*b=c*c alapján,
  • x=m-n, y=2k, z=m+n alapján (k*k=m*n)!
32. Fibonacci sorozat elemeit generálja a program!
33. Előjelfüggvény előállítása (sgn X)
34. Írjunk programot, amely beolvas egy pozitív egész számot és azt átalakítja:
  • kettes,
  • nyolcas,
  • tizenhatos számrendszerbeli számra!
35. Írjunk programot, amely beolvas egy pozitív 1-nél kisebb számot és azt átalakítja:
  • kettes,
  • nyolcas,
  • tizenhatos számrendszerbeli számra!
36. Írjunk programot, amely beolvas n számot és kiírja a számtani átlagát!
37. Írjunk programot, amely megjeleníti a Pascal háromszöget!
38. Írjunk programot, amely három számról, eldönti lehetnek-e egy háromszög oldalának mérőszámai!
39. Írjunk programot, amely megkeresi az összes pozitív egész megoldását a 3X+4Y=52 egyenletnek!
40. Írjunk programot, amely megkeresi egy konkrét másodfokú egyenlet gyökeit!
41. Írjunk programot, amely a négy alapművelet valamelyikét gyakoroltatja a felhasználókkal! Értékelést is adjon az eredményről!
42. Egy versidézet mondatait elemezteti a tanulóval a program. Kérdezzen rá az alanyra, majd az állítmányra! Hibás válasznál tanítsa meg, hogy hogyan kérdezzen az alany és az állítmány után!
43. Adott számokból ki kell számítani a magasvérnyomású alkoholisták számát!
44. Tetszőleges elem izotópjainak százalékos összetételéből számítsa ki az elem atomsúlyát!
45. A négy részből álló program tanítsa az arány fogalmával kapcsolatos tudnivalókat, példákon szemléltesse az arányos változásokat, mutasson rá az egyenes és a fordított arányosságra, tanítsa egy példa aránypárral történő megoldását a tanuló közreműködésével.
46. A program az Avogadro-számot számolja ki bármely elemi vagy két összetevőjű gáz segítségével!
47. N vezér elhelyezése egy N*N-es sakktáblán úgy, hogy ne üthessék egymást! Az első vezért maga a felhasználó tehesse le.
48. A program adja meg egy hitelben történi vásárlás kamatát!
49. Készítsünk gyufahúzó játékot! Aki az utolsó szálat húzza, veszít.

Programozási tételek - összegzés

50. Határozzuk meg egy egész szám számjegyeinek számát!
51. Egy kettes számrendszerbeli szám jegyeiből írjuk fel a szám tízesbeli alakját!
52. Írjunk programot kamatos kamat számítására!
53. Határozd meg egy adott N számig a páratlan számok összegét!
54. Írjunk sorozatok összegét számító programot!

Programozási tételek - eldöntés

55. Készítsünk programot, amely eldönti, hogy egy beadott név hónap-e?
56. Készítsünk programot, amely eldönti, hogy egy adott intervallumban van-e az egyenletnek gyöke!
57. Készítsünk programot, amely eldönti, hogy egy intervallumban van-e prímszám!
58. Készítsünk programot, amely eldönti, hogy egy adott számsorozatban, ami egy osztály tanulóinak magasságát jelenti, van-e 179 cm-es tanuló!
59. Készítsünk programot, amely eldönti, egy szóban van-e B betű!
60. Készítsünk programot, amely eldönti, hogy a maradékos osztásnál a maradék 0-e !

Programozási tételek - kiválasztás

61. Készítsünk programot, amely kiválasztja egy természetes szám 1-től különböző pozitív osztóját!
62. Készítsünk programot, amely kiválasztja a sorszámát egy olyan tanulónak, aki még nem felelt!

Programozási tételek - keresés

63. Készítsünk programot, amely megkeresi egy autóbusz-menetrend alapján, hogy van-e közvetlen járat, ha van, kiírja!
64. Készítsünk programot, amely megkeresi egy adott intervallumban az első tökéletes számot!
65. Írjunk programot, amely egy osztály tanulóinak adataiból (név, testsúly, magasság) egy adott magasságnál nem nagyobbak közül kiválasztja a legnagyobb testsúlyát!

A. Kódolási szabályok

Ebben a fejezetben megadjuk, hogy az 5.3. fejezetben bemutatott algoritmusleíró nyelv utasításait hogyan lehet egyes nyelveken kódolni.
Egy lehetőséget ismertetünk mindegyik szerkezetre!

    IS-BASIC
1. Program ...:
...
Program vége.
PROGRAM név [paraméterlista]
...
END
2. ... := ... LET ... = ...
3. Be: ... INPUT PROMPT "kérdés":vált.lista
4. Ki: ... PRINT ...
5. Ha... akkor ... IF ... THEN ...
 

Ha... akkor ... különben ...

Ha ... akkor
    ...
  különben
    ...
Elágazás vége

IF ... THEN
  ...
ELSE
  ...
END IF

6.

Ciklus .. = ..-tól ..-ig lépésköz
  ...
Ciklus vége

FOR ...=... TO ... STEP ...
  ...
NEXT

  Ciklus amíg...
  ...
Ciklus vége
DO UNTIL ... / DO WHILE ...
  ...
LOOP
  Ciklus
  ...
amíg...
Ciklus vége
DO
  ...
LOOP UNTIL ... / LOOP WHILE ...
7. eljárásnév:
  ...
Eljárás vége
DEF eljárásnév (paraméterlista)
  ...
END DEF
8. eljáráshívás CALL eljárásnév (paraméterlista)

  Pascal ELAN0
1. Program ...;
  deklarációs rész
begin
  ...
end.
program:
  ...
.
2. ... := ... ... := ...
3. write('kérdés'); readln(...) put (kérdés);
get (...)
4. write('...') put (...);
line
5.

if ... then

if ... then ... else ...

IF ...
  THEN
    ...
ENIF

  if ... then
  begin
    ...
  end
  else
  begin
    ...
  end
IF ...
  THEN
    ...
  ELSE
    ...
ENDIF
6. for ...:=... to...do
begin
  ...
end
FOR ... FROM ... UPTO ...
REPEAT

  ...
ENDREPEAT
  (csak -1-esével)
for ...:=... downto...do

begin

  ...
end
(csak -1-esével)
FOR ... FROM ... DOWNTO ...
REPEAT
  ...
ENDREPEAT
  while ... do
begin
  ...
end
WHILE ...
REPEAT
  ...
ENDREPEAT
  repeat
  ...
until ...
REPEAT
  ...
UNTIL...
ENDREPEAT
7. procedure ... (paraméterek);
  deklarációs rész
begin
  ...
end;
eljárásnév:
  ...
.
8. eljárásnév (paraméterek) eljárásnév

Irodalomjegyzék

Irodalomjegyzékünkben csak a könyvben ismertetett anyaghoz kapcsolódó művek közül ajánlunk néhányat. Nem célunk a teljes választék ismertetése, csupán azokat adjuk meg, amelyeket magunk is hasznosan alkalmaztunk tanításunk során.

I. Általános ismeretek

  1. Angol-német-orosz-magyar statisztikai és szim1tástechnikai szótár
    Közgazdasági és Jogi Könyvkiadó, 1977.
    A szótár a címben jelzett tudományterületeken kívül matematikai terminológiát is tartalmaz. Olyan szótári segédanyag, amelyet a tanulótól kezdve a szakemberig mindenki használhat.

  2. Bradbeer, R.- DeBono, P.- Laurie, P.: Műsoron a számítógép
    Műszaki Könyvkiadó, Budapest, 1984.
    A könyv közérthetően szól a számítógép szerepéről, működéséről. Megismertet a személyi számítógép használatával, a BASIC nyelvű programozás alapjaival. A kötet végén megtalálhatók a használt szakkifejezések és magyarázatuk.

  3. Coles, R.: Kulcs a mikroszámítógépekhez
    Műszaki Könyvkiadó, 1984.
    A könyv bevezető ismereteket ad a mikroprocesszorok és utasításkészleteik 'rejtelmeibe', a mikroprocesszorok alkalmazásáról a számítógépekben. Végül a szoftverről ad rövid tájékoztatót. Az olvasást könnyíti, hogy a használt kifejezésekhez a könyv végén szómagyarázat található.

  4. Csépai János: A számítástechnika alapjai
    Műszaki Könyvkiadó, Budapest, 1985.
    A tankönyv alapvetően nagygépes ismereteket tartalmaz középiskolai számítástechnikai fakultáción résztvevők számára. Olyan alapokat kiván megteremteni, amely lehetővé teszi a számítóközpontokban való munkavállalást. Emellett programozás alapismereteket is tárgyal és áttekintést ad a mikroszámítógépekről is.

  5. Fodor T. - Nagy I.: Digitális számítógépek
    Műszaki Könyvkiadó, 1984.
    A kétkötetes tankönyv a számítógép hardver alapjait adja meg. Elsősorban elektromos jellegű iskoláknak szól. Témái: számítógép alapismeretek, információelméleti alapok, logikai áramkörök, a számítógép fő egységei.

  6. Dr. Hámori Miklós: Tanulás és tanítás számítógéppel
    Tankönyvkiadó, Budapest, 1983.
    A könyv a gyakorló pedagógusnak készült. A számítógép szerepét, alkalmazási lehetőségét vizsgálja a tanulás-tanítás folyamatában. A könyv három részre tagolódik. Az első rész a tanulással, a tanítással kapcsolatos elképzelésekről ad áttekintést és bemutatja vázlatosan magát a számítógépet is. A második rész a számítógépnek az oktató-nevelő munkában lehetséges alkalmazási módjait, módszereit vizsgálja. A harmadik rész kettős feladatot lát el: Egyrészt módszertant ad új oktatási anyagok mikroszámítógépes megvalósításához, másrészt néhány tananyagrészt dolgoz fel példaként.

  7. Homonnay Péter: Angol-magyar számítástechnikai szótár
    NOVOTRADE RT. 1986.
    A számítástechnika területén gyors a változás, ráadásul a használt nyelv angol. Az előforduló szakkifejezések és az eredeti szövegkörnyezetben gyakran előforduló közhasznú szavak magyar megfelelői nagy segítséget adhatnak az angolul kevéssé tudó amatőr- és professzionális programozóknak. Ilyen szótár összeállítására vállalkozott a szerző.

  8. Kis Á. (szerk. ): Mi micsoda magyarul a számítástechnikában?
    Tömegkommunikációs Kutatóközpont, 1986.
    A könyv a számítógép használók és a laikusok számára is érthető magyarázatot ad a számítástechnika alapfogalmairól. A szótárban az értelmező részt (fogalmanként 2-5 sor) angol-magyar szótári rész követi, majd az adatátvitellel kapcsolatos angol szakkifejezések magyar megfelelői kaptak helyet. A Függelék a BASIC nyelv kulcsszavait tartalmazza magyar nyelvű feloldásaikkal együtt.

  9. Nievergelt, J. - Farrar, J.C. - Reingold, E.M.: Matematikai problémák megoldásának számítógépes módszerei
    Műszaki Könyvkiadó, 1977.
    A szerzők kettős célt tűztek maguk elé: elsősorban számítástechnikai problémák ismertetését, de emellett - a számos példán keresztül - sok feladatmegoldó fogás elsajátítását is. Az egyes fejezetek külön-külön is jól olvashatók. A begyakorlást a fejezetek végén levő feladatok kitűzésével segítik, a témakörök részletesebb tanulmányozásához a Megjegyzések és hivatkozások című szakaszok mutatnak irányt. A könyv segédkönyvként is használható.

II. Programozási módszerek

  1. Aho, A.V. - Hopcroft, J.E. - Ullman, J.D.: Számítógép algoritmusok tevezése és analízise
    Műszaki Könyvkiadó, 1982
    A könyv az algoritmus elmélet alapvető eredményeit gyűjti össze. Bevezetés az algoritmusok tervezésibe és elemzésébe. Közérthető nyelven ad intuitív magyarázatot a felmerülő problémákra. Olvasásához matematikai- és programozási előismeret szükséges.

  2. Dahl, O.J. - Dijkstra, E.W. - Hoare, C.A.R.: Strukturált programozás
    Műszaki Könyvkiadó, 1978.
    A könyv a strukturált programozásba, gyakorlati alkalmazásának lehetőségeibe nyújt betekintést. Az első fejezet a célszerű programstruktúra kialakításának alapelveivel, módszereivelm a második ezen - és hasonló alapelveknek az adatstruktúrák tervezésében való alkalmazásival ismeretet meg. A harmadik rész az első kettő szintézise: az adatok és a programok tervezése közötti szoros elméleti és gyakorlati kapcsolatot mutatja be feladatokon keresztül.

  3. Kernighan, B.W - Plauger, P.J.: A programozás fortélyai
    Műszaki Könyvkiadó, 1982.
    A könyv mind a kezdő, mind a gyakorló szakemberek számára hasznos segédeszköz. A magasszintű struktúrált programok készítését feladatokon keresztül mutatja be. A jó programozási stílus elsajátításihoz a legjellemzőbb hibalehetőségek bemutatása és a belőlük levont következtetések is segítséget adhatnak.

  4. Kernighan, B.W - Plauger, P.J.: A programozás magasiskolája
    Műszaki Könyvkiadó, 1982.
    A kötet a programozás alapjaival tisztában levő olvasót nagyobb programok, programrendszerek megtervezésének, elkészítésének módszereivel ismereti meg. Kettős feladatot tűz maga elé: Bemutatja a jó programozási stílust és hogy hogyan lehet a mindennapi gyakorlatban jól alkalmazható programokat írni. A példaanyag könnyen olvasható, több géptípuson kipróbált.

  5. Morvay J. - Dr. Sebők F.: Az adatkezelés módszertani alapjai
    Számítástechnika-alkalmazási Vállalat, 1982.
    A könyv egy három kötetből álló monográfiasorozat első tagja. Ebben a szerzők a rendszermodellezés alapjaival és a leginkább elterjedt adatmodellezési elképzelések lényeges jegyeivel foglalkoznak. Bemutatják azokat a módszereket, amelyek felhasználhatok az adatmodell számítógépes megvalósításához.

  6. Szlávi P. - Zsakó L.: Módszeres programozás
    Műszaki Könyvkiadó, 1986.
    A kötet a jól működő program készítéséhez amatőr szinten is alkalmazandó módszerek összefoglalását nyújtja. Ismerteti a programozás taktikai, technológiai és technikai elveit. Részletesen tárgyalja a programozási tételeket, a programozási hibák keresésének alapelveit és leggyakoribb módszereit. Bepillantást nyújt a programhelyesség vizsgálatának nehézségeibe, szól az algoritmusok és a programkódok hatékonyságáról, a pontos feladatmeghatározás fontosságáról. A függelékek közül az első az algoritmust leíró 'nyelv' szabályait foglalja össze, a második a BASIC kódolási szabályait, a harmadik a kötetben feldolgozott nagyobb méretű program különféle gépeken történő megoldását mutatja be.

  7. Varga L.: Rendszerprogramok elmélete és gyakorlata
    Akadémia Könyvkiadó, 1978.
    A könyv első része a program fogalmával, a programozási nyelvek és az automaták elméletével ismerteti meg az olvasót, majd az adatszerkezeteket és a rajtuk értelmezett legfontosabb algoritmusokat vizsgálja. Ezekre az alapokra építve ismerteti az assembly nyelvet, a nyelvek szintaxisának és szemantikájának formális leírását, az operációs rendszereket. Az utolsó fejezet a számítástudomány kérdései közül a programfejlesztés módszereivel, eszközeivel foglakozik.

  8. Várkonyi Zs.: Bevezetés a modern programtesztelésbe
    Műszaki Könyvkiadó, 1979.
    A jó minőségű szoftver előállításánál alapvető a programminőség ellenőrzése. A könyv elsősorban a különféle tesztelési módszerekről, azok alkalmazásáról kíván átfogó ismereteket nyújtani. Nyolc fejezete közül az első négyet szánja a szerző az átlagos számítástechnikai ismeretekkel rendelkező olvasóknak. Az első fejezet tisztázza az alapfogalmakat, a második a programtesztelés módszereit tárgyalja. A harmadik- és a negyedik rész a tesztelés automatizálásával, illetve a programhiba-kereséssel foglalkozik.

  9. Wirth, N.: Algoritmusok + adatstruktúrák = programok Műszaki Könyvkiadó, 1982.
    A szerző a programok készítésének egy rendszeres, tudományos megközelítését adja. A könyv az adatstruktúrákról szóló fejezettel kezdődik. A következő fejezetek rendező algoritmusokkal, rekurzív algoritmusokkal, dinamikus adatstruktúrákkal foglalkoznak. Az utolsó fejezet tömör bevezetést ad a formális nyelvek definíciójába, az elemzés problémájára valamint bemutatja egy egyszerű kis nyelv fordítóprogramjának elkészítését.

III. A BASIC programozási nyelv

  1. Alcock, D.: Ismerd meg a BASIC nyelvet!
    Műszaki Könyvkiadó, 1983.
    A szerző köznapi nyelvezettel, szokatlan (kézzel irt) formában írt bevezető könyvet a BASIC nyelvbe. A mű a BASIC általános leírását tartalmazza. Az elemek bemutatása után részletesen foglalkozik adatszerkezetekkel, adatállományokkal. Egy teljes fejezete példaprogramokat tartalmaz. A Függelék a BASIC egyik lehetséges nyelvjárását, a PROPER 8-at mutatja be.

  2. Bodor T. - Gerő P.: A BASIC-programozás technikája
    SZÁMALK, Budapest, 1983.
    A könyv elsősorban a BASIC használatának technikájára és nem magára a nyelvre koncentrál. Tartalmazza az alapvető programszerkezetek kódolási formáit, beszél a kódolási konvenciókról, a kód optimalizálásáról. A kényelmes, hatékony és biztonságos BASIC-programozáshoz nyújt segítséget.

  3. Dusza Á. - Varga A.: A BASIC-nyelvű programozás ábécéje
    Műszaki Könyvkiadó, Budapest, 1985.
    A könyv a teljesen kezdőket kívánja bevezetni a BASIC programozási nyelvbe. Az általános ismeretek után elsősorban matematika- és fizikafeladatok programjai találhatók benne. A melléklet a BASIC-programozás legfontosabb elemeit tartalmazza.

  4. Harmathy Z. - Helfenbein H. - Kőhegyi J. - Zsakó L.: Ismerd meg a BASIC nyelvjárásait! (HT-1080Z, ABC80, ZX81)
    Műszaki Könyvkiadó, 1984.
    A kötet Alcock (III.1.) könyvének stílusában készült, feltételezve annak ismeretét és a két kötet együttes használatát. A BASIC egymástól többé-kevésbé eltérő nyelvjárásaiból úgy mutatja be a címben jelzett hármat, hogy szorosan követi Alcock könyvének szerkezetét annak fejezetszámaira hivatkozva.

  5. Horváth L. - Kőhegyi J. - Marosváry E. - Sándor A.: Ismerd meg a BASIC nyelvjárásait! (Commodore 64, VIC 20, Sharp PC-1500)
    Műszaki Könyvkiadó, 1986.
    Lásd III.4.

  6. A HT-1080Z iskolaszámítógép programozása
    Fővárosi Pedagógiai Intézet, 1984.
    A Fővárosi Pedagógiai Intézet és az ELTE tanártovábbképzésének HT-1080Z gépre adaptált anyaga. Három fő részre bontható: az első rész a programozási alapokat, a második a BASIC alapszókészletét, a harmadik a speciális HT BASIC szolgáltatásokat ismerteti. Az elméleti ismereteket bő példaanyag illusztrálja. A használatot segítik a Függelékek, amelyek a rendszerezés mellett újabb hasznos tudnivalókat is közölnek.

  7. Kőhegyi J. - Pomózi I. - Seprődi L. - Szlávi P.: Ismerd meg a BASIC nyelvjárásait! (ZX Spectrum, TI-99/48 Proper 16/A)
    Műszaki Könyvkiadó, 1985.
    Lásd III.4.

  8. Lőcs Gyula: A BASIC és a Kíváncsi
    Tankönyvkiadó, Budapest, 1985.
    A könyv az általános számítástechnikai műveltség megalapozásához ad segítséget a BASIC programozási nyelv alapjainak párbeszédes megismertetése közben. A 14 egymásra épülő dialógus - a szerző és a Kíváncsi között - bemutatja a nyelv fontosabb építőköveit. A Függelékben a BASIC utasításkészlete, beépített függvényei és egy ASCII karakterkód-táblázat találhatók.

  9. dr. Úry László: Commodore 64 I - II. kötet
    LSI ATSZ,Budapest, 1984.
    A kézikönyv mind a kezdő, mind a gyakorlott programozók számára ajánlott segédeszköz a C-64 minél jobb megismerésében. A C-64 programozásához szükséges valamennyi ismeretet tartalmazza.

IV. Programozási nyelvek

  1. Erdős I.: Commodore 64 assembly
    LSI ATSZ, Budapest, 1985.
    A könyv célja, hogy a C-64-et ismerő, BASIC nyelven már tudó, az assemblyben kezdő programozók számára segítséget nyújtson. Megismertet a MOS 6510-es mikroprocesszor működésével, utasításkészletével, kézikönyvszerűen bemutatja az assembly programozásban felhasználható legismertebb szoftver-eszközöket. Bepillantást ad az assembly programozás módszereibe. A Függelékben több hasznos táblázat található.

  2. Jensen, K. - Wirth, N: A Pascal programozási nyelv
    Műszaki Könyvkiadó, Budapest, 1982.
    A két részből álló könyv első fele a Pascal nyelv felhasználói kézikönyvét, második fele a nyelv formális leírását tartalmazza. A Függelékben összefoglaló táblázatok és a szintaxis leírása található. A mű kiválóan használható tankönyvként; a megértést a sok példaprogram is jól segíti.

  3. Seres M. - Fenyő L. - Gyalogh K.:A FORTH programozási nyelv
    Műszaki Könyvkiadó, Budapest, 1986.
    A könyv a - haladó programozóknak ajánlott - FORTH nyelvbe ad betekintést. A szerzők mind a FORTH-79 STANDARD kötelező és ajánlott szavait, mind a legelterjedtebb rendszer, a fig-FORTH ettől eltérő utasításait tárgyalják. A Függelékben megtalálhatók a 1eggyakrabban előforduló konkrét FORTH implementációk.

  4. Sztrókay K.: A Z80 assembler
    Műszaki Könyvkiadó, Budapest, 1985.
    A kötet a Z80-as processzor bemutatásán túl a nyelv utasításait és azok használatát tárgyalja. A megismert utasítások alkalmazási lehetőségeit szemléltető fejezetek után a gép beépített rutinjainak alkalmazásira látunk példát. A Függelékben többek között megtalálható a HT-1080Z ROM listája.

  5. Turcsányiné Szabó M. - Seriftleben, D.: A LOGO programozási nyelv
    Műszaki Könyvkiadó, Budapest, 1986.
    A könyv első részében a - különösen a gyerekek körében népszerű - teknőc-grafikával ismerkedhetünk meg. A második, fejezet a nyelv rendszeres felépítését nyújtja. A Függelék a LOGO három nyelvjárását, az LCSI Apple LOGO-t, a C64 Terrapin LOGO-t és a Snail LOGO Sinclair ZX Spectrum-ot tartalmazza.

V. Példatár, feladatgyűjtemény

  1. Appel Gy. - Kőhegyi J. - Zsakó L. : Számítógépes feladatok
    INTERPRESS, Budapest, 1985.
    A kötet célja, hogy feladatokkal segítse a BASIC nyelv elsajátítását. Az első részben az önállóan tanulóknak ad elemi feladatokat. A második részben előbb a kezdők, majd a haladók számára találhatók feladatok. (Ezek megoldásait külön fejezetben találhatjuk). Végezetül 25 versenyfeladatot tűztek ki a szerzők.

  2. Bárdos A. - Körtvélyesi G.-né: Programozási alapfeladatok gyűjteménye
    SZÁMALK, Budapest, 1985.
    A 444 alapfeladatból álló gyűjtemény célja az önálló feladatmegoldás segítése. A nehézségi fok az 1-2 utasítástól a 200-300 utasításos, eljárásokat alkalmazó, közepes bonyolultságú programokig terjed. A könyv a feladatok negyedéhez megoldásokat, ötleteket közöl.

  3. Csákány A. - Vajda F.: Játékok számítógéppel
    Műszaki Könyvkiadó, Budapest, 1980.
    A szerzők a játékok csoportosítása után a játékhoz szükséges eszközeiket mutatják be. A logikai-, táblás-, szám- és szerencsejátékok után két fejezet is foglalkozik szimulációs játékokkal, majd a számítógép grafikus eszközként szerepel. A Függelékben a kötetet sok kész program egészíti ki.

  4. Lőcs Gyula: A BASIC és a Kíváncsi - Feladatgyűjtemény
    Tankönyvkiadó, Budapest, 1986.
    A szerző A BASIC és a Kíváncsi c. könyvének kiegészítéseként az ott tárgyalt számítástechnikai- és programozási ismereteinek elmélyítését és begyakorlását segíti elő számos feladat kitűzésével és megoldásaikkal. (A nehezebb feladatoknál útmutatást is találunk).

  5. Marx Gy.: A természet játékai
    ILK, Budapest, 1985.
    A könyv 30 játék leírását tartalmazza. Közös tulajdonságuk, hogy minden játék valamilyen természettudományos törvény működését teszi érzékletessé. A játékok mindegy kétharmadához számítógépes változatot is közöl.

Az általános ismeretek ki kibővítéséhez jól használható néhány kiadó számítástechnikai szakkönyvsorozata:

  1. DATA BECKER - NOVOTRADE
  2. Ipari Informatikai Központ
  3. LSI Alkalmazástechnikai Tanácsadó Szolgálat

Ezek gépek, nyelvek leírását, sajátosságait, specialitásait, hardverleírást, alkalmazói programok leírását tartalmazzák. Ezek a könyvek a megfelelő szakboltokban kaphatok, nagy számuk és újabbak gyors megjelenése miatt egyenként nem soroljuk fel őket.

Vissza