⌛⌛⌛ N
-ulotteinen taulukko¶
Aseta vastauksesi tiedostoon NdArray.java kansiossa Round8/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
size
jaiterator
toteuttamisen.Tämän luokan perinnän ansiosta
NdArray
on 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.
firstDimLen
kertoo ensimmäisen ulottuvuuden koon, jafurtherDimLens
ulottuvuuksien 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 + parametrienfurtherDimLens
lukumäärä (taulukon koko).
Jokaisen ulottuvuuden koon on oltava ei-negatiivinen (eli 0 on kuitenkin sallittu).
Jos jonkin ulottuvuuden koko on negatiivinen, heitetään
NegativeArraySizeException
viestillä “Illegal dimension size dimLen.
”, missädimLen
on 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 parametrienindices
kuvaamien indeksien mukaisen alkion.Parametrien
indices
lukumäärän tulee vastata taulukon ulottuvuuksien määrääN
.Jos parametreja on väärä määrä, heitetään
IllegalArgumentException
viestillä “The array has N dimensions but x indices were given.
”, missäN
on taulukon ulottuvuuksien määrä jax
on parametrienindices
lukumäärä.
Kunkin indeksin tulee olla laillinen eli välillä 0…kyseisen ulottuvuuden koko - 1.
Jos jollekin ulottuvuudelle annetaan laiton indeksi, heitetään
IndexOutOfBoundsException
viestillä “Illegal index i for dimension dim of length dimLen."
”, missäi
on ensimmäinen laiton indeksi parametrienindices
joukossa, jadim
sekädimLen
sitä 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 alkionitem
taulukon parametrienindices
kuvaamien indeksien mukaiseen kohtaan.Parametreja
indices
koskee 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 indeksini
kohtaan tallennettu arvo kertoo (``i``+1):nnen ulottuvuuden koon.NdArray
yllä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.