Algoritmit ja tietorakenteet / HL Copyright Hannu Laine

Samankaltaiset tiedostot
Tietorakenteet ja algoritmit

Tietorakenteet ja algoritmit

Algoritmit 1. Luento 4 Ke Timo Männikkö

Tietorakenteet ja algoritmit

Algoritmit 1. Luento 3 Ti Timo Männikkö

A TIETORAKENTEET JA ALGORITMIT

Tietorakenteet ja algoritmit

Pino S on abstrakti tietotyyppi, jolla on ainakin perusmetodit:

Tieto- ja tallennusrakenteet

Tietorakenteet ja algoritmit

Algoritmit 2. Luento 2 To Timo Männikkö

Tietorakenteet ja algoritmit

Algoritmit ja tietorakenteet / HL 1 Copyright Hannu Laine. Lista. Yleistä

Algoritmit 2. Luento 2 Ke Timo Männikkö

Algoritmit 1. Demot Timo Männikkö

Rakenteiset tietotyypit Moniulotteiset taulukot

811312A Tietorakenteet ja algoritmit II Perustietorakenteet

TIETORAKENTEET JA ALGORITMIT

Algoritmit 2. Luento 3 Ti Timo Männikkö

18. Abstraktit tietotyypit 18.1

815338A Ohjelmointikielten periaatteet Harjoitus 6 Vastaukset

Algoritmit 2. Luento 3 Ti Timo Männikkö

Algoritmit 1. Luento 9 Ti Timo Männikkö

Sisällys. 18. Abstraktit tietotyypit. Johdanto. Johdanto

Kaksiloppuinen jono D on abstrakti tietotyyppi, jolla on ainakin seuraavat 4 perusmetodia... PushFront(x): lisää tietoalkion x jonon eteen

Algoritmit 1. Demot Timo Männikkö

Tietorakenteet ja algoritmit Johdanto Lauri Malmi / Ari Korhonen

useampi ns. avain (tai vertailuavain) esim. opiskelijaa kuvaavassa alkiossa vaikkapa opintopistemäärä tai opiskelijanumero

Tietueet. Tietueiden määrittely

tietueet eri tyyppisiä tietoja saman muuttujan arvoiksi

Tietorakenteet ja algoritmit - syksy

Ohjelmoinnin perusteet Y Python

Tietorakenteet ja algoritmit

815338A Ohjelmointikielten periaatteet Harjoitus 3 vastaukset

815338A Ohjelmointikielten periaatteet Harjoitus 5 Vastaukset

Algoritmit 1. Luento 6 Ke Timo Männikkö

2. Perustietorakenteet

Tietorakenteet, laskuharjoitus 3, ratkaisuja

Algoritmit 2. Luento 6 To Timo Männikkö

Dynaamiset tietorakenteet

Luento 4 (verkkoluento 4) Aliohjelmien toteutus

Muita linkattuja rakenteita

Luento 4 (verkkoluento 4) Aliohjelmien toteutus

Harjoitustyö: virtuaalikone

Merkkijono määritellään kuten muutkin taulukot, mutta tilaa on varattava yksi ylimääräinen paikka lopetusmerkille:

1.1 Pino (stack) Koodiluonnos. Graafinen esitys ...

Aliohjelmatyypit (2) Jakso 4 Aliohjelmien toteutus

Tietorakenteet ja algoritmit

3. Muuttujat ja operaatiot 3.1

Algoritmit 2. Luento 13 Ti Timo Männikkö

Jakso 4 Aliohjelmien toteutus

Luku 6. Dynaaminen ohjelmointi. 6.1 Funktion muisti

Ohjelmoinnin perusteet Y Python

Lisää pysähtymisaiheisia ongelmia

LOAD R1, =2 Sijoitetaan rekisteriin R1 arvo 2. LOAD R1, 100

Sisällys. 3. Muuttujat ja operaatiot. Muuttujat ja operaatiot. Muuttujat. Operaatiot. Imperatiivinen laskenta. Muuttujat. Esimerkkejä: Operaattorit.

Kirjoita oma versio funktioista strcpy ja strcat, jotka saavat parametrinaan kaksi merkkiosoitinta.

Algoritmit 1. Luento 5 Ti Timo Männikkö

Sisältö. 2. Taulukot. Yleistä. Yleistä

Abstraktit tietotyypit. TIEA341 Funktio ohjelmointi 1 Syksy 2005

Algoritmit 2. Luento 4 To Timo Männikkö

Yleistä. Nyt käsitellään vain taulukko (array), joka on saman tyyppisten muuttujien eli alkioiden (element) kokoelma.

Lyhyt kertaus osoittimista

Osoitin ja viittaus C++:ssa

Jakso 4 Aliohjelmien toteutus

Luento 4 Aliohjelmien toteutus

Luku 3. Listankäsittelyä. 3.1 Listat

Muistin käyttö. Muistin käyttö. Muistin käyttö. Muistin käyttö. Muistin käyttö. Muistin käyttö. Muistin käyttö C-ohjelmassa

815338A Ohjelmointikielten periaatteet Harjoitus 7 Vastaukset

Ohjelmoinnin perusteet Y Python

Sisältö. 22. Taulukot. Yleistä. Yleistä

Monipuolinen esimerkki

Algoritmit 2. Luento 5 Ti Timo Männikkö

Ohjelmoinnin perusteet Y Python

Ohjelmassa muuttujalla on nimi ja arvo. Kääntäjä ja linkkeri varaavat muistilohkon, jonne muuttujan arvo talletetaan.

Algebralliset tietotyypit ym. TIEA341 Funktio ohjelmointi 1 Syksy 2005

Tietorakenteet ja algoritmit syksy Laskuharjoitus 1

Jokaisella tiedostolla on otsake (header), joka sisältää tiedostoon liittyvää hallintatietoa

Olio-ohjelmointi Syntaksikokoelma

Ohjelmoinnin perusteet Y Python

Ohjelmointi 1 Taulukot ja merkkijonot

ALGORITMIT 1 DEMOVASTAUKSET KEVÄT 2012

Se mistä tilasta aloitetaan, merkitään tyhjästä tulevalla nuolella. Yllä olevassa esimerkissä aloitustila on A.

Uolevin reitti. Kuvaus. Syöte (stdin) Tuloste (stdout) Esimerkki 1. Esimerkki 2

Ohjelmointi 2. Jussi Pohjolainen. TAMK» Tieto- ja viestintäteknologia , Jussi Pohjolainen TAMPEREEN AMMATTIKORKEAKOULU

Ohjelmoinnin perusteet Y Python

Luku 8. Aluekyselyt. 8.1 Summataulukko

Ohjelmoinnin peruskurssi Y1

Tarkennamme geneeristä painamiskorotusalgoritmia

Algoritmit 2. Luento 6 Ke Timo Männikkö

Chapel. TIE Ryhmä 91. Joonas Eloranta Lari Valtonen

811120P Diskreetit rakenteet

OHJE KILPIEN LISÄÄMISESTÄ ATJN KILPIVARASTOON

Sekvenssi: kokoelma peräkkäisiä alkioita (lineaarinen

Ohjelmoinnin perusteet Y Python

Tietotekniikan valintakoe

58131 Tietorakenteet ja algoritmit (syksy 2015)

TAMPEREEN TEKNILLINEN YLIOPISTO Digitaali- ja tietokonetekniikan laitos. Harjoitustyö 4: Cache, osa 2

Toinen harjoitustyö. ASCII-grafiikkaa 2017

(p j b (i, j) + p i b (j, i)) (p j b (i, j) + p i (1 b (i, j)) p i. tähän. Palaamme sanakirjaongelmaan vielä tasoitetun analyysin yhteydessä.

Transkriptio:

1 Pino ja jono Yleistä Pino Pino ja jono ovat abstrakteja tietotyyppejä, joilla on yleistä käyttöä. Pino ja jono ovat listan erikoistapauksia. Kummassakin tapauksessa erona on se, että tietotyypin operaatiofunktioita on rajoitettu. Pino ja jono ovat lineaarisen listan erikoistapauksia, joissa vain osa listan operaatioista on sallittuja. Määritelmä. Pino on järjestettyjen alkioiden kokoelma, jossa lisäykset tapahtuvat aina loppuun ja samoin alkion otto on mahdollista vain lopusta. Tässä tapauksessa loppua kutsutaan pinon huipuksi (top). Pinon tapauksessa alkioiden järjestyksen määrää syöttöjärjestys. Pinon operaatiot ovat: initialize (alustaa pinon) push (vie alkion pinon päälle) pop (ottaa alkion pinon päältä) is_empty (testaa, onko pino tyhjä) Pinon sovelluksia. Pinoa voidaan käyttää mitä erilaisimpien probleemoiden ratkaisuissa. Periaatteessa pino on tietoalkioiden säiliö, josta saadaan tiedot ulos käännetyssä järjestyksessä siihen nähden kuin ne on säiliöön viety. Voidaan myös sanoa, että pinoon viimeksi viety alkio saadaan ulos ensimmäiseksi. Siksi pinoa kutsutaan LIFO:ksi (Last In First Out list). Yhtä hyvin voidaan sanoa, että pinoon ensiksi viety alkio saadaan ulos viimeiseksi (First In Last Out : FILO). Yksinkertaisimmillaan pinoa voidaan käyttää tiedon järjestyksen kääntämiseen. Jos esimerkiksi pitää kääntää merkkijonon merkit päinvastaiseen järjestykseen, se voidaan tehdä siten, että viedään kaikki merkkijonon merkit ensimmäisestä alkaen ensin merkkien pinoon. Sen jälkeen ne otetaan pois pinosta ja viedään takaisin alkuperäiseen merkkijonoon taas ensimmäisestä alkaen. Jos olisi kirjoitettava ohjelma, joka selvittää, onko syötetty merkkijono palindromi vai ei, se voitaisiin tehdä siististi käyttämällä kolmea merkkipinoa. Tutkittavan merkkijonon merkit vietäisiin ensin kahteen merkkipinoon, merkkipinoon 1 ja 2. Sen jälkeen siirrettäisiin kaikki merkit pinosta 2 pinoon 3. Alkuperäinen merkkijono on palindromi, jos pinosta 1 ja pinosta 3 tasatahtiin otettavat merkit ovat loppuun saakka (kunnes pinot tyhjenevät) samoja. Kun monista osista rakentuva laite puretaan, saattaa olla vaikeuksia koota laite uudelleen. Asiaa helpottaa, jos laaditaan ohjelma, joka käyttää pinoa. Kun laite puretaan, syötetään ohjelmalle aina irrotettavan osan tunnus, nimi tai koodi. Ohjelma vie osan tiedot pinoon. Kun laitetta kootaan, ohjelmalta kysytään, mikä osa asennetaan seuraavaksi. Ohjelma ottaa osan koodin pinosta. Näin tulee varmistettua, että osat kootaan päinvastaisessa järjestyksessä kuin ne on purettu. Postfix-muodossa olevan laskulausekkeen laskemisessa käytetään hyväksi pinoa. RPNlaskimissa käytetään tällaista merkintätapaa. Silloin esimerkiksi laskulauseke (2+3)/5 merkitään 2 3 + 5 /. Postix-muodossa olevan lausekkeen tulkinta on koneellisesti paljon helpompi kuin infix-muodossa olevan lausekkeen tulkinta. Kysymys on siitä, että postfixmerkintäisen lausekkeen laskennassa voidaan aina edetä selkeästi vasemmalta oikealle ja

2 päätös tehtävästä toimenpiteestä voidaan tehdä välittömästi sen perusteella, mitä lausekkeesta on juuri löytynyt. Lausekkeen laskenta perustuu seuraaviin yksinkertaisiin sääntöihin: 1. Jos lausekkeesta löytyy operandi, se viedään pinoon. 2. Jos lausekkeesta löytyy operaattori, pinosta otetaan kaksi operandia, niille tehdään operaattorin mukainen operaatio ja tulos viedään pinoon. Kun koko lauseke on käyty läpi, pinossa on lausekkeen lopputulos. Sellaisen ohjelman kirjoittaminen, joka laskee infix-muotoisen aritmeettisen lausekkeen, joka voi sisältää myös ennalta määräämättömän määrän sulkumerkkejä, ei ole aivan yksinkertainen juttu. Näin siinä tapauksessa, jos ei ole tietoa pinon soveltamismahdollisuudesta (eikä rekursiosta). Edellä todettiin, että postix-merkintäisen lausekkeen laskenta puolestaan on hyvin suoraviivaista. Siksi yksinkertaisin menettely infix-merkintäisen lausekkeen laskemiseksi onkin kaksivaiheinen: 1. Muunnetaan infix-merkintäinen lauseke ensin postfix-merkintäiseksi. 2. Lasketaan sitten saatu postfix-merkintäinen lauseke. Edellä todettiin, että postfix-merkintäisen lausekkeen laskemisessa tarvittiin operandien pinoa. Infix-merkintäisen lausekkeen muuntamisessa postfix-merkintäiseksi tarvitaan puolestaan operaattorien pinoa. Tässä prosessissa käydään infix-merkintäistä lauseketta läpi vasemmalta oikealle seuraavan logiikan mukaan: 1. Jos infix-lausekkeesta löytyy operandi, se viedään suoraan posfixlausekkeen perään. 2. Jos infix-lausekkeesta löytyy operaattori, se viedään operaattorien pinoon. Sitä ennen kuitenkin pinosta otetaan pois kaikki sellaiset operaattorit, jotka ovat vahvempia tai yhtä vahvoja kuin tämä infix-lausekkeesta nyt löytynyt. Kaikki pinosta otetut operaattorit viedään postfix-lausekkeen loppuun. 3. Lopuksi pinosta otetaan pois kaikki operaattorit ja ne viedään postfixlausekkeen loppuun. Huomautus. Myös sulkumerkkejä voidaan pitää operaattoreina ja niille voidaan antaa asianmukaiset vahvuudet. Pinorakennetta käytetään tietokoneissa hyväksi esimerkiksi parametrien ja paikallisten muuttujien tilanvarauksessa funktioiden yhteydessä. Tällä saavutetaan etu, että funktio voi kutsua edelleen seuraavaa funktiota ja se taas seuraavaa jne. Kun funktiokutsusta palataan, kutsunut funktio saa taas käyttöönsä oman data-alueensa pinossa, sillä kutsutun funktion dataalue poistetaan pinon päältä. Parametrien ja paikallisten muuttujien varaaminen pinosta tekee mahdolliseksi myös rekursiivisten funktioiden laatimisen (näihin palataan myöhemmin). Pinon avulla on helposti toteutettavissa myös yksinkertainen rivieditori, jossa rivin lopusta voidaan poistaa merkkejä Backspace-painikkeella. Merkin syöttö tarkoittaa push-operaatiota, ja Backspace-painikkeen painallus pop-operaatiota. Myös ikkunoitu valikkojärjestelmä, jossa valikosta voidaan valita alavalikko, siitä edelleen alavalikon alavalikko jne, voidaan toteuttaa valikoiden pinona. Tällöin valikoista päästään kätevästi takaisin samaa reittiä alkuvalikkoon. Pinon taulukkototeutus 1: Listan taulukkototeutuksen yhteydessä mainittiin eräänä haittapuolena, että alkioiden lisäys ja poisto edellytti tietojen siirtoa taulukossa. Kun pinon tapauksessa alkioiden järjestys määräytyy aina syöttöjärjestyksestä, ja kun otto voi tapahtua vain lopusta, ei tällaista haittatekijää ole. Siksi taulukkototeutus pinolle on erittäin kätevä varsinkin silloin, kun pinon maksimikoko on etukäteen tiedossa.

3 Liitteenä on C-kielinen toteutus pinosta. Siinä pääohjelma, jolla pinoa voidaan testata, on sellainen, että se lukee näppäimistöltä merkin. Jos merkki on kirjain, ohjelma vien merkin pinoon. Jos syötetty merkki on 1, niin ohjelma ottaa merkin pinosta ja tulostaa sen näyttöön. Testauksen ja kokeilun selkiyttämiseksi pinolle on tehty myös ylimääräinen operaatio print, joka tulostaa ruutuun koko pinon sisällön. Vaikka esimerkkitoteutus on merkkipino, on huomattava, että toteutus on täysin riippumaton pinottavien alkioiden tyypistä. Muutos saadaan aikaan määrittelemällä tietotyyppi Titem uudelleen (poikkeuksena on print-funktio, jossa oletetaan, että alkion tyyppi on merkki). Myös pääohjelma olisi mahdollista saada riippumattomaksi pinottavien alkioiden tyypistä, jos siinä sovellettaisiin abstraktiota pinottaviin alkioihin. Tämä tarkoittaisi että, pinottavat alkiot tulisi toteuttaa abstrakteina tietotyyppeinä, joilla on omat operaatiofunktiot lue_alkio ja tulosta_alkio. Taulukkototeutuksen ideana on, että pinoon vietävät alkiot talletetaan taulukkoon. Pinon huippu (kenttä top) ilmoittaa aina sen paikan taulukossa, jossa sijaitsee viimeksi pinoon viety alkio. Huipun arvo -1 merkitsee tyhjää pinoa. Pinon tallennusrakenne on silloin seuraavan kuvan mukainen. Tstack array top 3 2 1 0 Abstraktin tietotyypin käyttö on toteutuksesta riippumaton Seuraavassa demonstroidaan, että abstraktin tietotyypin käyttö on riippumaton abstraktin tietotyypin sisäisestä toteutuksesta niin kauan, kuin tietotyypin liityntärajapinta (tietotyypin nimi ja operaatiofunktioiden prototyypit) pysyvät muuttumattomina. Liitteenä on myös pinon taulukkototeutus 2. Siinä taulukon alkioihin viitataan osoittimilla, eikä indeksillä niin kuin taulukkototeutuksessa 1 tehtiin. Listauksesta nähdään, että tietotyypin Tstack määrittely on nyt erilainen ja tämän seurauksena myös operaatiofunktioiden toteutukset ovat erilaisia kuin taulukkototeutuksessa 1. Siitä huolimatta sovellus (pääohjelma) on täsmälleen sama kuin taulukkototeutuksessa 1. Sovellukseen on siis vaihdettu uusi komponentti (pino) siten, että sovelluksessa ei ole tarvinnut tehdä mitään muutosta. Sovellus on vain käännetty uudelleen ja siihen on linkattu uusi pino. Tässä ratkaisussa käytetty pinon tietojen tallennusrakenne on seuraavan kuvan mukainen. Ajatuksena on, että osoitin top sisältää pinon päällimmäisen alkion osoitteen taulukossa (NULL edustaa tyhjää pinoa). Osoitin minpointer osoittaa aina taulukon ensimmäistä alkiota ja maxpointer sen viimeistä alkiota. Näitä käytetään taulukon ylivuodon estämiseen ja sen tilanteen tunnistamiseen, kun pinosta otettiin viimeinen alkio.

4 Tstack array top maxpointer minpointer Taulukkototeutus 2 on tehokkaampi kuin taulukkototeutus 1, koska nyt tietojen hakemiseen ja viemiseen taulukkoon ei käytetä indeksointia, joka käännetyssä koodissa merkitsee kertolaskun suoritusta. Taulukkototeutuksessa 2 lisäyksessä ja poistossa on vain osoittimen kasvatus tai vähennys alkion koolla eli niissä ei tarvita kertolaskua. Näissä molemmissa taulukkototeutuksissa on ongelmana taulukon kiinteä koko. Taulukon koko määräytyy jo käännösaikana ja sitä ei voida kasvattaa ajon aikana. Tämä ongelma voidaan korjata siirtymällä dynaamisen taulukon käyttöön. Yksinkertaisimmillaan asia voitaisiin toteuttaa siten, että funktiossa initialize_stack annettaisiin parametrina alkioiden maksimimäärä ja samassa funktiossa varattaisiin taulukko, johon mahtuu tämä määrä alkioita. Tällaisessa ratkaisussa pinotietueessa tulee säilyttää myös taulukon koko, jotta pushoperaatiossa voidaan testata, vieläkö pinoon mahtuu alkioita. Tämä olisi kuitenkin vain pieni askel parempaan. Siitä seuraisi myös, etä pinon interface olisi nyt erilainen alustusoperaation kohdalla. Tässä ratkaisussa alustusoperaatiolla olisi int-tyyppinen parametri, kun sillä aikaisemmin ei ollut parametriä. Tämän takia pinoa käyttävien sovellusten alustusfunktion kutsu olisi muutettava uuteen muotoon C-kieltä käytettäessä. Tämä on vakava puute, jos puhutaan komponenttiajattelusta ja komponenttien vaihtokelpoisuudesta. C++-kieltä käytettäessä ei tässä tapauksessa tarvitsisi muuttaa pinoa käyttäviä sovelluksia. Tämä johtuu funktioiden ylikuormitusmahdollisuudesta. Uudessa pinon toteutuksessa voitaisiin säilyttää myös vanha operaatiofunktio alustukseen, jossa parametriä ei ole. Tämän funktion sisällä käytettäisiin taulukon kokona sopivaa oletusarvoa. Huomautus 1. Myös C++:n mahdollisuus antaa parametreille oletusarvo, tarjoaisi saman mahdollisuuden. Dynaamisen taulukon avulla voidaan toteuttaa myös automaattisesti tarvittaessa kasvava pino. Silloin ei kannata antaa alkukokoa parametrina, vaan varataan joku kiinteä koko aluksi. Kun tämä tila on käytetty voidaan varata uusi isompi taulukko. Kaikki jo tallennetut tiedot siirretään silloin vanhasta taulukosta uuteen ja alkuperäinen taulukko vapautetaan. Näin saadaan taas uuden alkion lisääminen onnistumaan. Kaikki tämä logiikka voidaan tehdä pushoperaatiossa, jolloin käyttäjän ei tarvitse huolehtia siitä. Käyttäjän kannalta uusi piirre näkyy vain siinä, että push-operaatio onnistuu aina, koska tila ei lopu kesken. Perusideana on silloin,

5 että jos push-operaatiossa todetaan, että taulukossa ei ole enää tilaa uudelle alkiolle, tehdään seuraavat asiat: 1. Varataan uusi suurempi taulukko 2. Siirretään tiedot vanhasta taulukosta uuteen 3. Vapautetaan vanha taulukko 4. Päivitetään pinotietueen kentät siten, että ne vastaavat uutta tilannetta Dynaamista taulukkoa käytettäessä pinon rakenne näyttää seuraavalta: Tstack array top size Tämä vastaa taulukkototeutusta 1 dynaamisella taulukolla. Voitaisiin myös nyt käyttää vain osoittimia taulukkoon alkioita vietäessä ja sieltä haettaessa, jolloin saataisiin dynaamisella taulukolla toteutettu vastine taulukkototeutukselle 2. Molemmissa näissä ratkaisumalleissa siis alkioiden määrällä ei ole periaatteessa ylärajaa, koska dynaamisesta muistista voidaan varata suurempi taulukko aina tarvittaessa niin kauan kuin koneessa riittää muistia. Hintana sille, että alkioiden määrälle ei ole ylärajaa on se, että tietoja joudutaan siirtämään paikasta toiseen tilan kasvatuksen yhteydessä.. Tämän takia kannattaakin yleensä tilan lisäyksen yhteydessä varata sitä, enemmän kuin yhdelle alkiolle kerrallaan. Myöhemmin palaamme vielä yhteen ratkaisumalliin, jossa tästä tietojen siirtohinnasta päästään eroon. Sellainen ratkaisu saadaan aikaan käyttämällä dynaamisesti linkattua dynaamisesti varattu listaa tallennusrakenteena. Jono Määritelmä. Jono on järjestettyjen alkioiden kokoelma, jossa lisäykset tapahtuvat aina loppuun ja jossa alkio voidaan ottaa vain listan alusta. Lisäksi jonossa alkioiden järjestyksen määrää syöttöjärjestys. Jonon operaatiot ovat: initialize (alustaa jonon) enqueue (vie alkion jonon loppuun) dequeue (ottaa alkion jonon alusta) is_empty (testaa, onko jono tyhjä) Jonon sovelluksia. Myös jonoa voidaan käyttää monien erilaisten probleemoiden ratkaisuissa. Jono on tietoalkioiden säiliö, josta tiedot saadaan ulos siinä järjestyksessä kuin ne on sinne viety. Jono siis ikään kuin säilyttää alkioiden järjestyksen. Voidaan myös sanoa, että jonoon ensiksi viety alkio saadaan ulos ensimmäisenä. Siksi jono kutsutaan myös

6 FIFOksi (First In First Out: FIFO). Yhtä hyvin voidaan sanoa, että jonoon viimeksi viety alkio saadaan jonosta viimeisenä (LILO Last In Last Out). Yksinkertaisimmillaan jonoa voidaan käyttää tiedon säilyttämiseen siten, että ne pääsevät myöhemmin käsittelyyn siinä järjestyksessä kun ovat tulleet sisään. Pinon sovelluksena mainittiin, että palindromi-probleema voidaan ratkaista käyttämällä kolme pinoa. Palindromi-probleema voidaan ratkaista kätevästi myös käyttämällä yhtä pinoa ja yhtä jonoa. Tutkittavan merkkijonon merkit viedään pinoon ja jonoon. Sitten ruvetaan ottamaan merkkejä rinnakkain molemmista. Jos molemmista tulee loppuun saakka samoja merkkejä, alkuperäinen merkkijono on palindromi, koska pinosta merkit tulevat käänteisessä järjestyksessä ja jonosta alkuperäisessä järjestyksessä Abstraktia tietotyyppiä jono voidaan käyttää myös erilaisten odotusjonojen simulointiohjelmissa (esimerkiksi pankin palvelupisteiden odotusjonojen simulointi). Usean käyttäjän tietokoneiden käyttöjärjestelmissä käytetään jonoja kaikille yhteisten palvelujen tarjoamisessa (tulostusjonot, suoritusvuoroa odottavat taskit, i/o-pyynnöt levylle jne.). Myös puskureiksi kutsutut tietorakenteet ovat oikeastaan jonoja. Esimerkiksi BIOSnäppäimistöpuskuri on selkeästi jonorakenne, joka on toteutettu samantapaisella periaatteella kuin seuraavassa kuvattava jonon taulukkototeutus. Jonon taulukkototeutus 1: Taulukkototeutus sopii melko hyvin myös jonolle, koska siinäkin lisäykset tehdään aina listan loppuun. Se, että ottaminen tapahtuu aina listan alusta, johtaa kyllä tietojen siirtotarpeeseen, jos halutaan, että jonon ensimmäinen alkio on aina taulukon ensimmäisessä alkiossa. Tällöin jonoon jäljelle jääviä tietoja joudutaan siirtämään aina askel eteenpäin taulukossa. Tämä on kylläkin havainnollista, koska se vastaa esimerkiksi oikeaa henkilöiden jonoa, jossa ihmiset siirtyvät askeleen eteenpäin, kun yhtä asiakasta on palveltu jonon alusta. Yksinkertaisimmillaan tällainen ratkaisu saadaan aikaan määrittelemällä tietotyyppi Tqueue seuraavalla tavalla #define SIZE 100 typedef struct { Titem array[size]; int n; // alkioiden määrä jonossa }; Tästä voitaisiin kehittää dynaamista taulukkoa käyttävä versio, jossa alkioiden lukumäärällä ei olisi ylärajaa. Silloin tietueen määritelmä olisi kuten alla: typedef struct { Titem *array;; int n; // alkioiden määrä jonossa int size; // taulukon tämänhetkinen koko }; Tässä versiossa tietoa siirrettäisiin paikasta toiseen, jokaisessa otto-operaatiossa ja silloin kun tilaa kasvatettaisiin. Jonon taulukkototeutus 2: Yllämainituissa toteutuksissa tietoa siis siirretään aina jonosta otettaessa. Tästä päästään eroon, kun sallitaan, että jonon alku voi olla missä kohtaa taulukkoa tahansa, ja että jono voi jatkua taulukon lopusta taulukon alkuun. Tällaista jonon toteutusta sanotaan renkaaksi. Siinä pidetään kirjaa missä kohtaa taulukossa on jonon alku ja

7 missä kohtaa loppu. Ratkaisu yksinkertaistuu, jos pidetään erikseen kirjaa myös jonossa kulloinkin olevien alkioiden määrästä. Liitteenä on C-kielinen toteutus jonosta. Siinä pääohjelma, jolla jonoa voidaan testata, on samantapainen kuin pinon testausohjelma. Se siis lukee näppäimistöltä merkin. Jos merkki on kirjain, ohjelma vie merkin jonoon. Jos syötetty merkki on 1, niin ohjelma ottaa merkin jonosta ja tulostaa sen näyttöön. Testauksen ja kokeilun selkiyttämiseksi myös jonolle on tehty ylimääräinen operaatio print, joka tulostaa ruutuun koko jonon sisällön. Taulukkototeutuksen ideana on se, että jonoon vietävät alkiot talletetaan taulukkoon. Jonon tietokenttä last ilmoittaa aina sen paikan taulukossa, jossa sijaitsee viimeksi jonoon viety alkio. Arvo -1 merkitsee tyhjää jonoa. Tietokenttä first ilmoittaa jonon ensimmäisen alkion paikan taulukossa. Jonoon viemisen yhteydessä viedään aina kentän last ilmoittamaa paikkaa seuraavaan paikkaan. Jonosta otettaessa otetaan aina kentän first ilmoittamasta paikasta. Mikäli first tai last arvoa kasvatettaessa joudutaan taulukon ulkopuolelle, arvo asetetaan taulukon alkuun. Kenttä number_of_items ilmoittaa jonossa olevien alkioiden lukumäärän. Tqueue array first last number_of_items Myös tästä versiosta voidaan tehdä toteutus dynaamisella taulukolla, jossa siis ei ole ylärajaa alkioiden ylärajalle ja jossa tietoa ei siirretä otettaessa. Tietoa on kuitenkin edelleen siirrettävä taulukon tilaa kasvatettaessa. Myös jonosta tullaa vielä näkemään uusi versio, jossa tästäkin siirrosta päästään eroon dynaamisesti linkatulla aja varatulla listatoteutuksella. Abstrakti tietotyyppi toisen komponenttina Uusia abstrakteja tietotyyppejä voidaan rakentaa käyttäen hyväksi jo olemassa olevia tietotyyppejä. Esimerkkinä käsitellään prioriteettijono. Prioriteettijono on jono, jossa alkioihin liittyy prioriteetti. Kun alkio viedään jonoon, se viedään jonon loppuun, jos jonossa olevilla alkioilla on kaikilla sama tai korkeampi prioriteetti kuin uudella alkiolla. Uusi alkio viedään jonon alkuun, jos jonossa ei ole yhtään alkiota, jolla on korkeampi tai sama prioriteetti. Sääntönä on, että uusi alkio ohittaa jonossa kaikki sellaiset alkiot, joilla on matalampi prioriteetti kuin uudella. Prioriteettijono voidaan toteuttaa usealla eri tavalla. Tässä käsitellään toteutusta, jossa prioriteettijono rakennetaan erillisistä tavallista jonoista.

8 Esimerkissä prioriteetteja voi olla kolme (1, 2 ja 3). Toteutuksen ohjelmalistaus on liitteenä. Siinä käytetyn tietotyypin Tpriqueue rakenne selviää seuraavista määrittelyistä. typedef struct { Tqueue queue1; Tqueue queue2; Tqueue queue3; } Tpriqueue;