/* taulukko.h */ /****************************************************************************/ /* ** T A U L U K K O . H ** ** Yleisen dynaamisen Taulukko-luokan toteutus templaten avulla ** ** Tekijät: Vesa Lappalainen ** Ohjelmointikurssi 1996 ** Tehty: 04.02.1996 ** Muutettu: ** Mitä muutettu: ** ** ** Tässä tiedostossa on määrittely luokalle cPerusTaulukkoa ** ja tästä peritylle luokalle cTaulukko. ** ** Esimerkiksi Osotintaulukko kannattaa periä cPerustaulukosta ** ja esitellä sinne sitten lisää metodit: (ks. ptaulukk.h) ** lisaa ** korvaa ** poista_alkiot ** ** ** Käyttö esim: ** ** cTaulukko luvut(7); ** luvut.lisaa(10); ** luvut.lisaa(20); ** luvut.lisaa(175); ** for (int i=0; i|-----| ** ------ | 10 | ** |-----| ** | 20 | ** |-----| ** |175 | ** |-----| ** | ?? | ** |-----| ** | ?? | ** |-----| ** | ?? | ** |-----| ** | ?? | ** |-----| ** ** ** cTaulukko(int koko=0) ** - taulukon luominen, jos koko = 0, ei luoda alkiot-taulukkoa ** ** ~cTaulukko() ** - taulukon hävittäminen, ** ** const char *lisaa(const cTYPE &uusi); ** - lisätään uusi alkio. Jos tila loppuu, yritetään kasvattaa tilaa. ** ** const char *korvaa(int i,const cTYPE &uusi); ** - korvataan i:s alkio uudella ja palautetaan NULL ** Jos i väärin, ei tehdä mitään (pal virhe). ** ** const cJasen &anna(int i) const ** - otetaan i:s alkio. Jos i väärin, otetaan viim. alkio. ** Jollei ole viimeistäkään, palautetaan virhealkio. ** Alkiota voidaan muuttaa, kun otetaan alkiosta kopio ** anna-metodilla, muutetaan kopion tietoja ja laitetaan takaisin ** korvaa-metodilla. ** ** int lkm() const ** - palauttaa taulukon alkioiden määrän ** ** int max_lkm() const ** - palauttaa taulukon tämän hetkisen maksimikoon ** ** int Muutettu() const ** - palauttaa 1, mikäli taulukkoa on muutettu talletusten jälkeen ja ** 0 muuten. ** ** void talletettu() ** - muutetaan talletettu tilanteeseen, eli tätä metodia kutsutaan sen ** jälkeen kun alkiot on talletettu ** *****************************************************************************/ #ifndef __TAULUKKO_H #define __TAULUKKO_H #include //---------------------------------------------------------------------------- // Makro, jolla tutkitaan palauttiko kutsu v virheen vai ei ja jos // palautti, niin poistutaan aliohjelmasta palauttaen sama virhe. #define IF_ERR_RETURN(v) { const char *virhe=(v); if ( virhe ) return virhe; } //---------------------------------------------------------------------------- // Vakiota //---------------------------------------------------------------------------- #define MAX_ALKIOTA 5 #define LIIKAA_ALKIOTA "Liikaa alkiota, ei voi lisätä!" #define EI_VOI_LUODA "Alkiolle ei saada varattua tilaa muistista!" #define LAITON_INDEKSI "Laiton indeksi!" //---------------------------------------------------------------------------- // Taulukon määrittely ja käsittely: //---------------------------------------------------------------------------- template class cPerusTaulukko { protected: int max_alkioita; int alkioita; int muutettu; cTYPE *alkiot; virtual void poista_alkiot(); void poista_alkiotaulukko(); virtual const char *luo_alkiotaulukko(int koko=MAX_ALKIOTA); virtual const char *kasvata_kokoa(); void alusta_alkiot() { max_alkioita = 0; alkioita = 0; muutettu = 0; } int rajoihin(int i) const { if ( i<0 || alkioita <= i ) i = 0; return i; } int ulkona(int i) const { return ( rajoihin(i) != i ); } void poista_kaikki() { // if ( muutettu ) talleta(); // Käyttöliittymä?? poista_alkiot(); poista_alkiotaulukko(); } public: cPerusTaulukko(int koko=0) { alusta_alkiot(); luo_alkiotaulukko(koko); } virtual ~cPerusTaulukko() { poista_kaikki(); } int lkm() const { return alkioita; } int max_lkm() const { return max_alkioita; } int Muutettu() const { return muutettu; } void talletettu() { muutettu = 0; } }; //---------------------------------------------------------------------------- template const char *cPerusTaulukko::kasvata_kokoa() /* ** Yritetään allokoida uutta tilaa 50% maksimimäärään nähden lisää. ** Paitsi jos vanha koko on 1, niin kasvatetaan 2:ksi. ** Jos vanha tila on 0, niin tehdään uusi tila. ----------------------------------------------------------------------------*/ { if ( max_alkioita <= 0 ) return luo_alkiotaulukko(2); int uusi_koko = 3*(max_alkioita)/2; if ( uusi_koko <= 1 ) uusi_koko=2; cTYPE *uusi_tila = new cTYPE[uusi_koko]; if ( uusi_tila == NULL ) return LIIKAA_ALKIOTA; for (int i=0; i inline void cPerusTaulukko::poista_alkiotaulukko() { if ( max_alkioita > 0 ) delete [] alkiot; max_alkioita = 0; } //---------------------------------------------------------------------------- template void cPerusTaulukko::poista_alkiot() { alkioita = 0; } //---------------------------------------------------------------------------- template inline const char *cPerusTaulukko::luo_alkiotaulukko(int koko) /* ** Luodaan taulukko valitun kokoiseksi. Jos taulukko on ** ennestään siellä on se parasta poistaa. ** Luomisessa käytetään malloc-funktiota, jotta koon muuttaminen on ** jatkossa helpompaa realloc-funktiolla. (ks. lisaa-metodi). ----------------------------------------------------------------------------*/ { poista_kaikki(); if ( koko <= 0 ) return NULL; alkiot = new cTYPE[koko]; alkioita = 0; max_alkioita = 0; if ( alkiot == NULL ) return EI_VOI_LUODA; max_alkioita = koko; return NULL; } //---------------------------------------------------------------------------- // Taulukon määrittely ja käsittely: //---------------------------------------------------------------------------- template class cTaulukko : public cPerusTaulukko { protected: cTYPE virhealkio; public: cTaulukko(int koko=0) : cPerusTaulukko(koko) { ; } virtual const char *lisaa(const cTYPE &alkio); virtual const char *korvaa(int i,const cTYPE &alkio); virtual const cTYPE &anna(int i) const; }; //---------------------------------------------------------------------------- template inline const char *cTaulukko::lisaa(const cTYPE &uusi) /* ** Lisätään uusi jäsen kerhoon. EI tarkisteta esiintyykö ** nimi jo ennestään. Mikäli tilaa ei ole, yritetään allokoida uutta ** tilaa 50% maksimimäärään nähden lisää. ** ** Algoritmi: Jos uudelle jäsenelle saadaan varattua tilaa, lisätään ** uuden paikan osoite taulukkoon ja kopioidaan tiedot ** uuteen paikkaan. ----------------------------------------------------------------------------*/ { const char *virhe = NULL; if ( alkioita >= max_alkioita && ( virhe = kasvata_kokoa() ) != NULL ) return virhe; muutettu = 1; alkiot[alkioita] = uusi; alkioita++; return NULL; } //---------------------------------------------------------------------------- template inline const char *cTaulukko::korvaa(int i,const cTYPE &alkio) /* ** Korvataan paikassa i oleva alkio uudella alkiolla. ----------------------------------------------------------------------------*/ { if ( ulkona(i) ) return LAITON_INDEKSI; if ( alkiot[i] == alkio ) return 0; muutettu = 1; alkiot[i] = alkio; return NULL; } //---------------------------------------------------------------------------- template inline const cTYPE &cTaulukko::anna(int i) const { if ( i < 0 || alkioita <= i ) i = alkioita-1; // Väärästä viimeinen alkio if ( i < 0 ) return virhealkio; // Paitsi jollei ole yhtään return alkiot[rajoihin(i)]; } #endif