Osnove programiranja 2 - Shrani.sishrani.si/files/prosojnice106nk.pdf · Osnove programiranja...
Transcript of Osnove programiranja 2 - Shrani.sishrani.si/files/prosojnice106nk.pdf · Osnove programiranja...
Osnove programiranja 2Interdisciplinarni študij Računalništvo in matematika
Matjaž Kukar
http://ltpo.fri.uni-lj.si/predmeti/rmosprog2/index.htm
UNIVERZA V LJUBLJANIFakulteta za računalništvo in informatiko
Pregled
• Java - ponovitev: spremenljivke, objekti in razredi
• Delo z grafiko (AWT, Swing)– delo z okni, dogodkovni model– risanje
• Apleti (applets)
• Algoritmi– Urejanje– Rekurzija
• Zbirke (Collections)
• Novosti Jave 5 in Jave 6
Literatura• Core Java(TM) 2, 7th Edition
Cay Horstmann, Gary CornellPrentice Hall 2004
• Beginning Java 2, JDK 5 Edition Ivor HortonWrox, 2004
• Data Structures with JavaJohn R. Hubbard McGraw-Hill, 2003 (druga izdaja junij 2007)
• Algorithms and Data StructuresNiklaus WirthPrentice Hall, 1985
• Spletni viriOsnove programiranja 2 - 4 - ©Matjaž Kukar, Viljan Mahnič
Zgradba programa in dostopnost deklaracij
• Zgradba programa v Javi
• Območje veljavnosti deklaracij– 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
Groba zgradba programa v Javi
/* */ ali // Komentar/** */ Javadoc komentar
package ime_paketa; // Lahko ga tudi izpustimo
import uvoz_obstojecih_paketov; // Po potrebi
class ime_razreda {deklaracije globalnih spremenljivk
deklaracije metod
static void main() { // Posebna metoda za. . . // glavni program
}}
Osnove programiranja 2 - 6 - ©Matjaž Kukar, 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 - 7 - ©Matjaž Kukar, Viljan Mahnič
Lokalne in globalne spremenljivke
• Lokalne spremenljivke– deklarirane so znotraj posameznih metod– dostopne so samo v metodi, kjer so deklarirane
• Globalne spremenljivke– deklarirane so na ravni razreda– dostopne so vsem metodam v razredu
• 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 - 8 - ©Matjaž Kukar, 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 in spr5
}}
Osnove programiranja 2 - 9 - ©Matjaž Kukar, Viljan Mahnič
Dostopna določila:public, private in protected
• Določajo način dostopa do posameznih atributov in metod v razredu in/ali paketu
Dostopno določilo Dovoljen dostop
brez dostopnega določila iz kateregakoli razreda v istem paketu
public iz kateregakoli razreda ne glede na paket
private samo znotraj razredaprotected iz kateregakoli razreda v istem
paketu in iz kateregakoli podrazreda ne glede na paket
Osnove programiranja 2 - 10 - ©Matjaž Kukar, Viljan Mahnič
Statične spremenljivke in spremenljivke objekta
• Statične (razredne) spremenljivke (ang. class variables)– tipične so za razrede, ki predstavljajo aplikacije, vendar lahko nastopajo
tudi v drugih razredih– 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 - 11 - ©Matjaž Kukar, 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 - 12 - ©Matjaž Kukar, Viljan Mahnič
Statične metode (metode razreda)
• Dostopno določilo static pri metodah– statične metode ali metode razreda (ang. class methods)– ne mešajmo z metodami 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 - 13 - ©Matjaž Kukar, Viljan Mahnič
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 - 14 - ©Matjaž Kukar, 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 - 15 - ©Matjaž Kukar, 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 - 16 - ©Matjaž Kukar, Viljan Mahnič
Vnaprej deklarirani razredi
• V Javi obstaja več tisoč 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 - 17 - ©Matjaž Kukar, 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>)
abs(x) absolutna vrednost xsin(x),cos(x),
tan(x)trigonometrične funkcije sinus, kosinus, tangens
asin(x),acos(x),atan(x)
obratne trigonometrične funkcije
round(x) zaokroževanje na najbližje celo številosqrt(x) kvadratni koren iz xrandom() naključno število med 0.0 in 1.0exp(x),log(x) eksponentna in logaritemska funkcija
Osnove programiranja 2 - 18 - ©Matjaž Kukar, Viljan Mahnič
Razred Character
• Vsebuje koristne metode za delo z znaki– deklariran je v paketu java.lang– klicanje metod: Character.<ime metode>(<argChar>)
isUpperCase() Preveri, ali je znak velika črkatoUpperCase() Pretvori malo črko v velikoisLowerCase() Preveri, ali je znak mala črkatoLowerCase() Pretvori veliko črko v maloisDigit() Preveri, ali je znak številka ('0' – '9')isLetter() Preveri, ali je znak črkaisLetterOrDigit() Preveri, ali je znak črka ali številkaisWhiteSpace() Preveri, ali je znak presledek, tab, newline, carriage
return ali form feed
Materiali
• Java programi:– Krogla1.java– Krogla2.java– Krogla3.java
Osnove programiranja 2 - 21 - ©Matjaž Kukar, Viljan Mahnič
Uvod v delo z grafiko
• Knjižnici AWT in Swing
• Kreiranje okna– okno kot podrazred razreda JFrame
• Dogodkovni model: razredi dogodkov, vmesniki, adapterji, poslušalci– primer: zapiranje okna
• Upoštevanje karakteristik uporabnikovega računalnika
• Risanje na panel
• Pregled metod za risanje
Osnove programiranja 2 - 22 - ©Matjaž Kukar, Viljan Mahnič
Uvod v delo z grafiko
• JFC vsebuje dve knjižnici razredov za programiranje grafičnega uporabniškega vmesnika (GUI)– AWT (Abstract Window Toolkit)
• starejša (prvotna) knjižnica, skupni imenovalec obstoječih GUI• realizacija komponent prepuščena ciljni platformi• problemi: skromnost, različno obnašanje na različnih platformah
– Swing• novejša knjižnica• večji nabor komponent GUI• enostavnejša uporaba• manjša odvisnost od ciljne platforme• enak videz na vseh platformah• Swing uporablja dogodkovno voden način programiranja, kot ga
definira AWT– V programih kombiniramo uporabo obeh knjižnic
Delček hierarhije knjižnice AWT
Delček hierarhije knjižnice Swing
Primer hierarhije AWT in Swing
Osnove programiranja 2 - 26 - ©Matjaž Kukar, Viljan Mahnič
Kreiranje okna
• Osnovno okno, v katerem rišemo, je objekt razreda JFrame– v paketu AWT obstaja razred Frame– razred JFrame je razširitev razreda Frame– osnovno okno je ena redkih komponent, ki jih ne nariše Swing, ampak
okenski sistem ciljne platforme– osnovno okno je kontejner (ang. container), ki lahko vsebuje druge
komponente grafičnega uporabniškega vmesnika (gumbi, tekstovnapolja, ...)
• Program za kreiranje okna mora vsebovati– napoved uporabe paketa Swing: import javax.swing.*;– kreiranje objekta tipa JFrame: JFrame okno=new JFrame();– prikaz okna na zaslonu: okno.setVisible(true);
zastarela sintaksa okno.show();
Osnove programiranja 2 - 27 - ©Matjaž Kukar, Viljan Mahnič
Kreiranje okna
• Boljša rešitev za kakršna koli zahtevnejša okna– iz razreda JFrame izpeljemo podrazred, ki natančneje definira lastnosti
okna– v podrazredu deklariramo konstruktor, ki vsebuje ukaze, kot so npr.
setTitle(<naslov>); // imesetSize(<širina>,<višina>); // velikostsetLocation(<x>,<y>); // legasetBounds(<x>,<y>,<širina>,<višina>); // velikost in legasetResizable(<vrednostBoolean>); // spreminjanje velikosti
• Privzeto delovanje– ko okno zapremo, se izvajanje programa ne prekine– za prekinitev je potrebno vtipkati CTRL+C
MVC (model-view-controller) arhitektura GUI
• Model: hrani podatke, ki definirajo komponento GUI
• View: vizualni prikaz podakov iz modela
• Controller: interakcija z uporabnikom; po potrebi spreminja pogled ali model
MVC arhitektura v Swingu
Osnove programiranja 2 - 30 - ©Matjaž Kukar, Viljan Mahnič
Krmiljenje programa kot reakcija na dogodke
• Swing temelji na AWT dogodkovnem modelu– dogodek je sprememba v stanju določene komponente zaradi interakcije s
strani uporabnika (npr. klik z miško, pritisk tipke na tipkovnici, vpis podatka v polje za vnos ipd.)
– vsaka komponenta GUI s katero je uporabnik v interakciji, mora vsebovati poseben objekt, ki nastopa v vlogi poslušalca
– poslušalec: objekt, ki prestreže določen dogodek, in izvrši primerno akcijo– vsi poslušalci skupaj predstavljajo ekvivalent MVC controllerja
• Dogodki so razvrščeni v več razredov– primeri: KeyEvent, MouseEvent, ActionEvent, WindowEvent– za vsak tip (razred) dogodka lahko dodamo ustreznega poslušalca
Nizkonivojski dogodki
Osnove programiranja 2 - 32 - ©Matjaž Kukar, Viljan Mahnič
Pregled dogodkov, vmesnikov in odzivnih metod (1/3)
mousePressed(MouseEvent e)mouseReleased(MouseEvent e)mouseEntered(MouseEvent e)mouseExited(MouseEvent e)mouseClicked(MouseEvent e)mouseDragged(MouseEvent e)mouseMoved(MouseEvent e)
MouseListener
MouseMotionListener
MouseEvent
Tip dogodka Vmesnik Odzivne metodeTextEvent TextListener textValueChanged(ActionEvent e)
ContainerEvent ContainerListener componentAdded(ContainerEvent e)componentRemoved(ContainerEvent e)
ComponentEvent ComponentListener componentMoved(ComponentEvent e)componentHidden(ComponentEvent e)componentResized(ComponentEvent e)componentShown(ComponentEvent e)
Osnove programiranja 2 - 33 - ©Matjaž Kukar, Viljan Mahnič
Pregled dogodkov, vmesnikov in odzivnih metod (2/3)
keyPressed(KeyEvent e)keyTyped(KeyEvent e)keyReleased(KeyEvent e)
KeyListenerKeyEvent
windowActivated(WindowEvenet e)windowClosing(WindowEvenet e)windowClosed(WindowEvenet e)windowDeactivated(WindowEvent e)windowDeiconified(WindowEvenet e)windowIconified(WindowEvenet e)windowOpened(WindowEvenet e)
WindowListenerWindowEvent
Tip dogodka Vmesnik Odzivne metode
FocusEvent FocusListener focusGained(FocusEvent e)focusLost(FocusEvent e)
Semantični (višjenivojski) dogodki
Osnove programiranja 2 - 35 - ©Matjaž Kukar, Viljan Mahnič
Pregled dogodkov, vmesnikov in odzivnih metod (3/3)
Tip dogodka Vmesnik Odzivne metode
ActionEvent ActionListener actionPerformed(ActionEvent e)
ItemEvent ItemListener itemStateChanged(ItemEvent e)
AdjustmentEvent AdjustmentListener adjustmentValueChanged(AdjustmentEvent e)
Osnove programiranja 2 - 36 - ©Matjaž Kukar, Viljan Mahnič
Pregled metod za dodajanje poslušalcev
Komponente (izvori dogodkov)
Metode za dodajanje poslušalcev
JButton, JCheckBox, JComboBox, JToolBar, JTextField, JRadioButton
addActionListener()
JScrollBar addAdjustmentListener()
Vse Swing komponente addFocusListener(), addKeyListener(), addMouseListener(), addMouseMotionListener()
JButton, JCheckBox, JComboBox, JRadioButton
addItemListener()
JWindow, JFrame addWindowListener()
JSlider addChangeEvent()
Osnove programiranja 2 - 37 - ©Matjaž Kukar, Viljan Mahnič
Prekinitev izvajanja programa ob zapiranju okna• Potrebujemo poslušalca za dogodke tipa WindowEvent
• Deklaracija poslušalca– poslušalec mora pripadati razredu, v katerem so implementirane VSE metode za
določeno vrsto dogodkov– delo nam olajša uporaba adapterjev (implementacije vmesnikov z metodami, ki
ne naredijo ničesar); implementiramo samo tisto, kar potrebujemo– za dogodke tipa WindowEvent uporabimo razred WindowAdapter, ki je
implementacija vmesnika WindowListener– vmesnik WindowListener predpisuje 7 metod, ki ustrezajo posameznim
dogodkom tipa WindowEvent
public void windowActivated(WindowEvent e)public void windowClosed(WindowEvent e)public void windowClosing(WindowEvent e)public void windowDeactivated(WindowEvent e)public void windowDeiconified(WindowEvent e)public void windowIconified(WindowEvent e)public void windowOpened(WindowEvent e)
Osnove programiranja 2 - 38 - ©Matjaž Kukar, Viljan Mahnič
Prekinitev izvajanja programa ob zapiranju okna
• Deklaracija poslušalca (nadalj.)– iz razreda WindowAdapter izpeljemo podrazred, ki redefinira
metodo WindowClosingclass Poslusalec extends WindowAdapter{public void windowClosing(WindowEvent e){System.exit(0);
}}
– v konstruktorju za okno deklariramo poslušalcaWindowListener p=new Poslusalec();okno.addWindowListener(p);
Osnove programiranja 2 - 39 - ©Matjaž Kukar, Viljan Mahnič
Prekinitev izvajanja programa ob zapiranju okna
• Uporaba metode setDefaultCloseOperation()– s pomočjo metode setDefaultCloseOperation() lahko določimo
operacijo, ki se izvede ob zapiranju okna– operacijo podamo kot argument ob klicu metode– obstajajo vnaprej deklarirane konstante, ki določajo posamezne operacije
• DO_NOTHING_ON_CLOSE: ne naredi nič• HIDE_ON_CLOSE: zapre okno, program teče naprej • DISPOSE_ON_CLOSE: zapre okno in uniči objekt, ki predstavlja okno;
program teče naprej• EXIT_ON_CLOSE: prekine izvajanje programa (od Jave 3 (JDK 1.3) dalje)
– če ne določimo operacije ob zapiranju, se avtomatsko privzame HIDE_ON_CLOSE
Osnove programiranja 2 - 40 - ©Matjaž Kukar, Viljan Mahnič
Upoštevanje karakteristik uporabnikovega računalnika
• Razred Toolkit iz paketa java.awt.*– metoda getDefaultToolkit() vrne objekt tipa Toolkit– ugotovimo lahko velikost zaslona
Toolkit tk=Toolkit.getDefaultToolkit(); // statičnaDimension d=tk.getScreenSize();int sirina=d.width;int visina=d.height;
– ob odpiranju okna upoštevamo dejansko širino in višino zaslona– primer za centrirano okno, katerega širina in višina je enaka polovici
širine in višine zaslona; točka (0,0) je zgoraj levosetSize(sirina/2,visina/2);setLocation(sirina/4,visina/4);
alisetBounds(sirina/4, visina/4, // Location
sirina/2, visina/2); // Size
Nitna varnost (thread safety) v Swingu
• Niti (threads): vzporedni procesi znotraj istega programa
• Po kreiranju komponente (okna) z ukazom setVisible se taizvaja v ločeni dogodkovni niti (event dispatching thread)
• Swing ni nitno varen, zato z njegovimi elementi upravlja le dogodkovna nit
• Posledice:– Modifikacije GUI se smejo izvajati samo v dogodkovni niti (uporaba
metode invokeLater iz javax.swing.SwingUtilities)– Daljši izračuni v aplikaciji, ki so posledica neke akcije uporabnika v
GUI naj se izvajajo v ločeni niti, sicer lahko pride do neodzivnosti
Materiali
• Java programi:– OsnovnoOkno.java– TestOkna1.java– TestOkna2.java– TestOkna3.java– TestOknaDefaultClose.java– GUI_Thread.java
Razpored študentov po ciklih vaj
• Kropivšek-Žonta (1.skupina), 16.15 - 17.45
• Ambrožič-Krnc (2.skupina), 18.00 - 19.45
• Kandidati za težje domače naloge?
Spreminjanje videza aplikacij
import javax.swing.UIManager;import javax.swing.SwingUtilities;
UIManager.setLookAndFeel(“ime_izgleda”);SwingUtilities.updateComponentTreeUI(window);
• Nekateri izgledi:
javax.swing.plaf.metal.MetalLookAndFeelcom.sun.java.swing.plaf.motif.MotifLookAndFeelcom.sun.java.swing.plaf.windows.WindowsLookAndFeel
Osnove programiranja 2 - 45 - ©Matjaž Kukar, Viljan Mahnič
Risanje
• Vsebina okna je določena s ploščo content pane– v konstruktorju za okno je treba
• pridobiti ploščo z vsebino content pane• deklarirati komponento, na katero želimo risati na plošči• dodati komponento na ploščo
– če hočemo v oknu risati različne geometrijske oblike (črte, pravo-kotnike, kroge ipd.), je treba deklarirati komponento tipa JPanelContainer vsebina=getContentPane();JPanel panel1=new JPanel();vsebina.add(panel1);
– rišemo dejansko na panel• panel ima risalno površino, na katero rišemo• je kontejner (vsebuje lahko druge komponente)• podobno kot ostale komponente vsebuje metodo paintComponent
Osnove programiranja 2 - 46 - ©Matjaž Kukar, Viljan Mahnič
Risanje
• Risanje na panel– deklarirati je treba podrazred razreda JPanel– redefinirati je treba metodo paintComponent(Graphics g)
• risanje realiziramo s klici ustreznih metod razreda Graphics• obvezen je klic istoimenske metode nadrazreda• metode paintComponent ni treba klicati, ampak se izvede avtomatsko
• Primer deklaracije panela, v katerem se nariše črtaclass Panel1 extends JPanel{public void paintComponent(Graphics g){super.paintComponent(g);g.drawLine(10,10,100,70);
}}
Osnove programiranja 2 - 47 - ©Matjaž Kukar, Viljan Mahnič
Pregled metod za risanje• "Risanje" nizov
– drawString(niz,x,y)• izpiše niz tako, da je prvi znak niza (oziroma njegov skrajno levi
spodnji del) odmaknjen od gornjega levega oglišča panela za x točk v desno in y točk navzdol
– setFont(f)• nastavi obliko črk v skladu s parametrom f• f objekt je tipa Font in mora biti prej določen, npr.
Font f=new Font(“Ime instal. fonta",Font.BOLD,15);
• logična imena fontov v AWT: SansSerif, Serif, Monospaced,Dialog, DialogInput
• način izpisa (ang. style): Font.PLAIN, Font.BOLD,Font.ITALIC, Font.BOLD+Font.ITALIC
– getHeight(), stringWidth(niz)• metoda razreda FontMetrics, ki za font f vrne dolžino niza
FontMetrics fm=g.getFontMetrics(f);int dolzina=fm.stringWidth(niz);
Osnove programiranja 2 - 48 - ©Matjaž Kukar, Viljan Mahnič
Pregled metod za risanje
• Risanje črt, lokov in mnogokotnikov– drawLine(x1,y1,x2,y2);
• nariše črto med točkama (x1,y1) in (x2,y2)– drawArc(x,y,sirina,visina,zacKot,kot)
• nariše lok, ki se nahaja znotraj navideznega pravokotnika z levim zgornjim ogliščem v točki (x,y) in stranicama a=sirina, b=visina
• lok se prične pri kotu zacKot in oklepa kot kot (tj. se konča pri zacKot+kot); koti so podani v stopinjah
– drawPolygon(p)• nariše mnogokotnik, katerega stranice so določene s točkami objekta p• primer za risanje trikotnika
Polygon p=new Polygon();p.addPoint(10,10);p.addPoint(10,30);p.addPoint(20,20);g.drawPolygon(p);
Osnove programiranja 2 - 49 - ©Matjaž Kukar, Viljan Mahnič
Pregled metod za risanje
– drawPolygon(x,y,n)
• nariše mnogokotnik, katerega oglišča so podana s koordinatami točk v tabelah x in y
• parameter n določa število oglišč– drawPolyline(x,y,n)
• nariše lomljeno črto, ki povezuje točke, katerih koordinate so v tabelah x in y
• n je število točk, ki jih je treba povezati• če sta prva in zadnja točka identični, je črta zaključena
• Risanje pravokotnikov, krogov in elips– drawRect(x,y,sirina,visina)
• nariše pravokotnik z z levim zgornjim ogliščem v točki (x,y) in stranicama a=sirina, b=visina
Osnove programiranja 2 - 50 - ©Matjaž Kukar, Viljan Mahnič
Pregled metod za risanje
– drawRoundRect(x,y,sirina,visina,rH,rV)
• nariše pravokotnik z zaobljenimi oglišči• rH in rV določata horizontalni in vertikalni polmer loka
– draw3DRect(x,y,sirina,visina,dvig)
• nariše pravokotnik, ki daje vtis gumba• če je parameter dvig enak true, je pravokotnik "dvignjen" nad
površino okna, sicer pa "vgreznjen"• učinek postane viden, če narišemo več pravokotnikov, katerih stranice
se povečujejo za eno piko, koordinate levega zgornjega oglišča pa zmanjšujejo za eno piko
– drawOval(x,y,sirina,visina)
• nariše elipso, ki se nahaja znotraj navideznega pravokotnika z levim zgornjim ogliščem v točki (x,y) in stranicama a=sirina,b=visina
• če sta parametra sirina in visina enaka, dobimo krog
Osnove programiranja 2 - 51 - ©Matjaž Kukar, Viljan Mahnič
Pregled metod za risanje
• Določanje barv– setColor(barva) // Graphics
• nastavi barvo, s katero rišemo od tega trenutka dalje• paramater barva je objekt tipa Color• v razredu Color so definirane konstante za 13 standardnih barv
black green redblue lightGray whitecyan magenta yellowdarkGray orangegray pink
• primer klica: g.setColor(Color.green);• druga možnost: objekte tipa Color lahko generiramo sami kot
mešanico rdeče, zelene in modre barve z naslednjim konstruktorjemColor(int rdeca, int zelena, int modra)
• delež vsake barve lahko zavzame vrednost od 0 do 255• primer klica: g.setColor(new Color(0,128,128));
Osnove programiranja 2 - 52 - ©Matjaž Kukar, Viljan Mahnič
Pregled metod za risanje– setBackground(barva) // JComponent (JPanel)
• nastavi barvo podlage• metodo je treba poklicati, preden prikažemo okno na zaslonu
– setForeground(barva) // JComponent (JPanel)• nastavi privzeto barvo, s katero rišemo
• Risanje polnjenih likov– imena metod so enaka kot za risanje likov, le predpona draw se
nadomesti s fillfillRect(x,y,sirina,visina)fillRoundRect(x,y,sirina,visina,rH,rV)fill3DRect(x,y,sirina,visina,dvig)fillOval(x,y,sirina,visina)fillPolygon(p)fillPolygon(x,y,n)fillArc(x,y,sirina,visina,zacKot,kot)
Osnove programiranja 2 - 54 - ©Matjaž Kukar, Viljan Mahnič
Apleti
• Koncept apleta
• Postopek izdelave
• Razlike med aplikacijo in apletom, metode apleta:– init(), start(), stop(), destroy()
• Osnovne komponente grafičnega vmesnika– labela, gumb, vnosno polje– razporejanje komponent po risalni plošči
• Primeri– preprost aplet s tremi komponentami– aplet za zajem podatkov o delavcih
Osnove programiranja 2 - 55 - ©Matjaž Kukar, Viljan Mahnič
Apleti
• Aplet– program, ki teče znotraj spletnega brskalnika (npr. Internet Explorer,
Firefox, Mozilla, Opera, …)– je sestavni del neke spletne strani– pokličemo ga iz dokumenta, napisanega v HTML (Hypertext Markup
Language)– stroge zahteve glede varnosti
• Postopek izdelave apleta– aplet napišemo podobno kot druge samostojne programe (aplikacije)
• shranimo ga na datoteki s podaljškom .java• prevedemo ga v vmesno kodo (datoteka s podaljškom .class)
– kreiramo HTML dokument, ki mora vsebovati ukaz za klic apleta– poženemo spletni brskalnik in naložimo HTML dokument
Osnove programiranja 2 - 56 - ©Matjaž Kukar, Viljan Mahnič
Apleti
• Izdelava HTML dokumenta– vsak HTML dokument se prične z ukazom <html> in konča z ukazom </html>; večina ukazov ima podobno obliko
• vsi ukazi so v lomljenih oklepajih• HTML ni občutljiv na velike in male črke
– izvajanje apleta sprožimo z ukazom <applet>• ob ukazu <applet> navedemo tri argumente: code, width in heightcode podaja ime datoteke z vmesno kodo (prevod apleta)width in height določata širino in višino apleta
• ukaz <applet> zaključimo z </applet> – primer:
<html><applet code="Aplet1.class" width=450 height=200></applet></html>
Osnove programiranja 2 - 57 - ©Matjaž Kukar, Viljan Mahnič
Razvoj apletov
• Orodje appletviewer– omogoča izvajanje apletov brez uporabe brskalnika– uporabno je predvsem med razvojem in testiranjem– aplet poženemo iz GUI ali iz ukazne vrstice z ukazom appletviewer <ime HTML dokumenta>
• Razred JApplet– vsak aplet napišemo kot razširitev osnovnega razreda JApplet– razred JApplet se nahaja v paketu javax.swing in je izpeljan
iz razredov java.awt.Component, java.awt.Container injava.awt.Panel
– na začetku vsakega apleta so zato prisotni ukaziimport javax.swing.*;import java.awt.*;public class Aplet1 extends JApplet
Mesto razreda JApplet v Swing/AWT hierarhiji
→ JApplet
Osnove programiranja 2 - 59 - ©Matjaž Kukar, Viljan Mahnič
Apleti
• Metode apleta– za razliko od aplikacij apleti nimajo statične metode main()– vsebujejo 4 metode, ki jih brskalnik kliče avtomatsko
• public void init()• public void start()• public void stop()• public void destroy()
– Java avtomatsko kreira prazne metode– v praksi moramo napisati vsaj eno izmed njih, praviloma init()
• Metoda init()
– se izvede, ko se aplet prvič naloži in požene v brskalniku– služi za inicializacijo spremenljivk, razmestitev komponent na zaslonu
ipd.
Osnove programiranja 2 - 60 - ©Matjaž Kukar, Viljan Mahnič
Apleti
• Metoda start()– se izvede takoj za metodo init() in nato vsakokrat, ko postane aplet
aktiven (ko se uporabnik vrne na stran z apletom, ki jo je prej zapustil ali minimiziral)
– primer uporabe: nadaljevanje animacije, ki je bila prekinjena, ko je uporabnik zapustil stran
• Metoda stop()– se izvede vsakokrat, ko uporabnik zapusti stran z apletom
• Metoda destroy()– se izvede, ko uporabnik zapre brskalnik ali appletviewer– če je potrebno sprostiti vire, ki jih je zasedal aplet
• Isti program lahko ob primernem pisanju uporabimo tako za aplet, kot za aplikacijo
Osnove programiranja 2 - 61 - ©Matjaž Kukar, Viljan Mahnič
Apleti
• Aplet lahko vsebuje različne komponente GUI– labela (ang. label): izpis besedila (razred JLabel)– vnosno polje: polje za vnos nekega podatka (razred JTextField)– gumb: za sprožitev neke akcije (razred JButton)– ostale komponente: JCheckBox, JRadioButton, JComboBox,
JToolBar, JScrollBar, …– komponente dodajamo na risalno ploščo (ang. content pane) z metodo add()– primer: dodajanje labele, vnosnega polja in gumba
JLabel zi=new JLabel("Ime:");JTextField i=new JTextField();JButton potrdi=new JButton("Potrdi");Container rp=getContentPane();rp.add(zi); rp.add(i);rp.add(potrdi);
– URL: enostaven aplet
Osnove programiranja 2 - 62 - ©Matjaž Kukar, Viljan Mahnič
Apleti
• Razred JLabel– za izpis teksta in slik– več različnih konstruktorjev
• JLabel(): labela brez teksta in slike• JLabel(String text): labela s tekstom• JLabel(String text, int horizontalAlignment): labela s
tekstom, poravnanim v skladu s parametrom horizontalAlignment• JLabel(Icon image): labela s sliko• JLabel(Icon image, int horizontalAlignment): labela s
sliko, ki je poravnana v skladu s parametrom horizontalAlignment• JLabel(String text, Icon image, int horizontalAlignment): labela s tekstom in sliko ter predpisano poravnanostjo
– metoda l.setText(niz): vpiše niz v že kreirano labelo l– metoda l.getText(): vrne niz, ki ga vsebuje labela l
Osnove programiranja 2 - 63 - ©Matjaž Kukar, Viljan Mahnič
Apleti
• Razred JTextField– za kreiranje vnosnih polj– konstruktorji
• JTextField(): prazno vnosno polje dolžine 0 (dimenzija komponente)• JTextField(int numColumns): prazno vnosno polje dolžine numColumns (dimenzija komponente na zaslonu)
• JTextField(String text): vnosno polje z vnaprej vpisanim tekstom
• JTextField(String text, int numColumns): vnosno polje s tekstom text in dolžino numColumns (dimenzija komponente)
– metoda vp.setText(niz): vpiše niz v vnosno polje vp– metoda vp.getText(): vrne niz, ki ga vsebuje vnosno polje vp– metoda vp.setEditable(bool): določi, ali je možno vpisovanje
(bool ima vrednost true) ali ne (bool je false)Osnove programiranja 2 - 64 - ©Matjaž Kukar, Viljan Mahnič
Apleti
• Razred JButton– za kreiranje gumbov– konstruktorji
• JButton(): gumb brez napisa• JButton(String text): gumb z napisom text• JButton(String text, Icon icon): gumb z napisom in sliko• JButton(Icon icon): gumb s sliko
– metoda g.setText(niz): nastavi napis na gumbu g– metoda g.getText(): vrne napis, ki ga vsebuje gumb g
• Nastavljanje fokusa– metoda requestFocus() omogoča, da vnaprej nastavimo kurzor
tipkovnice v izbrano vnosno polje ali izpostavimo določen gumb– primer uporabe: vp.requestFocus(); ali g.requestFocus();
Osnove programiranja 2 - 65 - ©Matjaž Kukar, Viljan Mahnič
Razporejanje komponent
• Razporejanje komponent po risalni plošči– uporabimo enega izmed razporejevalnikov (ang. layout managers),
ki avtomatsko razporeja komponente znotraj kontejnerja
• Pregled razporejevalnikov– FlowLayout
• komponente razporedi po vrsticah, ko v neki vrstici zmanjka prostora, nadaljuje v naslednji vrstici
• Lahko določamo poravnavanje komponent (levo-desno-centrirano), razmik med komponentami in vrsticami
– BorderLayout• se uporabi, če ne specificiramo nobenega razporejevalnika• površino kontejnerja razdeli na 5 con, ki se imenujejo "North","West", "Center", "East" in "South"
• ob dodajanju vsake komponente je treba navesti tudi cono, kamor naj se komponenta doda
Osnove programiranja 2 - 66 - ©Matjaž Kukar, Viljan Mahnič
Razporejanje komponent
– GridLayout• komponente razporedi v celice, ki tvorijo matriko dimenzije m×n,
sestavljeno iz m vrstic in n stolpcev• število vrstic in stolpcev določimo ob inicializaciji razporejevalnika• vsaka nova komponenta se doda v naslednjo celico• preskakovanje celic ni možno
– GridBagLayout• omogoča dodajanje komponent v točno določene celice• posamezne komponente lahko zasedajo več celic
– CardLayout• komponente se nalagajo ena na drugo• primeren, ko želimo, da je naenkrat vidna samo ena komponenta
Osnove programiranja 2 - 67 - ©Matjaž Kukar, Viljan Mahnič
Razporejanje komponent
– BoxLayout• vse komponente razporedi v eno vrstico (horizontal box) ali v en stolpec
(vertical box)• posamezne škatle (vrstice ali stolpce) razporejamo znotraj BoxLayout
razporejevalnika– SpringLayout
• komponente so povezane z elastičnimi povezavami (spring=vzmet) narobove kontejnerja ali na druge komponente
– null (brez avtomatskega razporejevalnika)• sami določimo položaje in velikosti komponent, npr. z metodo SetBounds()
• Razporejevalnika BoxLayout in SpringLayout sta definirana v paketu javax.swing, ostali pa v java.awt
Osnove programiranja 2 - 68 - ©Matjaž Kukar, Viljan Mahnič
Apleti
• Določitev razporejevalnika– najprej generiramo objekt, ki pripada ustreznemu razporejevalniku, npr.
FlowLayout flow=new FlowLayout();aliGridLayout grid=new GridLayout(4,7);
– nato nastavimo razporejevalnik z metodo setLayout()Container rp=getContentPane();rp.setLayout(flow);alirp.setLayout(grid);
– oba koraka lahko združimorp.setLayout(new FlowLayout());
• Brez razporejevalnika– razporejevalnik nastavimo na null
rp.setLayout(null);
Osnove programiranja 2 - 69 - ©Matjaž Kukar, Viljan Mahnič
Primer preprostega apleta
• Aplet s tremi komponentami: labelo, vnosnim poljem in gumbom– napovemo uporabo paketov javax.swing in java.awt– aplet deklariramo kot razširitev razreda JApplet– generiramo vse tri komponente– izberemo razporejevalnik– pripravimo risalno ploščo– dodamo vse tri komponente na risalno ploščo– nastavimo fokus (kurzor tipkovnice)– URL: aplet
• Določanje barve– za vsako komponento lahko določimo barvo podlage in barvo črk
gumb.setForeground(Color.red);gumb.setBackground(Color.yellow);
Osnove programiranja 2 - 70 - ©Matjaž Kukar, Viljan Mahnič
Primer preprostega apleta• Določanje pisave
– uporabimo že znano metodo setFont(f)
– argument f je objekt tipa Font in mora biti prej določen, npr.Font pisava1=new Font("TimesRoman",Font.ITALIC,24);Font pisava2=new Font("Helvetica",Font.BOLD,20);
– pisavo določimo za vsako komponento posebej, npr.labela.setFont(pisava1);vnPolje.setFont(pisava2);
• URL: aplet
• Odstranjevanje komponent– komponente odstranjujemo z metodo remove(<ime komponente>), npr.
remove(gumb); ali remove(labela);– po odstranitvi komponente je treba vsebino risalne plošče ponovno narisati z
metodo repaint()
Osnove programiranja 2 - 71 - ©Matjaž Kukar, Viljan Mahnič
Primer preprostega apleta
• Aplet se mora odzivati na dogodke– v našem apletu lahko uporabnik zaključi vnos na dva načina
• s klikom na gumb• s tipko Enter
– oba dogodka sta tipa ActionEvent– določiti je treba poslušalca, ki bo zaznal omenjena dogodka
• poslušalec je aplet (ni treba vpeljati posebnega objekta)• poslušalec mora implementirati metode, ki so določene z vmesnikom
(ang. interface) ActionListener– vmesnik ActionListener zahteva samo eno metodo public void actionPerformed(ActionEvent d)
• za vmesnike, ki zahtevajo samo eno metodo, ne obstaja ustrezen adapter, v katerem bi bila ta metoda realizirana kot prazna metoda
• zato mora poslušalec obvezno implementirati vmesnikpublic class Pozdrav2 extends JApplet
implements ActionListenerOsnove programiranja 2 - 72 - ©Matjaž Kukar, Viljan Mahnič
Primer preprostega apleta
• Potrebne spremembe v našem apletu– dodaten stavek import java.awt.event.*;– sprememba glave
public class Pozdrav2 extends JApplet implements ActionListener
– registracija poslušalcev: obema komponentama, ki nastopata kot možna izvora dogodkov, dodamo poslušalcagumb.addActionListener(this);vnPolje.addActionListener(this);
– metoda actionPerformed(ActionEvent d)• ugotoviti mora izvor dogodka in izvršiti ustrezno akcijo• izvor dogodka določimo z metodo getSource()Object izvor=d.getSource();
• akcija, ki sledi dogodku, je odvisna od izvoraif (izvor==gumb) ...
• če nas zanima samo tip izvora uporabimo rezervirano besedo instanceofif (izvor instanceof JTextField) ...
– URL: aplet
Osnove programiranja 2 - 73 - ©Matjaž Kukar, Viljan Mahnič
Aplet za zajem podatkov o delavcih
• Opis problema– zajeti želimo naslednje podatke:
• matično številko• priimek• ime• število ur
– zajeti podatki se vpišejo v tabelo, v kateri vsak element predstavlja enega delavca (objekt tipa Delavec6)
– uporabnik vnaša podatke v 4 vnosna polja• ko vnese vse podatke za enega delavca, s pritiskom na gumb "Vnesi"
sproži vpis v tabelo• če želi, lahko pobriše vsebino vseh vnosnih polj in ponovi vnos
(gumb "Briši")• vnos poteka v zanki: ko se podatki za enega delavca vpišejo v tabelo,
se vnosna polja izpraznejo, da je možen vnos podatkov za naslednjega delavca
• ko so zajeti podatki za vse delavce, se izpiše ustrezno obvestiloOsnove programiranja 2 - 74 - ©Matjaž Kukar, Viljan Mahnič
Aplet za zajem podatkov o delavcih
• Potrebne komponente– štiri vnosna polja
JTextField ms=new JTextField(); // matična št.JTextField p=new JTextField(); // priimekJTextField i=new JTextField(); // imeJTextField u=new JTextField(); // število ur
– pred vsakim vnosnim poljem izpišemo ustrezen zahtevek: štiri labeleJLabel zms=new JLabel("Matična številka:");JLabel zp=new JLabel("Priimek:");JLabel zi=new JLabel("Ime:");JLabel zu=new JLabel("Število ur:");
– dva gumbaJButton vnesi=new JButton("Vnesi");JButton brisi=new JButton("Briši");
– obvestilo o zaključku vnosa: labela, ki je na začetku praznaJLabel obv=new JLabel("");
Osnove programiranja 2 - 75 - ©Matjaž Kukar, Viljan Mahnič
Aplet za zajem podatkov o delavcih
• Razporejanje komponent– ne bomo uporabili razporejevalnika
Container rp=getContentPane();rp.setLayout(null);
– komponente razporejamo s pomočjo metode setBounds()– razmestitev zahtevkov za vnos in vnosnih polj
zms.setBounds(30,30,110,20); ms.setBounds(150,30,60,20);zp.setBounds(30,50,110,20); p.setBounds(150,50,100,20);zi.setBounds(30,70,110,20); i.setBounds(150,70,100,20);zu.setBounds(30,90,110,20); u.setBounds(150,90,60,20);
– razmestitev gumbovbrisi.setBounds(30,120,70,20);vnesi.setBounds(150,120,70,20);
– položaj obvestilaobv.setBounds(30,180,150,20);
– URL: Implementacija apleta za vnos delavcev
Osnove programiranja 2 - 76 - ©Matjaž Kukar, Viljan Mahnič
Aplet za zajem podatkov o delavcih
• Dodajanje komponent na risalno ploščorp.add(zms); rp.add(ms);rp.add(zp); rp.add(p);rp.add(zi); rp.add(i);rp.add(zu); rp.add(u);rp.add(vnesi); rp.add(brisi);rp.add(obv);
• Nastavitev kurzorja tipkovnice v prvo vnosno poljems.requestFocus();
• Deklaracija tabele delavcevstatic final int ST_DEL=5;static Delavec6[] td=new Delavec6[ST_DEL];int j=-1; // indeks v tabeli delavcev// vrednost -1 označuje, da je na začetku tabela// prazna; ob dodajanju vsakega delavca se j poveča// za 1
Osnove programiranja 2 - 77 - ©Matjaž Kukar, Viljan Mahnič
Aplet za zajem podatkov o delavcih
• Deklaracija razreda Delavec6– atributi
private int matStev;private String priimek;private String ime;private int stUr;
– konstruktor– metode
• za vpis vrednosti posameznih atributov• za vračane vrednosti posameznih atributov• za izpis vrednosti vseh atributov: izpisiVse()
• Dodajanje poslušalca– izvora dogodkov sta gumba "Vnesi" in "Briši", poslušalec je aplet
vnesi.addActionListener(this);brisi.addActionListener(this);
Osnove programiranja 2 - 78 - ©Matjaž Kukar, Viljan Mahnič
Aplet za zajem podatkov o delavcih
• Metoda actionPerformed(ActionEvent d)
– ugotavljanje izvora dogodkaObject izvor=d.getSource();if (izvor==vnesi){}else if (izvor==brisi){}
– pritisk na gumb "Vnesi"• branje podatkov iz vnosnih polj in generiranje novega elementa
tabele; preverjanje pravilnosti vnosa in izpis obvestila ob napaki• če je tabela polna, odstranimo oba gumba in izpišemo obvestilo• če tabela ni še polna, izpraznimo vnosna polja in jih pripravimo za
vnos naslednjega delavca– pritisk na gumb "Briši"
• izpraznimo vnosna polja in s tem omogočimo uporabniku ponoven vnos podatkov
Osnove programiranja 2 - 79 - ©Matjaž Kukar, Viljan Mahnič
Aplet za zajem podatkov o delavcih
• Branje podatkov iz vnosnih polj v nov element tabeleint matSt=Integer.parseInt(ms.getText());String priimek=p.getText();String ime=i.getText();int stUr=Integer.parseInt(u.getText());++j;td[j]=new Delavec6(matSt,priimek,ime,stUr);
• Odstranitev obeh gumbov in izpis obvestilaremove(vnesi); remove(brisi);obv.setText("Tabela je polna.");repaint();
• Izpraznitev vnosnih poljms.setText("");p.setText("");i.setText("");u.setText("");ms.requestFocus();
Primer
• Implementacija apleta za vnos delavcev
Dolgotrajni apleti
• Računanje, dostop do oddaljenih podatkov, ipd.
• Izvajanje dolgotrajne akcije v metodi poslušalca pripelje do blokade uporabniškega vmesnika
• Razlog:– Poslušalec se izvaja v dogodkovni niti (event dispatching thread)
• Rešitev:– Akcija naj se izvaja v ločeni niti
Niti v apletih
• Izvajalni razred razširi razred Thread in implementirametodo run()
class Dolgotrajna extends Thread {Dolgotrajna(. . .) // Prenos parametrov{} // v nit
void run() {. . . // dolgotrajno opravilo
}}
r = new Dolgotrajna(); // še ne zažener.start(); // zažene nit
Delo z nitmi
• Nekatere metode– start() začne izvajanje niti– stop() konča izvajanje niti– suspend() zaustavi nit– resume() nadaljuje izvajanje niti– join() počaka da se nit konča– join(t) počaka (največ t milisekund) da se nit konča
• Posebne tehnike programiranja (semaforji, zaklepanje, občutljive – volatile – spremenljivke)
• Primer: Večnitni dolgotrajni aplet
Materiali
• Java programi:– Risar.java
• Java apleti:– Pozdrav.java, TestPozdrav.html– Pozdrav1.java, TestPozdrav1.html– Pozdrav2.java, TestPozdrav2.html– Delavec5Glavni.java, TestDelavec5.html– Delavec6Glavni.java, TestDelavec6.html– DolgotrajniApplet.java, Racunar.java, DolgotrajniApplet.html
Osnove programiranja 2 - 85 - ©Matjaž Kukar, 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– obstajajo tudi algoritmi z zahtevnostjo n pa tudi n · n!
Bachmanova asimptotična notacija
Osnove programiranja 2 - 87 - ©Matjaž Kukar, Viljan Mahnič
Urejanje (v pomnilniku)
• 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 - 88 - ©Matjaž Kukar, Viljan Mahnič
Urejanje
• Deklaracija razred Elementpublic abstract class Element{public abstract boolean manjsi (Element b);
}
• Primer razširitve, ko želimo urediti podatke o študentih…{String priimek, ime;double povpOcena;
Student(String p,String i,double po){priimek=p;ime=i;povpOcena=po;
}
Osnove programiranja 2 - 89 - ©Matjaž Kukar, Viljan Mahnič
Urejanje
• … po povprečnih ocenah
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 - 90 - ©Matjaž Kukar, 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 - 91 - ©Matjaž Kukar, 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 - 92 - ©Matjaž Kukar, 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 - 93 - ©Matjaž Kukar, 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 - 94 - ©Matjaž Kukar, Viljan Mahnič
Urejanje z navadnim vstavljanjem
• Analiza učinkovitosti– število primerjanj– število premikov
• Š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 - 95 - ©Matjaž Kukar, 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+=
Izboljšava urejanja z navadnim vstavljanjem
• Binarno vstavljanje: iskanje mesta za vstavljanje v urejenem podzaporedju a[0] do a[i] z bisekcijo:
6 12 18 42 44 55 94 671 2 ↑ 3
• Število primerjav se zmanjša; namesto C=O(n2) imamo C=O(n log n)
• V praksi je prihranek komaj opazen, ker so premiki mnogo zamudneješa operacija kot primerjave
Prikaz delovanja
• URL: urejanje (Insertsort, Variant 1)
Osnove programiranja 2 - 98 - ©Matjaž Kukar, 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 - 99 - ©Matjaž Kukar, 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 - 100 - ©Matjaž Kukar, 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 - 101 - ©Matjaž Kukar, 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(n2)
Osnove programiranja 2 - 102 - ©Matjaž Kukar, Viljan Mahnič
Urejanje s porazdelitvami - Quicksort
• Problemi Quicksorta: nestabilnost, najslabše delovanje O(n2)– 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
2 4 1 3 52 3 1 4 52 1 3 4 51 2 3 4 5
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
Prikaz delovanja
• URL: urejanje (Quicksort, obe varianti)
Osnove programiranja 2 - 105 - ©Matjaž Kukar, Viljan Mahnič
Rekurzija
• Splošne značilnosti– Primer preproste rekurzivne metode: izračun n!
• osnova: zagotavlja prekinitev rekurzije• rekurzivni del
• Preproste rekurzivne metode z enostavno iterativno rešitvijo– 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
• Odprava rekurzije s pomočjo skladaOsnove programiranja 2 - 106 - ©Matjaž Kukar, 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 - 107 - ©Matjaž Kukar, 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 - 108 - ©Matjaž Kukar, 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– Fibonaccijeva števila– binarno iskanje– palindrom– binomski koeficienti– za vse omenjene probleme obstaja preprosta iterativna rešitev
Fibonaccijeva števila (1)
• Leonardo iz Pise, 17. stoletje, populacijska dinamika
• 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, …
• Fn=0, n=0Fn=1, n=1Fn= Fn-1+ Fn-2, n >1
• Preprosta rekurzivna rešitevpublic static int fib(int n) { if (n <= 1) return n; // osnovareturn fib(n-1) + fib(n-2); // rekurzivni del
}
• Razumljiva, a izjemno neučinkovita O(1.62n)
Fibonaccijeva števila (2)
• Rešitev z dinamičnim programiranjem O(n)public static int fib(int n) { int f[n+1]; f[0] = 0; f[1] = f[2] = 1; for (int i = 3; i <= n; i++)
f[i] = f[i-1] + f[i-2]; return f[n];
}
• Rešitev v konstantnem času O(1):– Binetova formula– Tabelirane vrednosti; Fn zelo hitro narašča;
F100 ≈ 69 bitov, F200 ≈ 138 bitov, F1000 ≈ 694 bitov
Osnove programiranja 2 - 111 - ©Matjaž Kukar, 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 - 112 - ©Matjaž Kukar, 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 - 113 - ©Matjaž Kukar, 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 (diagonalnega) stolpca v Pascalovem trikotniku
Osnove programiranja 2 - 114 - ©Matjaž Kukar, 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 nad k elementov
k...3211)k2)...(n1)(nn(n
k)!(nk!n!
kn
k)c(n,⋅⋅⋅⋅
+−−−=
−=⎟⎟
⎠
⎞⎜⎜⎝
⎛=
Osnove programiranja 2 - 115 - ©Matjaž Kukar, 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 - 116 - ©Matjaž Kukar, 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 - 117 - ©Matjaž Kukar, 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 - 118 - ©Matjaž Kukar, Viljan Mahnič
Rekurzija
• Prikaz delovanja: strategija sestopanja (ang. backtracking)klic poz st v stavku for permutacija
dolociStevilo(0) 0 1 1dolociStevilo(1) 1 1,2 1 2dolociStevilo(2) 2 1,2,3 1 2 3dolociStevilo(3) 3 1,2,3,4 1 2 3 4dolociStevilo(2) 2 4 1 2 4dolociStevilo(3) 3 1,2,3 1 2 4 3dolociStevilo(2) 2 konec zankedolociStevilo(1) 1 3 1 3dolociStevilo(2) 2 1,2 1 3 2dolociStevilo(3) 3 1,2,3,4 1 3 2 4dolociStevilo(2) 2 3,4 1 3 4dolociStevilo(3) 3 1,2 1 3 4 2
Sestopanje (backtracking)
• Predstavitev problema kot graf prehodov v prostoru stanj
• Preiskovanje v globino, dokler imamo na voljo še kakšno neobiskano stanje, nato vračanje nazaj
• V danem trenutku imamo več možnosti za nadaljevanje postopka
• Bistvo sestopanja: po vrnitvi iz rekurzivne metode ostanemo v zanki in poskušamo preiskati alternativne rešitve
• Primer: iskanje izhoda iz labirintahttp://www.matheprisma.uni-wuppertal.de/Module/BackTr/index.htm
Osnove programiranja 2 - 120 - ©Matjaž Kukar, 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 v navpični navzdol, b v vodoravni desni smeri)
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;
4 3
5 2
x
6 1
7 0
Osnove programiranja 2 - 121 - ©Matjaž Kukar, 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.
13 4 9
14 5 10 12
1 8 3
15 6 11
2 7
18 13 4 9
5 10 17 12
19 14 1 8 3
6 11 16
20 15 2 7
Osnove programiranja 2 - 122 - ©Matjaž Kukar, 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)
Osnove programiranja 2 - 123 - ©Matjaž Kukar, 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 : zaporedna številka poteze, ki jo želimo nareditivr,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 - 124 - ©Matjaž Kukar, 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 - 125 - ©Matjaž Kukar, 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 - 126 - ©Matjaž Kukar, 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
• Primer: http://www.mazeworks.com/hanoi/
• 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 - 127 - ©Matjaž Kukar, Viljan Mahnič
Rekurzija
• Rekurzivna verzija metode hanoiprivate static void hanoi(int n, char a, char b, char c){if (n==1)
System.out.println("Premakni z "+a+" na "+c);else{
hanoi(n-1,a,c,b);hanoi(1,a,b,c);hanoi(n-1,b,a,c);
}}
Osnove programiranja 2 - 128 - ©Matjaž Kukar, 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 - 129 - ©Matjaž Kukar, 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 - 130 - ©Matjaž Kukar, 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 - 131 - ©Matjaž Kukar, 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 - 132 - ©Matjaž Kukar, 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 skladu obravnavamo 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 - 133 - ©Matjaž Kukar, 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 - 134 - ©Matjaž Kukar, 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 - 135 - ©Matjaž Kukar, 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 - 136 - ©Matjaž Kukar, 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 - 137 - ©Matjaž Kukar, 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 - 138 - ©Matjaž Kukar, Viljan Mahnič
Razred Vector
• Kreiranje vektorjev: 4 konstruktorji– konstruktor brez argumentov kreira vektor standardne dolžine 10
Vector v=new Vector(); // prazen vektor s kapaciteto 10– kot argument lahko navedemo zahtevano dolžino
Vector 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 - 139 - ©Matjaž Kukar, 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 vektorjaOsnove programiranja 2 - 140 - ©Matjaž Kukar, Viljan Mahnič
Razred Vector
• Shranjevanje objektov v vektorv.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 - 141 - ©Matjaž Kukar, 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 - 142 - ©Matjaž Kukar, 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 - 143 - ©Matjaž Kukar, 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 - 144 - ©Matjaž Kukar, Viljan Mahnič
Razred Vector
• Iskanje elementov v vektorjuint 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 redefiniratiint 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 - 145 - ©Matjaž Kukar, 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 - 146 - ©Matjaž Kukar, 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 - 147 - ©Matjaž Kukar, 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 - 148 - ©Matjaž Kukar, 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 - 149 - ©Matjaž Kukar, Viljan Mahnič
Zbirke (Collections)Object
AbstractCollection CollectionAbstractList List
AbstractSequentialListLinkedList
ArrayListVector
StackAbstractSet Set
HashSetTreeSet SortedSet
AbstractMap MapHashMapTreeMap SortedMapWeakHashMap
ArraysBitSet IteratorCollections ListIteratorDictionary
Hashtable MapProperties
Osnove programiranja 2 - 150 - ©Matjaž Kukar, 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 - 151 - ©Matjaž Kukar, 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 - 152 - ©Matjaž Kukar, 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 - 153 - ©Matjaž Kukar, 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 - 154 - ©Matjaž Kukar, 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 - 155 - ©Matjaž Kukar, 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 - 156 - ©Matjaž Kukar, 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 - 157 - ©Matjaž Kukar, 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 - 158 - ©Matjaž Kukar, 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 do verzije 1.5
ni vsebovala posebnega vmesnika oziroma razreda za vrsto– izhajali bomo iz vmesnika Collection, ki mu bomo dodali 4 metode,
tipične za vrstoimport 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 - 159 - ©Matjaž Kukar, 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 - 160 - ©Matjaž Kukar, 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 - 161 - ©Matjaž Kukar, 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 - 162 - ©Matjaž Kukar, 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 - 163 - ©Matjaž Kukar, 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 - 164 - ©Matjaž Kukar, 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 - 165 - ©Matjaž Kukar, 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 - 166 - ©Matjaž Kukar, 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 - 167 - ©Matjaž Kukar, Viljan Mahnič
Zbirke (Collections)
• Vrsta v splošnemheader
prvi element zadnji elementobj1 objnobj3obj2
null
Osnove programiranja 2 - 168 - ©Matjaž Kukar, 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 - 169 - ©Matjaž Kukar, 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 - 170 - ©Matjaž Kukar, 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 - 171 - ©Matjaž Kukar, 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 - 172 - ©Matjaž Kukar, 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();}
};}
Osnove programiranja 2 - 173 - ©Matjaž Kukar, Viljan Mahnič
Novosti Jave 5
• Generična koda (Generics)– varna raba podatkovnih tipov v javanskih podatkovnih strukturah– odprava potrebe po pretvarjanju tipov (casting)
• Izboljšana zanka for– odprava potrebe po iteratorjih za sprehod čez vse elemente – iterator še vedno potrebujemo, če gre za spreminjanje elementov
• Samodejno pretvarjanje enostavnih podatkovnih tipov– odprava potrebe po ročnem pretvarjanju med enostavnimi podatkov-
nimi tipi in njihovimi ovijalnimi razredi (npr. int in Integer)
• Naštevni podatkovni tip
• Spremenljivo število parametrovOsnove programiranja 2 - 174 - ©Matjaž Kukar, Viljan Mahnič
Generična koda
• Generični razredi in vmesniki– predstavljajo podatkovne strukture, za katere lahko predpišemo tip
objektov, ki jih hranijo– vsi razredi in vmesniki iz Java Collection Framework so generični
• prej: podatkovna struktura vsebuje objekte poljubnega tipa• sedaj: ob deklaraciji podatkovne strukture predpišemo tip objektov
– Primer iz razreda DemoVectorVector osebe=new Vector(10); // poljuben tip objektovVector<String> osebe=new Vector<String>(10); // samo nizi
– Odpade potreba po pretvorbi tipaString o=(String)osebe.get(i); // prejString o=osebe.get(i); // sedaj
Osnove programiranja 2 - 175 - ©Matjaž Kukar, Viljan Mahnič
Generična koda
• Pravilnost programa preverja že prevajalnik– razred TestVector1
• prevajalnik opozori na nekontrolirano dodajanje objektov • stikalo -Xlint omogoča izpis problematičnih vrstic kode• zavestno omogočimo dodajanje objektov poljubnega tipa
– razred TestVector2• dopuščamo samo objekte tipa String• napako odkrije že prevajalnik
• Uporaba pri argumentih metodpublic static Vector<String> zlij(Vector<String> v1,
Vector<String> v2)
• Uporaba pri iteratorjufor(Iterator<String> it=v.iterator(); it.hasNext(); )
Osnove programiranja 2 - 176 - ©Matjaž Kukar, Viljan Mahnič
Generična koda
• Nekaj posebnosti– elementi podatkovne strukture so lahko samo objekti
Vector<int> v=new Vector<int>(); // narobeVector<Integer> v=new Vector<Integer>(); // pravilno
– pri prirejanju vrednosti se upošteva medsebojna skladnost tipov podatkovnih struktur ne pa tipov objektov, ki jih hranijoLinkedList<Integer> l1=new LinkedList<Integer>();List<Integer> l2=l1; // pravilnoLinkedList<Number> l3=l1; // narobeLinkedList<Object> l4=l1; // narobe
– generično opredeljena spremenljivka, ki se lahko sklicuje na zbirko poljubnega generičnega tipaCollection<?> x;//spremenljivki x lahko priredimo poljubno zbirko
– uporaba pri dedovanjuVector<? extends Zival> z; // vektor, ki ga priredimo
spremenljivki z, lahko vsebuje objekte tipa Pes, Krava in Kaca
Osnove programiranja 2 - 177 - ©Matjaž Kukar, Viljan Mahnič
Generična koda
• Lastni generični tipiimport java.util.*;
public class MojaZbirka<T> { protected List<T> zbirka;public MojaZbirka() { zbirka=new LinkedList<T>;
}public int getSize() { return zbirka.size();
}public int isEmpty() { return (zbirka.size()==0);
}public T grab() { if (!isEmpty()) return zbirka.remove(0);return null;
}}
Osnove programiranja 2 - 178 - ©Matjaž Kukar, Viljan Mahnič
Generična koda
• Omejitev na določen tip objektovimport java.util.*;public class ZbirkaStevil<N extends Number> extends MojaZbirka<N> { public ZbirkaStevil() {super();
}...public double vsota() {double v=0;for (Iterator<N> i=zbirka.iterator(); i.hasNext(); )v+=i.next().doubleValue();
return v;}
}
Osnove programiranja 2 - 179 - ©Matjaž Kukar, Viljan Mahnič
Izboljšana zanka for
• Pri poljubni zbirkiCollection c=...; // kreiramo poljubno zbirkofor (Object o : c)System.out.println(o);
• Pri zbirki z določenim generičnim tipomVector<String> osebe=new Vector<String>(10);for (String s : osebe)
System.out.println(s);
• V tabeliint[] t={1,2,3,4,5,6,7,8,9,10};for (int i : t)
System.out.println(i);
• Za spreminjanje elementov še vedno porebujemo iteratorOsnove programiranja 2 - 180 - ©Matjaž Kukar, Viljan Mahnič
Samodejno pretvarjanje (Boxing/Unboxing)
• Ovijalni razredi: omogočajo, da tudi enostavne podatkovne tipe obravnavamo na objektni način– primeri: Integer, Double, Short, Boolean, Character– objekt razreda Integer vsebuje en sam atribut tipa int
• Pretvorba iz enostavnega tipa v pripadajoč ovijalni tip in obratno se izvrši samodejno– pred Javo 5: Integer i1=new Integer(5);
int i2=(int)i1;
– v Javi 5: Integer i1=5; // (auto)boxingint i2=i1; // unboxing
– možnost napake: Integer i1=null;int i2=i1; // napaka
Osnove programiranja 2 - 181 - ©Matjaž Kukar, Viljan Mahnič
Naštevni podatkovni tip
• Uporaba– kadar nek podatek zavzame omejeno število različnih vrednosti– prevajalnik lahko preveri pravilnost pri prirejanju vrednosti
• Deklaracija– ključna beseda enum– ime naštevnega tipa– seznam vrednosti, ki jih lahko zavzame
public enum Ocena {A, B, C, D, NI_PISAL};
• Naštevni tip je razred– omogoča deklaracijo spremenljivk/atributov– vsaka spremenljivka/atribut je “objekt” naštevnega tipa
• zavzame lahko le eno izmed naštetih vrednosti• kontrola tipa se izvaja že v času prevajanja
Osnove programiranja 2 - 182 - ©Matjaž Kukar, Viljan Mahnič
Naštevni podatkovni tip
• Primer: obdelava rezultatov testiranja
• Ostale značilnosti– naštevni tip je razširitev tipa java.lang.Enum
• Enum je nov razred v Javi 5, ki pa sam ni naštevni tip– za naštevni tip ne obstaja javni konstruktor
• s tem je preprečeno kreiranje dodatnih primerkov, ki niso bili deklarirani v času prevajanja
– vrednosti naštevnega tipa so public, static in final– vrednosti naštevnega tipa lahko primerjamo z ==, equals()incompareTo()
• metoda compareTo() upošteva vrstni red pri naštevanju– na voljo sta metodi toString() in valueOf()
• Ocena.NI_PISAL.toString()vrne "NI_PISAL"• Ocena.valueOf("NI_PISAL") vrne Ocena.NI_PISAL
Osnove programiranja 2 - 183 - ©Matjaž Kukar, Viljan Mahnič
Naštevni podatkovni tip
• Zanka po vseh možnih vrednostih– metoda values() vrne tabelo vseh vrednosti naštevnega tipa
public void izpisiVse(){for (Ocena oc:Ocena.values())System.out.println(oc)
}
• Uporaba v stavku switchswitch (k.vrniOceno()){case A: System.out.println("zelo primeren"); break;case B: System.out.println("primeren"); break;case C: System.out.println("manj primeren"); break;case D: System.out.println("neprimeren"); break;case NI_PISAL: System.out.println(k.vrniOceno().toString());
}
Osnove programiranja 2 - 184 - ©Matjaž Kukar, Viljan Mahnič
Spremenljivo število parametrov (varargs)
• Uporaba tripičja– public static void xy(int a1, String... s)
– ob klicu lahko navedemo 0, 1 ali več parametrov tipa String– primeri veljavnih klicev
xy(25);xy(25,"Prvi niz");String niz="Drugi niz";xy(25,"Prvi niz",niz);
– parameter s obravnavamo kot tabelo nizovfor (String niz : s)System.out.println(niz);
– omejitev: tripičje lahko uporabimo samo pri enem (zadnjem) parametru