INF, 22. mai 23 Prøveeksamen 23 (Eksamen 2. juni 22) Stein Gjessing Inst. for Informatikk Universitetet i Oslo
Oppgave a Tegn klassehierarkiet for de 9 produkttypene som er beskrevet over. Inkluder også eventuelle grensesnitt. Grensesnitt Pant Embalasje Abstrakt Nedbrytbar Grensesnitt Plastembalasje Glassembalasje Metallembalasje Pappembalasje Abstrakt Abstrakt Abstrakt Abstrakt PlastflaskeMedPant Abstrakt StorNedbrytbarPappflaskeMedPant LitenPlastflaskeMedPant LitenNedbrytbarPlastflaskeMedPant Oppgave b:... produseres det bare ting av disse 3:.. 2
Oppgave b Programmer 7 av de 9 klassene i klassehierarkiet og eventuelle grensesnitt. Du skal ikke programmere klasser for Glassemballasje og Metallemballasje. Alle variable i alle klasser skal få verdier i det objektene opprettes. Det er derfor viktig at alle klasser har konstruktører med parametere der disse verdiene kan oppgis, unntatt panten på små flasker som alltid har samme verdi, en konstant med verdi øre. abstract class Embalasje { int volum; // i kubikkcentimeter String produsent; Embalasje(int vol, String prod) { volum = vol; produsent = prod; Alle variable i alle klasser skal få verdier i det objektene opprettes... produseres det bare ting av disse 3:.. 3
abstract class Plastembalasje extends Embalasje { Plastembalasje(int vol, String prod) { Plastemballasje har ingen flere super(vol,prod); egenskaper enn Emballasje... abstract class Pappembalasje extends Embalasje { int vekt; // i gram mens Pappemballasje i Pappembalasje(int vekt, int vol, String prod) { tillegg har en vekt (i gram). super(vol,prod); this.vekt = vekt; Alle variable i alle klasser skal få verdier i det objektene opprettes... produseres det bare ting av disse 3:.. interface Pant { int panteverdi(); // i øre String returordning(); Når det er pant på en ting må en kunne vite hvor stor panten er (i antall øre) og en kode (en tekst) som identifiserer returordningen. interface Nedbrytbar { Ar(); Når noe er nedbrytbart må en kunne vite hvor lenge (hvor mange år) det tar før tingen er gått i oppløsning. 4
/* Siden LitenPlastflaskeMedPant og LitenNedbrytbarPlastflaskeMedPant er de to subklassene til PlastflaskeMedPant, og PlastflaskeMedPant er abstrakt, velger jeg å ikke implementere metoden panteverdi. Men du får like mye uttelling om du lager en slik implementasjon. Da må panteverdien være en variabel her, og den bør også inkluderes i konstruktøren, men da vil alle små plastfalsker ha en (unødvendig) variabel. */ abstract class PlastflaskeMedPant extends Plastembalasje implements Pant { String retur; public String returordning() {return retur; // int pant; // abstract public int panteverdi() { return pant; PlastflaskeMedPant(String ret, int vol, String prod) { super(vol,prod); retur = ret; Alle variable i alle klasser skal få verdier i det objektene opprettes... produseres det bare ting av disse 3:.. 5
class LitenPlastflaskeMedPant extends PlastflaskeMedPant { final static int PANTV = ; public int panteverdi ( ) {return PANTV; LitenPlastflaskeMedPant (String ret, int vol, String prod) { // Når panteverdi ikke er definert i superklassen skal ikke // panteverdien være med som parameter super(ret,vol,prod);... panten på små flasker som alltid har samme verdi, en konstant med verdi øre. class LitenNedbrytbarPlastflaskeMedPant extends LitenPlastflaskeMedPant implements Nedbrytbar { A; public Ar(){return antalla; LitenNedbrytbarPlastflaskeMedPant (String ret, int vol, String prod, int aar) { super(ret,vol,prod); antalla = aar; Alle variable i alle klasser skal få verdier i det objektene opprettes 6
class StorNedbrytbarPappflaskeMedPant extends Pappembalasje implements Pant, Nedbrytbar { int pantv; A; String returord; public int panteverdi ( ) {return pantv; public String returordning() {return returord; public Ar(){return antalla; StorNedbrytbarPappflaskeMedPant (String ret, int vol, String prod,int vekt, int pnt, int anta) { super(vekt,vol,prod); returord = ret; pantv = pnt; antalla = anta; Alle variable i alle klasser skal få verdier i det objektene opprettes Slutt oppgave 7
Oppgave 2a Tegn datastrukturen i et objekt av klassen Frekvens, ved først å vise hvordan datastrukturen ser ut rett etter at objektet er opprettet (og konstruktøren er utført), og deretter hvordan datastrukturen ser ut etter at metoden likesammen er kalt. Objekt av klassen Frekvens<E> der E er String likesammen hentflestobjektet hentflestantallet Node forste Node neste Anne Anne Anne Ole Rita Rita Rita Objekt av klassen Frekvens<E> der E er String likesammen hentflestobjektet hentflestantallet Node forste Node neste 3 3 Når konstruktøren er ferdig vil eksemplet over gi en liste som inneholder: Anne, Anne, Anne, Ole, Rita, Rita, Rita. 3 Anne Ole Rita... så vil resultatet være (etter at like objekter er slått sammen) Anne 3, Ole, Rita 3
Oppgave 2b Programmer deklarasjonene og datastrukturen i klassen Frekvens slik den er beskrevet over, og med alt du trenger for å besvare oppgavene 2b og 2c. class Frekvens <E> { = null; // tingen det er flest forekomster av = ; // tilsvarende antall Node forste = null; int [] frekvenstabell; // til oppgave 4 (må gjentas i oppgave 4) class Node { Node neste = null; ; = ; Node(E s) { tingen= s;... Bare lag "set" og "get" metoder hvis du bli bedt om det. 9
Frekvens Node forste E[ ] tabell Oppgave 2c Programmer konstruktøren i klassen Frekvens. Frekvens (E[ ] tabell) { Node siste = null; for (E s: tabell) if (forste == null) { forste = new Node(s); siste = forste; else { siste.neste= new Node(s); siste= siste.neste; Node neste Konstruktøren skal ha som parameter en tabell (array) med pekere til alle objektene som skal legges inn Anne Anne Anne Ole Rita Rita Rita
Oppgave 2d. Programmer de tre metodene likesammen, hentflestobjektet og hentflestantallet i klassen Frekvens. public void likesammen () { Node denne = forste; if (forste!= null) while (denne.neste!= null) { if (denne.tingen.equals(denne.neste.tingen)) { // fjern, dvs. hopp over neste denne.neste = denne.neste.neste; denne.antall ++; sjekkombest(denne.tingen,denne.antall); else denne = denne.neste; public E hentflestobjektet() {return tingen; // NB! Veldig enkel og kort public int hentflestantallet() {return antall; // NB! Veldig enkel og kort private void sjekkombest(e s, int t) { if (t > antall) {antall = t; tingen = s; Slutt oppgave 2
class FrekvensTrad<E> extends Thread{ E ting = null; // flest forekomster = ; // tilsvarende antall Frekvens<E> minbeholder; Monitor<E> monitor; E [ ] mintab; int til, fra; // nedre og øvre indeks for min del av tabellen public void run(){ minbeholder = new Frekvens<E>(minTab); minbeholder.likesammen(); ting = (E) minbeholder.hentflestobjektet(); antall = minbeholder.hentflestantallet(); monitor.legginn(ting, antall); Oppgave 3a. Programmer trådklassen og monitorklassen. FrekvensTrad (E[ ] tabell, int fra, int til, Monitor<E> m) { this.fra = fra; this.til = til; monitor = m; mintab = (E[]) new Object[til-fra+]; // Denne castingen har vi brukt ofte på forelesningen int ovreindeks = til-fra; for (int i = ; i<= ovreindeks; i++) mintab[i] = tabell[i+fra]; Når en tråd har funnet det største antallet av like forekomster i sin del av tabellen, skal den legge disse verdiene inn i en monitor For å kunne bruke klassen Frekvens fra oppgave 2 på en enkel måte, skal konstruktøren i trådklassen opprette en egen lokal tabell (array) (av riktig lengde), og kopiere den delen av tabellen som denne tråden har fått i oppgave å undersøke, over i denne lokale tabellen. Når tråden oppretter en beholder (av klassen Frekvens) er det denne tabellen som brukes som parameter til konstruktøren i beholderen. De siste tre linjene av konstruktøren burde vært gjort i run-metoden 2
class Monitor<T> { // Beste Objekt og antall: T tingen = null; = ; Trader = ; Når en tråd har funnet det største antallet av like forekomster i sin del av tabellen, skal den legge disse verdiene inn i en monitor som har som oppgave å ta i mot resultatene fra alle trådene, og til slutt sitte igjen med det største resultatet. Når hovedprogrammet har startet alle trådene må det vente på at alle er ferdige, og da først kan det hente ut av monitoren det største resultatet. synchronized void legginn(t s, int t) { if (t > antall) { antall = t; tingen = s; antalltrader++; notify(); T hentteksten() { return tingen; int hentantallet() { return antall; // Metode for å vente på at antalltrader har lagt inn sine resultater: synchronized void ventpaaalleferdig(tr) { while (antalltrader!= antalltr) { try { wait(); catch (InterruptedException e) { System.out.println("Uventet avbrudd"); System.exit(); 3
Main-metoden skal lese en fil med navn mangeordsortert.txt, der første linje inneholder antallet ord i filen, og resten av filen inneholder dette antallet ord (som du for eksempel kan lese med next-metoden i Scanner-klassen) i ferdig sortert rekkefølge. Disse ordene skal legges inn i String-tabellen. Deretter skal mainmetoden opprette monitoren... class BrukFrekvensTraderMedWait { A. Omtrent hvor lang hver del av tabellen skal være er forhåndsbestemt av en konstant i programmet. // Jeg velger alternativ A. Antall elementer per tråd er forhåndsbestemt : static final int ANTALL = 64; // Antall elementer per tråd public static void main (String [ ] args) throws IOException { Scanner filinn = new Scanner(new File("mangeordsortert.txt")); = filinn.nextint(); String [ ] alleord = new String[antall]; for (int i = ; i < antall; i++) alleord[i] = filinn.next(); Monitor m = new Monitor<String>(); 4
Deretter skal main-metoden opprette... alle trådene... int tellertrader = ; int nedregrense = ; int ovregrense = ANTALL-; while (nedregrense < alleord.length) { if (ovregrense >= alleord.length-) ovregrense = alleord.length-; while (ovregrense < alleord.length-2 && alleord[ovregrense]. equals(alleord[ovregrense+])) ovregrense++; // like, øk antallet // En tråd arbeider fom nedregrense tom ovregrense if (ovregrense + > alleord.length) ovregrense = alleord.length-; // lite igjen Thread t = new FrekvensTrad<String>(alleOrd,nedreGrense,ovreGrense,m); t. start(); tellertrader++; nedregrense = ovregrense + ; ovregrense = ovregrense + ANTALL; m.ventpaaalleferdig(tellertrader); System.out.println(((String)(m.hentTeksten()))); System.out.println(m.hentAntallet()); Delene av tabellen behøver ikke være akkurat like lange. Du må være oppmerksom på at tabellen ikke skal deles mellom to like objekter. Om du er i ferd med å gjøre dette kan du f.eks. øke antallet som skal undersøkes av en tråd (helt til alle like objekter blir undersøkt av samme tråd).... og til slutt skal main-metoden hente ut resultatet fra monitoren og skrive ut det ordet som har flest forekomster og hvor mange dette er. Slutt oppgave 3 5
Objekt av klassen Frekvens<E> der E er String lagalleantall finnantall 3 Node forste Node neste 3 3 Oppgave 4 Anne Ole Rita FrekvensTabell ( brukes ikke) 2 3 public void lagalleantall() { Anne 3 ganger: Ole gang: Rita 3 ganger: 2 2 3 2 3 2 3 Metoden lagalleantall har ingen parametre og returnerer ingen verdi. Den skal lage en oversikt over hvor mange (forskjellige) objekter forekommer bare gang, hvor mange (forskjellige) objekter forekommer 2 ganger, hvor mange (forskjellige) objekter forekommer 3 ganger, osv., helt opp til det antallet som angir flest like objekter. F.eks. hvis listen er (som før): Anne 3, Ole, Rita 3, så skal oversikten si at objekt forekommer gang, objekter forekommer 2 ganger og 2 objekter forekommer 3 ganger. 6
Oppgave 4 Etter at lagalleantall() er utført: Objekt av klassen Frekvens<E> der E er String lagalleantall finnantall 3 Node forste Node neste 3 3 Anne Ole Rita FrekvensTabell 2 ( brukes ikke) 2 3 Metoden finnantall skal gjøre oppslag i denne oversikten. Metoden har som parameter et heltall som angir et antall like forekomster, og metoden skal returnere hvor mange ganger beholderen inneholder så mange like objekter. Høyeste parameterverdi vil derfor være det største antallet like forekomster. I vårt eksempel vil finnantall() returnere, finnantall(2) returnere og finnantall(3) returnere 2. finnantall() = finnantall(2) = finnantall(3) = 2 7
Oppgave 4a Programmer metodene lagalleantall og finnantall samt de deklarasjoner og datastruktur du trenger til disse metodene i klassen Frekvens. // I klassen Frekvens: int [] frekvenstabell; // til oppgave 4 public void lagalleantall() { frekvenstabell = new int [antall+]; // er startverdi i hele tabellen Node denne; denne = forste; while (denne!= null) { frekvenstabell[denne.antall]++; denne = denne.neste; public int finnantall() { return frekvenstabell[antall]; Metoden lagalleantall har ingen parametre og returnerer ingen verdi. Den skal lage en oversikt over hvor mange (forskjellige) objekter forekommer bare gang, hvor mange (forskjellige) objekter forekommer 2 ganger, hvor mange (forskjellige) objekter forekommer 3 ganger, osv., helt opp til det antallet som angir flest like objekter. F.eks. hvis listen er (som før): Anne 3, Ole, Rita 3, så skal oversikten si at objekt forekommer gang, objekter forekommer 2 ganger og 2 objekter forekommer 3 ganger. Metoden finnantall skal gjøre oppslag i denne oversikten. Metoden har som parameter et heltall som angir et antall like forekomster, og metoden skal returnere hvor mange ganger beholderen inneholder så mange like objekter. Høyeste parameterverdi vil derfor være det største antallet like forekomster. I vårt eksempel vil finnantall() returnere, finnantall(2) returnere og finnantall(3) returnere 2. 8
Oppgave 4b Noen av metodene i klassen Frekvens må kalles i en bestemt rekkefølge. Diskuter meget kort hvordan metodene ideelt sett bør oppføre seg hvis denne rekkefølgen ikke følges. Det er ikke nødvendig å gå tilbake og endre noen av de metodene du har skrevet. Metoden lagalleantall kan bare kalles etter likesammen, og metoden finnantall kan bare kalles etter at metoden lagalleantall er kalt. Vi kan legge inn boolske verdier som sier om en metode alt er kalt eller ikke. Hvis lagalleantall kalles før likesammen kan den enten ha ingen virkning, eller et unntak kan kastes. Hvis de to andre metodene ikke er kalt først, kan f.eks. finnantall returnere - eller et unntak kan kastes. Slutt oppgave 4 9