LULEÅ TEKNISKA UNIVERSITET Tentamen i Objektorienterad programmering och design Totala antalet uppgifter: 5 Lärare: Håkan Jonsson, 491000, 073-820 1700 Resultatet o entliggörs senast: 2012-05-29. Tillåtna hjälpmedel: Inga. Kurskod D0010E Datum 2012-05-15 Skrivtid 5tim OBS! Lösningar får inte baseras på fördefinierade klasser ur t ex Javas standardbibliotek annat än där detta uttryckligen tillåts. Sådana lösningar ger inga poäng. 1. Teori a) Klassen X ärver klassen Y. Både Y och en annan klass Z ärver klassen T, som implementerar gränssnitten G1 och G2. Rita UML-diagrammet. (1p) b) Ange något som är typiskt för objektorienterad programmering och motivera varför det är bra eller dåligt. (2p) c) Klassen A innehåller en publik metod f och ärvs av klassen B som ärvs av klassen C. Både B och C överskuggar f. Omvinugör A a = new C(); a.f(); (och detta fungerar), vilken klass sker då anropet på andra raden till? (1p) d) Vad skrivs ut när följande kod körs? (2p) Node[] p = { new Node(null), new Node(null), new Node(null) ; p[0].next = p[1]; p[1].next = p[2]; p[2].next = p[0]; p[1].next.data = p[2].next.next.data + p[0].data; p[0].next.data = p[p[1].data].data + p[p[2].data].data; System.out.println(p[0].data + p[1].data + p[2].data); I koden skapas först en nodarray med längden 3, vars element omedelbart initieras till att referera till objekt av typen Node (se nedan) som skapas i den ordning de är uppradade. class Node { Node next, previous; static int counter = 0; int data = 0; Node(Node p) { next = p; data = counter; counter++; 2. Jämnt och udda a) Skriv en metod public static boolean iseven(int n) som avgör om ett heltal n 0 är jämnt eller ej genom att utnyttja följande samband: Ett tal n är jämnt om det är noll eller om n 1 är udda. Ett tal n är inte udda om det är noll; annars är det udda endast om n 1 är jämnt. Utgå från att n 0, dvs detta behöver inte kollas. Tips: Använd en hjälpmetod som avgör om ett tal är udda. (3p) 1
b) Använd iseven för att implementera funktionen 8 < 1, if n =1, n f(n) = : 2, if n is even, and 3n + 1 otherwise. 3. Stackar som en metod public static int f(int n) i java. Du får använda iseven som om du löst a) helt korrekt. (3p) En stack fungerar som en vertikal stapel med data i vilken man endast kan utföra operationer direkt på dess topp: Operationen pop() tar bort det som ligger överst, och returnerar det, medan push(x) lägger x överst (dvs det som tidigare låg överst hamnar nu direkt under x). En metod isempty() ger true omm stacken är tom. a) Skriv en klass IntegerStack för heltalsstackar. Använd gärna LinkedList från uppgift 5 om du vill. (3p) b) Utöka med arv din stack till en klass BoundedPositiveIntegerStack för stackar som fungerar exakt som IntegerStack förutom att de kan ha maximalt 100 element och endast innehålla positiva heltal. (3p) 4. Spekulativa elavtal (6p) NordpoolsAvtal + dagspris() : double <<abstract>> Elavtal <<abstract>> + pris() : double <<abstract>> + bindningstid() : int Fast + bindningstid() : int Rörligt + bindningstid() : int ChansAvtal + ChansAvtal(prisnivå : double, multipel : int) Figur 1: UML-diagram för uppgift 4. Implementera klasserna i figur 1 utom NordpoolsAvtal för att hantera olika typer av elavtal enligt nedan. OBS! För att lösa uppgiften kan du behöva lägga till metoder och variabler som inte finns med i diagrammet. Elavtal representerar generella avtal. Metoden pris() ger priset i kr/kwh medan bindningstid() ger tillbaka under hur många dagar avtalet inte får säljas upp eller förändras. OBS! Du ska inte implementera NordpoolsAvtal och dess publika metod dagspris() som ger dagens aktuella pris på elbörsen Nordpool där el köps och säljs. Fast står för ett avtal med fast pris och en viss bindningstid (dessa ska anges när ett fast avtal skapas). 2
Rörligt är ett avtal med bindningstiden 0 och ett pris som är dagspriset plus 10%. ChansAvtal står för ett slags rörligt avtal som sluts utgående ifrån en överenskommen prisnivå n och multipel m. Om priset för ett vanligt rörligt avtal är p, är priset för detta avtal m(p n). När n>poch m>1 riskerar man att få betala dyrt, men chansen är att priset för ett rörligt avtal är under prisnivån och då får man istället betalt av elbolaget. 5. Länkad lista Skriv en klass LinkedList för dubbellänkade listor med heltal. Till en lista ska finns en pekare som markerar ett av elementen, om sådana finns, eller som är odefinierad då listan är tom. Listans element numreras 1, 2, 3,... där 1 är det första (dvs elementet vid listans början). Numreringen är inte statisk utan förändras naturligt vid insättningar och borttag. Internt ska listans element sparas i objekt av typen Node ur uppgift 1. Dessa ska på lämpligt sätt länkas ihop till en intern nodkedja. Klassen ska innehålla följande 11 metoder: Allmänna metoder: (6p) public LinkedList() skapar en tom lista. Pekaren är då odefinierad. public int size() ger listans längd, dvs antalet element den innehåller. public int num() ger tillbaka numret på det element som pekaren markerar. Om pekaren är odefinierad ska undantag kastas. Kontroll av pekaren: public boolean atfirst() och public boolean atlast() avgör om pekaren markerar listans första (nr 1) respektive sista (nr size()) element. Om pekaren är odefinierad ska istället undantag kastas. public void forward() ändrar pekaren till att markera nästa element i nummerordning. Kastar undantag om pekaren är odefinierad eller om pekaren redan markerar det sista elementet. public void backward() fungerar som forward men ändrar till närmast föregående. Åtkomstmetoder: public void insertafter(int p) sätter in p. Om listan är tom blir p det första elementet, pekaren blir definierad och pekaren sätts att markera p. Annars sätts p in direkt efter det som pekaren markerar (utan att pekaren förändras). public void insertbefore(int p) fungerar precis som insertafter men sätter istället in före det som pekaren markerar (och pekaren markerar efteråt samma element som före anropet). public int getelement() returnerar elementet som pekaren markerar. Om listan är tom ska undantag kastas. public void delete() tar bort elementet som pekaren markerar. Skulle listan efteråt bli tom blir pekaren odefinierad. Annars, om elementet som tas bort är...... det första, sätts pekaren till att markera det som efter borttaget är först.... det sista, sätts pekaren till att markera det som efter borttaget är sist....ett annat element än det första eller det sista så sätts pekaren till att markera det som låg (och ligger) direkt före det borttagna. Om listan till att börja med är tom ska undantag kastas. 3
Errata (D0010E, 2012-05-15) Rent allmänt gäller att man ska skriva ner sin lösning på ett sånt sätt att examinator blir övertygad om att man löst uppgiften. Förutom svenska och engelska får man utan vidare här använda kod skriven i Java och UML. Använder man andra språk eller andra uttryckssätt (t ex bilder, skisser) gör man klokt i att förklara dem noga så att deras betydelse är helt klar för någon som endast förväntar sig svenska, engelska, UML och Java. För de enskilda uppgifterna har följande uppdagats: 1. (Inget.) 2. (Inget.) 3. (Inget.) 4. (Inget.) 5. (Inget.) 6. (Inget.) 4
Existing suggested solutions (D0010E, 2012-05-15) ---------------1--------------- Kommentarer på uppgift 1: a) Se bild: T G1 G2 Y Z X b) c) Den i C och det pga dynamic dispatch. d) 3. Svaret 0 1 2 gav 1p. ---------------2--------------- Kommentarer på uppgift 2: Lösningsförslag public static boolean iseven(int n) { return n==0 odd(n-1); public static boolean odd(int n) { return n==0? false : iseven(n-1); Metoden som efterfrågas i b) är tagen ur lab 1. ---------------3--------------- Kommentarer på uppgift 3: Lösningsförslag public class Stack { protected LinkedList list = new LinkedList(); public void push(int x) { list.insertafter(x); if (list.size()!= 1) { list.forward(); 5
public int pop() { int tmp = list.getelement(); list.delete(); return tmp; public boolean isempty() { return list.size() == 0; public class BoundedPositiveIntegerStack extends Stack { public void push(int x) { if (list.size()==100 x<0) { throw new RuntimeException("Can t push"); else { super.push(x); ---------------4--------------- Kommentarer på uppgift 4: Lösingsförslag: abstract public class Elavtal extends NordpoolsAvtal { abstract public double pris(); abstract public int bindningstid(); public class Fast extends Elavtal { private int bindningstid; private double pris; public Fast(double pris, int bindningstid) { this.pris = pris; this.bindningstid = bindningstid; public double pris() { return pris; public int bindningstid() { return bindningstid; public class Rörligt extends Elavtal { public double pris() { return dagspris() * 1.1; public int bindningstid() { 6
return 0; public class ChansAvtal extends Rörligt { private double prisnivå; private int multipel; public ChansAvtal(double prisnivå, int multipel) { this.prisnivå = prisnivå; this.multipel = multipel; public double pris() { return multipel * (prisnivå - super.pris()); ---------------5--------------- Kommentarer på uppgift 5: (OBS! Klassen Node i lösningsförslaget nedan inte exakt ut som den i uppgift 1. En korrekt lösning på tentan skulle förstås utgå från klassen i tentans första uppgift.) Lösingsförslag: package d0010e120515; public class LinkedList { private class Node { Node next, previous; int data = 0; Node(Node p) { next = p; data = 0; private Node firstheader, lastheader; private int size = 0; private boolean isdefined = false; private Node ptr = null; private int ptrnum = -1; public LinkedList() { firstheader = new Node(null); lastheader = new Node(null); firstheader.next = lastheader; lastheader.previous = firstheader; public int size() { return size; 7
public int num() { throw new RuntimeException("Empty list: num undefined"); else { return ptrnum; public boolean atfirst() { throw new RuntimeException("Empty list: Can t be at first"); else { return ptrnum == 1; public boolean atlast() { throw new RuntimeException("Empty list: Can t be at last"); else { return ptrnum == size(); public void forward() { if (!isdefined atlast()) { throw new RuntimeException("Already at last element"); else { ptrnum++; ptr = ptr.next; public void backward() { if (!isdefined atfirst()) { throw new RuntimeException("Already at first element"); else { ptrnum--; ptr = ptr.previous; private void insertfirst(node t) { t.next = lastheader; lastheader.previous = t; t.previous = firstheader; firstheader.next = t; size = 1; isdefined = true; ptr = t; ptrnum = 1; public void insertafter(int p) { Node t = new Node(null); 8
t.data = p; insertfirst(t); else { t.next = ptr.next; t.previous = ptr; ptr.next.previous = t; ptr.next = t; size++; public void insertbefore(int p) { Node t = new Node(null); t.data = p; insertfirst(t); else { t.next = ptr; t.previous = ptr.previous; ptr.previous.next = t; ptr.previous = t; size++; ptrnum++; public int getelement() { throw new RuntimeException("Empty list: Can t get element"); else { return ptr.data; public void delete() { throw new RuntimeException("Empty list: Can t delete element"); else { if (size() == 1) { isdefined = false; else { if (atfirst()) { firstheader.next = ptr.next; ptr = ptr.next; ptr.previous = firstheader; // ptrnum is still 1 here else { if (atlast()) { lastheader.previous = ptr.previous; ptr = ptr.previous; ptr.next = lastheader; else { ptr.next.previous = ptr.previous; ptr.previous.next = ptr.next; 9
ptr = ptr.previous; ptrnum--; // since ptr has moved a step towards the start size--; // since we have deleted an element, one way or another 10