1(4) LUNDS TEKNISKA HÖGSKOLA Institutionen för datavetenskap Omkontrollskrivning, Programmeringsteknik för D/C 2005–01–29, 9.00–14.00 Anvisningar: Skrivningen består av tre ordinarie uppgifter (nr 1–3) och en extrauppgift (nr 4). Preliminärt ger de ordinarie uppgifterna 10, 10 resp 20 poäng. Du kan få betyg 3 eller 4 genom att lösa de ordinarie uppgifterna och kanske till och med betyg 5, men då måste dina lösningar vara väldigt bra. Extrauppgiften är bara avsedd för dig som eftersträvar betyg 5. Lös denna uppgift i sista hand! Tillåtet hjälpmedel: Java-snabbreferens. Resultatlistan anslås på institutionens anslagstavla när rättningen är klar, förhoppningsvis på måndag den 31 januari. Betyget på denna skrivning utgör betyget på kontrollskrivningarna, oavsett resultatet på tidigare skrivningar (dock sänks inte ett tidigare godkänt betyg). 2(4) 1. Samsortering (”merge” på engelska) kallas det när man har två sorterade följder och man slår ihop dem till en ny sorterad följd. Vi förutsätter här att följderna består av heltal som är lagrade i två vektorer first och second. När man skall samsortera vektorerna till en ny vektor result så tar man hela tiden det minsta oanvända talet från first eller second och lägger det i result. Exempel på samsortering (här råkar vektorerna first och second vara lika långa, men det är inte säkert att så är fallet): first second result 5 7 10 12 1 8 11 19 5 7 10 12 1 8 11 19 1 5 7 10 12 1 8 11 19 1 5 5 7 10 12 1 8 11 19 1 5 7 5 7 10 12 1 8 11 19 1 5 7 8 5 7 10 12 1 8 11 19 1 5 7 8 10 5 7 10 12 1 8 11 19 1 5 7 8 10 11 5 7 10 12 1 8 11 19 1 5 7 8 10 11 12 5 7 10 12 1 8 11 19 1 5 7 8 10 11 12 19 Skriv en metod som utför samsorteringen. Metoden skall ha följande rubrik: public int[] merge(int[] first, int[] second); Metoden skall alltså returnera den samsorterade vektorn. Tips: inför tre heltalsvariabler: i som håller reda på platsen för det första oanvända talet i first, j som gör samma sak i second och k som håller reda på den första lediga platsen i result. 2. Ett rationellt tal är ett bråktal med täljare och nämnare, till exempel 2/3 eller 54/7. Vi vill skriva ett program som kan räkna exakt med rationella tal. I programmet utnyttjar vi följande klass: specification Rational { /** skapa ett rationellt tal med täljaren num och nämnaren denom (det förutsätts att denom är skilt från 0) */ Rational(int num, int denom); /** skriv ut talet på formen täljare/nämnare (bara täljare om nämnaren = 1) */ void print(); /** addera det rationella talet r till detta tal */ void add(Rational r); // ... tre operationer till, för att subtrahera, multiplicera och // ... dividera. Dessa operationer skall du inte skriva. } Implementera klassen. Ett rationellt tal skall alltid vara förkortat så långt som möjligt; till exempel skall 4/6 representeras som 2/3, 12/144 som 1/12. När du skall utföra förkortningen får du använda följande funktion i klassen Rational, som du inte behöver skriva: /** beräkna den största gemensamma faktorn till talen a och b. Till exempel är gcd(4,6)=2, gcd(12,144)=12, gcd(5,7)=1 */ private int gcd(int a, int b); 3(4) 3. En engelsk-svensk och svensk-engelsk ordbok beskrivs av följande klass: specification Dictionary { /** skapa en tom ordbok */ Dictionary(); /** lägg in ett nytt svenskt ord sw med den engelska översättningen eng (dessa ord finns inte tidigare i ordlistan) */ void insert(String sw, String eng); /** tag reda på den svenska översättningen av det engelska ordet eng, tom sträng om ordet inte finns i ordlistan */ String getSwedish(String eng); /** tag reda på den engelska översättningen av det svenska ordet sw, tom sträng om ordet inte finns i ordlistan */ String getEnglish(String sw); } Man kan alltså utnyttja ordboken för översättning både från engelska till svenska (med getSwedish) och från svenska till engelska (med getEnglish). Implementera ordboken enligt följande anvisningar: • Varje par av ord (svenskt/engelskt) representeras av ett objekt av följande färdigskrivna klass: specification WordPair { /** ett svenskt ord sw med den engelska översättningen eng */ WordPair(String sw, String eng); /** tag reda på det svenska ordet */ String getSw(); /** tag reda på det engelska ordet */ String getEng(); } • WordPair-objekten skall lagras i listor av typen ArrayList. • Det skall finnas 26 olika listor. I den första listan lagras alla ord där den engelska översättningen börjar på ’a’, i den andra listan lagras alla ord på ’b’, osv. De 26 listorna lagras i en vektor. Du får förutsätta att de engelska orden bara innehåller små bokstäver a-z. Schematiskt kan det se ut så här: [0] [1] [2] … ant myra aardvark jordsvin both båda blue blå cat katt arm arm 4(4) 4. Observera: lös denna uppgift i sista hand (se anvisningarna). Metoden för att implementera ordlistan som vi använt i uppgift 3 är inte särskilt bra, eftersom söktiderna blir långa om man har många ord (listorna blir långa, även om vi försökt att göra dem kortare genom att ha olika listor för olika begynnelsebokstäver). Betydligt kortare söktider får man om man organiserar orden i ett binärt sökträd. Nedanstående uppgift visar vad det går ut på. Ett binärt sökträd är en datastruktur som tillåter effektiv sökning efter element. Elementen, som brukar kallas noder, läggs in i sorterad ordning i ett träd enligt följande figur (här är värdena i noderna strängar): carin bo filip anna eva kalle Noden överst i trädet kallas trädets rot. Under roten finns till vänster noder med värde mindre än rotvärdet, till höger noder med värde större än rotvärdet (vi förutsätter att alla värdena är olika). Detta upprepas sedan för alla nivåer i trädet. Vid sökning efter ett visst värde börjar man i roten. Om värdet finns i roten är man klar, annars jämför man det sökta värdet med värdet i roten. Om det sökta värdet är mindre går man ner en nivå till vänster, om det är större går man ner en nivå till höger. Detta upprepar man tills man hittar det sökta värdet eller tills det är slut på noder. Vi ser att varje nod måste hålla reda på omedelbart underliggande noder, en till vänster och en till höger. En klass som implementerar en nod kan ha följande utseende: class Node { private Node left; private Node right; private String value; // noden till vänster, null om ingen // noden till höger, null om ingen // värdet i noden /** skapa en nod med värdet value */ public Node(String value) { this.value = value; left = right = null; } // ... här finns metoder getValue(), getLeft() och getRight() samt // ... metoder för att bygga upp trädet (dessa används inte i // ... denna uppgift) } Ett binärt sökträd beskrivs av följande klass: class BinarySearchTree { private Node root; // roten i trädet, null om trädet är tomt /** skapa ett tomt träd */ public BinarySearchTree() { root = null; } /** undersök om strängen value finns i trädet */ public boolean exists(String value) { // ... } // ... ytterligare metoder som inte används i denna uppgift } Implementera operationen exists.