Interdisciplinarni študij Računalništvo in matematika
Transcript of Interdisciplinarni študij Računalništvo in matematika
Osnove programiranja 2Interdisciplinarni študij Računalništvo in matematika
Viljan Mahnič
UNIVERZA V LJUBLJANIFakulteta za računalništvo in informatiko
Osnove programiranja 2 - 2 - ©Viljan Mahnič
Organizacija programa in dostopnost deklaracij
• Območje veljavnosti deklaracij spremenljivk– lokalne in globalne spremenljivke
• Dostopno določilo static– spremenljivke objekta in spremenljivke razreda– metode objekta in metode razreda– referenca this v metodah objekta
• Dostopno določilo final
• Dostopna določila public, private in protected
• Uporaba vnaprej deklariranih razredov– Math– Character
Osnove programiranja 2 - 3 - ©Viljan Mahnič
Območje veljavnosti deklaracij spremenljivk
• Deklaracija spremenljivke velja– od mesta, kjer je bila spremenljivka deklarirana– do konca bloka, v katerem smo jo deklarirali
• Primer: gnezdenje blokov{ // zunanji blok
int spr1=10;...{ // notranji blok
int spr2=20;... // obstajata spr1 in spr2int spr1=34; // napaka
}// spr1 še vedno obstaja, spr2 pa ne...
}
Osnove programiranja 2 - 4 - ©Viljan Mahnič
Lokalne in globalne spremenljivke
• Globalne spremenljivke– deklarirane so na ravni razreda– dostopne so vsem metodam v razredu
• Lokalne spremenljivke– deklarirane so znotraj posameznih metod– dostopne so samo v metodi, kjer so deklarirane
• Globalne spremenljivke so lahko statične ali vezane na posamezne objekte, odvisno od dostopnega določila static– statične spremenljivke: obstaja ena sama spremenljivka za celoten
razred, zato jim rečemo tudi spremenljivke razreda (ang. class variables)
– spremenljivke objekta: vsakemu objektu pripada svoja spremenljivka, ki vsebuje vrednost atributa tistega objekta (ang. instance variables)
Osnove programiranja 2 - 5 - ©Viljan Mahnič
Lokalne in globalne spremenljivke
• Primer: Razred, ki opisuje zgradbo objektovpublic class Primer1{private double atr1; // vsak objekt ima 2 atributa, ki sta globalniprivate int atr2; // spremenljivki, dostopni v celem razredupublic void metoda1(){int spr3=1; // lokalni spremenljivki,int spr4=25; // dostopni v metodi metoda1()// obstajajo atr1, atr2, spr3 in spr4
}public int metoda2(){
double spr5=500.0; // lokalna spremenljivka// obstajajo atr1, atr2=10 in spr5
}}
Osnove programiranja 2 - 6 - ©Viljan Mahnič
Lokalne in globalne spremenljivke
• Primer: Razred, ki predstavlja aplikacijopublic class Primer2{static double spr1=2.5; // globalni spremenljivki,static int spr2=10; // dostopni v celem razredupublic static void main(String[] args){int spr3=1; // lokalni spremenljivki,int spr2=25; // dostopni v metodi main()// obstajajo spr1=2.5, spr2=25 in spr3=1
}public static void xy(){
double spr4=500.0; // lokalna spremenljivka// obstajajo spr1=2.5, spr2=10 in spr4=500.0
}}
Osnove programiranja 2 - 7 - ©Viljan Mahnič
Statične spremenljivke in spremenljivke objekta
• Statične spremenljivke (ang. class variables)– tipične so za razrede, ki predstavljajo aplikacije, vendar lahko nastopajo
tudi v razredih, ki opisujejo zgradbo objektov– deklarirane so z rezervirano besedo static– obstaja samo ena kopija spremenljivke– to kopijo uporabljajo vse metode in vsi objekti– spremenljivka obstaja tudi v primeru, ko nismo kreirali nobenega objekta– sprememba vrednosti je dostopna vsem objektom in metodam v razredu
• Spremenljivke objekta (ang. instance variables)– nastopajo v razredih, ki opisujejo zgradbo objektov– pri deklaraciji ne smemo uporabiti dostopnega določila static– vsak objekt ima svojo kopijo spremenljivke (tj. svojo vrednost atributa)– sprememba vrednosti se odraža samo znotraj objekta
Osnove programiranja 2 - 8 - ©Viljan Mahnič
Statične metode in metode objekta
• Dostopno določilo static pri metodah– statične metode ali metode razreda (ang. class methods)– metode objekta (ang. instance methods)
• Statične metode – tipične so za razrede, ki predstavljajo aplikacije, in razrede, ki služijo
kot knjižnice podprogramov (npr. razred Math)– deklariramo jih z dostopnim določilom static– v pomnilniku so shranjene samo enkrat – niso vezane na posamezne objekte, ampak so skupne za celoten razred– uporabljamo jih tudi takrat, ko ne obstaja noben objekt– ne morejo posegati v atribute posameznih objektov– metoda main() mora biti obvezno statična– če deklariramo statično metodo v razredu, ki je namenjen generiranju
objektov, potem je ta skupna (tj. enaka) za vse objekte
Osnove programiranja 2 - 9 - ©Viljan Mahnič
Metode razreda in metode objekta
• Metode objekta– vezane so na posamezne objekte (tj. primerke nekega razreda)
• predstavljamo si lahko, da ima vsak objekt svoje metode• v resnici so tudi metode, ki pripadajo objektom istega tipa, shranjene
v pomnilniku samo enkrat; s posebnim mehanizmom dosežemo, da se izvede prava metoda (dinamično povezovanje)
– tipične so za razrede, ki so namenjeni generiranju objektov– omogočajo dostop do posameznih atributov v objektu– pri njihovi deklaraciji ne smemo uporabiti dostopnega določila static
– ob klicu metode objekta je treba obvezno navesti tudi ime objekta, ki mu metoda pripada
<ime objekta> . <ime metode> (<dejanski parametri>)<ime razreda> . <ime objekta> . <ime metode> (<dejanski parametri>)
Osnove programiranja 2 - 10 - ©Viljan Mahnič
Referenca this• Implicitno prisotna v vsaki metodi objekta
– predstavlja naslov objekta, na katerega se nanaša klic metode– ta naslov omogoča, da dostopamo do spremenljivk pravega objekta– pred vsakim sklicevanjem na spremenljivko objekta dejansko stoji
referenca this– referenco this avtomatsko vstavi prevajalnik, lahko pa jo vključi že
programer
public void izpisiVse(){System.out.println("Maticna stevilka: "+this.matStev);System.out.println("Priimek in ime: "+this.priimek+''+this.ime);
System.out.println("Stevilo ur: "+this.stUr);}
Osnove programiranja 2 - 11 - ©Viljan Mahnič
Določilo final• Kadar želimo preprečiti spremembo neke deklaracije
– pri spremenljivkah: vrednost spremenljivke se ne more več spremeniti– pri metodah: metode ni moč redefinirati (je dokončna)– pri razredih: razreda ni moč razširiti (vse metode so dokončne)
• Deklaracije konstant– konstante deklariramo na enak način kot spremenljivke, le da dodamo
rezervirano besedo final– velja dogovor, da imena konstant pišemo z velikimi črkami– static final double PI=3.14159;– konstanti moramo prirediti vrednost ob deklaraciji; kasneje to ni več
mogoče– prednost uporabe konstant
• boljša čitljivost programa• enostavnejše vzdrževanje
Osnove programiranja 2 - 12 - ©Viljan Mahnič
Dostopna določila public, private in protected
• Določajo način dostopa do posameznih atributov in metod v razredu
iz kateregakoli razreda v istem paketu in iz kateregakoli podrazreda ne glede na paket
protected
samo znotraj razredaprivate
iz kateregakoli razreda ne glede na paket
public
iz kateregakoli razreda v istem paketu
brez dostopnega določila
Dovoljen dostopDostopno določilo
Osnove programiranja 2 - 13 - ©Viljan Mahnič
Vnaprej deklarirani razredi
• V Javi obstaja približno 500 vnaprej deklariranih razredov– ti razredi so shranjeni v obliki paketov– paket si lahko predstavljamo kot skupino sorodnih razredov, ki so
shranjeni v isti mapi (poddirektoriju)– paket java.lang vsebuje osnovne razrede, ki se največ uporabljajo
• Uporaba vnaprej deklariranih razredov– nekateri paketi, kot npr. java.lang, so na razpolago avtomatsko – uporabo ostalih paketov ali razredov je treba napovedati s stavkom import, ki mora biti naveden na začetku programa• import java.util.* napove uporabo vseh razredov iz paketa java.util
• import java.util.Date napove uporabo razreda Date iz paketa java.util
Osnove programiranja 2 - 14 - ©Viljan Mahnič
Razred Math• Vsebuje matematične konstante in metode
– deklariran je v paketu java.lang– klicanje konstant (PI, E): Math.<ime konstante>– klicanje metod: Math.<ime metode>(<argumenti>)
eksponentna in logaritemska funkcijaexp(x),log(x)
naključno število med 0.0 in 1.0random()
kvadratni koren iz xsqrt(x)
zaokroževanje na najbližje celo številoround(x)
obratne trigonometrične funkcijeasin(x),acos(x),atan(x)
trigonometrične funkcije sinus, kosinus, tangenssin(x),cos(x),
tan(x)
absolutna vrednost xabs(x)
Osnove programiranja 2 - 15 - ©Viljan Mahnič
Razred Character• Vsebuje koristne metode za delo z znaki
– deklariran je v paketu java.lang– klicanje metod: Character.<ime metode>(<argChar>)
Preveri, ali je znak presledek, tab, newline, carriage return ali form feed
isWhiteSpace()
Preveri, ali je znak črka ali številkaisLetterOrDigit()
Preveri, ali je znak črkaisLetter()
Preveri, ali je znak številka ('0' – '9')isDigit()
Pretvori veliko črko v malotoLowerCase()
Preveri, ali je znak mala črkaisLowerCase()
Pretvori malo črko v velikotoUpperCase()
Preveri, ali je znak velika črkaisUpperCase()
Osnove programiranja 2 - 16 - ©Viljan Mahnič
Urejanje
• Seznanitev z nekaterimi algoritmi
• Maksimalno izkoriščanje konceptov objektno usmerjenega programiranja– rešitev, ki jo bomo sprogramirali, bo omogočala urejanje objektov
kateregakoli tipa
• Ocenjevanje časovne zahtevnosti posameznih algoritmov– ocenimo število tipičnih operacij (primerjanje, premik)– preprosti algoritmi zahtevajo čas velikostnega reda n2
– izpopolnjeni algoritmi zahtevajo čas velikostnega reda n·log2n
Osnove programiranja 2 - 17 - ©Viljan Mahnič
Urejanje
• Algoritmi– urejanje z navadnim izbiranjem (že poznamo)– urejanje z navadnim vstavljanjem– urejanje s porazdelitvami (Quicksort)
• Uporaba konceptov objektno usmerjenega programiranja omogoča, da sprogramiramo rešitev, ki je uporabna za vse vrste podatkov– urejamo tabelo, ki vsebuje podatke tipa Element– Element je abstraktni razred, ki vsebuje samo metodo manjsi– to zadostuje, da sprogramiramo katerikoli algoritem za urejanje– dejanske podatke, ki jih želimo urediti, deklariramo kot razširitev
razreda Element
Osnove programiranja 2 - 18 - ©Viljan Mahnič
Urejanje
• Deklaracija razred Elementpublic abstract class Element{public abstract boolean manjsi (Element b)
}
• Primer razširitve, ko želimo urediti podatke o študentihpublic class Student extends Element{String priimek, ime;double povpOcena;
Student(String p,String i,double po){priimek=p;ime=i;povpOcena=po;
}
Osnove programiranja 2 - 19 - ©Viljan Mahnič
Urejanje
• Primer razširitve (nadalj.)
public boolean manjsi(Element b){// konverzija iz abstraktnega tipa v tip StudentStudent s=(Student) b; // primerjava povprečnih ocen return this.povpOcena<s.povpOcena;
}
public String toString(){return priimek+" "+ime+" "+povpOcena;
}}
Osnove programiranja 2 - 20 - ©Viljan Mahnič
Urejanje z navadnim vstavljanjem
• Grob opis algoritmafor (i=1; i<a.length; ++i) //za vse elemente od drugega do
zadnjega{x=a[i];vstavi x na pravo mesto, upoštevajoč elemente a[0] do a[i];
}
• Prikaz delovanja na konkretnem primeru (za cela števila)i=1 44 55 12 42 94 18 6 67i=2 44 55 12 42 94 18 6 67i=3 12 44 55 42 94 18 6 67i=4 12 42 44 55 94 18 6 67i=5 12 42 44 55 94 18 6 67i=6 12 18 42 44 55 94 6 67i=7 6 12 18 42 44 55 94 67
6 12 18 42 44 55 67 94
Osnove programiranja 2 - 21 - ©Viljan Mahnič
Urejanje z navadnim vstavljanjem
• Formulacija v obliki podprogramapublic static void straightinsertion(Element[] a){
int i,j;Element x;for (i=1; i<a.length; ++i){x=a[i];j=i-1;while (j>=0 && x.manjsi(a[j])){a[j+1]=a[j];--j;
} a[j+1]=x;
} }
Osnove programiranja 2 - 22 - ©Viljan Mahnič
Urejanje z navadnim vstavljanjem
• Sestavni deli rešitve– razred Element: abstraktna metoda manjsi– razred SortiranjeObjektov: knjižnica metod za urejanje– razred Student: tip podatkov, ki jih bomo urejali, redefinicija
metode manjsi– razred GlavniProgram: naša aplikacija
• Razred GlavniProgrampublic class GlavniProgram{public static void main(String[] args){ Student[] s=new Student[10];pripraviPodatke(s);izpisiPodatke(s); // pred urejanjemSortiranjeObjektov.straightinsertion(s);izpisiPodatke(s); // po urejanju
}
Osnove programiranja 2 - 23 - ©Viljan Mahnič
Urejanje z navadnim vstavljanjem
• Razred GlavniProgram (nadalj.)static void pripraviPodatke(Student[] s){ s[0]=new Student("Novak","Janez",8.12);s[1]=new Student("Petelin","Marko",7.72);s[2]=new Student("Kranjec","Ludvik",9.04);s[3]=new Student("Lenko","Friderik",6.74);s[4]=new Student("Pametnjakovic","Zdravko",8.04);...s[9]=new Student("Kopac","Ivan",6.89);
}
static void izpisiPodatke(Student[] s){for (int i=0; i<s.length; ++i)System.out.println(s[i].toString());
System.out.println();}
}
Osnove programiranja 2 - 24 - ©Viljan Mahnič
Urejanje z navadnim vstavljanjem
• Analiza učinkovitosti– število primerjanj– število pomikov
• Število primerjanj– najprej določimo število primerjanj v i-tem koraku– nato izračunamo vsoto po vseh korakih
– zaključna ugotovitev: C = o(n2)
2i
C
iC
1C
i
i
i
ave
max
min
=
=
=
41)n(n1)n...32(1
21
2i
21)n(n1n...321i
1n
1n
1iave
1n
1imax
min
C
CC
−=−++++==
−=−++++==
−=
∑
∑−
=
−
=
Osnove programiranja 2 - 25 - ©Viljan Mahnič
Urejanje z navadnim vstavljanjem
• Število premikov– v i-tem koraku: število premikov je za 1 večje od števila
primerjanj
– v celoti: izračunamo vsoto po vseh korakih
• Obe oceni pokažeta, da čas narašča s kvadratom števila elementov: T=o(n2)
4)3nn(411)(n
41)n(n
1)(n1)n...32(1211)
2i(
2
1n
1iaveM
−+=−+−
=
=−+−++++=+= ∑−
=
1CM ii aveave+=
Osnove programiranja 2 - 26 - ©Viljan Mahnič
Urejanje s porazdelitvami - Quicksort
• Osnova je porazdelitveni algoritem, ki tabelo razdeli na 2 dela1. naj bo x poljubni element tabele (npr. element na sredini)2. pregledujemo tabelo z leve, dokler ne naletimo na element ai, ki je večji ali
enak x3. pregledujemo tabelo z desne, dokler ne naletimo na element aj, ki je manjši ali
enak x4. zamenjamo ai in aj5. ponavljamo korake 2, 3 in 4, dokler se obe pregledovanji ne srečata sredi tabele
• Primer: 44 55 12 42 94 6 18 67i j
18 55 12 42 94 6 44 67i j
18 6 12 42 94 55 44 67i j
18 6 12 42 94 55 44 67j i
Osnove programiranja 2 - 27 - ©Viljan Mahnič
Urejanje s porazdelitvami - Quicksort
• Zapis porazdelitvenega algoritma v Javiint i=0, j=a.length-1;Element x=a[(i+j)/2], w;do{ while (a[i].manjsi(x)) ++i;while (x.manjsi(a[j])) --j;if (i<=j){w=a[i]; a[i]=a[j]; a[j]=w;++i;--j;
}} while (i<=j);
• Po porazdelitvi– levi del tabele: a[k]<x, k=0,1,2,...,j– desni del tabele: a[k]>x, k=i,i+1,...,n– sredina: a[k]=x, k=j+1,...,i-1
Osnove programiranja 2 - 28 - ©Viljan Mahnič
Urejanje s porazdelitvami - Quicksort
• Postopek porazdeljevanja rekurzivno uporabimo na levem in desnem delu tabelepublic static void quicksort(Element[] a){ sort(a,0,a.length-1);}public static void sort(Element[] a, int l, int r){int i=l, j=r;Element x=a[(i+j)/2], w;do{ while (a[i].manjsi(x)) ++i;while (x.manjsi(a[j])) --j;if (i<=j){w=a[i]; a[i]=a[j]; a[j]=w;++i; --j;
}} while (i<=j);if (l<j) sort(a,l,j);if (i<r) sort(a,i,r);
}
Osnove programiranja 2 - 29 - ©Viljan Mahnič
Urejanje s porazdelitvami - Quicksort
• Analiza– vsaka porazdelitev zahteva n primerjanj (pregledati je treba vse
elemente tabele)– pri popolnoma naključni razporeditvi elementov se tabela razdeli
na 2 enaka dela: potrebnih je log2n porazdelitev– celotno število primerjanj je potem n·log2n– v najslabšem primeru (ko je izbrani element x enak največjemu ali
najmanjšemu elementu tabele), je potrebnih n porazdelitev– v tem primeru je celotno število primerjanj n2
• Zaključek– pričakovani čas: TE= o(n·log2n)– najslabši čas: TW=o(n·log2n)
Osnove programiranja 2 - 30 - ©Viljan Mahnič
Urejanje s porazdelitvami - Quicksort
• Primer najslabšega delovanja– določiti želimo tisto permutacijo ključev od 1 do 5, pri kateri se
algoritem najslabše obnaša– vsakokrat bomo za mejo x izbrali največje število– rešitev: 2 4 5 3 1
• Priporočilo (Hoare)– za mejo x izberemo srednjo vrednost majhnega vzorca npr. treh
ključev– bistveno se izboljša delovanje v najbolj neugodnih primerih– na povprečno obnašanje algoritma ta izbira nima posebnega vpliva
Osnove programiranja 2 - 31 - ©Viljan Mahnič
Rekurzija
• Splošne značilnosti– Primer preproste rekurzivne metode: izračun n!
• osnova: zagotavlja prekinitev rekurzije• rekurzivni del
• Preproste rekurzivne metode, ki imajo enostavno iterativno rešitev– binarno iskanje– palindrom– binomski koeficienti
• Uporaba strategije sestopanja– eleganten način za iskanje ene ali vseh možnih rešitev– iskanje vseh permutacij– skakačev obhod
Osnove programiranja 2 - 32 - ©Viljan Mahnič
Rekurzija
• Splošne značilnosti (iz Osnov programiranja 1)– rekurzivna metoda je tista, ki kliče samo sebe– rekurzija omogoča eleganten zapis problemov, ki so definirani
rekurzivno– rekurzije ne smemo zlorabljati: če obstaja za nek problem
preprosta iterativna rešitev, se raje odločimo za iteracijo
• Primer preproste rekurzivne metode: izračun n!(a) 0!=1(b) n! = n·(n-1)!
1! = 1·0! = 1·1 = 12! = 2·1! = 2·1·0! = 2·1·1 = 23! = 3·2! = 3·2·1! = 3·2·1·0! = 3·2·1·1 = 64! = 4·3! = 4·3·2! = 4·3·2·1! = 4·3·2·1·0! = 4·3·2·1·1 = 24 itd.
Osnove programiranja 2 - 33 - ©Viljan Mahnič
Rekurzija
• Zapis ustrezne metode v Javipublic static int f(int n){if (n==0) // osnova (basis)return 1;
else // rekurzivni del (recursive part)return n*f(n-1);
}
• Vsaka rekurzivna metoda mora imeti osnovo in rekurzivni del– osnova zagotavlja, da se rekurzija prekine– rekurzivni del vsebuje rekurzivni klic z argumentom, ki se
spreminja tako, da zagotavlja prekinitev rekurzije
Osnove programiranja 2 - 34 - ©Viljan Mahnič
Rekurzija
• Iterativna rešitevpublic static int f(int n){
int f=1;for (int i=2; i<=n; i++)f*=i;
return f;}
• Nekaj preprostih rekurzivnih programov– binarno iskanje– palindrom– binomski koeficienti– za vse omenjene probleme obstaja preprosta iterativna rešitev
Osnove programiranja 2 - 35 - ©Viljan Mahnič
Rekurzija
• Binarno iskanje: v urejeni tabeli iščemo element x– naj bo t[sr] element, ki se nahaja sredi tabele– če je t[sr] enak x, je iskanje končano– če je t[sr] manjši od x, ponovimo postopek na gornjem delu tabele– če je t[sr] večji od x, ponovimo postopek na spodnjem delu tabele– postopek prekinemo, ko spodnja meja preseže zgornjo
public static int poisci(int[] t, int x, int sp, int zg)
{ if (sp>zg) return -1;int sr=(sp+zg)/2; // izračun sredineif (t[sr]==x)return sr; // element smo našli
else if (t[sr]<x)return poisci(t,x,sr+1,zg); // nadaljujemo v gornji polovici
elsereturn poisci(t,x,sp,sr-1); // nadaljujemo v spodnji polovici
}
Osnove programiranja 2 - 36 - ©Viljan Mahnič
Rekurzija
• Rekurzivna metoda jePalindrom– Niz je palindrom, če je njegova dolžina 0 ali 1– Niz je palindrom, če sta prvi in zadnji znak enaka in je preostanek
niza (brez prvega in zadnjega znaka) tudi palindrom
public static boolean jePalindrom(String n){int d=n.length();if (d<=1)return true;
else if (n.charAt(0)==n.charAt(d-1))return jePalindrom(n.substring(1,d-1));
elsereturn false;
}
Osnove programiranja 2 - 37 - ©Viljan Mahnič
Rekurzija
• Binomski koeficienti– koeficienti, ki jih dobimo pri izračunu potence binoma, npr.
(x +1)6 = x6 + 6x5 + 15x4 + 20x3 + 15x2 + 6x +1– izračunamo jih lahko s pomočjo Pascalovega trikotnika
11 1
1 2 11 3 3 1
1 4 6 4 11 5 10 10 5 1
1 6 15 20 15 6 1
– vsako število znotraj trikotnika je vsota dveh števil nad njim:c(n,k)=c(n-1,k-1)+c(n-1,k) za 0<k<n
n je številka vrstice, k je številka kolone v Pascalovem trikotniku
Osnove programiranja 2 - 38 - ©Viljan Mahnič
Rekurzija
• Zapis ustrezne rekurzivne metodepublic static int binKoef(int n, int k){if (k==0 || k==n) return 1;return binKoef(n-1,k-1)+binKoef(n-1,k);
}
• Iterativna rešitev– uporabimo formulo za kombinacije n elementov po k
k...3211)k2)...(n1)(nn(n
k)!(nk!n!
kn
k)c(n,⋅⋅⋅⋅
+−−−=
−=
=
Osnove programiranja 2 - 39 - ©Viljan Mahnič
Rekurzija
• Primeri, ko je rekurzivna rešitev elegantna, iterativna pa ne– generiranje permutacij, hanojski stolpiči, skakačev obhod, problem
osmih dam
• Generiranje permutacij– napisati želimo program, ki generira vse permutacije števil od 1 do 4– naivni iterativni pristop bi dal naslednjo rešitev:
for (int i1=1; i1<=4; i1++)for (int i2=1; i2<=4; i2++)if (i1!=i2)for (int i3=1; i3<=4; i3++)if (i1!=i3 && i2!=i3) for (int i4=1; i4<=4; i4++)if (i1!=i4 && i2!=i4 && i3!=i4)System.out.println(i1+" "+i2+" "+i3+" “+i4);
Osnove programiranja 2 - 40 - ©Viljan Mahnič
Rekurzija
• Problemi pri tej rešitvi– če povečamo število elementov, moramo
• dodati nove stavke for• dodati nove, še daljše pogoje v stavkih if
– ne moremo napisati splošne rešitve za poljubno število elementov n
• Uporaba rekurzije– napišemo rekurzivno metodo, ki doda število na pozicijo poz
for(int st=1; st<=N; ++st)if (st še ni v permutaciji){
dodaj st v permutacijo;rekurzivno ponovi postopek za naslednjo pozicijo;
}
Osnove programiranja 2 - 41 - ©Viljan Mahnič
Rekurzija
• Predstavitev permutacije: tabela p dolžine Nstatic final int N=4;static int[] p=new int[N];
• Rekurzivna metoda dolociStevilostatic void dolociStevilo(int poz){for(int st=1; st<=N; ++st)if (seNiUporabljeno(st,poz)){p[poz]=st; // dodaj st v permutacijoif (poz==N-1) // osnovaizpisiPermutacijo();
else // rekurzivni deldolociStevilo(poz+1);
}}
Osnove programiranja 2 - 42 - ©Viljan Mahnič
Rekurzija
• Prikaz delovanja: strategija sestopanja (ang. backtracking)
24311,23dolociStevilo(3)4313,42dolociStevilo(2)
42311,2,3,43dolociStevilo(3)2311,22dolociStevilo(2)
3131dolociStevilo(1)konec zanke2dolociStevilo(2)
34211,2,33dolociStevilo(3)42142dolociStevilo(2)
43211,2,3,43dolociStevilo(3)3211,2,32dolociStevilo(2)
211,21dolociStevilo(1)110dolociStevilo(0)
permutacijast v stavku forpozklic
Osnove programiranja 2 - 43 - ©Viljan Mahnič
Rekurzija
• Skakačev obhod– podana je šahovska deska velikosti N x N– skakač se na začetku nahaja na enem izmed polj– obiskati mora vsa polja tako, da se na vsakem polju ustavi samo enkrat
• Z vsakega polja je možnih največ 8 potez
odmiki pri posameznih potezah
a[0]=2; b[0]=1; a[4]=-2; b[4]=-1;
a[1]=1; b[1]=2; a[5]=-1; b[5]=-2;a[2]=-1; b[2]=2; a[6]=1; b[6]=-2;
a[3]=-2; b[3]=1; a[7]=2; b[7]=-1;07
16
x
25
34
Osnove programiranja 2 - 44 - ©Viljan Mahnič
Rekurzija
• Prikaz postopka: zopet uporabimo sestopanjeS 15. polja ne moremo nadaljevati poti, zato sevrnemo za en nivo nazaj in skušamo nadaljevativ drugi smeri.
S 14. polja ne moremo nadaljevati poti, zato sevrnemo za en nivo nazaj in skušamo nadaljevativ drugi smeri.
S 13. polja je nadaljevanje možno, vendar po20. potezi spet zaidemo v slepo ulico.
Vračamo se nazaj in brišemo poteze, dokler nepridemo do 15. polja. Od tam lahko spet nadaljujemo pot v drugi smeri.
72
11615
381
1210514
9413
721520
16116
3811419
1217105
941318
Osnove programiranja 2 - 45 - ©Viljan Mahnič
Rekurzija
• Rekurzivni postopek za izbor naslednje potezedo // zanka za vseh 8 možnih potez{
izberi naslednjo potezo;if (poteza je možna){
zabeleži potezo;if (deska ni polna){
rekurzivno ponovi postopek za naslednjo potezo;if (nadaljevanje ni uspelo) briši potezo;
}}
} while (nadaljevanje ni uspelo && so še možne poteze)
• Bistvo sestopanja: po vrnitvi iz rekurzivne metode ostanemo v zanki in poskušamo nadaljevati v drugi smeri
Osnove programiranja 2 - 46 - ©Viljan Mahnič
Rekurzija
• Dogovori, ki jih upoštevamo pri zapisu v Javi– ponazoritev šahovnice
static final int N=5, NKV=N*N; // velikost šahovnicestatic int[] a=new int[8]; // tabeli odmikovstatic int[] b=new int[8];static int[][] s=new int[N][N]; // šahovnica
s[x][y]==0 // polje še ni bilo obiskanos[x][y]==i // polje je bilo obiskano v i-ti potezi
– izbor argumentovi : zaporedma številka potezevr,st : koordinati polja, s katerega delamo potezo
– izberi naslednjo potezoint k; // indeks v tabelah odmikov a in bint x,y; // koordinati polja, kamor skoči skakačk++; x=vr+a[k]; y=st+b[k]; // izračun naslednjega polja
Osnove programiranja 2 - 47 - ©Viljan Mahnič
Rekurzija
• Dogovori, ki jih upoštevamo pri zapisu v Javi (nadalj.)– poteza je možna
• polje, kamor skoči skakač, mora biti znotraj šahovnice• polje, kamor skoči skakač, ne sme biti še obiskano
if (x<N && x>=0 && y<N && y>=0) // znotraj šahovniceif (s[x][y]==0) // polje še ni bilo obiskano
– zabeleži potezos[x][y]=i;
– briši potezos[x][y]=0;
– deska ni polna i<NKV
– nadaljevanje je uspelometodo sprogramiramo kot funkcijo, ki vrne true, če je skakač prišel do konca
Osnove programiranja 2 - 48 - ©Viljan Mahnič
Rekurzija
• Iskanje vseh možnih rešitev– metoda naslednjaPoteza() se poenostavi
• tudi v primeru, ko je bilo nadaljevanje uspešno, se zanka za izbor naslednje poteze ne prekine
• namesto stavka do...while uporabimo stavek for• metodo lahko sprogramiramo kot proceduro (vračanje vrednosti ni
več potrebno)– ostale spremembe v programu SkakacevObhod2
• izpis rešitve sprogramiramo kot posebno metodo• po izpisu vsake rešitve se izvajanje programa prekine, dokler
uporabnik ne pritisne tipke Enter• zaradi branja podatkov je potreben dodatek throws Exception
Osnove programiranja 2 - 49 - ©Viljan Mahnič
Rekurzija
• Hanojski stolpiči– imamo n obročev različnih velikosti, ki jih moramo prestaviti z ene
palice na drugo– pri tem lahko uporabljamo pomožno palico– manjši obroč lahko postavimo na večjega, ne pa obratno
• Rekurzivni opis problema– prestavimo n-1 obročev z začetne palice na pomožno– prestavimo največji obroč z začetne palice na končno– prestavimo n-1 obročev s pomožne palice na končno
Osnove programiranja 2 - 50 - ©Viljan Mahnič
Rekurzija
• Odprava rekurzije s pomočjo sklada– zahtevke za rekurzijo odlagamo na sklad– sklad (ang. stack) je podatkovna struktura, ki deluje na principu LIFO
(Last-in, First-out)– zahtevke odlagamo na sklad v obratnem vrstnem redu, kot se pojavijo
• Razred Stack iz paketa java.util– empty() funkcija, ki vrne true, če je sklad prazen– peek() funkcija, ki vrne objekt, ki se nahaja na vrhu sklada– pop() funkcija, ki odstrani objekt z vrha sklada (vrne
referenco na odstranjen objekt)– push(objekt) doda objekt na vrh sklada– search(objekt) vrne zaporedno številko objekta (objekt na vrhu
sklada ima številko 1, tisti pod njim številko 2 itd.)
Osnove programiranja 2 - 51 - ©Viljan Mahnič
Rekurzija
• Primer: Hanojski stolpiči– najprej postavimo na sklad začetni zahtevek– nato v zanki vsakokrat odvzamemo s sklada en zahtevek in ga
obdelamo (med obdelavo se lahko na sklad postavijo novi zahtevki)
– postopek ponavljamo dokler sklad ne postane prazen
• Grob opis postopka:postavi začetni zahtevek na sklad;dokler sklad ni prazen{odvzemi zahtevek z vrha sklada;obdelaj zahtevek;
}
Osnove programiranja 2 - 52 - ©Viljan Mahnič
Rekurzija
• Predstavitev zahtevka: vsak zahtevek je objekt s 4 atributi– n : število obročev, ki jih je treba prestaviti– a : izvor– b : pomožna palica– c : ponor
class Zahtevek{public int n;public char a,b,c;
public Zahtevek(int n, char a, char b, char c){this.n=n;this.a=a;this.b=b;this.c=c;
}}
Osnove programiranja 2 - 53 - ©Viljan Mahnič
Rekurzija
• Iterativna verzija metode hanoiprivate static void hanoi(int n, char a, char b, char c){
Stack s=new Stack();s.push(new Zahtevek(n,a,b,c));while (!s.empty()){Zahtevek z=(Zahtevek)s.pop();n=z.n; a=z.a; b=z.b; c=z.c; if (n==1)
System.out.println("Premakni z "+a+" na "+c);else{s.push(new Zahtevek(n-1,b,a,c));s.push(new Zahtevek(1,a,b,c));s.push(new Zahtevek(n-1,a,c,b));
}}
}
Osnove programiranja 2 - 54 - ©Viljan Mahnič
Rekurzija
• Iterativna verzija metode quicksort– Vzdrževati je treba seznam zahtev po porazdelitvah, ki še niso bile
opravljene.– Na vsakem koraku nastaneta 2 zahtevi po porazdelitvi:
• eno obdelamo takoj (tj. zahtevo za levi del tabele)• drugo uvrstimo v seznam (tj. zahtevo za desni del tabele)
– Zahteve v seznamu moramo obravnavati v obratnem vrstnem redu, kot smo jih vstavili: utripajoč sklad.
– Ponazoritev vsake zahteve: z levo in desno mejo tistega dela tabele, znotraj katerega je potrebna nova porazdelitev
– Ponazoritev sklada: uporabimo tabelo, v kateri vsak element ustreza enemu zahtevku
Osnove programiranja 2 - 55 - ©Viljan Mahnič
Rekurzija
• Ponazoritev sklada– uporabimo tabelo, v kateri vsak element ustreza enemu zahtevku
private static class ElementSklada{int l,r;ElementSklada(int l, int r){this.l=l; this.r=r;
}}
final int M=12; // max. število elementov v skladuElementSklada[] sklad=new ElementSklada[M];int s; // vrh sklada – indeks zadnjega zahtevka
Osnove programiranja 2 - 56 - ©Viljan Mahnič
Rekurzijas=0; sklad[0]=new ElementSklada(0,a.length-1);do {
l=sklad[s].l; r=sklad[s].r; s=s-1;do // sprotna obdelave zahtevkov za porazdelitev levega dela{
i=l; j=r; x=a[(l+r)/2];do{
while (a[i].manjsi(x)) ++i;while (x.manjsi(a[j])) --j;if (i<=j){
w=a[i]; a[i]=a[j]; a[j]=w;++i; --j;
}} while (i<=j);if (i<r){
s=s+1; sklad[s]=new ElementSklada(i,r);}r=j;
} while (l<=r);} while (s>=0);
Osnove programiranja 2 - 57 - ©Viljan Mahnič
Rekurzija
• Določitev velikosti sklada– v najslabšem primeru vsebuje desni del en sam element, vsi ostali
so v levem delu. – v tem primeru bi morali na sklad postaviti n zahtev, kar ni
sprejemljivo.
• Rešitev – na sklad postavimo vedno zahtevo po sortiranju večjega dela,
krajši del obdelamo sproti– velikost sklada v tem primeru ne preseže log2n – sprememba je potrebna samo v tistem delu, ki postavlja zahteve na
sklad
Osnove programiranja 2 - 58 - ©Viljan Mahnič
Rekurzija
• Sprememba v tistem delu, ki postavlja zahteve na sklad
if ((j-l)<(r-i)) // levi del je manjši, desni gre na sklad{if (i<r){s=s+1; sklad[s]=new ElementSklada(i,r);
}r=j; // nadaljujemo s porazdeljevanjem levega dela
}else // desni del je manjši, levi gre na sklad{if (l<j){s=s+1; sklad[s]=new ElementSklada(l,j);
}l=i; // nadaljujemo s porazdeljevanjem desnega dela
}
Osnove programiranja 2 - 59 - ©Viljan Mahnič
Razred Vector• Definira zbirko (angl. collection) elementov tipa Object,
ki se obnaša podobno kot tabela– deklariran je v paketu java.util, zato je na začetku programa
potrebno napovedati uporabo tega paketa z import java.util.*;
• Razlike v primerjavi s tabelo– velikost vektorja se po potrebi avtomatsko povečuje– vektor lahko hrani objekte različnih tipov (ker so vsi izpeljani iz
razreda Object)
• Podobno kot pri tabelah in objektih velja, da spremenljivka tipa Vector vsebuje naslov tiste lokacije v pomnilniku, kjer se dejansko nahajajo elementi vektorja.
Osnove programiranja 2 - 60 - ©Viljan Mahnič
Razred Vector• Kreiranje vektorjev: 4 konstruktorji
– konstruktor brez argumentov kreira vektor standardne dolžine 10Vector v=new Vector(); // prazen vektor s kapaciteto 10
– kot argument lahko navedemo zahtevano dolžinoVector v=new Vector(100); // prazen vektor s kapaciteto 100
– poleg začetne dolžine navedemo še prirastek ob vsakem povečanju velikosti (sicer velja, da se ob vsaki potrebi po povečanju velikosti kapaciteta vektorja podvoji).Vector v=new Vector(100,10); // ob vsakem povečanju se
// doda prostor za 10 objektov– kreiramo lahko vektor, ki vsebuje objekte iz neke druge, že obstoječe
zbirke (za zbirke objektov obstaja v javi vmesnik Collection, ki je nadrazred razreda Vector)Vector v=new Vector(c); // c je zbirka objektov tipa// Collection ali nekega drugega, iz Collection izpeljanega tipa
Osnove programiranja 2 - 61 - ©Viljan Mahnič
Razred Vector• Kapaciteta in velikost vektorja
– Kapaciteta (angl. capacity): število objektov, ki jih lahko v določenem trenutku shranimo v vektor (tj. razpoložljiv prostor)
– Velikost (angl. size): število dejansko shranjenih objektov
• Metodi capacity in sizeint kapaciteta=v.capacity(); // trenutna kapacitetaint velikost=v.size(); // trenutna velikostint prostor=v.capacity()-v.size(); // razpoložljiv prostor
• Ostale metode, povezane s kapaciteto in velikostjov.ensureCapacity(150); // če je kapaciteta v manjša od 150, jo
// poveča na 150, v nasprotnem primeru ostane kapacitetea nespremenjenav.setSize(50); // če je velikost manjša od 50, se v elemente do vključno
// petdesetega, vpišejo vrednosti null; če je velkost večja od 50, se vsi // elementi nad 50 izgubijo (ni več referenc, objekti še obstajajo)
v.trimToSize(); // nastavi kapaciteto na dejansko velikost vektorja
Osnove programiranja 2 - 62 - ©Viljan Mahnič
Razred Vector• Shranjevanje objektov v vektor
v.add(novObjekt); // v prvi prost element vektorja v vpiše kazalec na novObjekt; velikost vektorja se poveča za 1; ob uspešnem dodajanju vrne true
v.add(2,novObjekt); // doda novObjekt na pozicijo 2 (pozicije so oštevilčene od 0 dalje); elementi na pozicijah od vključno dva dalje se pomaknejo za eno mesto naprej; vrednost prvega argumenta ne sme biti večja od velikosti vektorja; če je enaka velikosti, gre za dodajanje na prvo prosto pozicijo
v.addElement(novObjekt); // isto kot add(novObjekt), le da ne vrne vrednosti true ali false
v.set(2,novObjekt); // novObjekt "povozi" tistega, ki je bil prej na pozicji 2; metoda vrne kazalec na element, ki je bil prej na tej poziciji
v.addAll(c); // na konec vektorja doda vse elemente iz zbirke cv.addAll(2,c); // na pozicije od vključno 2 dalje vrine vse elemente iz
zbirke c
Osnove programiranja 2 - 63 - ©Viljan Mahnič
Razred Vector
• Branje elementov iz vektorjaDelavec d=(Delavec)v.get(4); // vrne objekt, ki se nahaja na
poziciji 4; potrebna je eksplicitna pretvorba tipa, ker metoda get vrne vrednost tipa Object
Delavec d=(Delavec)v.elementAt(4); // isto kot zgorajDelavec d=(Delavec)v.firstElement(); // vrne prvi elementDelavec d=(Delavec)v.lastElement(); // vrne zadnji element
• Obdelava vseh elementov: podobna zanka kot pri tabelahDelavec d;for (int poz=0; poz<v.size(); ++poz){d=(Delavec)v.get(poz);// sledijo stavki za obdelavo objekta d
}
Osnove programiranja 2 - 64 - ©Viljan Mahnič
Razred Vector
• Prepis elementov iz vektorja v tabelo– Uporaba vektorjev zahteva dodatno režijo, zato je včasih ugodno
prepisati elemente v običajno tabelo. – To lahko naredimo z metodo toArray na dva načina:
• standardno dobimo tabelo z elementi tipa ObjectObject[] delavci=v.toArray();
med obdelavo je treba vsak element tabele pretvoriti v ustrezen tip
• če hočemo dobiti tabelo objektov ustreznega tipa, jo moramo najprej deklarirati// deklaracija tabele ustreznega tipa in ustrezne velikostiDelavec[] delavci=new Delavec[v.size()];
// prepis v tabelov.toArray(delavci);
Osnove programiranja 2 - 65 - ©Viljan Mahnič
Razred Vector• Odstranjevanje elementov iz vektorja
– Pri odstranjevanju elementov se kapaciteta vektorja ne zmanjšuje, manjša se samo velikost.v.remove(3); // odstrani element na poziciji 3; preostali elementi
// se pomaknejo za eno mesto proti začetkuDelavec d=(Delavec)v.remove(3); // metoda remove vrne
// naslov izločenega elementaboolean brisan=v.remove(d); // odstrani prvo nastopanje
// elementa d iz vektorja v; če elementa d ni v vektorju, vrne // false, sicer true
v.removeElementAt(3); // odstrani element na poziciji 3, vendar ne // vrne njegovega naslova
v.clear(); // odstrani vse elementev.removeAll(c); // iz v odstrani vse elemente, ki se nahajajo
// v zbirki c (odstrani vsa nastopanja)
Osnove programiranja 2 - 66 - ©Viljan Mahnič
Razred Vector• Iskanje elementov v vektorju
int poz=v.indexOf(d); // vrne indeks elementa d v vektorju v (če ga ni, vrne -1); za iskanje uporablja metodo equals(), ki jo je treba redefinirati
int poz=v.indexOf(d,5); // išče od vključno pozicije 5 dalje (drugi paramater pove, kje naj se prične iskanje)
int poz=v.lastIndexOf(d); // išče od konca vektorja proti začetkuint poz=v.lastIndexOf(d,5); // išče od pozicije 5 proti začetku
• Primer: želimo poiskati vsa nastopanja objekta d v vektorju vint poz=0;// začetna pozicija za iskanjewhile (poz<v.size() && poz>=0) // dokler je pozicija v mejah vektorja{poz=v.indexOf(d,poz); // poišči naslednjegaif (poz!=-1) // če ga najde{..... // stavki za obdelavo najdenega elementa ++poz; // nova pozicija za iskanje
}}
Osnove programiranja 2 - 67 - ©Viljan Mahnič
Razred Vector• Obhod s pomočjo iteratorja
– V vsaki zbirki lahko definiramo objekt, imenovan iterator, ki omogoča "sprehajanje" po posameznih elementih te zbirke.
– Iterator ima tri metode:next() // vrne naslednji objekt hasNext() // vrne true, če obstaja naslednji objekt remove() // odstrani objekt, ki smo ga dobili ob zadnjem klicu next
• Primer obhodaDelavec d;Iterator it=v.iterator(); // razred Vector podeduje
metodo iterator od razreda AbstractListwhile (it.hasNext()){d=(Delavec)it.next();... // stavki za obdelavo d
}
Osnove programiranja 2 - 68 - ©Viljan Mahnič
Razred Vector• Razred Stack je podrazred razreda Vector
– metode empty, peek, pop, push in search so definirane s pomočjo metod iz razreda Vector
public boolean empty(){ return size()==0;}
public Object peek(){ if (size()==0) throw new EmptyStackException();return elementAt(size()-1);
}
public Object pop(){ Object object=peek();removeElementAt(size()-1);return object;
}
Osnove programiranja 2 - 69 - ©Viljan Mahnič
Razred Vector
public Object push(Object object){ addElement(object);return object;
}
public int search(Object object){ // išče od konca proti začetku// elementi so oštevilčeni tako, da ima vrhnji element številko 1, // tisti pod njim številko 2 itd.int i=lastIndexOf(object);if (i<0) return -1;return size()-i;
}
public Stack() // konstruktor{}
Osnove programiranja 2 - 70 - ©Viljan Mahnič
Zbirke (Collections)
• Collections Framework: hierarhija vmesnikov in razredov za realizacijo različnih zbirk objektov– v paketu java.util– 8 različnih vmesnikov:
• Collection: zbirka objektov• List: seznam (zaporedje) elementov• Set: množica med seboj različnih (ang. unique) elementov• SortedSet: urejena množica med seboj različnih elementov• Map: zbirka parov (ključ,vrednost); ključi morajo biti med
seboj različni• SortedMap: urejena zbirka parov (ključ,vrednost)• Iterator: objekt, s katerim se sprehajamo po zbirki• ListIterator: objekt, s katerim se sprehajamo po seznamu
Osnove programiranja 2 - 71 - ©Viljan Mahnič
Zbirke (Collections)Object
AbstractCollection CollectionAbstractList List
AbstractSequentialListLinkedList
ArrayListVector
StackAbstractSet Set
HashSetTreeSet SortedSet
AbstractMap MapHashMapTreeMap SortedMapWeakHashMap
ArraysBitSet IteratorCollection ListIteratorDictionary
Hashtable MapProperties
Osnove programiranja 2 - 72 - ©Viljan Mahnič
Zbirke (Collections)
• Vmesnik Collectionpublic interface Collection {public boolean add(Object o);// vrne true, če se je vsebina zbirke spremenilapublic boolean addAll(Collection c);// doda objekte iz zbirke c// vrne true, če se je vsebina zbirke spremenilapublic void clear();
public boolean contains(Object o);public boolean containsAll(Collection c);// vrne true, če zbirka vsebuje vse objekte iz zbirke cpublic boolean equals(Object o);
public int hashCode(); // vrne hash kodo zbirkepublic int size();
public boolean isEmpty();
Osnove programiranja 2 - 73 - ©Viljan Mahnič
Zbirke (Collections)
• Vmesnik Collection (nadalj.)public Iterator iterator();// vrne iterator, ki služi za obhod zbirkepublic boolean remove(Object o);
public boolean removeAll(Collection c);// odstrani tiste objekte, ki so v zbirki c// vrne true, če se je vsebina zbirke spremenilapublic boolean retainAll(Collection c);// obdrži samo tiste objekte, ki so v zbirki c// vrne true, če se je vsebina zbirke spremenilapublic Object[] toArray();// prepiše zbirko v tabelo objektovpublic Object[] toArray(Object[] o);// prepiše zbirko v tabelo objektov točno določenega tipa, npr.// String[] x = (String[]) v.toArray(new String[0]);
Osnove programiranja 2 - 74 - ©Viljan Mahnič
Zbirke (Collections)
• Razred AbstractCollection– delna implementacija vmesnika Collection
• javap java.util.AbstractCollection
– implementira, kar se da, ne da bi poznali dejansko pomnilniško strukturo za predstavitev zbirke
– metodi equals() in hashCode() podeduje od razreda Object• njihova redefinicija je prepuščena podrazredom
– metodi iterator() in size() sta še vedno abstraktni• s tem prisilimo podrazrede, da ju definirajo• vseeno ju lahko uporabljamo pri deklaraciji ostalih metod, npr. toString() in isEmpty()
– metoda toString() je redefinirana tako, da med dvema oglatima oklepajema izpiše vsebino vseh objektov v zbirki
Osnove programiranja 2 - 75 - ©Viljan Mahnič
Zbirke (Collections)
• Redefinicija metode toString()public String toString(){ if (isEmpty()) return "[]";Iterator it=iterator();String str="["+it.next;while (it.hasNext())str += ", "+it.next();
return str+"]";}
– za obhod potrebujemo iterator– dejanska deklaracija iteratorja je v podrazredu– pravilen izpis posameznih objektov nam zagotavlja dinamično
povezovanje metode toString()• uporabi se metoda toString() iz tistega razreda, ki mu pripada
objekt, ki ga izpisujemo
Osnove programiranja 2 - 76 - ©Viljan Mahnič
Zbirke (Collections)
• Deklaracija metode isEmpty()– uporabljena je metoda size(), čeprav še ni definirana
public boolean isEmpty(){ return size()==0;
}
• Primer: Razred Bag
– bag (torba) je neurejena zbirka objektov, ki lahko vsebuje duplikate– realizirali jo bomo kot razširitev razreda AbstractCollection– za predstavitev objektov bomo uporabili tabelo
private Object[] objects; // tabela za predstavitev torbeprivate int size=0; // število objektov v torbiprivate static final int CAPACITY=16; // kapaciteta
– iterator bo realiziran s pomočjo notranjega razreda BagIterator
Osnove programiranja 2 - 77 - ©Viljan Mahnič
Zbirke (Collections)
• Notranji razred (ang. inner class)– razred, ki je deklariran znotraj nekega drugega (zunanjega) razreda – ima dostop do vseh spremenljivk zunanjega razreda– običajno je deklariran kot private
private class BagIterator implements Iterator{private int cursor=0;
public boolean hasNext(){ return cursor<size;}public Object next(){ if (cursor>=size) return null;return objects[cursor++];// ob izstopu cursor vsebuje indeks naslednjega elementa
}
Osnove programiranja 2 - 78 - ©Viljan Mahnič
Zbirke (Collections)public void remove()// odstrani objekt, ki smo ga dobili ob zadnjem klicu next// na izpraznjeno mesto prestavi zadnji objekt{ objects[--cursor] = objects[--size];objects[size] = null;
}}
– iterator generiramo kot objekt notranjega razredapublic Iterator iterator(){return new BagIterator();
}
• Anonimni notranji razred– krajši zapis, kadar potrebujemo en sam objekt notranjega razreda– v tem primeru za notranji razred ne potrebujemo imena
Osnove programiranja 2 - 79 - ©Viljan Mahnič
Zbirke (Collections)
public Iterator iterator(){ return new Iterator() // anonimni notranji razred vsebuje samo telo razreda{ private int cursor=0;public boolean hasNext(){ return cursor<size;}public Object next(){ if (cursor>=size) return null;return objects[cursor++];
}public void remove(){ objects[--cursor] = objects[--size];objects[size] = null;
}}; // obvezno podpičje
}
Osnove programiranja 2 - 80 - ©Viljan Mahnič
Zbirke (Collections)
• Vrsta– podatkovna struktura, ki deluje na principu FIFO (First-in, First-out)
• primer: vrsta za nakup vstopnic v kinu– hierarhija vmesnikov in razredov Collections Framework ne vsebuje
posebnega vmesnika oziroma abstraktnega razreda za vrsto– izhajali bomo iz vmesnika Collection, ki mu bomo dodali 4 metode,
tipične za vrsto
import java.util.*;public interface Queue extends Collection{ public Object dequeue(); // odvzame objekt z začetka vrstepublic Object enqueue(Object object); // doda na koncu vrstepublic Object getBack(); // vrne vrednost prvegapublic Object getFront(); // vrne vrednost zadnjega
}
Osnove programiranja 2 - 81 - ©Viljan Mahnič
Zbirke (Collections)
• Primer delovanja vrste
Recimo, da je q objekt tipa vrsta:
q.enqueue("Novak"); [Novak]
q.enqueue("Kranjc"); [Novak, Kranjc]q.enqueue("Petelin"); [Novak, Kranjc, Petelin]q.enqueue("Vidmar"); [Novak, Kranjc, Petelin, Vidmar]
q.dequeue() [Kranjc, Petelin, Vidmar]q.dequeue() [Petelin, Vidmar]q.enqueue("Kajzer"); [Petelin, Vidmar, Kajzer]
Na koncu metoda getFront() vrne niz "Petelin", getBack() pa "Kajzer".
Osnove programiranja 2 - 82 - ©Viljan Mahnič
Zbirke (Collections)
• Dva načina za realizacijo vrste– realizacija s pomočjo tabele– realizacija v obliki dvosmernega seznama
• Hierarhija razredov in vmesnikovObject
AbstractCollection CollectionAbstractQueue Queue
ArrayQueueLinkedQueue
• Razred AbstractQueue– je razširitev razreda AbstractCollection– implementira vmesnik Queue– vsebuje tiste dele rešitve, ki so neodvisni od predstavitve vrste
Osnove programiranja 2 - 83 - ©Viljan Mahnič
Zbirke (Collections)
• Predstavitev s pomočjo tabele: razred ArrayQueueprotected Object[] objects;protected int front=0; // prvo zasedeno mestoprotected int back=0; // prvo prosto mestoprotected int capacity=16; // trenutna kapaciteta
• Tabela objects
0 1 2 3 ... capacity-1frontback
0 1 2 3 front back capacity-1
Osnove programiranja 2 - 84 - ©Viljan Mahnič
Zbirke (Collections)
• Dodajanje v vrsto– nov objekt dodamo v element z indeksom back, back povečamo za 1– če v tabeli ni več prostora, generiramo novo tabelo z dvakrat večjo
kapaciteto in vanjo prepišemo vsebino vrstepublic Object enqueue(Object object){ if (back>=capacity){ Object[] temp = objects;capacity *= 2; // podvojimo kapacitetoobjects = new Object[capacity];for (int i=0; i<back-front; i++)objects[i] = temp[i+front];
back -= front;front = 0;
}objects[back++] = object;return object;
}
Osnove programiranja 2 - 85 - ©Viljan Mahnič
Zbirke (Collections)
• Odvzemanje iz vrste– odvzamemo element z indeksom front in povečamo front za 1– če je leva polovica tabele prazna, pomaknemo vse elemente na
začetek
public Object dequeue(){ if (isEmpty()) throw
new NoSuchElementException("Queue is empty");Object object = objects[front++];if (2*front>=capacity) // pomik v levo{ for (int i=0; i<size(); i++)
objects[i] = objects[i+front];back -= front;front = 0;
}return object;
}
Osnove programiranja 2 - 86 - ©Viljan Mahnič
Zbirke (Collections)
• Iteratorpublic Iterator iterator(){ return new Iterator() // anonimni notranji razred{ private int cursor=front;public boolean hasNext(){ return cursor<back;}public Object next(){ if (cursor>=back) throw
new NoSuchElementException();return objects[cursor++];
}public void remove() // odvzemanje dovolimo samo z metodo// dequeue(), zato metoda remove() ni implementirana{ throw new UnsupportedOperationException();}
};}
Osnove programiranja 2 - 87 - ©Viljan Mahnič
Zbirke (Collections)
• Predstavitev v obliki seznama: razred LinkedQueue– vrsta je predstavljena kot zaporedje elementov, ki so med seboj
povezani v obeh smereh– vsak element seznama (vozlišče) vsebuje
• objekt (naslov objekta)• naslov naslednika• naslov predhodnika
– razred Nodeprivate static class Node{ // atributi vozliščaObject object;Node next, previous;// sledijo deklaracije metod
}
Osnove programiranja 2 - 88 - ©Viljan Mahnič
Zbirke (Collections)
• Prazna vrsta– na začetek seznama kaže "kazalec" header– seznam vsebuje eno samo vozlišče: slepi element– kazalca next in previous kažeta na slepi element
header
null
Osnove programiranja 2 - 89 - ©Viljan Mahnič
Zbirke (Collections)
• Vrsta v splošnemheader
prvi element zadnji elementobj1 objnobj3obj2
null
Osnove programiranja 2 - 90 - ©Viljan Mahnič
Zbirke (Collections)
• Kreiranje vozlišč v seznamu: 2 konstruktorja– konstruktor za slepi element
Node(){ this.next = this.previous = this;}
– konstruktor za vozlišče, ki hrani objektNode(Object object, Node next, Node previous){ this.object = object;this.next = next;this.previous = previous;
}
– prvi konstruktor se kliče na začetku, ko kreiramo prazno vrsto– drugi konstruktor se kliče ob dodajanju objektov v vrsto z metodo enqueue()
Osnove programiranja 2 - 91 - ©Viljan Mahnič
Zbirke (Collections)
• Dodajanje v vrsto– zapomnimo si kazalec na zadnji element– ustvarimo novo vozlišče in vpišemo vrednosti atributov– vzpostavimo povezavi
• od (pred tem) zadnjega elementa naprej• od header-ja nazaj
– povečamo število objektov v vrstipublic Object enqueue(Object object){ Node p = header.previous; // zadnji elementheader.previous=p.next=new Node(object,header,p);++size;return object;
}
Osnove programiranja 2 - 92 - ©Viljan Mahnič
Zbirke (Collections)
• Odvzemanje iz vrste– metoda dequeue() vrne objekt header.next.object
– kazalec na začetek vrste prestavimo na naslednje vozlišče– kazalec previous iz naslednjega vozlišča mora kazati na slepi
element– število objektov v vrsti se zmanjša za 1
public Object dequeue(){ if (isEmpty()) throw new
NoSuchElementException("queue is empty");Object object = header.next.object;header.next = header.next.next;header.next.previous = header;--size;return object;
}
Osnove programiranja 2 - 93 - ©Viljan Mahnič
Zbirke (Collections)
• Iterator– kurzor je tipa Node in na začetku kaže na slepi element– naslednik obstaja, če atribut next v trenutnem vozlišču ne kaže na
slepi element– operacija remove() ni dovoljena; odvzemanje dovolimo samo z
operacijo dequeue()public Iterator iterator(){ return new Iterator() // anonimni notranji razred{ private Node cursor=header;public boolean hasNext(){ return cursor.next != header;}
Osnove programiranja 2 - 94 - ©Viljan Mahnič
Zbirke (Collections)
• Iterator (nadalj.)public Object next(){ if (cursor.next==header) throw new
NoSuchElementException();cursor = cursor.next;return cursor.object;
}
public void remove(){ throw new UnsupportedOperationException();}
};}