• Nem Talált Eredményt

Nevezetes algoritmusok

In document Bevezetés az informatikába (Pldal 77-82)

Gyakori programozási feladat egy tömb elemeinek bizonyos szempont(ok) szerinti rendezése (esetleg eleve rendezett tömb létrehozása), illetve bizonyos feltétel(ek)nek eleget tevő tömbelem keresése, kiválasztása. Az alábbiakban néhány ilyen alapalgoritmust ismertetünk.

Kereső algoritmusok

Keresést rendezetlen és rendezett tömbökön egyaránt végezhetünk. Rendezetlen tömb esetén a keresés nehézkesebb, lassúbb, de az egyéb tömbkezelő műveletek (pl. új elem beszúrása) egyszerűbbek. Rendezett tömb esetén gyorsabb a keresés, viszont a kapcsolódó tömbműveletek bonyolultabbak, hiszen pl. egy új elem beszúrása után is meg kell tartani a tömb rendezettségét.

Lineáris keresés

A legegyszerűbb keresési algoritmus, amely rendezetlen tömbön dolgozik. A tömb első elemétől kezdve összehasonlítjuk a tömbelemeket a keresendő elemmel. A keresési ciklus akkor ér véget, ha valamelyik tömbelem megegyezik a keresettel, vagy, ha a tömb végére érünk. Az utóbbi esetben a keresett elem nincs a tömbben. Az algoritmus onnan kapta nevét, hogy a keresések száma, és így a futási idő, lineáris függvénye a tömb elemszámának.

Megjegyzés: A n jelöli a számsorozat elemeinek számát, az a[1..n] tömb tárolja a számsorozat elemeit, x a keresett érték. Eredményként a keresett elem tömbbeli indexét írassuk ki, amennyiben az elem megtalálható.

i := 1;

while (i ≤ n) AND (a[i] ≠ x) do i := i + 1;

endwhile

if i ≤ n then write i

else write "A keresett szám nem található meg a számsorozatban."

endif.

Logaritmikus (bináris) keresés

A logaritmikus vagy bináris keresési algoritmus rendezett tömbön működik, így az előző módszernél lényegesen gyorsabb keresést tesz lehetővé. A keresendő elemet először a tömb középső eleméhez hasonlítjuk. Ha a két elem egyezik, megtaláltuk a tömbelemet, ha nem, a keresést abban a tömbfélben folytatjuk, amelyet a középső és a keresett elem viszonya kijelöl. Ha a tömb növekvő sorrendbe rendezett és a keresendő elem nagyobb, mint a középső elem, akkor a második tömbrészben, egyébként pedig az elsőben folytatjuk a keresést. A keresést akkor fejezzük be, ha megtaláltuk a keresett tömbelemet, vagy a tömbrész elfogyott. Az összehasonlítások száma, s így a futási idő, az elemszám kettesalapú logaritmusával arányos, ami nagy elemszámok esetén lényegesen kisebb lehet, mint a lineáris keresés esetén.

Megjegyzés: A n jelöli a számsorozat elemeinek számát, az a[1..n] tömb tárolja a számsorozat elemeit, x a keresett érték. Eredményként a keresett elem tömbbeli indexét írassuk ki, amennyiben az elem megtalálható.

eleje := 1;

vége := n;

repeat

közepe := (eleje + vége) / 2;

70

else write "A keresett szám nem található meg a számsorozatban."

endif.

Rendező algoritmusok Beszúrás

Van egy n elemű rendezett tömbünk. Be akarunk szúrni egy n+1-edik elemet a rendezettség megtartásával.

Egyik lehetőség, hogy végigszaladunk a halmazon, és betesszük a beszúrandó elemet az elé az elem elé, ami már nem előzi meg. Átlagosan (n+1)/2, de a legrosszabb esetben n összehasonlításra van szükség. Másik lehetőség, hogy a kérdéses elemet a középső elemmel hasonlítjuk össze. Ha az új elem megelőzi a középsőt, akkor a továbbiakban a halmaz első felében keressük a helyét, stb. A lépésszám log2n, vagy az erre következő első egész szám, azaz [log2n]+1, ha n nem 2 hatványa.

Megjegyzés: A n jelöli a számsorozat elemeinek számát, az a[1..n] tömb tárolja a számsorozat elemeit, x a beszúrandó érték. A kereséséhez a logaritmikus algoritmust használjuk.

eleje := 1;

A rendezés során sorrendbeli hibát keresünk egy tömbben. Ennek során használhatunk lineáris, illetve bináris keresést. A kialakult sorrendtől eltérő helyen levő elemet kiemeljük, majd megkeressük a sorrendnek megfelelő helyét. Amikor a helyét megtaláltuk, akkor a közbeeső elemeket eltoljuk, majd az imént kiemelt elemet a felszabaduló helyre beszúrjuk. Ez a rendezés túl sok mozgatást igényel.

Megjegyzés: A n jelöli a számsorozat hosszát, az a[1..n] tömb tárolja a számsorozat elemeit.

for i := 2 to n do

a[j+1] := a[j];

endfor

a[helye] := x;

endfor.

Shell rendezés

A beszúrásos módszer lépésenként finomított változata. A tömbnek csak minden d-edik elemét vizsgáljuk, azaz d lépésközzel végezzük el a beszúrásos rendezést. Ha a rendezettség nem alakul ki, akkor csökkentjük a

Rendezés közvetlen kiválasztással és cserével (minimum [maximum] elven alapuló rendezés)

Egy adott résztömbben (kezdetben a teljes tömb) megkeressük a legkisebb (legnagyobb) elemet, és ezt tesszük az első helyre. A következő lépésben a második elemtől kezdve vizsgáljuk és ismét a legkisebb (legnagyobb) elemet visszük előre, és így tovább. A mindenkori legkisebb elem keresése lineáris kereséssel történik.

Megjegyzés: A n jelöli a számsorozat hosszát, az a[1..n] tömb tárolja a számsorozat elemeit.

for i := 1 to n-1 do

Általánosan az a[j]-t hasinlítjuk az a[j+1]-gyel, ahol j = 1, 2 … , n-1. Valahányszor úgy találjuk, hogy a[j] >

a[j+1], felcseréljük őket. A tömb elejéről induló rendezésnél a legnagyobb elem biztosan a helyére fog kerülni.

A többi elem azonban még nem feltétlenül került a végleges helyére. (A tömb végéről induló rendezésnél mindig a legkisebb elem kerül biztosan az adott rendezési ciklusban a helyére.) A következő bejárásokban hasonlóképpen járunk el, és további elemek kerülnek a helyükre, ahhoz hasonlóan, ahogy a levegőbuborékok szoktak feljönni a víz felszínére. A rendezést folytatni kell mindaddig, míg a teljes tömb rendezett nem lesz.

Előfordulhat, hogy a tömb már menet közben, a rendezési ciklus vége előtt, rendezetté válik, esetleg eleve

72

Created by XMLmind XSL-FO Converter.

rendezett volt. Ezt onnan vehetjük észre, hogy az adott rendezési ciklusban nem történik csere. Ha megjegyezzük az utolsó csere helyét (ucs), akkor a következő bejárás csak addig megy.

u := n;

Van két rendezett tömbünk, a[1..n] és b[1..m]. Ezeket kell összefésülni egy c[1..n+m] tömbbe. Az i változó az a tömb, a j pedig a b tömb elemein fog lépegetni. Az a[i] és b[j] elemek közül mindig a kisebbiket tesszük a c tömbbe, majd lepünk egyet abban a tömbben, amelyből „kikerült" az az elem, amelyet a c tömbbe helyeztünk.

i := 1; rekurzívan visszavezethető a c[1..n/2] és a c[n/2+1..n] tömbszakaszok külön-külön történő rendezésére, és az ezt követő összefésülésükre. Az általános rendez eljárást egy c[i..j] tömbszakasz rendezésére kell megírnunk. A feladat akkor triviális, ha a rendezendő tömbszakasz egyelemű (i = j).

Megjegyzés: A rendez eljárást kezdetben a teljes tömbre hívjuk meg, rendez (c[1..n]);. Az összefésül eljárás az a és b segédtömböket használja.

endprocedure nagyobbak mögötte legyenek). Egy i, illetve egy j változót a tömb elejére, illetve végére állítunk. Kezdetben az elem, amely szerint a szétválogatás történik (továbbiakban kulcselem), nyilván az i-edik pozícióban van.

Miközben i áll, jövünk előre j-vel (magunk mögött hagyva a kulcselemnél nagyobb elemeket), míg nem találunk egy a[j]-t, ami kisebb, mint az a[i]. Felcserélve egymás közt az a[i]-t és az a[j]-t, a kulcselem hátra kerül a j-edik pozícióba, a nála kisebb elem pedig előre az i-edikbe. Ekkor „váltás” történik. Miközben j áll, i-vel megyünk hátrafele (magunk mögött hagyva a kulcselemnél kisebb elemeket), míg nem találunk egy a[i]–t, ami nagyobb, mint az a[j]. Ismét felcserélve egymás közt az a[i]-t és az a[j]-t, a kulcselem visszakerül az i-edik pozícióba, a nála nagyobb elem pedig hátra a j-edikbe. Most újra j-vel jövünk előre (1. eset), majd ismét i-vel megyünk hátra (2. eset) mindaddig, amíg i és j találkozik. A kulcselem mindig az álló index irányában van, az előre lepegető j a kulcselemnél nagyobb, a hátrafele mozgó i pedig a kulcselemnél kisebb elemeket hagyja maga mögött. A kulcselem a helyét, amelyet a rendezett számsorozatban foglalna el, ott találja meg, ahol találkoznak az i es j indexek.

Ez az algoritmus is rekurzív elven működik. Szétválogatjuk az aktuális tömbszakasz (a[i..j]) elemeit a szakasz első eleme (az a[i] kulcselem) szerint, majd folytatjuk a rendezést a szakasz kulcselem előtti, illetve mögötti elemei rendezésével.

Megjegyzés: A rendez eljárást kezdetben a teljes tömbre hívjuk meg, a szétválogat függvény adja vissza a helyére került kulcselem pozícióját.

74

A számítógép számára a feladat meghatározását programozásnak nevezzük. A programozás valamilyen a programozási nyelv segítségével történik. A programozási nyelv a számítástechnikában használt olyan, az ember által is olvasható és értelmezhető utasítások sorozata, amivel közvetlenül, vagy közvetve (például gépi kódra fordítás után) közölhetjük a számítógéppel egy adott feladat elvégzésének módját.

A programozás egy összetett folyamat, melynek célja és eredménye a programok előállítása. A programozás lépései:

• a megoldandó feladat megfogalmazása, definiálása;

• a megfelelő algoritmus kiválasztása, megtervezése;

• az algoritmus logikai szerkezetének megtervezése;

• az algoritmus szerkezeti lebontása;

• az algoritmus kódolása;

• a kész program futtatása, tesztelése;

• a dokumentáció elkészítése;

• a program karbantartása, felügyelete, nyomon követése.

A programozási nyelveket történeti fejlődésük alapján sokféleképpen lehet osztályozni, csoportosítani. A programnyelvek változásának egy-egy fontosabb állomását a programozási nyelvek generációjának nevezzük.

A programozási nyelvek első generációja, a legalacsonyabb szintű programnyelv, a gépi (bináris) kód. A gépi kódot tulajdonképpen nem is lehet igazi programnyelvnek tekinteni, hiszen erre a klasszikus értelemben vett programnyelvi elemek (utasítások, vezérlőszerkezetek, kifejezések) nem jellemzőek.

A számítógéppel való kapcsolat megteremtésének a legközvetlenebb módja viszont a gépi nyelv használata. A gépi nyelvek a számítógépek speciális műszaki tulajdonságait használják ki. Ez az a nyelv, amelyet a processzor közvetlenül megért. A gépi kódú programok az adott számítógép típusokhoz kötődnek, azok más felépítésű

In document Bevezetés az informatikába (Pldal 77-82)