Tentamen Programmeringsteknik II 2009-05-26 med lösningar Skrivtid: 0900-1200 Uppgifter 1. Programbilagan ListMap.java innehåller en klass som implementerar en avbildning mellan mängden strängar och mängden heltal dvs man kan till en sträng koppla ett heltalsvärde. Klassen är implementerad med en länkad lista. Vissa delar av koden är utelämnade. a) Implementera metoden boolean containskey(string key) som returnerar true om en nod med nyckeln key finns lagrad, annars false. Ledning: Använd den befintliga metoden search. public boolean containskey(string key) { return search(key, head)!= null; b) Implementera metoden void put(string key, int value). Om key redan är lagrad skall dess värde ändras till value, annars skall en ny listnod med key och value skapas och läggas först i listan. Ledning: använd den befintliga metoden search. public void put(string key, int value) { ListNode l = search(key, head); if ( l==null ) { head = new ListNode(key, value, head); else { l.value = value; c) Skriv den kod som fattas i metoden ListNode remove(string key, ListNode h). Metoden skall ta bort den nod som innehåller nyckel key ur den (del-)lista som börjar med h och returnera en referens till första noden i den modifierade listan. Om nyckeln inte finns skall listan inte förändras. l.next=remove(key,l.next); return l; 2. Klassen BST (se programbilagan BST.java) implementerar en mängd av heltal. Observera att ett givet tal bara kan finnas med en gång i mängden. a) Skriv färdigt hjälpmetoden tostring(node r) som returnerar ett String-objekt bestående av det träd som har sin rot i r. Se körutskrifterna i slutet av bilagan! Ledning: Utnyttja tostring()-metoden i Node-klassen. 1
protected static String tostring(node r) { if (r==null) return ""; else return tostring(r.left) + r + tostring(r.right); b) Skriv metoden int first() som skall returnera det första (minsta) värdet i trädet. public int first() { if (root==null) { throw new BSTException("first() on an empty tree"); else { Node r = root; while (r.left!=null) { r = r.left; return r.elem; c) Skriv färdigt hjälpmetoden Node add(int e, Node r) som ser till att en nod med värdet e lagras i det (sub-)träd som har sin rot i r. Alltså: Om e redan finns görs ingenting annars adderas en ny nod med e som värde på rätt plats i trädet. Metoden skall returnera en referens till rotnoden i det modifierade (del-)trädet. protected Node add(int e, Node r) { if (r==null) { r = new Node(e); else if (e<r.elem) { r.left = add(e, r.left); else { r.right = add(e, r.right); return r; 3. I programbilagan finns ett program som läser aritmetiska uttryck, representerar dem internt i ett träd, evaluerar trädet och skriver värdet (mycket likt projektuppgiften men utan funktioner). Programmet består av en Calculator-klass med en main-metod, en Parser-klass med metoder för inläsning och uppbyggnad av trädrepresentationen av uttrycken, en klasshierarki för representation av noderna i uttrycksträdet med klassen Sexpr som basklass samt klassen Symbolic för symbolisk/numerisk aritmetik. Vissa delar av koden är utelämnade. Dessutom finns klassen SimplifiedTokenizer som används av Parser-klassen. Förutom det som fanns i projektuppgiften kan programmet hantera operationen fakultetsberäkning genom operatorn!. Denna är, som brukligt, en postfixoperator 2
dvs den skrivs efter argumentet. Inläsningen hanteras av factor-metoden i Parserklassen. Som framgår av körexemplen skall fakultetsberäkning av negativa tal och av tal som inte är heltal betraktas som evalueringsfel. a) Skriv färdigt metoden assignment i klassen Parser. Metoden skall bygga noder som representerar tilldelningsoperationer dvs noder av typen Assignment. private Sexpr assignment() { Sexpr res = expression(); while (st.getchar()== = ) { st.nexttoken(); if (st.isword()) { res = new Assignment(res, new Variable(st.getWord())); st.nexttoken(); else { throw new SyntaxException("= måste följas av en variabel"); return res; b) Skriv färdigt metoden diff i subklassen Variable. Metoden skall returnera derivatan av variabeln med avseende på den variabel som parametern v står för. public Sexpr diff(sexpr v) { if (ident.equals(v.getname())) { return new Constant(1.); else { return new Constant(0.); c) Skriv färdigt metoden eval i subklassen Differentiation. Metoden skall returnera derivatan av sitt evaluerade vänstra argument med avseende på den variabel som finns som högra argument. public Sexpr eval(map<string, Sexpr> v) { Sexpr e = left.eval(v); return e.diff(right); d) Implementera tostring()-metoden för klassen Factorial som representerar fakultetsoperationen. Operatorn skall, som vanligt, skrivas efter operanden. Metoden skall vid (och endast vid) behov sätta ut parenteser. 3
public String tostring() { if ( argument.priority() < this.priority() ) { return "(" + argument + ")" + getname(); else { return argument + getname(); e) Implementera metoden factorial i klassen Symbolic så att den fungerar i enlighet med körexemplet. Se anropet från eval-metoden i klassen Factorial. public static Sexpr factorial(sexpr arg) { if (!arg.isconstant()) { return new Factorial(arg); else { if ( arg.getvalue()<0 ((int) arg.getvalue())!= arg.getvalue()) { throw new EvaluationException("Illegal fakultetsberäkning: " + arg + "!"); else { int res = 1; for (int i= 1; i<=arg.getvalue(); i++) { res = i*res; return new Constant(res); Nedan följer ett körexempel. jeltz$ java Calculator Välkommen till kalkylatorn! > 1+2*3 = a = b +2.0*3.0 = a = b 7.0 > a a 7.0 > 3=a 3.0 = a 3.0 > z=2 *** Syntaxfel: = måste följas av en variabel > x x x x > 1=x = x > x x x x 0.0 > "x x 4
"x x > (x*z) z (x*z) z > 10=x 10.0 = x 10.0 > (x*z) z (x*z) z 10.0 > 3! 3.0! 6.0 > 4! 4.0! 24.0 > 3!! 3.0!! 720.0 > (n-m)! (n-m)! (n-m)! > n!! n!! n!! > -3! -3.0! -6.0 > (-3)! (-3.0)! *** Evalueringsfel: Illegal fakultetsberäkning: -3.0! > 2.5! 2.5! *** Evalueringsfel: Illegal fakultetsberäkning: 2.5! > quit Tack för idag (och för fisken) jeltz$ 5