Download as pdf or txt
Download as pdf or txt
You are on page 1of 26

Algoritmin valintaan vaikuttavat

• lajiteltavien alkioiden lukumäärä

• lajiteltavien alkioiden järjestys

• alkioiden erityisominaisuudet (esim. kokonaisluvut)

• sisäinen (keskusmuisti) vai ulkoinen (levy) lajittelu eli järjestäminen

• tietorakenne.
Muistitilan analysointi

• Muistitilaa tarvitaan

– ohjelmakoodille

– käsiteltävälle datalle.

• Kiinteä osa muistitilasta

– ei riipu ongelman esiintymästä.

• vaihteleva osa muistitilasta

– esiintymän data, muuttujat, työtilat, aliohjelmakutsut jne.

• Muistitilan tarpeen laskenta voi olla yksinkertaisempaa kuin suoritusajan laskenta.


Tietorakenteet

• Algoritmin toteutus vaatii sopivan tietorakenteen.

• Ongelman tiedot, algoritmin tiedot, työtilat.

• Tallennustapa vaikuttaa suoritusaikaan ja muistitilan tarpeeseen.

• Tarkastellaan tietorakenteita abstrakteina tietotyyppeinä.


Abstrakti tietotyyppi (engl. abstract data type)

• Tietotyypin kuvaus, jossa ei oteta kantaa tyypin toteutukseen tai toteutuskieleen.


• Koostuu

– operaatioista: tyypin liittymä ympäristöön (lisäys, poisto, . . . )

– tietorakenteesta: tyypin sisäinen tiedonesitystapa (esim. taulukko tai dynaami-


nen muistinvaraus eli linkitys)

• Tietorakenne voidaan vaihtaa ilman, että operaatioita tarvitsee muuttaa.


• Käyttäjä ei ole kiinnostunut tietorakenteesta vaan tietotyypin tarjoamista operaa-
tioista.
• Jos tietorakenne sisältää useita tietoja, yksittäistä tietoa sanotaan alkioksi tai tie-
tueeksi.
• Abstrakti tietotyyppi voidaan toteuttaa kapseloituna luokkana.

– operaatiot metodeiksi

– tietorakenne private-tyyppiseksi attribuutiksi

Tällä luennolla käsitellään esimerkkeinä abstrakteista tietotyypeistä pino, jono ja lista.


Pino ja jono ovat listan erikoistapauksia.

Tietorakenteesta puhuessa viitataan yleensä abstraktin tietotyypin toteutukseen, esim.


taulukko tai linkitetty lista.
Pino (engl. stack)

https://www.cs.usfca.edu/˜galles/visualization/SimpleStack.html

• Lisättävä alkio menee aina pinon päälle.

• Poistettava alkio otetaan aina pinon päältä.

• Last-In-First-Out (LIFO) periaate.

• Lisäykset ja poistot alkio kerrallaan.


• push(): lisää alkion pinon päälle, mikäli pinoon mahtuu vielä uusi alkio

• pop(): (palauttaa ja) poistaa pinon päällimmäisen alkion, mikäli pinossa on alkioita

• size(): alkioiden lukumäärä (≥ 0) pinossa

• isEmpty(): palauttaa totuusarvon true, jos pino on tyhjä ja totuusarvon false, jos
pinossa ainakin yksi alkio

• top(): palauttaa päällimmäisen alkion sitä poistamatta, mikäli pinossa on alkioita


Esimerkki:
Luodaan tyhjä pino, push(A) push(B) push(C)
jossa tilaa korkein- size()=1 size()=2 size()=3
taan 4 alkiolle. isEmpty()=false push(D)
isEmpty=true size()=4

D
C
B B
A A A

top()=D pop()=D pop()=C pop()=A


size=4 size=3 size=2 size=0
pop()=B isEmpty=true
D size=1
C C
B B
A A A
Pinon käyttökohteita

• Ohjelmointikielet: Kun aliohjelmaa kutsutaan, paluuosoite ja osa parametreista tal-


lennetaan pinoon.

• Käyttöjärjestelmät: Kun suorittimessa tapahtuu keskeytys, osa rekistereistä tallen-


netaan pinoon.

Esimerkki

• Merkkijonossa sulkumerkkejä []()

• Testataan, sulkeutuvatko sulut oikein

• Oikein: ( ) ( [ ( ) ( ) ] ( ) )

• Väärin: [ ( ) ( ] )
| ( [ ( | ) ] { ( ) } )
pohja pino huippu merkkijono
Sulkujen tarkistaminen

1. Pino tyhjäksi, asetutaan merkkijonon alkuun.

2. Jos merkkijono loppu ja pino tyhjä, lopetetaan (sulut oikein).

3. Merkkijonosta seuraava merkki a.

4. Jos a jokin vasen sulku, niin push(a).

5. Jos a jokin oikea sulku ja pinon päällä saman tyyppinen vasen sulku, niin pop().
Muuten lopetetaan (sulut väärin).

6. Jos a muu merkki, ei tehdä mitään.

7. Toistetaan kohdasta 2.
Esimerkki

pohja pino huippu merkkijono


| | ( ) ( [ ( ) ( ) ] { ( ) } )
| ( | ) ( [ ( ) ( ) ] { ( ) } )
| | ( [ ( ) ( ) ] { ( ) } )
| ( | [ ( ) ( ) ] { ( ) } )
| ( [ | ( ) ( ) ] { ( ) } )
| ( [ ( | ) ( ) ] { ( ) } )
| ( [ | ( ) ] { ( ) } )
| ( [ ( | ) ] { ( ) } )
| ( [ ( | ) ] { ( ) } )
| ( [ | ] { ( ) } )
| ( | { ( ) } )
| ( { | ( ) } )
| ( { ( | ) } )
| ( { | } )
| ( | )
| |
Esimerkki
while((merkki = seuraava(merkin_arvo) ) != lausekkeen_loppumerkki){
Aritmeettiset lausekkeet voidaan esit- switch (merkki) {
tää postfix-muodossa siten, että ope- case numero: push(pino, merkin_arvo);
raattori seuraa aina operandiensa (las- break;
kutoimituksessa käytettävät numerot) default: b = top(pino), pop(pino);
a = top(pino), pop(pino);
jäljessä. Tällä merkintätavalla ei tarvi- switch (merkki) {
ta sulkuja. case ’+’: push(pino, a+b);
break;
case ’-’: push(pino, a-b);
break;
Esimerkiksi infix-muodossa oleva case ’*’: push(pino, a*b);
((a + b)c − d/e)f + g(h − i) break;
esitettäisiin postfix-muodossa case ’/’: if (b != 0)
push(pino, a/b);
ab + cde/ − f ghi − + else
VIRHE;
ja infix-muodossa oleva ((1+2)∗4)+3 }
olisi postfix-muodossa 1 2 + 4 ∗ 3+. }
}

| | 1 2 + 4 * 3 +
Aliohjelma seuraava() käy pinoa hyö- | 1 2 | + 4 * 3 +
dyntämällä lauseketta läpi vasemmalta | 3 | 4 * 3 +
oikealle ja palauttaa operaattorimerkin | 3 4 | * 3 +
tai numeron tai merkin, joka ilmoittaa, | 12 | 3 +
että ollaan päästy lausekkeen loppuun. | 12 3 | +
| 15 |

Kukin pino-operaatio vie vakioajan O(1), n alkiota, algoritmin aikavaativuus O(n).


Pino voidaan toteuttaa esim. taulukon avulla
(vrt. https://www.cs.usfca.edu/˜galles/visualization/StackArray.html)

• Alkioita n kappaletta.
• Tallennetaan alkiot taulukkoon taulu[0...n-1] (taulukon koko mahdollisesti tätä
suurempi).
• Ensimmäisenä pinoon tallennettava alkio asetetaan (pinon pohjalle) paikkaan taulu[0],
toinen paikkaan taulu[1] jne.
• Pinon huipulla oleva (päällimmäinen) alkio on paikassa taulu[n-1].
• Ennen push-operaatiota testataan, että pino ei ole täysi.
(alkiota lisätessä taulu[n]=alkio, n kasvaa yhdellä)
• Ennen pop-operaatiota testataan, että pino ei ole tyhjä.
(alkiota palauttaessa ja poistaessa n pienenee yhdellä, alkio=taulu[n])
• Pino-operaatiot ovat vaativuudeltaan O(1).
• Pinon käyttö algoritmissa ei kasvata oleellisesti algoritmin aikavaatimusta.

On mahdollista tallentaa kaksi pinoa samaan taulukkoon.


Pino voidaan toteuttaa myös linkitettynä rakenteena (dynaamisesti)
(vrt. https://www.cs.usfca.edu/˜galles/visualization/StackLL.html)

• Alkiot tallennetaan tyyppiä PinoSolmu oleviin tietueisiin, joissa viite pinossa kyseisen
alkion alla olevan alkion PinoSolmu-tietueeseen (linkitys pinon huipulta kohtii pohjaa
ja viite päällimmäiseen alkioon).

public class Pino { public void push(Object k) {


private class PinoSolmu { PinoSolmu uusi
Object key; = new PinoSolmu(k,top);
PinoSolmu next; top = uusi;
private PinoSolmu }
(Object k,
PinoSolmu seur) { public Object pop() {
key = k; PinoSolmu pois = top;
next = seur; top = pois.next;
} return pois.key;
} }
private PinoSolmu top;
Pino() { public boolean empty() {
top = null; return (top == null);
} }
}
Jono (engl. queue)

https://www.khanacademy.org/computer-programming/queue-visualization/47347064774

• Lisättävä alkio menee aina jonon loppuun.

• Poistettava alkio otetaan aina jonon alusta.

• First-In-First-Out (FIFO) periaate.

• Lisäykset ja poistot alkio kerrallaan.


• enqueue(): lisää alkion jonon loppuun, mikäli jonossa on vielä tilaa

• dequeue(): palauttaa ja poistaa ensimmäisen alkion jonosta, mikäli jono ei ole tyhjä

• size(): alkioiden lukumäärä (≥ 0) jonossa

• isEmpty(): palauttaa totuusarvon true, jos jono on tyhjä ja totuusarvon false, jos
jonossa ainakin yksi alkio

• front(): mikäli jono ei ole tyhjä, palauttaa jonon ensimmäisen alkion (keula-alkion)
sitä poistamatta.
Esimerkki:
Luodaan tyhjä jono, jossa tilaa korkeintaan 4 alkiolle. isEmpty=true

enqueue(A), size()=1, isEmpty()=false A

enqueue(B), size()=2, enqueue(C), size()=3, A B C

enqueue(D), size()=4, front()=A A B C D

dequeue()=A, size()=3 B C D

dequeue()=B, size()=2, dequeue()=C, size()=1, D

dequeue()=D, size()=0, isEmpty()=true


Jonon käyttökohteita

• vuoroaan odottavien tehtävien jono moniajokäyttöjärjestelmissä

• I/O-komentojen jono käyttöjärjestelmän levypalvelimessa

• tapahtumajonot (hiiren ja näppäimistön painallukset) graafisten käyttöliittymien


ohjausohjelmistoissa

• todellisten jonojen mallintaminen simulointiohjelmistoissa.


Jono voidaan toteuttaa esim. taulukon avulla
(vrt. https://www.cs.usfca.edu/˜galles/visualization/QueueArray.html)

• Alkioita n kappaletta.

• Tallennetaan alkiot taulukkoon taulu[0...n-1].

• Jonon ensimmäinen alkio taulu[0].

• Jonon viimeinen alkio taulu[n-1].

• Ennen enqueue-operaatiota testataan, että jono ei ole täysi.

• Ennen dequeue-operaatiota testataan, että jono ei ole tyhjä.


Kiertävä taulukko
• Kun jono on täyttynyt taulukon viimeiseen paikkaan saakka, asetetaan seuraava al-
kio taulukon paikkaan 0.
• Jonon ensimmäisen alkion indeksi f (front).
• Viimeistä seuraavan paikan indeksi b (operaatio back) osoittaa aina tyhjää paikkaa.
• Kun jonon ensimmäinen alkio poistetaan, siirtyy jonon ensimmäinen paikka aske-
leen eteenpäin.
• Kun taulukon loppu ohitetaan, siirtyy uusi jonon alkukohta paikkaan 0.
• Tyhjässä jonossa f=b; täydessä jonossa f=0 ja b=QMAX-1 tai f>0 ja f-b=1.

• enqueue: varmistetaan, että jono ei ole täysi; taulu[b] = alkio;


jos b < QMAX-1, niin b kasvaa yhdellä, muuten b = 0.
• dequeue: varmistetaan, että jono ei ole tyhjä; alkio = taulu[f];
jos f < QMAX-1, niin f kasvaa yhdellä, muuten f = 0.
• Jono-operaatiot ovat vaativuudeltaan O(1).
• Jonon käyttö algoritmissa ei kasvata oleellisesti algoritmin aikavaatimusta.
Jono voidaan toteuttaa myös linkitettynä rakenteena (dynaamisesti) (ks. https://www.
cs.usfca.edu/˜galles/visualization/QueueLL.html)

• Viitteet/linkitys jonon ensimmäisestä alkiosta kohti viimeistä.

• Osoittimet jonon ensimmäiseen ja viimeiseen alkioon.


Lista

• Lista l voi olla tyhjä.

• Epätyhjässä listassa on ensimmäinen alkio first(l) ja viimeinen alkio last(l).

• Jos listassa l on vain yksi alkio, niin first(l) = last(l).

• Listan ensimmäinen (ja mahdollisesti viimeinen) alkio ovat välittömästi käytettävis-


sä.

• Listan alkiot muodostavat täydellisesti järjestetyn joukon.

– Jokaisella alkiolla a, paitsi viimeisellä, on välitön seuraaja succ(a).


– Jokaisella alkiolla a, paitsi ensimmäisellä, on välitön edeltäjä pred(a)./

• Listan jokaiselle alkiolle voidaan antaa järjestysnumero.


– Alkion first(l) järjestysnumero on 0 (tai 1).
– Jos alkion a järjestysnumero on i, alkiolla succ(a) se on i+1 ja alkiolla pred(a)
se on i-1 (edellyttäen, että alkiot ovat olemassa).
Listaoperaatioita

• Listan kulku eteenpäin: siirrytään alkiosta a alkioon succ(a) (paitsi jos a viimeinen).

• Listan kulku taaksepäin: siirrytään alkiosta a alkioon pred(a) (paitsi jos a ensim-
mäinen).

• Alkion lisäys listaan: lisäys ensimmäiseksi tai viimeiseksi yleensä erikoistapauksena.

• Alkion poisto listasta: esimmäisen tai viimeisen poisto yleensä erikoistapauksena.

• Alkion käyttöönotto (saanti, engl. access): alkion tietoja käytetään tai muutetaan

– alkio löytyy kulkemalla listaa eteenpäin tai taaksepäin

– alkiota ei poisteta listasta

– ensimmäisen ja viimeisen alkion saannit erikoistapauksina.


• Listan läpikäynti etenevästi: suoritetaan jotkin toimenpiteet alkioille järjestyksessä
alusta loppuun

– alkion a = first(l) saanti

– suoritetaan toimenpiteet alkiollea

– seuraavan alkion succ(a) saanti

– suoritetaan toimenpiteet alkiolle a

– jatketaan, kunnes viimeinenkin alkio last(l) käsitelty.

• Listan läpikäynti takenevasti: vastaavasti kuin etenevä, mutta lopusta alkuun.

Listan läpikäynnin sovelluksena on esimerkiksi haku listasta.


• Listojen yhdistäminen

– Kahden listan l1 ja l2 alkiot viedään kolmanteen listaan l3.

∗ Listat l1 ja l2 voidaan poistaa tai säilyttää ennallaan.

– katenointi on yhdistämisen erikoistapaus; esim. lista l2 liitetään l1 perään.

• Listan perustaminen ja alustaminen tyhjäksi.

• Listan tyhjennys.

• Muistitilan varaaminen listalle.

• Muistilan vapauttaminen.

Pino ja jono ovat erikoistapauksia listasta.


Tietorakenteita
jonon, pinon ja listan toteuttamiseksi
Taulukko: Dynaaminen muistinvaraus (linkitetty lista):

• alkioita ei voi (helposti) lisätä • alkioita voidaan lisätä


(koko ennalta määrätty) (kunnes muisti loppuu)

• alkiot tietokoneen muistissa • alkiot tietokoneen muistissa


peräkkäin (ehkä) erillään

• mikä tahansa alkio aina • alkiot saadaan “peräkkäin”


saatavissa (random access) (serial access)

You might also like