Tietorakenteet ja algoritmit Merkintöjen tulkintoja *++Pstack->top = item *Pstack->top++ = item (*Pstack->top)++ *(Pstack++)->top = item *(++Pstack)->top = item Lisää pinon toteutuksia Dynaaminen taulukko Itsestään kasvava (ja kutistuva) pino Enum tyyppi Jonon määritelmä Jonon sovelluksia Jonon toteutustapoja Yksinkertainen taulukkototeutus Rengaspuskuritoteutus Prioriteettijono 1
Lisää pinon toteutuksia Olemme nähneet kaksi erilaista pinon toteutusta. Niissä molemmissa on käytetty kiinteän kokoista taulukkoa. Pinon toteutukset ovat muuten, hyviä ja tehokkaita, mutta niissä on kiinteän koon ongelma. Jos taulukolle varattu kiinteä tila loppuu kesken, pinoon ei enää voi lisätä alkioita. Esimerkkipinoissamme push-funktio palauttaa NOT_OK. Jos ohjelmoija on varannut mahdollisimman ison taulukon, edellisen ongelman poistuminen ei ole kuitenkaan taattu ja voi olla niin, että pino käyttää tarpeettoman paljon muistia myös silloin, kun alkioita on pinossa vähän. Kiinteän koon ongelma voidaan poistaa käyttämällä dynaamista taulukkoa. Taulukon koko voitaisiin päättää ajonaikana esimerkiksi initialize_stack funktiossa (tällöin pinon interface muuttuisi, jos tästä vaihtoehdosta ei tehtäisi uutta funktiota, esim. initialize_stack_with_size). Dynaamista taulukkoa käytettäessä voidaan toteuttaa jopa automaattisesti kasvava pino. Seuraavassa tutustutaan tähän periaatteeseen. 2
Pinon toteutus dynaamisella taulukolla 1 Vertaa tätä osan 6 sivun 11 ratkaisuun. #define INCR_SIZE 4 typedef... Titem; typedef struct { Titem* array; int size; int top; } Tstack; Käytetään indeksointia taulukon alkioiden osoittamiseen. Stack segment or other Tstack array size 8 top 1 Dynamic memory b a 7 6 3 45 2 1 0 3
Funktioiden toteutusperiaatteet automaattisesti kasvavalla pinolla Automaattisesti kasvava pino saadaan, kun Power Point osan 6 sivun 11 pinoratkaisun eli Monisteen osan 4 Esimerkin 1 ratkaisun kahden funktion eli initialize-stack ja push toimintaa muutetaan seuraavasti. Funktion intialize_stack muutokset Varataan tilaa taulukolle vakion INCR_SIZE (alkioiden määrä) verran. Alustetaan myös Tstack tietueen kenttä size vakiolla INCR_SIZE. Funktion push muutokset Testataan onko taulukossa vielä tilaa lisättävälle alkiolle. Jos kaikki tila on jo varattu tehdään seuraavat toimenpiteet: 1) varataan tila uudelle suuremmalle taulukolle, johon mahtuu size + INCR_SIZE alkiota. 2) Siirretään jo syötetyt alkiot tähän uuteen taulukkoon 3) Poistetaan vanha pienempi taulukko muistista 4) Päivitetään array osoitin ja size kenttä. Lisätään lisättävä tieto uuteen taulukkoon kuten ennen. 4
Pinon toteutus dynaamisella taulukolla 2 #define INCR_SIZE 4 typedef... Titem; typedef struct { Titem* maxpointer; Titem* top; Titem* array; } Tstack; Käytetään osoittimia taulukon alkioiden osoittamiseen. Tstack maxpointer top Stack segment or other array Dynamic memory b a 7 6 3 45 2 1 0 5
Jonon määritelmä (Queue) Määritelmä. Jono on järjestettyjen alkioiden joukko, jossa lisäykset tapahtuvat aina loppuun ja jossa alkio voidaan ottaa vain 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ä) FIFO Vastaavat funktioiden prototyypit voisivat olla void initialize_queue (Tqueue *pqueue); Tboolean enqueue( Tqueue *pqueue, Titem item); Tboolean dequeue( Tqueue *pqueue, Titem *pitem); int is_empty(const Tqueue* pqueue); void print_queue (const Tqueue *pqueue); // apufunktio testaukseen 6
Jonon sovelluksia Jono säilyttää järjestyksen Palindromiprobleeman ratkaisu pinolla ja jonolla Erilaiset simulointitehtävät Service line Waiting line Käyttöjärjestelmissä Print queues Disk access Kaikki yhteiset resurssit moniajojärjestelmissä Näppäimistöpuskuri (ja muut puskurit) Hakemistorakenteen tulostus tasoittain Jne. 7
Palindromiprobleema pinolla ja jonolla #include stack.h #iinclude queue.h int onko_palindromi(const char* mrk_jono) { Tstack pino; Tqueue jono; // initialisoi pino ja jono // vie merkkijonon merkit pinoon ja jonoon for ( i = 0 ; i < strlen(mrk_jono) ; i++) { push(&pino, mrk); enqueu(&jono, mrk); } // Ota merkit tasatahtiin pinosta ja jonosta while(!is_empty(&pino) { pop(pino, &mrk1); dequeu(&jono, mrk2); if(mrk1!= mrk2) return 0; } return 1; } 8
Jonon erilaisia toteutustapoja 1. Yksinkertainen taulukkototeutus Taulukon koko on vakio Tiedon siirtämistä tarvitaan alkion poistoissa Yksinkertainen ja havainnollinen toteutus 2. Yksinkertainen taulukkototeutus dynaamisella taulukolla Taulukkoa voidaan kasvattaa ajonaikana automaattisesti Tiedon siirtämistä tarvitaan alkion poistoissa Tiedon siirtoa tarvitaan myös tilan kasvatuksessa 3. Rengaspuskuri kiinteäkokoisella taulukolla Taulukon koko on vakio Tiedon siirtämistä ei tarvita 4. Rengaspuskuri dynaamisella taulukolla Taulukkoa voidaan kasvattaa ajonaikana automaattisesti Tiedon siirtämistä ei tarvita alkion poistoissa Tiedon siirtoa tarvitaan tilan kasvatuksessa 5. Taulukoiden käyttö pointtereilla ilman indeksointia Tehokkaampi toteutus. Voidaan käyttää tapauksissa 1-4 6. Dynaamisesti linkattu listatoteutus Käsitellään myöhemmin 9
Yksinkertainen taulukkototeutus indeksoinnilla #define N 8 typedef... Titem; typedef struct { Titem array[n]; int n; } Tqueue; Täydellinen toteutus verkossa (Käytetään harjoituksen 7 pohjana) Edut: Yksinkertainen Havainnollinen Haitat: Kiinteä koko Poistossa tarvitaan tiedon siirtoa Tqueue array n a b c 3 10
Rengaspuskuritoteutus #define N 8 typedef... Titem; typedef struct { Titem array[n]; int first; int last; int no_of_items; } Tqueue; Täydellinen toteutus verkossa (Esimerkki 4, Moniste 4) Kuvassa tilanne, kun syötetty ensin a, b, c, d, e, f, g h Sitten poistettu kaksi alkiota ja sitten lisätty i Tqueue array first last no_of_items 0 1 2 3 4 5 6 7 i b c d e f g h 2 0 7 11