Tentamen Programmeringsteknik II 2014-01-09 Skrivtid: 0800-1300 Hjälpmedel: Java-bok (vilken som helst) Tänk på följande Skriv läsligt! Använd inte rödpenna! Skriv bara på framsidan av varje papper. Börja alltid ny uppgift på nytt papper. Lägg uppgifterna i ordning. Skriv uppgiftsnummer och din kod på alla papper. Skriv inte längst upp i vänstra hörnet - det går inte att läsa där efter sammanhäftning. Fyll i försättssidan fullständigt. Det är principer och idéer som är viktiga. Skriv så att du övertygar rättaren att du har förstått dessa även om detaljer kan vara felaktiga. Programkod skall vara läslig dvs den skall vara vettigt strukturerad och indenterad. Namn på variabler, metoder, funktioner, klasser etc skall vara beskrivande men kan ändå hållas ganska korta. Såvida inget annat anges så får man bygga på lösningar till föregående uppgifter även om dessa inte har lösts. Det är tillåtet att införa hjälpmetoder och hjälpklasser. Uttrycket skriv en metod som skall alltså inte tolkas så att lösningen inte får struktureras med hjälp av flera metoder. Uppgifterna kommer inte i svårighetsordning. Betygsgränser: 15 ger säkert 3, 21 ger säkert 4, 26 ger säkert 5. Lycka till! 1
Uppgifter 1. Nedanstående figur visar noderna i ett binärt sökträd med heltal som nycklar. 12 3 23 1 7 17 31 5 20 42 a) Rita hur trädet ser ut efter inlägg av nycklarna 22, 19, 24, 18 och 15 (i den givna ordningen). (2p) b) Skriv en klass Node som skall representera noderna i trädet samt en klass BST som representerar trädet. Klasserna skall innehålla nödvändiga instansvariabler och lämpliga konstruktorer. Eftersom Node och BST är olika klasser uppstår ett problem med åtkomst av instansvariabler. Visa hur man löser detta med den design du presenterat ovan. c) Skriv en metod public int complete() i klassen BST som returnerar antalet kompletta noder i trädet. En komplett nod är en nod med två barn. (2p) d) Skriv en metod void postordertraverse() i klassen BST som traverserar trädet i postorderordning och skriver ut värdet i varje nod som besöks. Ange också det resultat man får om man gör en sådan traversering av trädet ovan. 2
2. Betrakta följande klasshierarki och testmetod: public abstract class Animal { public String name; public final String s = "Animal"; public Animal(String name){ this.name = name; public String getname() { return name; public abstract String speak(); public class Dog extends Animal { public final String s = "Dog"; public String speak() { return getname() + ": " + s + " Woof "; public class Labrador extends Dog { public final String s = "Labrador "; public class Cat extends Animal { public final String s = "Cat"; public String speak() { return getname() + ": " + s + " Miaow "; public class Test { public static void main(string[] args) { Animal a1 = new Animal("Nisse"); System.out.println(a1.speak() + a1.s); Animal a2 = new Dog("Fido"); System.out.println(a2.speak() + a2.s); Dog a3 = new Labrador("Labbe"); System.out.println(a3.speak() + a3.s); Animal a4 = new Labrador("Lubbe"); System.out.println(a4.speak() + a4.s); Cat a5 = new Animal("Muppet"); System.out.println(a5.speak() + a5.s); Dog a6 = new Labrador("Ludde"); System.out.println(a6.speak() + a6.s); a) Det går inte att kompilera klassen Animal med dess underklasser som de är defininerade ovan, beroende på det sätt konstruktorerna är deklarerade. Förklara problemet och visa hur man ska rätta till det så att det fungerar på avsett sätt, dvs så att alla djur får ett namn när de skapas. b) Efter att du löst problemet ovan försöker du kompilera klassen Test med sin main-metod. Den går inte heller att kompilera. Stryk satser i main-metoden som är illegala och ange sedan vad metoden skriver ut. Förklara också varför du tar bort de satser du strukit. 3
3. Vi har följande klass som representerar en sorterad länkad lista: public class List { private Node first; private static class Node { private int value; private Node next; private Node(int value, Node next) { this.value = value; this.next = next; public List() { first = null; private List(Node n) { first = n; public String tostring() { String res = ""; for (Node n = first; n!= null; n = n.next) { res = res + n.value; if (n.next!= null) { res = res + ", "; return "{" + res + ""; private static Node insert(int k, Node n) { if (n==null k<n.value) { return new Node(k, n); else if (k>n.value) { n.next = insert(k, n.next); return n; public void insert(int k) { first = insert(k, first); a) Man skulle kunna tänka sig att implementera en sökmetod search på detta sätt: public boolean search(int k) { return search(first, k); private boolean search(node r, int k) { if (r == null) return false; else if (r.value == k) return true; else return search(r.next, k); Vilken komplexitet har denna algoritm utrryckt med Ordo-notation? Det går att med givna förutsättningar förbättra denna algoritm så att man utnyttjar listans egenskaper optimalt. Visa hur detta kan göras. Vilken komplexitet har din förbättrade algoritm? b) Skriv en metod boolean equals(list l) som testar om aktuell lista och listan l är lika. Med lika menas med samma antal noder och med samma innehåll. Om det är så ska metoden returnera true, annars false. Metoden ska vara O(n), dvs linjärt beroende av listornas längd. (5p) 4
4. I bilagan finns kod som delvis implementerar en kalkylator. (Det är väsentligen samma kod som gavs till obligatorisk uppgift 5. ) Av utrymmesskäl är vissa delar som saknar betydelse för uppgiften utelämnade. a) Vi vill utöka kalkylatorn med en funktion power(x,n) som returnerar värdet av x upphöjt till n. Denna funktion har alltså två parametrar till skillnad från de övriga funktioner vi använt. Förklara hur arvshierarkin ska förändras för att införa sådana funktioner. Förklara vilka klasser som behövs och vilka ändringar i övrigt som behövs för att göra detta. Det hela ska göras på ett generellt sätt så att vi enkelt kan införa flera funktioner som har två parametrar. Du behöver inte skriva någon kod för de klasser du inför, beskriv mer abstrakt hur du tänker. b) De trigonometriska funktionerna (sin, cos... ) förutsätter att argumentet är givet i radianer. Ibland kan man ju vilja uttrycka sig i grader. För att kunna ange att man vill använda grader har kommandot set lagts in i metoden statement. Kommandot skall följas antingen av ordet degrees eller ordet radians. Exempel: Input : sin(0.5*pi) Parsed: sin(0.5*pi) Result: 0.8939966636005579 Input : set degrees Input : sin(30) Parsed: sin(30.0) Result: 0.49999999999999994 Input : set radians Result: 0.8939966636005579 Input : set nygrader *** Syntax error: Expected radians or degrees *** The error occurred at token nygrader just after token set Input : sin(0.5*pi) Parsed: sin(0.5*pi) Input : Skriv klart metoden performset() i klassen Calculator som skall se till att grader respektive radianer används enligt exemplet ovan. Skriv också de övriga kompletteringarna av koden som krävs! Tips: Grader (g) kan räknas om till radianer (r) med formeln r = g=180 5