2. Perustietorakenteet

Samankaltaiset tiedostot
811312A Tietorakenteet ja algoritmit II Perustietorakenteet

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

18. Abstraktit tietotyypit 18.1

A TIETORAKENTEET JA ALGORITMIT

4. Perustietorakenteet

Pino S on abstrakti tietotyyppi, jolla on ainakin perusmetodit:

Algoritmit 1. Luento 4 Ke Timo Männikkö

811312A Tietorakenteet ja algoritmit IV Perustietorakenteet

Algoritmit 2. Luento 2 To Timo Männikkö

Tietorakenteet ja algoritmit Johdanto Lauri Malmi / Ari Korhonen

Tietorakenteet ja algoritmit - syksy

811312A Tietorakenteet ja algoritmit Kertausta kurssin alkuosasta

Algoritmit 2. Luento 7 Ti Timo Männikkö

Algoritmit 1. Luento 3 Ti Timo Männikkö

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

Algoritmit 2. Luento 2 Ke Timo Männikkö

Tietorakenteet ja algoritmit

Algoritmit 1. Luento 5 Ti Timo Männikkö

811312A Tietorakenteet ja algoritmit, , Harjoitus 5, Ratkaisu

Tietorakenteet ja algoritmit

4. Perustietorakenteet: pino, jono ja lista

811312A Tietorakenteet ja algoritmit, , Harjoitus 5, Ratkaisu

Tarkennamme geneeristä painamiskorotusalgoritmia

Tieto- ja tallennusrakenteet

(a) L on listan tunnussolmu, joten se ei voi olla null. Algoritmi lisäämiselle loppuun:

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

Tehtävän V.1 ratkaisuehdotus Tietorakenteet, syksy 2003

Algoritmit 1. Demot Timo Männikkö

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

Aikavaativuuden perussäännöt

Algoritmit 2. Luento 6 Ke Timo Männikkö

811312A Tietorakenteet ja algoritmit Kertausta jälkiosasta

Algoritmit 1. Luento 9 Ti Timo Männikkö

Algoritmit 1. Luento 6 Ke Timo Männikkö

Abstraktit tietotyypit. TIEA341 Funktio ohjelmointi 1 Syksy 2005

Tietorakenteet, laskuharjoitus 3, ratkaisuja

Algoritmit 2. Luento 4 To Timo Männikkö

Algoritmit 1. Demot Timo Männikkö

58131 Tietorakenteet ja algoritmit (kevät 2013) Kurssikoe 1, , vastauksia

Algoritmit 1. Luento 1 Ti Timo Männikkö

Algoritmit 2. Luento 5 Ti Timo Männikkö

Algoritmit 1. Luento 12 Ke Timo Männikkö

58131 Tietorakenteet ja algoritmit (kevät 2014) Uusinta- ja erilliskoe, , vastauksia

Algoritmit 1. Luento 12 Ti Timo Männikkö

TIETORAKENTEET JA ALGORITMIT

Ohjelmoinnin perusteet Y Python

Tietorakenteet ja algoritmit

1. (a) Seuraava algoritmi tutkii, onko jokin luku taulukossa monta kertaa:

58131 Tietorakenteet ja algoritmit (kevät 2016) Ensimmäinen välikoe, malliratkaisut

2. Seuraavassa kuvassa on verkon solmujen topologinen järjestys: x t v q z u s y w r. Kuva 1: Tehtävän 2 solmut järjestettynä topologisesti.

811312A Tietorakenteet ja algoritmit V Hash-taulukot ja binääriset etsintäpuut

811312A Tietorakenteet ja algoritmit, , Harjoitus 7, ratkaisu

ALGORITMIT 1 DEMOVASTAUKSET KEVÄT 2012

Algoritmit 2. Luento 6 To Timo Männikkö

Algoritmit 2. Luento 4 Ke Timo Männikkö

Hakupuut. tässä luvussa tarkastelemme puita tiedon tallennusrakenteina

Luku 3. Listankäsittelyä. 3.1 Listat

Algoritmit 1. Luento 7 Ti Timo Männikkö

Ohjelmoinnin peruskurssien laaja oppimäärä

TIE Tietorakenteet ja algoritmit 1. TIE Tietorakenteet ja algoritmit

Algoritmit 2. Luento 3 Ti Timo Männikkö

Algoritmit 2. Demot Timo Männikkö

Algoritmit 1. Luento 10 Ke Timo Männikkö

lähtokohta: kahden O(h) korkuisen keon yhdistäminen uudella juurella vie O(h) operaatiota vrt. RemoveMinElem() keossa

Ohjelmoinnin perusteet Y Python

4 Tehokkuus ja algoritmien suunnittelu

Algoritmit 2. Luento 3 Ti Timo Männikkö

Ohjelmoinnin peruskurssien laaja oppimäärä

TIEA341 Funktio-ohjelmointi 1, kevät 2008

1.1 Tavallinen binäärihakupuu

Ohjelmoinnin perusteet Y Python

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

811312A Tietorakenteet ja algoritmit I Johdanto

TIEA341 Funktio-ohjelmointi 1, kevät 2008

Rakenteiset tietotyypit Moniulotteiset taulukot

Tietorakenteet ja algoritmit

Ohjelmoinnin perusteet Y Python

Algoritmit 1. Luento 14 Ke Timo Männikkö

Algoritmit 2. Luento 5 Ti Timo Männikkö

1 Erilaisia tapoja järjestää

Osoitin ja viittaus C++:ssa

Kannan vektorit siis virittävät aliavaruuden, ja lisäksi kanta on vapaa. Lauseesta 7.6 saadaan seuraava hyvin käyttökelpoinen tulos:

Tietorakenteet, laskuharjoitus 10, ratkaisuja. 1. (a) Seuraava algoritmi tutkii, onko jokin luku taulukossa monta kertaa:

(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ä.

Ohjelmoinnin peruskurssi Y1

Tietorakenteet, laskuharjoitus 7, ratkaisuja

D B. Harvat hakemistot. Harvat hakemistot

Ohjelmoinnin perusteet Y Python

Tietorakenteet, laskuharjoitus 4,

Algoritmit 1. Luento 8 Ke Timo Männikkö

Olio-ohjelmointi Syntaksikokoelma

A TIETORAKENTEET JA ALGORITMIT

Opintojakso TT00AA11 Ohjelmoinnin jatko (Java): 3 op. Tietorakenneluokkia 2: HashMap, TreeMap

7/20: Paketti kasassa ensimmäistä kertaa

Ohjelmoinnin perusteet Y Python

Oikeasta tosi-epätosi -väittämästä saa pisteen, ja hyvästä perustelusta toisen.

Fibonacci-kasoilla voidaan toteuttaa samat operaatiot kuin binomikasoilla.

5. Hash-taulut ja binääriset etsintäpuut

Tietorakenteet ja algoritmit

815338A Ohjelmointikielten periaatteet Harjoitus 5 Vastaukset

Transkriptio:

2. Perustietorakenteet Tässä osassa käsitellään erilaisia perustietorakenteita, joita algoritmit käyttävät toimintansa perustana. Aluksi käydään läpi tietorakenteen abstrakti määritelmä. Tämän jälkeen käsitellään pino, jono sekä linkitetty lista. Käsiteltävät tietorakenteet liittyvät olennaisesti tiedon tallentamiseen sekä hakemiseen. Teoksessa [Cor] käsitellään tässä esitettäviä luvussa 10. 2.1. Tietorakenteen abstrakti määritelmä Erilaiset joukot ovat keskeisessä roolissa sekä tietotekniikassa että yleisemmin matematiikassa. Siinä missä matemaattiset joukot ovat staattisia, algoritmien käyttämät joukot voivat kasvaa, pienentyä tai muuttua sisällöltään ajan funktiona. Kutsutaan näitä yhteisnimityksellä dynaamiset joukot. Jotta algoritmit pääsevät muokkaamaan dynaamista joukkoa, on joukon ensin toteutettava tiettyjä operaatioita kuten esimerkiksi lisää alkio tai poista alkio. Dynaamiseen joukkoon liittyvät operaatiot kokonaisuudessaan määrittävät rajapinnan jota algoritmi voi käyttää joukkoa muokatessaan. Tämän alustuksen kautta saadaan tietorakenteelle seuraava abstrakti määritelmä: Tietorakenne on äärellinen dynaaminen joukko, joka toteuttaa rajapintanaan sarjan operaatioita joiden kautta algoritmi voi muokata joukkoa. Ylläolevassa määritelmässä on kaksi ydinasiaa. Ensimmäinen on tietorakenteen määrittely joukkona, seuraten siten tiivisti yleisempää matemaattista käytäntöä. Toinen on sarja operaatioita, joka muodostaa tietorakenteen rajapinnan. Usein tietorakenteen suunnittelu alkaa tämän rajapinnan määrittelyllä (operaatioiden rakenne ja tehokkuusvaatimukset), jonka jälkeen yksittäiset operaatiot toteutetaan tietorakenteeseen vaatimuksia noudattaen. Huomaa, että ylläoleva määritelmä on siis abstrakti eikä vielä ota millään tavalla kantaa siihen, miten tietorakenne käytännössä toteutetaan. Tämän takia määritelmä eroaa teknologialäheisemmistä määritelmistä kuten esim. tietty tapa säilöä ja järjestellä dataa tietokoneen muistissa. Tietorakenteen sisäinen rakenne koostuu joukosta alkioita, joilla on sisäinen rakenne ja joihin voidaan toteutetussa rakenteessa yksikäsitteisesti osoittaa osoittimella. Oliosuuntautuneen ajattelun mukaisesti voidaan ajatella että kukin alkio on olio ja että sisäinen rakenne muodostuu joukosta kenttiä. Tyypillisesti yhtä alkiota edustava olio sisältää seuraavat kentät: Avain, joka identifioi yksittäisen alkion tietorakenteen sisällä. Usein avainten tulee olla järjestettyjä (totally ordered set), jolloin kahdelle avaimelle pätee joukon sisällä täsmälleen yksi seuraavista ehdoista: a < b, a = b tai a > b. Tämä mahdollistaa avainten keskinäisen vertailun. Järjestysdata, joka määrittelee miten alkiot suhtautuvat toisiinsa joukon sisällä. Operaatiot voivat muokata tätä dataa muokatessaan tietorakenteen sisäistä rakennetta. Satelliittidata, joka on talletettuna alkioon mutta jolla ei ole merkitystä tietorakenteen sisäisen toiminnan kannalta. Tietorakenteeseen liittyvä operaatiot voidaan korkealla tasolla jaotella kahteen kategoriaan: kyselyt jotka palauttavat tietoa rakenteesta muokkaamatta sitä, sekä muokkausoperaatiot jotka muuttavat joukon rakennetta. Operaation aikatehokkuus ilmaistaan joukon koon mukaan.

Joukossa jossa on n alkiota, tietyn operaation tehokkuus voi olla esim. O(n). Seuraavassa listataan yleisimpiä operaatioita. Huomaa että usein tietty algoritmi vaatii ainoastaan osan näistä operaatioista toteutetuiksi. ETSI(S,k) Kysely joka palauttaa olion osoittimen x joukosta S siten, että x.key = k, tai NIL jos haettua oliota ei ole tallennettuna joukkoon. Huomaa että osoitin x eroaa avaimesta k: Osoitin on alustaspesifinen keino osoittaa tiettyyn olioon joukossa ja avain on tietorakenteen sisäisesti uniikki tunniste. LISÄÄ(S,x) Muokkausoperaatio joka kasvattaa joukkoa S uudella elementillä jonka osoitin on x. Huomaa että uuteen olioon liittyvät arvot oletetaan alustetuiksi valideilla kentillä. POISTA(S,x) Muokkausoperaatio joka poistaa joukosta S elementin osoittimella x. Huomaa että operaatio käyttää osoitinta avaimen sijasta. MINIMI(S) Kysely monotonisesti järjestettyyn joukkoon S joka palauttaa osoittimen alkioon jonka avainarvo on pienin. MAKSIMI(S) Kysely monotonisesti järjestettyyn joukkoon S joka palauttaa osoittimen alkioon jonka avainarvo on suurin. SEURAAJA(S,x) Kysely, joka järjestettyjen avainten muodostamassa joukossa S palauttaa osoittimen alkioon joka seuraa alkiota osoittimella x. EDELTÄJÄ(S,x) Kysely, joka järjestettyjen avainten muodostamassa joukossa S palauttaa osoittimen alkioon joka edeltää alkiota osoittimella x. 2.2. Pino, jono ja lista Seuraavaksi esitellään kolme dynaamista joukkoa: pino, jono ja linkitetty lista, jotka toimivat johdantona tietorakenteisiin. Jokainen näistä tietorakenteista toteuttaa rakenteensa puolesta yllämainitut operaatiot hieman eri tavalla, joten operaatioiden lähempi tarkastelu auttaa tietorakenteiden erojen havainnollistamisessa. Pino (Stack) on dynaaminen joukko jolle POISTA-operaation kohdealkio on ennalta määrätty. Tämä johtuu pinon sisäisestä rakenteesta, joka muistuttaa fyysisten esineiden pinoamista. Pino toteuttaa niin kutsutun viimeiseksi sisään, ensimmäiseksi ulos (last in, first out, LIFO) menettelytavan alkioiden määrän muokkaamisessa. Pinolle määritelty LISÄÄ-operaatio on nimeltään PUSH, ja se lisää uuden alkion pinon huipulle. POISTA-operaatiota vastaa POP, joka poistaa yhden alkion pinon huipulta. Operaatioiden nimet viittaavat reaalimaailman malleihin pinoista, kuten esimerkiksi lautaspino johon lisätään lautasia huipulle sekä myös otetaan lautasia huipulta. Kuvassa 2.1 on havainnollistettu PUSH ja POP operaatiot, sekä pinon toteutus käyttäen indeksoitua taulukkoa. Taulukon indeksi S.head (top) osoittaa aina viimeisimpänä lisättyyn alkioon. Kun S.head = 0, pino on tyhjä, ja POISTA

operaation kutsuminen tässä tilanteessa johtaa pinon alivuotoon, joka on algoritmin sisällä käsiteltävä virhetilanne. Yhtäläisesti ylivuotoon johtava virhetilanne syntyy jos LISÄÄ operaatiota kutsutaan tilanteessa jossa S.head = n, eli kapasiteetiltaan n alkiota olevaan pinoon yritetään lisätä uutta alkiota. Huomaa että lisätilan dynaamista allokointia ei tässä esimerkkitilanteessa ole. Tässä toteutuksessa taulukon indeksit lähtevät arvosta 1; esimerkiksi C- kielisessä toteutuksessa olisi tarkoituksenmukaista käyttää taulukon ensimmäisenä indeksinä arvoa 0. Koodin muuntaminen tähän tapaukseen on suoraviivaista. Kuva 2.1. Pinon perusominaisuudet. Määritellään taulukolla toteutettuun pinoon liittyvät perusoperaatiot ylläolevien ominaisuuksien perusteella seuraavasti. Huomaa ettei pinon ylivuotoa käsitellä tässä esimerkissä. Riippumatta pinossa olevien alkioiden lukumäärästä kaikki operaatiot kuluttavat saman vakioajan. EMPTY(S) 1. if S.head == 0 2. return TRUE 3. else 4. return FALSE PUSH(S,x) 1. S.head = S.head + 1 2. S[S.head] = x POP(S) 1. if EMPTY(S) 2. error Alivuoto pinossa 3. else 4. S.head = S.head 1 5. return S[S.head + 1] #Lisäys #Poisto

Jono (Queue) on tietorakenne joka toteuttaa niinkutsutun ensimmäiseksi sisään, ensimmäiseksi ulos (first in, first out,fifo) menettelytavan alkioiden määrän muokkaamisessa. Jonon reaalimalli on mikä tahansa jono esim. ihmisiä, ja jonolla on pää (head) ja häntä (tail). POISTA operaation (DEQUEUE) osoitin on rakenteen puolesta määritelty aina jonon päähän, ja LISÄÄ operaatio (ENQUEUE) lisää uuden alkion jonon häntään. Kuva 2.2 havainnollistaa jonon toteutusta indeksoidulla taulukolla. Taulukolla on nyt kaksi erillisesti määriteltyä indeksiä. Indeksi Q.head osoittaa aina jonon päähän ja indeksi Q.tail jonon hännässä olevaan seuraavaan tyhjään paikkaan. Jonon oma attribuutti pituus määrittelee jonon kapasiteetin. Itse jono koostuu alkioista Q[head], Q[head + 1], Q[head + 2],..., Q[tail 1]. Jos Q[head] = Q[tail], jono on tyhjä, lisäksi tyhjän jonon alkutilanteelle pätee head = tail = 1. Paikkaa indeksillä Q[tail] ei voi täyttää, koska tällöin jonon päitä edustavat indeksit limittyvät ja jono tulkitaan tyhjäksi. Huomaa että taulukolla toteutettu jono voi kiertää taulukon lopusta sen alkupuolelle, eli indeksi 1 seuraa indeksiä n. Tässäkin toteutuksessa taulukon indeksit lähtevät arvosta 1. Kuten pinon tapauksessakin, koodin muuntaminen käyttämään taulukkoa, jonka indeksit alkavat arvosta 0, on suoraviivaista. Kuva 2.2. Jonon perusominaisuudet. Määritellään taulukolla toteutettuun jonoon liittyvät perusoperaatiot ylläolevien ominaisuuksien perusteella seuraavasti. Huomaa että jonoon liittyvissä LISÄÄ ja POISTA operaatioissa on mahdollisuus yli- ja alivuotoon, joita ei kuitenkaan seuraavissa listauksissa käsitellä. Käytännön ohjelmaa laadittaessa tällaiset tapaukset on luonnollisesti aina otettava huomioon. Myön jonon operaatiot kuluttavat saman vakioajan riippumatta jonossa olevien alkioiden lukumäärästä.

ENQUEUE(Q,x) #Lisäys 1. Q[Q.tail] = x 2. if Q.tail == Q.pituus 3. Q.tail = 1 4. else 5. Q.tail = Q.tail + 1 DEQUEUE(Q) #Poisto 1. x = Q[Q.head] 2. if Q.head == Q.pituus 3. Q.head = 1 4. else 5. Q.head = Q.head + 1 5. return x Linkitetty lista (Linked list) on tietorakenne jossa alkiot ovat lineaarisessa järjestyksessä. Toisin kuin aiemmissa taulukkopohjaisissa rakenteissa, linkitetyssä listassa lineaarisuus määräytyy jokaisessa alkiossa olevien osoittimien perusteella. Jokainen alkio sisältää osoittimen sekä listassa edellisenä että seuraavana olevaan alkioon, ja operaatiot mahdollistavat listan muokkaamisen osoittimien arvoja muuttamalla. Seuraavissa esimerkeissä kuvataan kahteen suuntaan linkitetyn listan toiminnallisuutta, tämä sekä kaksi muuta listatyyppiä ovat havainnollistettuna kuvassa 2.3. Kuva 2.3. Linkitetyn listan kolme toteutusvaihtoehtoa: Yhteen suuntaan (a), kahteen suuntaan (b) sekä renkaan muotoon (c) linkitetty lista. Linkitetyn listan alkio (eli solmu) sisältää kolme kenttää avain (key), osoitin edelliseen alkioon (previous) sekä osoitin seuraavaan alkioon (next) sekä mahdollisesti satelliittidataa. Jos alkiolle x pätee x.previous = NIL, alkio x on listan pää (head). Jos taas alkiolle x pätee x.next = NIL, alkio x on listan häntä (tail). Tietorakenteen sisäinen attribuutti L.head osoittaa listan päähän, ja jos L.head = NIL, lista on tyhjä. Operaatio LISTA_ETSI(L,k) etsii ei-järjestetystä listasta L ensimmäisen alkion jonka avaimen arvo on k yksinkertaisella lineaarisella hakumenetelmällä, ja palauttaa osoittimen tähän alkioon (NIL jos avainarvoa ei löydy). Käsitellessään n alkiota sisältävää listaa, ETSI_LISTA voi huonoimmassa tapauksessa joutua käymään kaikki listan alkiot yksi kerrallaan läpi. Näin ollen vaadittavien operaatioiden lukumäärä on suoraan verrannollinen listassa olevien alkioiden lukumäärään n.

Operaatio LISTA_LISÄÄ(L,x) lomittaa uuden alustetun alkion x listan päähän muuttamalla listan head[l] attribuuttia sekä edellisen päänä toimineen alkion sisäistä previous osoitinta. Koska listan päähän lisääminen tekee korkeintaan neljä sijoitusta ja yhden vertailun, se on vakiokestoinen operaatio. Myös tietyn avaimen lisääminen järjestämättömään listaan on vakiokestoinen operaatio, koska edellisen lisäksi on ainoastaan tehtävä uusi solmu, jonka avainkenttänä on lisättävä avain. Operaatio LISTA_POISTA(L,x) lomittaa alkion x ulos listasta L muokkaamalla sitä ympäröivien alkioiden osoittimia. Uudet osoittimet asetetaan osoittamaan ohi alkiosta x, jolloin se ei ole enää mukana listassa. Operaatio on vakiokestoinen, kun tiedetään poistettava solmu x. Sen sijaan poistettaessa listasta tietty avain, on ensin etsittävä solmu kutsumalla ensin LISTA_ETSI operaatiota jonka ansiosta tällöin operaatioiden lukumäärä on suoraan verrannollinen listassa olevien alkioiden lukumäärään n. Linkitetyn listan lisäys- ja poisto-operaatioiden suorituskykyä voidaan jonkin verran parantaa käyttämällä nk. vartioalkioita (sentinel) [Cor], joiden käsittely sivuutetaan tässä yhteydessä. LISTA_ETSI(L,k) 1. x = L.head 2. while x NIL and x.avain k 3. x = x.next 4. return x LISTA_LISÄÄ(L,x) 1. x.next = L.head 2. if L.head NIL 3. L.head.previous = x 4. L.head = x 5. x.previous = NIL LISTA_POISTA(L,x) 1. if x.previous NIL 2. (x.previous).next = x.next 3. else 4. L.head = x.next 5. if x.next NIL 6. (x.next).previous = x.previous Lähteet: [Cor] Cormen, T.H., Leiserson, C.E., Rivest, R.L., Stein, C. Introduction to Algorithms, 2 nd edition, The MIT Press 2001.