Lösningsförslag till tentamen i EDA011/EDA017 Programmeringsteknik för F, E, I, π och N 25 maj 2009

Storlek: px
Starta visningen från sidan:

Download "Lösningsförslag till tentamen i EDA011/EDA017 Programmeringsteknik för F, E, I, π och N 25 maj 2009"

Transkript

1 Lösningsförslag till tentamen i EDA011/EDA017 Programmeringsteknik för F, E, I, π och N 25 maj 2009 Christian 5 mars 2010 Observera att poängen nedan är preliminära det är möjligt att vi korrigerar något när vi har rättat några tentor. Uppgift 1 klassen PriceList Som framgick av uppgiftsformuleringen kan vi ha nytta av en klass som håller reda på priset på en vara i en given butik. I denna klass kan vi antingen lagra butik och vara som separata strängattribut, eller baka ihop dem till ett enda attribut (som föreslogs i uppgiften) de båda alternativen är lika goda, och ger lika många poäng vid rättningen. Med separata attribut för butik och vara får vi en klass PriceInfo med följande utseende: class PriceInfo { private String shop; private String item; private double price; public PriceInfo (String shop, String item, double price) { this.shop = shop; this.item = item; this.price = price; public String getshop() { return shop; public String getitem() { return item; public double getprice() { return price; Om vi istället slår ihop butiks- och varunamn till en enda nyckel får vi: class PriceInfo { private String key; private double price; public PriceInfo (String key, double price) { this.key = key; this.price = price; public String getkey() { return key; public double getprice() { return price; 1

2 Klassen PriceList kan implementeras som (jag har här använt den andra typen av PriceInfo-klass ovan): class PriceList { private List<PriceInfo> items = new LinkedList<PriceInfo>(); Det finns andra sätt att lösa uppgiften man fick använda Javas standardklasser, och det finns en fiffig klass (eller snarare typ av klasser) som heter Map med hjälp av en sådan skulle vi kunna skriva PriceList som (vi använder här dessutom hasnextline() på vårt Scanner-objekt, vilket innebär att vi inte behöver ha någon avslutande #): class PriceList { private String makekey(string shop, String item) { return shop + ":" + item; public PriceList (Scanner s) { String shop = s.nextline(); if (shop.equals("#")) { items.add(new PriceInfo(makeKey(shop, s.nextline()), s.nextdouble())); s.nextline(); // För att läsa bort radslutet e f t e r priset // Ni behövde inte göra detta! public double findprice(string shop, String item) { String key = makekey(shop, item); for (PriceInfo priceinfo : items) { if (priceinfo.getkey().equals(key)) { return priceinfo.getprice(); return -1; Om vi hade använt den första PriceInfo-klassen ovan hade vi fått ändra villkoret i if-satsen i findprice till: if (priceinfo.getshop().equals(shop) && priceinfo.getitem().equals(item)) { return priceinfo.getprice(); private Map<String, Double> prices = new HashMap<String, Double>(); private String makekey(string shop, String item) { return shop + ":" + item; public PriceList (Scanner s) { while (s.hasnextline()) { prices.put(makekey(s.nextline(), s.nextline()), s.nextdouble()); s.nextline(); // För att läsa bort radslutet e f t e r priset // Ni behövde inte göra detta! public double findprice(string shop, String item) { String key = makekey(shop, item); if (!prices.containskey(key)) { return -1; return prices.get(key); Poängsättning PriceList Ingen använde Map, så vid rättningen behöver vi inte hantera detta fall. Poäng hela klassen PriceList: 19 min 6 4 p Fungerande hjälpklass 2 p Korrekta attribut 1 p Konstruktor 1 p Sätt att accessa attribut 2

3 2 p Deklarerar och skapar en lista/vektor med rätt sorts element 7 p Inläsning av prislista 1 p Loopar rätt antal varv 1 p Läser butiksnamn 1 p Läser varunamn 1 p Läser pris 1 p Skapar rätt sorts objekt 2 p Lägger in objekt i lista 6 p Operationen findprice 1 p Går igenom alla varor 3 p Testar varunamn på rätt sätt 2 p Returnerar rätt pris (båda fallen) Uppgift 2 klassen ShopTotal I klassen ShopTotal behöver vi hålla reda på tre saker: butikens namn, som vi kan lagra i ett String-attribut, totalpriset, namnen på de varor som saknas. public void additemprice(double price) { total += price; public void addmissingitem(string item) { missingitems.add(item); public boolean sellsallitems() { return missingitems.size() == 0; public String tostring() { StringBuilder sb = new StringBuilder(); sb.append(shopname); if (sellsallitems()) { sb.append(": " + total); else { sb.append("--- säljer inte:"); for (String item : missingitems) { sb.append(" " + item); return sb.tostring(); Vi kan lagra namnen på varorna på olika sätt mest naturligt är väl en lista med strängar, men det skulle i detta fall faktiskt fungera bra även med bara ett String-attribut (eller, hellre, ett StringBuilder-attribut) som vi bygger på vid varje addmissingitem-anrop. Klassen ShopTotal kan implementeras som: class ShopTotal { private String shopname; private List<String> missingitems = new LinkedList<String>(); private double total; public ShopTotal (String shopname) { this.shopname = shopname; Poängsättning ShopTotal Poäng ShopTotal: 18 min 6 4 p Attribut och konstruktor 1 p Butiksnamn 1 p Ackumulerat pris 2 p Lista/StringBuilder/String med saknade varor 2 p additemprice 2 p addmissingitem 3 p sellsallitems 7 p tostring 3

4 1 p Deklarerar och skapar en StringBuilder/String 1 p Får med butikens namn 1 p Får med totalsumma på rätt sätt 3 p Får med markering av varor som saknas 1 p Returnerar ett String-objekt Uppgift 3 klassen ShoppingList class ShoppingList { private PriceList pricelist; private List<String> items = new LinkedList<String>(); private List<String> shops = new LinkedList<String>(); public ShoppingList (PriceList pricelist) { this.pricelist = pricelist; public void additem(string item) { items.add(item); public void addshop(string shop) { shops.add(shop); public List<ShopTotal> gettotalprices() { List<ShopTotal> totals = new LinkedList<ShopTotal>(); for (String shop : shops) { ShopTotal total = new ShopTotal(shop); for (String item : items) { double price = pricelist.findprice(shop, item); if (price < 0) { total.addmissingitem(item); else { total.additemprice(price); totals.add(total); return totals; Poängsättning ShoppingList Poäng ShoppingList: 23 min 10 5 p Attribut och konstruktor 1 p Sparar prislista 2 p Deklarerar och sparar lista med varor 2 p Deklarerar och sparar lista med butiker 2 p additem 2 p addshop 14 p gettotalprices 2 p Deklarerar och skapar lista med ShopTotal 2 p Går igenom samtliga butiker (före varor!) 2 p Deklarerar och skapar ny ShopTotal för varje butik 1 p Går igenom samtliga varor i butiken 2 p Hämtar pris på rätt sätt 3 p Uppdaterar ShopTotal på rätt sätt 1 p Lägger in ShopTotal i lista 1 p Returnerar listan Uppgift 4 huvudprogram I huvudprogrammet skulle ni läsa in från tangentbordet ni fick gärna använda Keyboard-operationerna, i lösningsförslaget nedan har jag istället använt ett Scannerobjekt (det ger lika många poäng): class Shopping { public static void main(string[] args) { new Shopping().run(); void run() { ShoppingList list = new ShoppingList( 4

5 new PriceList(Utils.createScanner("prices.data"))); Scanner s = new Scanner(System.in); System.out.println("Ange namnen på varorna:"); String item = s.nextline(); if (item.length() == 0) { list.additem(item); System.out.println("Ange namnen på butikerna:"); String shop = s.nextline(); if (shop.length() == 0) { list.addshop(shop); System.out.println("Totalpriser:"); for (ShopTotal st : list.gettotalprices()) { System.out.println(st); Poängsättning huvudprogram Poäng Huvudprogram: 11 min 4 3 p Deklarerar och skapar ShoppingList 2 p Läser in och sparar samtliga varor (+ rätt antal varv) 2 p Läser in och sparar samtliga butiker (+ rätt antal varv) 2 p Går igenom samtliga ShopTotal-objekt 2 p Skriver ut varje ShopTotal Uppgift 5 primtal Denna uppgift kan man naturligtvis lösa på många olika sätt man känner idag till väldigt snabba metoder att bestämma om ett tal är ett primtal eller ej, men i uppgiften räcker det utmärkt att bara testa sig fram genom att leta bland potentiella divisorer. När vi testar potentiella divisorer är det lite fiffigt att bara testa primtal, för om vi börjar nedifrån kan vi inte hitta några nya faktorer om vi testar ett sammansatt tal (någon av dess faktorer hade redan delat det tal vi testar). Inte heller denna effektivisering krävs för full poäng på uppgiften, men nedan är ett program som bygger upp en längre och längre lista med primtal, och som använder de hittills funna primtalen för att bestämma nästa. Programmet hittar det :e primtalet ( ) på några sekunder på en normal dator. class Primes { public static void main(string[] args) { new Primes().run(); boolean isdivisiblebyany(int value, List<Integer> factors) { for (int factor : factors) { if (value % factor == 0) { return true; return false; int next(list<integer> primes) { int n = primes.get(primes.size()-1) + 1; while (isdivisiblebyany(n, primes)) { n++; // l i t e naivt, vi kunde ha börjat på 3 // och hoppat över jämna tal, men v i // kommer å andra sidan att hitta faktorn // 2 väldigt fort varje gång... return n; int primenumber(int n) { List<Integer> primes = new ArrayList<Integer>(); primes.add(2); while (primes.size() < n) { primes.add(next(primes)); return primes.get(primes.size()-1); 5

6 void run() { int n = Keyboard.nextInt("Ange n: "); if (n <= 0) { System.out.printf("Primtal nummer %d är %d\n", n, primenumber(n)); Poängsättning del 2 System.out.println("Tack för denna gång"); Vi har ännu inte bestämt hur protokollet skall se ut för del 2 (det var bara drygt en handfull som löste uppgiften, och vi har därför tid att göra en lite mer individuell bedömning). 6