⌛⌛⌛ N-ulotteinen taulukko¶
Aseta vastauksesi tiedostoon NdArray.java kansiossa Round7/ndarray. Muista hakea materiaalit ``student_template_project``sta.
Tässä tehtävässä toteutetaan vakiokokoisen N-ulotteisen taulukon tarjoava geneerinen
säiliöluokka NdArray<E>. Ajatus on, että esimerkiksi tapaan new NdArray<String>(2, 5, 4)
luotu NdArray-olio toimisi 3-ulotteisena String-taulukkona, jonka ulottuvuuksien koot ovat
2, 5 ja 4. Edellä tarkemmin ottaen ensimmäisen ulottuvuuden koko olisi 2, toisen ulottuvuuden 5 ja
kolmannen 4. Vastaavasti esimerkiksi new NdArray<Double>(3, 3, 3, 3, 3) toimisi 5-ulotteisena
Double-taulukkona, jonka kaikkien viiden ulottuvuuden koot olisivat 3.
Alussa mainittu taulukon “vakiokokoisuus” viittaa siihen, että rakentimelle annetut parametrit määrittävät taulukon ulottuvuuksien määrän sekä koot, eikä ulottuvuuksien määrää tai kokoja voi myöhemmin muuttaa.
Geneerisellä luokalla NdArray<E> tulee tarkemmin ottaen olla seuraavat julkiset ominaisuudet:
Perii Javan luokkakirjaston abstraktin luokan
AbstractCollection<E>.Kyseinen luokka edellyttää alempana kuvattujen funktioiden
sizejaiteratortoteuttamisen.Tämän luokan perinnän ansiosta
NdArrayon pitkälti “täysiverinen” Java-säiliö.NdArray-olion alkioita voidaan esimerkiksi käsitellä streamina hyödyntäen jäsenfunktiotastream().
Rakennin
NdArray(Integer firstDimLen, Integer ...furtherDimLens), joka ottaa vastaan yhden tai useamman ulottuvuuden koot.Parametrit luettelevat taulukon kunkin ulottuvuuden 1…``N`` koot.
firstDimLenkertoo ensimmäisen ulottuvuuden koon, jafurtherDimLensulottuvuuksien 2…``N`` koot (jos ulottuvuuksia enemmän kuin yksi).Ensimmäisen ulottuvuuden koko otetaan erikseen, jotta rakentimelle olisi pakko antaa vähintään yksi parametri.
Eli taulukon ulottuvuuksien määrä
N= parametrien lukumäärä = 1 + parametrienfurtherDimLenslukumäärä (taulukon koko).
Jokaisen ulottuvuuden koon on oltava ei-negatiivinen (eli 0 on kuitenkin sallittu).
Jos jonkin ulottuvuuden koko on negatiivinen, heitetään
NegativeArraySizeExceptionviestillä “Illegal dimension size dimLen.”, missädimLenon ensimmäinen rakentimen saama negatiivinen koko.
Jäsenfunktio
int size(), joka palauttaa taulukon koon (eli sen kaikkien ulottuvuuksien kokojen tulon). Esimerkiksi 3-ulotteisen taulukon, jonka ulottuvuuksien koot ovat 2, 5 ja 4, koko on 2 · 5 · 4 = 20.Jäsenfunktio
E get(int... indices), joka palauttaa taulukon parametrienindiceskuvaamien indeksien mukaisen alkion.Parametrien
indiceslukumäärän tulee vastata taulukon ulottuvuuksien määrääN.Jos parametreja on väärä määrä, heitetään
IllegalArgumentExceptionviestillä “The array has N dimensions but x indices were given.”, missäNon taulukon ulottuvuuksien määrä jaxon parametrienindiceslukumäärä.
Kunkin indeksin tulee olla laillinen eli välillä 0…kyseisen ulottuvuuden koko - 1.
Jos jollekin ulottuvuudelle annetaan laiton indeksi, heitetään
IndexOutOfBoundsExceptionviestillä “Illegal index i for dimension dim of length dimLen."”, missäion ensimmäinen laiton indeksi parametrienindicesjoukossa, jadimsekädimLensitä vastaavan ulottuvuuden järjestysnumero ja koko. Ulottuvuuksien järjestysnumerot ovat 1, …,N.Esim. jos on 3-ulotteinen taulukko, jonka ulottuvuuksien koot ovat 2, 5 ja 4, on muotoa
get(i, j, k)oleva kutsu laillinen jos ja vain jos 0 ≤i< 2, 0 ≤j< 5 ja 0 ≤k< 4.
Jäsenfunktio
void set(E item, int... indices), joka asettaa alkionitemtaulukon parametrienindiceskuvaamien indeksien mukaiseen kohtaan.Parametreja
indiceskoskee samat vaatimukset kuin edellä funktiossaget, ja laittomien parametrien tapauksessa heitetään samanlaiset poikkeukset.
Jäsenfunktio
int[] getDimensions(), joka palauttaa taulukon ulottuvuuksien koot sisältävän taulukon.Palautettavan taulukon koko on
N, ja indeksinikohtaan tallennettu arvo kertoo (``i``+1):nnen ulottuvuuden koon.NdArrayylläpitänee tällaista taulukkoa sisäisesti muistaakseen omien ulottuvuuksiensa koot, mutta huomio: älä palauta suoraan tällaista sisäistä taulukkoa! Luo uusi taulukko ja aseta ulottuvuuksien koot siihen, sillä funktion kutsuja voi muuttaa saamansa taulukon sisältämiä arvoja ja voisi muuten sotkea olion sisäistä dataa.
Toteuttaa rajapinnan
Iterable<E>(koska perittyAbstractCollection<E>toteuttaa sen).Käy läpi taulukon alkiot samassa järjestyksessä kuin tyypillinen
N:stä sisäkkäisestä silmukasta koostuva tapa, jossa uloin silmukka iteroi ensimmäistä ulottuvuutta, sen sisällä oleva silmukka toista ulottuvuutta, jne.Määritä sopiva rajapinnan
Iterator<E>toteuttava iteraattoriluokka (esim. yksityisenä sisäisena luokkana).Jos noudatat (ja kannattaa noudattaa) alla annettua ohjetta, iteraattori on mahdollisesti hyvinkin yksinkertainen: ylläpitää vain tietoa siitä, missä kohtaa yksiulotteista taulukkoa iterointi tällä hetkellä etenee.
Toteuta funktio
Iterator<E> iterator(), joka luo ja palauttaa edellä viitatun iteraattoriluokkasi toteuttaman iteraattoriolion.
Ohje: eräs suhteellisen yksinkertainen ja yleinen lähestymistapa N-ulotteisen taulukon
tallentamiseen on tallettaa alkiot tosiasiassa yksiulotteiseen taulukkoon. Tässä suurin haaste on
toteuttaa kuvaus moniulotteisen taulukon indekseistä yksiulotteisen taulukon indeksiksi. Idea on
kuvattu esim.
tässä artikkelissa
(tässä kannattaa noudattaa artikkelissa ensimmäiseksi kuvattua “row-major” järjestystä, jolloin
iterointi on triviaalia). En suosittele yrittämään “aidosti” moniulotteista ratkaisua; se
monimutkaistaisi ratkaisua oleellisesti.
Toteutuksen testaus¶
Voit testata luokkiasi tiedostossa NdArrayTest.java annetun valmiin testiohjelman ja
tiedostoissa output1.txt, output2.txt, output3.txt ja output4.txt annettujen
esimerkkitulosteiden avulla. Aseta nämä tiedostot sekä omat luokkatoteutuksesi samaan hakemistoon,
käännä ohjelma esim. tapaan javac *.java, ja suorita testit tapaan java NdArrayTest 1,
java NdArrayTest 2, java NdArrayTest 3 ja java NdArrayTest 4. Suoritusten pitäisi
tuottaa tiedostoissa output1.txt, output2.txt, output3.txt ja output4.txt kuvatut
tulosteet.
A+ esittää tässä kohdassa tehtävän palautuslomakkeen.