Večrazsežne tabele

V programih podatki pogosto ne nastopajo enorazsežno (npr. zaporedje števil), temveč v več razsežnostih. Bodisi gre pri tem za več poskusov z večimi meritvami, poljubno tabelarično obdelavo podatkov, izvajanje matričnih operacij, obdelovanje ravninskih slik....,ali nek podoben primer. V takih primerih je zaželeno imeti podatkovno strukturo, ki se po potrebi lahko širi preko večih dimenzij.

Java v osnovi ne pozna termina 'večrazsežna tabela' oz. naravno ne pozna take podatkovne strukture. Vendar :

Zgornje trditve držijo, tabelo int[][] tab; lahko potemtakem pojmujemo kot dvorazsežno tabelo celoštevilskih vrednosti

 

Deklaracija, kreiranje in predstavitev večrazsežnih tabel

Kot je bilo v uvodu nakazano, večrazsežno tabelo deklariramo kot tabelo referenc. Tako

int[][] tab2D; 

predstavlja 'deklaracijo' dvodimenzijske tabele

int[][][] tab3D;

tridimenzijske in

int[][][][] tab4D; 

deklaracijo štirirazsežne tabele celih števil.

Samo tabelo podobno kot enorazsežno ustvarimo z operatorjem new :

tab2D = new int [2][2];
tab3D = new int[7][9][2];
tab4D = new int[2][3][2][3];

opazimo, da smo operatorju new podali toliko razsežnosti, kolikor razrežna je tabela, ki jo želimo ustvariti.

Po rezervaciji pomnilnika so vsi elementi tabele avtomatično inicializirani z vrednostjo 0 (ali ustrezno 0, če gre za tabele elementov drugačnih kot številskih tipov).

Vprašanje, ki se ponavadi zastavlja pri velikem številu dimenzij je, koliko je tisto največje število razsežnosti, ki ga je še smiselno uporabiti. Odgovor je seveda preprost : toliko, kolikor jih lahko programsko obvladujemo. Mimogrede. Java omejuje tako velikost dimenzije kot tudi število dimenzij z velikostjo celoštevilskega podatka.

Vendar je pri tem potrebno pomisliti tudi na trošenje pomnilnika vsled uporabe velikega števila razsežnosti:

in ponavadi element tabele ni celoštevilska vrednost, temveč celoten objekt, ki lahko zaseda nekaj 1000 zlogov pomnilnika ...

Kakorkoli že, v večini primerov se izkaže, da je običajna še obvladljiva razsežnost tabele 3 (živimo v 3D svetu, več razsežnosti si težko predstavljamo, ...)

 

Poglejmo si primer dvorazsežne tabele Ar velikosti 3 krat po 2 elementa :

in še logična predstavitev iste tabele :



Rezervacija pomnilnika za elemente večrazsežne tabele

(ustvarjanje tabele)

Rezervacija pomnilnika za elemente tabele dejansko ustvari tabelo (objekt) v pomnilniku. Tabelo ustvarimo z uporabo operatorja new, kot smo to počeli v primeru enorazsežnih tabel.

Zaradi same narave (zdradbe) večrazsežnih tabel, pa sta možna 2 načina (pristopa) k kreiranju tabele :

Celotno tabelo naenkrat

je najpreprostejši način rezervacije pomnilnika in pri njem praktično ne moremo storiti nobene napake. Torej tak način rezervacije lahko smatramo za varen način. Slabost postopka je v tem, da so vse tako ustvarjene tabele 'pravokotnih' oblik (število vrstic x število stolpcev) :

Postopno kreiranje :

Ker je npr. dvorazsežna tabela zgolj tabela referenc na tabele elementov lahko rezervacijo izvedemo postopoma :

V nadaljevanju bomo skušali zgraditi enako strukturo, kot jo zgradi int[][] in2D = new int[3][5]; :

Slabost postopnega kreiranja je dolgotrajnosti njegovega postopka, saj zahteva kar nekaj programskih korakov in kaj lahko se nam zgodi, da katero izmed dimenzij pozabimo kreirati.

Dobra stran tega postopka pa je, da nam omogoča kreirati le tiste dimenzija, ki jih v danem trenutku potrebujemo, ter da konec koncev lahko ustvarimo tabelo, pri kateri vse dimenzije niso enake !



Naslavljanje elementov večrazsežnih tabel

(indeksiranje)

Pri naslavljanju enorazsežnih tabel smo podali zaporedno številko (indeks) elementa, ki smo ga želeli nasloviti. Ker indeksa v programski kodi ne moremo pisati na matematični način, podajamo njegovo vrednost pri naslavljaju znotraj oglatih oklepajev.

Zelo podobno je pri večdimenzijskih tabelah. Razlika nastopa le v tem, da je naslovljeni element v taki tabeli dejansko na preseku vseh možnih dimenzij tabele; torej ima toliko indeksev, kot je dimenzija same tabele v kateri element naslavljamo.

Primer je podan za tabelo dimenzij 3 x 2, ki si jo logično predstavljamo kot tabelo treh vrstic (prva dimenzija, prvi indeks) in dveh stolpcev (druga dimenzija, drugi indeks) :

V primeru, da bi podali le en indeks, bi to bil avtomatično indeks 'vrstice'; to pa pomeni, da ne bi naslovili števila, temveč celotno vrstico ('vrstica' je v pomnilniški predstavitvi referenca na tabelo dveh celih števil).


Večrazsežne tabele neenakih dimenzij

Predhodno smo omenili, da s postopkom postopnega kreiranja tabele lahko ustvarimo tabelo, pri kateri vse dimenzije niso enako velike. Primer take tabele predstavlja tab :

 



Inicializacija vrednosti elementov tabel, odstranitev tabele iz pomnilnika

Inicializacija

Primer rezervacije z inicializacijo :

Sproščanje tabele iz pomnilnika (odstranitev tabele)

Kot vsak drug referenčnega tipa, lahko tudi tabelo odstranimo iz pomnilnika s tem, da ji priredimo vrednost null. S tem prirejanjem naredimo tabelo nedostopno za uporabo, iz pomnilnik pa jo (ob priliki) odstrani mehanizem za odstranjevanje ( hm., smeti) oz. garbage collector .

 

Utrjevanje - večrazsežen tabele


Vprašanje 1
Katera izmed kombinacij znakov (simbolov) je tista, ki vam da vedeti, da gre za tabelo ?
 
[[
{}
((
[]
((
   
Vprašanje 2
Dano zaporedje stavkov
for (int i=0;i<tab.length-1;i++){
  tab[i][0]=1;
  tab[i][2]=tab[0][i]+1;
}

izvedemo na tabeli

int tab[][] = new int[3][5];

Po izvedbi je v tabeli vsebina :
10200
10100
00000
10100
00000
20100
10200
10200
00000
11000
00000
22000
   
Vprašanje 3
Koliko celoštevilskih elementov 'vsebuje' tabela:
int tab[][] = new int[2][3];
5
6
7
12
   
Vprašanje 4
Katera izmed deklaracij nakazuje, da gre za večrazsežno tabelo ?
 
int [][][][]tab;
String []tabela;
char tab[][];
float [[]]tab;
   
Vprašanje 5
Izberite stavke, ki vsebujejo pravilno deklaracijo, rezervacijo in inicializacijo večrazsežne tabele.
 
int tab[][]=new int[3];
int tab[][]={{1,2},{3,4}};
int[] tab; tab=new int[3][5];
int [][][]tab=new int[2][2][2];
   
Vprašanje 6
Izberite stavek, ki padaja pravilno deklaracijo tabele, s pravilno rezervacijo in inicializacijo le te
 
int tab[]=new int[2][4];
int tab[][]=new int[][];
int tab[][]=new char[1][1];
int tab[][]=new int[2][8];
   
Vprašanje 7
Dana je tabela 'tab' :
int tab[][] = new int[2][3];

katera izmed spodnjih slik predstavlja 'vizualizacijo' take tabele ?
-maxInt -maxInt -maxInt
-maxInt -maxInt -maxInt
-1 -1 -1
-1 -1 -1
0 0 0
0 0 0
1 1 1
1 1 1
vrednosti vseh elementov tabele so neopredeljivi (naključne vrednosti)
   
Vprašanje 8
Povežite deklaracije s smiselno ustreznimi naslavljanji elementov tabele
 
1 int [ ][ ][ ]tab;      A. tab[2][3]=33;
2 int tab[ ];      B. tab[133]=62;
3 char tab[ ];      C. tab[3][3]=7;
4 int tab[ ][ ];      D. tab[2]='A';
     
Vprašanje 9
Določite pomen posameznih deklaracij
 
1 int tab[ ][ ];      A. enorazsežna tabela
2 int tab;      B. dvorazsežna tabela
3 int [ ][ ][ ]tab;      C. tri razsežna tabela
4 int [ ][ ]tab[ ][ ];      D. štiri razsežna tabela
  E. ni tabela
  F. napaka v sintaksi
   
Vprašanje 10
Kateri izmed stavkov vrednost vseh štirih 'ogliščnih' elementov tabele
int tab[][] = new int[2][3];

postavi na 33 ?
tab[0][0]=tab[2][3]=tab[0][3]=tab[2][0]=33;
tab[1][1]=tab[2][3]=tab[1][3]=tab[2][1]=33;
tab[0][0]=tab[1][2]=tab[0][2]=tab[1][0]=33;
tab[0][0]=tab[0][2]=tab[3][0]=tab[2][3]=33;
tab[0][0]=tab[2][0]=tab[1][0]=tab[1][2]=33;
   
Vprašanje 11
Prepisati bi želeli vrednosti elementov zadnje vrstice tabele
int [][]tab=new int[5][5];

tako, da bi bile vrednosti elementov zadnje in predzadnje vrstice po postopku enake. Izberite vse stavke,ki zadostijo podani zahtevi.
tab[4]=tab[5];
tab[3]=tab[4];
for(int i=0;i<5;tab[4][i]=tab[5][i],i++);
for( int i=0;i<tab[0].length; tab[ tab[3].length-2 ][i] = tab[tab[4].length-1][i],i++);
noben izmed zgornjih stavkov ne zadosti zahtevam
   
Vprašanje 12
Določite pravilen rezultat izvajanja spodnjega zaporedja stavkov
int [][]tab={{1,2,3,4},{2,2,2,2},{1,3,2,5}};

System.out.println(tab.length+tab[0].length+tab[1].length);
1244
20
18
11
10
344
   
Vprašanje 13
Vsebina tabele 'tab' po izvedbi
       int tab[][]=new int[3][5];
  
       for (int i=0;i<tab.length;i++){
           tab[0][i]=1;
           tab[2][i]=1;
       }

je enaka :
11111
00000
11111
11100
00000
11100
10001
10001
10001
10100
10100
10100
pri izvajanju pride do prekoračitve obsega indeksov na tabeli,zato nobena ob zgoraj naštetih rešitev ni pravilna

Programske naloge

Naloga 1

Spodnji program deklarira tabelo, rezervira prostor zanjo v pomnilniku in izvrši inicializacijo:

 

 class Nal12_1{


       public static void main(String[] arg){


              char tab[][]={{‘s’,’o’,’s’,’e’,’d’},
                            {‘o’,’p’,’e’,’r’,’a’},
                            {‘k’,’r’,’a’,’v’,’a’}};
              v = tab.length;
              s = tab[0].length;


              System.out.println(v);
              System.out.println(s);
              System.out.println("Tabela :"+v+" x "+s);
       }
} 
  

Odpravite napake v programu. Kako interpretirate rezultate, ki jih nato program izpiše ? Narišite tabelo tab!

 

Naloga 2

Glede na program Nal12_1 izvedite naslednje :

  1. Izpišite vsebino tabele na zaslon tako, da se bo vsaka vrstica tabel e izpisala v svojo vrstico (privzeto: prva v deklaracija podana razsežnost večrazsežne tabele naj predstavlja vrstico, druga razsežnost stolpec ).
  2. Izpišite vsebino tabele na zaslon tako, da se vsak stolpec tabele izpiše v lastno vrstico;
  3. Napišite metodo (statično), ki bo izpisala na zaslon s parametrom podano vrstico tabele:
     static void izpisiVrstico(char tab[][], int vrstica); 

 

  1. Napišite metodo (statično), ki bon a zaslon izpisala s parametrom podan stolpec tabele:
     static void izpisiVrstico(char tab[][], int stolpec); 

 

  1. Napišite metodo, ki bo vsebino celotne tabele izpisala na zaslon po vrsticah. Pri tem naj bo metoda napisana tako, da se bo izpis lahko izvršil za poljubno dvorazsežno tabelo, katere elementi so znaki :
     static void izpisiTabelo(char [][]tab); 

 

Naloga 3

Recimo, da deklaracijo tabele tab iz naloge Nal12_1 popravimo na naslednji način :

 

class Nal12_3{ 
 
   public static void main(String[] arg){ 


       char tab[][] = new char[3][5];

     
       . . . 


       . . . 



 }


}

 

dokončajte začeti program. Pri tem pa mora tabela vsebinsko postati enaka tisti, ki je podana v prvi nalogi. Izvedite tudi test izpisa celotne tabele na zaslon s pomočjo ustrezne metode iz druge naloge.

 

Naloga 4

Ponovite izvedbo naloge 3. Deklaracija tabele je v tem primeru dana z :

 class Nal12_4{


      public static void main(String[] arg){


          char tab[][];
   
          . . .


      . . . 
 

dokončajte začeti program. Rezervacijo za vsako izmed razsežnosti bi pri tem želeli izvesti ločeno. Pri tem pa mora tabela vsebinsko postati enaka tisti, ki je podana v prvi nalogi. Izvedite tudi test izpisa celotne tabele na zaslon s pomočjo ustrezne metode iz druge naloge.

 

Naloga 5

Javanski program Nal12_5 prepiše vsebino elementov tabele tab1 v elemente tabele tab2 tako, da se prepiše vrednost istoležnih indeksov tabele :

class Nal12_5{  


    public static void main(String[] arg){
         char tab1[][]={{‘s’,’o’,’s’,’e’,’d’},{‘o’,’p’,’e’,’r’,’a’},  
                        {‘k’,’r’,’a’,’v’,’a’}};


         char tab2[][]=new char[3][5];   


          . . .   
  1. Dopišite manjkajoči del programa, da bo izvedel zahtevano funkcionalnost.
  2. Spremenite program iz razdelka a) te naloge tako, da bo prepisovanje izvedel v tabelo tab3, ki je podana kot :

    char tab3[][] = new char[5][3];

Pri tem pa upoštevajte, da se lahko izvede prepis le takrat, kadar naslovljeni element v tabeli obstaja!

  1. Iz cilja razdelka 2) te naloge sestavite delujočo metodo razreda, ki bo prepisovala vrednosti iz ene v drugo tabelo :

    static void prepisiTabeloVDrugo(char [][]ponorna, char[][] izvorna);