Inledning I bilagor finns ett antal mer eller mindre ofullständiga klasser. Klassen List innehåller några grundläggande komponenter för att skapa och hantera enkellänkade listor av heltal. Listorna hålls inte sorterade och ett tal kan förekomma flera gånger. Klassen ListSet är en subklass till List. Dessa listor hålls sorterade i storleksordning med det minsta talet först och varje tal förekommer högst en gång (inga dubbletter alltså). Klassen BST innehåller binära sökträd med heltal som nycklar. En nyckel kan förekomma högst en gång i trädet. Alla klasser innehåller main-metoder med utskrifter som demonstrerar metoderna. Del A (obligatorisk för alla) A1. Skriv undantagsklassen ExamException som en underklass till RuntimeException. Det skall gå att kasta undantag till exempel på följande sätt: if (i < 0) { throw new ExamException("Illegal index value"); public class ExamException extends RuntimeException { public ExamException(String msg) { super(msg); A2. Skriv metoden public void addfirst(int data) i klassen List som lägger in en ny nod med värdet data först i listan. public void addfirst(int data) { first = new Node(data, first);
A3. Skriv klart den rekursiva hjälpmetoden till copy-metoden i klassen List: public List copy() { return new List(copy(first)); protected static Node copy(node n) { if (n==null) { return null; else { return new Node(n.data, copy(n.next)); A4. Skriv färdigt metoden toarraylist nedan. Metoden ska lägga in alla tal från listan i en arraylist och de ska ligga i samma ordning som i listan. Metoden ska vara iterativ och komplexiteten O(n) där n är antalet element i listan. public ArrayList<Integer> toarraylist() { ArrayList<Integer> result = new ArrayList<Integer>(); for (Node n = first; n!= null; n = n.next) { result.add(n.data); return result;
A5. Skriv metoden int smallest() (inklusive eventuella hjälpmetoder) i klassen List som beräknar och returnerar det minsta värdet lagrat i listan. Välj själv mellan iterativ och rekursiv implementation! public int smallest() { if (first == null) { throw new ExamException("Empty list in smallest"); return smallest(first); protected static int smallest(node n) { if (n.next==null) { return n.data; else { return Math.min(n.data, smallest(n.next)); A6. Vad blir den interna väglängden i det träd som genereras av nedanstående kodsekvens? (Titta på den givna metoden ipl om du glömt hur begreppet intern väglängd definieras!) BST bst = new BST(); bst.add(10); bst.add(5); bst.add(1); bst.add(17); bst.add(10); bst.add(6); bst.add(4); bst.add(3); 1 (för 10) + 2 (för 5) + 3 (för 1) + 2 (för 17) + 3 (för 6) + 4 (för 4) + 5 (för 3) = 20
A7. Vad är den minsta möjliga väglängden för ett träd med 7 noder? Motivera! Ett träd med 3 fyllda nivåer rymmer 1+2+4 = 7 noder vilket ger väglängden 1 + 2 2 + 4 3 = 17 A8. Antag att cirka 1 000 000 olika slumptal matas in i ett binärt sökträd. Ungefär hur många jämförelser bör det i genomsnitt krävas för att återfinna ett lagrat tal? Motivera svaret! Tips: 10 6 2 20 Det genomsnittligt noddjupet i ett träd med n noder är 1.38 log 2 n (trädet väglängd / antalet noder). 1.38 log 2 (10 6 ) 1.38 log 2 (2 20 ) = 1.38 20 28 jämförelser.
A9. I subklassen ListSet till klassen List ska listorna vara sorterade och dessutom får varje värde förekomma högst en gång. Dessa listor byggs upp med metoden add (se bilagan). En av metoderna i klassen List får inte användas på subklassen ListSet. Vilken och varför? Hur förhindrar man att den obemärkt används? Metoden addfirst. Implementera den så att den kastar ett undantag. A10. Två metoder som är definierade i klassen List fungerar visserligen fortfarande för ListSet men bör av effektivitetsskäl ändå omdefinieras. Vilka? Vad har de för komplexitet om de inte omdefinieras? Metoderna smallest (Θ(n) som letar genom hela listan trots att det minsta ligger först) och tobst (Θ(n 2 ) eftersom trädet blir urartat 1 + 2 + 3 + + n = n(n + 1)/2) A11. Välj en av de metoderna från ovanstående uppgift (lämpligen den enklaste den svårare får du göra i B-delen) och skriv den. Vad är dess komplexitet? public int smallest() { if (first == null) { throw new ExamException("Empty list in smallest"); return first.data;
A12. I den första programmeringskursen gjordes paddorna rörliga genom att man hade en loop som dels innehöll en flyttning och omritning av paddorna och dels ett anrop till Thread.sleep(). Nackdelen med detta är att programmet är låst när det sover. I denna kurs har vi använt en annan teknik för att göra rörliga figurer. Beskriv kortfattat (rutan ska inte fyllas med text) denna teknik! Vilka de är de viktiga programdelarna? Vi använder en Timer som genererar en händelse med visst tidsintervall. Dessa händelser tas om han av en lyssnare (ActionListener) som flyttar figurerna och ritar om dem i sina nya positioner. Program som fungerar på detta sätt kallas händelsestyrda.
Del B (för betyg 4 och 5) Svaren skrivs på lösa papper med ny uppgift på nytt papper. B1. Skriv en rekursiv metod static int noof(int x) som räknar antalet udda siffror i talet x (betraktat som ett decimalt heltal). Exempel: noof(12345) ska bli 3 (siffrorna 1, 3 och 5), noof(3050) ska bli 2 och noof(400004) ska bli 0. Du kan förutsätta att talet inte är negativt. public static int noof(int x) { if (x==0) return 0; else if (x%2==1) return 1 + noof(x/10); else return noof(x/10); B2. Givet tre olika algoritmer för att lösa ett givet problem. Algoritm A har komplexiteten Θ(n), algoritm B har komplexiteten Θ(n log n) och algoritm C har komplexiteten Θ(n 2 ). För n = 100 har mätningar visat att algoritm A tar 1000 sekunder, algoritm B tar 100 sekunder och algoritm C tar 10 sekunder. a) För vilket värde på n kan vi vänta oss att algoritm A blir snabbare än algoritm B? b) För vilket värde på n kan vi vänta oss att algoritm A i blir snabbare än algoritm C? c) För vilket värde på n kan vi vänta oss att algoritm B i blir snabbare än algoritm C? Här räcker det med att ange första 10-potens som gör att B snabbare än C (alltså 10 3, 10 4, 10 5,... ) Svaren ska motiveras! Algoritm A t a (n) = c a n t a (100) = c a 100 = 1000 c a = 10 t a (n) = 10n Algoritm B t b (n) = c b n log n t b (100) = c b 100 log 100 = 100 c b = 0.5 t b (n) = 0.5n log n Algoritm C t c (n) = c c n 2 t c (100) = c c 10 4 = 10 c a = 10 3 t c (n) = 10 3 n 2 a) t a (n) < t b (n) 10n < 0.5n log n 20 < log n Svar: När n > 10 20 b) t a (n) < t c (n) 10n < 10 3 n 2 10 < 10 3 n Svar: När n > 10 4 c) t b (n) < t c (n) är svår att lösa analytiskt. Prova: n t b (n) t c (n) 100 100 10 1000 1500 1000 10000 2000 100000 Svar: För n = 10 4 är algoritm B (betydligt) snabbare än algoritm C. B3. I klassen List finns en metod atindex(int index) som returnerar värdet lagrat i angiven position.
Om index-värdet är mindre än 0 eller större än eller lika med antalet element i listan kastas ett undantag. Se körexemplet! Tyvärr får användaren inte veta värdet på det felaktiga indexet. Som synes i körexemplet blir utskriften: *** Error *** nonexisting index Modifiera koden (huvudmetoden och/eller hjälpmetoden) så att även värdet inkluderas i felmeddelandet! Utskriften ska således bli: *** Error *** nonexisting index: 35 Beräkningarna ska fortfarande göras på samma rekursiva sätt och du får inte ändra i parameterlistorna! public int atindex(int index) { // B try { return atindex(index, first); catch(examexception e) { throw new ExamException(e.getMessage() + " : " + index); B4. Skriv metoden contains(listset s) i klassen ListSet som returnerar true om alla element i listan s också finns i den egna listan. Se körexemplet! Obs: Metodens komplexitet ska vara O(n + m) där n och m är antalet element i den egna listan respektive listan s public boolean contains(listset s) { return contains(first, s.first); private static boolean contains(node f, Node s) { if (s == null) { return true; else if (f == null s.data < f.data) { return false; else if (f.data == s.data) { return contains(f.next, s.next); else { return contains(f.next, s); B5. Skriv en metod boolean contains(bst bst) i klassen BST som returnerar true om alla värden i trädet bst också finns med i det egna trädet, annars false. Metodens komplexitet ska vara O(n + m) där n och m är antalet noder i respektive träd. public boolean contains(bst t) { return this.tolistset().contains(t.tolistset()); B6. Implementera den andra (den svårare) av de två metoder som man bör omdefiniera i subklassen ListSet. Hur blir komplexiteten för denna implementation?
public BST tobst() { BST result = new BST(); ArrayList<Integer> temp = this.toarraylist(); tobst(result, temp, 0, temp.size()); return result; private static void tobst(bst bst, ArrayList<Integer> temp, int low, int high) { if (low < high) { int mid = low + (high - low)/2; bst.add(temp.get(mid)); tobst(bst, temp, low, mid); tobst(bst, temp, mid+1, high); Komplexiteten bli Θ(n log n) (trädet får minmal väglängd).