Programmeringoch databaser LÖSNINGSFÖRSLAG TILL ÖVNINGAR EDAA20 2017/2018
LUNDS TEKNISKA HÖGSKOLA EDAA20 Programmeringsteknik Institutionen för datavetenskap 2017/2018 Övning 1 Variabler och tilldelningssatser 1. int sum = 3 + 8 + 12; System.out.println("Summan är: " + sum); Alternativt kan man t.ex. lagra termerna i varsin variabel, för att sedan räkna ut resultatet. Vilket kan vara en fördel om man i framtiden vill bygga ut programmet för att t.ex. låta värdena bero av andra saker eller använda samma termer i en annan uträkning. //Alternativ lösning: int a = 3; int b = 8; int c = 12; int sum2 = a + b + c; System.out.println("Summan är: " + sum2); Det är även möjligt att ha uträkningen direkt i utskriften (om man inte behöver använda summan till något annat än just att skriva ut den en gång). Tänk på att ett plustecken i en utskrift normalt anger att en text läggs till i utskriften. Vid uträkning i en utskrift skulle det krävas extra parenteser: System.out.println("Summan är: " + (a+b+c)); 2. Följande variabler finns efter de två första tilldelningssatserna: nbra 2 nbrb 5 och efter tredje, fjärde respektive femte tilldelningssatsen: nbra nbrb nbrc 2 5 20 nbra nbrb nbrc 4 5 20 nbra nbrb nbrc 4 5 0 3. a) Parentesen runt c + d i tilldelningssatsen int e =... är onödig. Om den utelämnas görs ändå c + d först, eftersom den additionen står först. b) 6 2 6 8 9 c) 7 2 10 4 9 4. Man måste använda en variabel (här kallar vi den temp) för att mellanlagra det ena värdet. Satser: int temp = a; a = b; b = temp; 2
3 Inläsning och beräkning 5. public class TimeDifference { public static void main(string[] args) { System.out.println("Skriv starttid och sluttid (timmar och minuter):"); Scanner scan = new Scanner(System.in); int starthour = scan.nextint(); int startmin = scan.nextint(); int stophour = scan.nextint(); int stopmin = scan.nextint(); int minutes = 60 * (stophour - starthour) + (stopmin - startmin); System.out.println("Tidsavstånd i minuter: " + minutes); 6. För att skriva ut tidsavståndet i timmar och minuter subtraherar vi timmarna för sig, minuterna för sig. Vi måste ta hänsyn till att minutskillnaden kan bli negativ och i så fall korrigera det. Nya satser (efter inläsningssatserna): int diffhour = stophour - starthour; int diffmin = stopmin - startmin; if (diffmin < 0) { diffmin = diffmin + 60; diffhour = diffhour - 1; System.out.println("Tidsavstånd: " + diffhour + " timmar, " + diffmin + " minuter"); Den andra varianten, med heltalsdivision: int minutes = 60 * (stophour - starthour) + (stopmin - startmin); int diffhour = minutes / 60; int diffmin = minutes % 60; System.out.println("Tidsavstånd: " + diffhour + " timmar, " + diffmin + " minuter"); Slumptal 7. I det intervall som efterfrågas finns 100 möjliga utfall (100-199) och det minsta möjliga värdet är 100. nextint i anropet nedan ger ett slupmtal i intervallet 0-99. Random rand = new Random(); int slumptal = rand.nextint(100)+100; System.out.println(slumpTal); 8. I det intervall som efterfrågas finns 21 möjliga utfall och det minsta möjliga värdet är 10. Random rand = new Random(); int slumptal = rand.nextint(21)+10;
4 System.out.println(slumpTal); 9. Här visas två möjliga lösningar. De skiljer sig i hur man säkerställer att de två slumptalen är olika. I den första lösningen används en while-sats för att dra nya slumptal tills de två är olika: public class TwoRandomNumbers { public static void main(string[] args) { Random rand = new Random(); int nbr1 = rand.nextint(100) + 1; int nbr2 = rand.nextint(100) + 1; while (nbr2 == nbr1) { nbr2 = rand.nextint(100) + 1; System.out.print("Två slumptal: "); if (nbr1 < nbr2) { System.out.println(nbr1 + ", " + nbr2); else { System.out.println(nbr2 + ", " + nbr1); While-satsen ovan kan potentiellt behöva köras flera gånger (även om det är rätt osannolikt). Man kan därför utgå från att det andra slumptalet bara ska ha 99 utfall: public class TwoRandomNumbers { public static void main(string[] args) { Random rand = new Random(); int nbr1 = rand.nextint(100) + 1; int nbr2 = rand.nextint(99) + 1; if (nbr2 >= nbr1) { nbr2++; System.out.print("Två slumptal: "); if (nbr1 < nbr2) { System.out.println(nbr1 + ", " + nbr2); else { System.out.println(nbr2 + ", " + nbr1); Aritmetiska uttryck 10. a) y = Math.sin(20 * Math.PI / 180); //Eller y = Math.sin(Math.toRadians(20)); b) z = a * Math.exp(x) + b * Math.exp(-Math.cos(x)); c) hyp = Math.hypot(a, b); // eller: hyp = Math.sqrt(a * a + b * b); 11. (int) Math.round(x) 12. a) if (n % 2 == 0)... b) if (n % 10 == 0)... c) digit1 = number / 100;
digit2 = (number % 100) / 10; // eller: digit2 = (number / 10) % 10; digit3 = number % 10; 5
LUNDS TEKNISKA HÖGSKOLA EDAA20 Programmeringsteknik Institutionen för datavetenskap 2017/2018 Övning 2 Logiska uttryck 1. a) a > 5 b) a > 2 c) a <= 2 d) a <= 2 a >= 9 e) a >= 0 && a <= 10 f) ready g)!ready Loopar 2. Lösningen gör antagandet att användaren skriver in ett positivt tal. Lägg gärna till en kontroll av detta. Scanner scan = new Scanner(System.in); int n = scan.nextint(); int factorial = 1; for (int i = 2; i <= n; i++) { factorial = factorial * i; System.out.println(n + "! = " + factorial); 3. Scanner scan = new Scanner(System.in); System.out.println("Skriv in ett tal"); int n = scan.nextint(); int factorial = 1; int i = 2; while (i <= n) { factorial = factorial * i; i++; System.out.println(n + "! = " + factorial); Summering 4. public class AverageTemperature { public static void main (String[] args) { final int NBR = 30; //Behöver inte vara final för att fungera double sum = 0; Scanner scan = new Scanner(System.in); for (int i = 0; i < NBR; i++) { double temperature = scan.nextdouble(); sum = sum + temperature; scan.close(); double averagetemperature = sum / NBR; 6
7 System.out.println("Medeltemperatur: " + averagetemperature + " grader"); 5. Scanner scan = new Scanner(System.in); double limit = scan.nextdouble(); double smallsum = 0; double largesum = 0; for (int i = 0; i < 100; i++) { double nbr = scan.nextdouble(); if (nbr < limit) { smallsum = smallsum + nbr; else if (nbr > limit) { largesum = largesum + nbr; System.out.println("Summan av tal < " + limit + " = " + smallsum); System.out.println("Summan av tal > " + limit + " = " + largesum); Observera att man måste skriva...else if(nbr > limit)... och inte bara else. Med enbart else kommer tal lika med limit med i largesum. 6. public class HugeSalary { public static void main (String[] args) { int daysalary = 1; int totalsalary = 0; int days = 0; while (totalsalary < 1000000) { totalsalary = totalsalary + daysalary; days = days + 1; daysalary = 2 * daysalary; System.out.println("Man måste arbeta " + days + " dagar."); Beräkna max och min 7. a) public class Max { public static void main(string[] args) { int max = Integer.MIN_VALUE; System.out.println("Skriv talen:"); Scanner scan = new Scanner(System.in); while (scan.hasnextint()) { int nbr = scan.nextint(); if (nbr > max) { max = nbr; System.out.println("Största talet = " + max);
8 b) Byt namn på variabeln max till (det nu lämpligare) namnet min och tilldela den ett stort startvärde: int min = Integer.MAX_VALUE; Vänd på jämförelsen i if-satsen: if (nbr < min)... min = nbr;... Vektorer 8. 4, 48, 55, 1 9. double[] a = new double[10]; Scanner scan = new Scanner(System.in); for (int k = 0; k < 10; k++) { a[k] = scan.nextdouble(); for (int k = 9; k >= 0; k ) { System.out.println(a[k]); 10. a) /** Beräknar summan av talen i vektorn v. */ public static int sum(int[] v) { int sum = 0; for (int i = 0; i < v.length; i++) { sum += v[i]; return sum; b) /** Hittar minsta talet i vektorn v. */ public static int min(int[] v) { int minnbr = Integer.MAX_VALUE; for (int i = 0; i < v.length; i++) { if (v[i] < minnbr) { minnbr = v[i]; return minnbr;
LUNDS TEKNISKA HÖGSKOLA EDAA20 Programmeringsteknik Institutionen för datavetenskap 2017/2018 Övning 3 Använda färdiga klasser 1. Följande ritas: 2. Lösningen illustreras genom att de kodsnuttar och begrepp som hänger ihop nu står på samma rad. Begrepp Kodsnutt metodanrop sq1.draw(w); ett nytt objekt skapas new Square(100, 100, 200); en ny referensvariabel deklareras Square sq1 typ Square namn på en referensvariabel sq1 argumentet w skickas in till metod draw(w) argument till konstruktor (400, 400, Squares"); klassrubrik public class SquareExample här börjar exekveringen public static void main(string[] args) 3. public class ErrorTest { public static void main(string[] args) { SimpleWindow w = new SimpleWindow(600, 600, "ErrorTest"); Square sq = new Square(100, 200, 50); // deklaration while (sq.getx() < 300) { // parentes sq.draw(w); sq.move(10, 10); // parameter Objekt i minnet 4. a) Efter satsen sq2 = sq1 refererar båda referensvariablerna till samma objekt: sq1 sq2 x y side 20 30 40 b) Satsen sq1 = null sätter referensvariabeln till null objektet som variabeln refererar till påverkas inte: 9
10 sq1 sq2 null x y side 20 30 40 5. Variablerna sq1 och sq2 innehåller samma värde efter andra tilldelninssatsen:... 5200 5204... 47540 47544 47548... 47540 47540... 20 30 40 sq1 sq2 x y side Från kod till specifikation 6. Klassen Apartment har följande specifikation: /** Skapa en lägenhet med lägenhetsnumret nbr och ytan area kvadratmeter. */ Apartment(int nbr, double area); /** Sätt lägenhetens hyra per kvadratmeter och månad till sqmr. */ void setsquaremetrerent(double sqmr); /** Returnera lägenhetens månadshyra. */ double getrent(); Namnen på de formella parametrarna behöver inte överensstämma med de i lösningsförslaget.
LUNDS TEKNISKA HÖGSKOLA EDAA20 Programmeringsteknik Institutionen för datavetenskap 2017/2018 Övning 4 Implementera metoder 1. Observera att grodan inte ska ritas ut någonstans. a) Det är inte bara en ny metod som tillkommer. Klassen måste nu spara meters som ett attribut och se till att attributet uppdateras när grodan hoppar. public class Frog { private int x; private int y; private int meters; public Frog() { x = 0; y = 0; meters = 0; public int getx() { return x; public int gety() { return y; public void jumpsouth(int n){ y = y-n; meters = meters+n; public int getmeters(){ return meters; b) public void jumpnorth(int n){ y = y+n; meters = meters+n; c) public void jumpwest(int n){ x = x-n; meters = meters+n; public void jumpeast(int n){ x = x+n; meters = meters+n; 11
12 Implementera klasser 2. public class Car { private String nbr; private Person owner; // registreringnummer // ägare /** Skapar en bil med registreringsnummer licensenbr som ägs av personen owner. */ public Car(String licensenbr, Person owner) { nbr = licensenbr; this.owner = owner; /** Tar reda på bilens registreringsnummer. */ public String getlicensenbr() { return nbr; /** Tar reda på bilens ägare. */ public Person getowner() { return owner; /** Sätter bilens ägare till newowner. */ public void changeowner(person newowner) { owner = newowner; 3. Minnessituation: p c1 c2 nbr owner "ABC123" name "Bo Ek" owner "XYZ789" name "Eva Alm" 4. public class RailwayCoach { private int seats; // antalet platser i vagnen private int free; // antalet lediga platser /** Skapar en vagn med nbrseats platser. */ public RailwayCoach(int nbrseats) { seats = nbrseats; free = nbrseats; /** Tar reda på antalet platser i vagnen. */
13 public int getnbrseats() { return seats; /** Tar reda på antalet lediga platser. */ public int getnbrfreeseats() { return free; /** Bokar n platser i vagnen. Det får förutsättas att n är <= antalet lediga platser. */ public void makereservation(int n) { free = free - n; 5. public class Person { private int age; /** Skapar en person med åldern age. */ public Person(int age) { this.age = age; /** Undersöker om denna person är äldre än personen p. Returnerar då true, annars false. */ public boolean isolderthan(person p) { return age > p.age; Observera att det går bra att nå den andra personens (p) attribut age direkt med punktnotation. Det beror på att p har typen Person och den kod vi skriver finns i klassen Person. Ett attribut deklarerat private är privat för klassen (och inte för ett specifikt objekt).
LUNDS TEKNISKA HÖGSKOLA EDAA20 Programmeringsteknik Institutionen för datavetenskap 2017/2018 Övning 5 Strängar 1. /** Undersöker om strängarna s1 och s2 är lika långa och alla tecknen i s1 är lika med motsvarande tecken i s2. */ public static boolean equals(string s1, String s2) { if (s1.length()!= s2.length()) { return false; for (int i = 0; i < s1.length(); i++) { if (s1.charat(i)!= s2.charat(i)) { return false; return true; 2. /** Bildar en sträng som innehåller tecknen i s i omvänd ordning. */ public String reverse(string s) { StringBuilder sb = new StringBuilder(); for (int i = s.length() - 1; i >= 0; i--) { sb.append(s.charat(i)); return sb.tostring(); 3. String exempel = "Detta är en sträng"; int nbroft=0; int nbrofp=0; for(int i =0;i<exempel.length();i++){ if(exempel.charat(i)== t ){ nbroft++; else if(exempel.charat(i)== P ){ nbrofp++; System.out.println("Antalet t är: " + nbroft + " och antalet P är: " + nbrofp); Vektorer 4. a) /** Hittar minsta talet i vektorn v. Returnerar -1 om x ej finns i vektorn. */ public static int min(int[] v) { for (int i = 0; i < v.length - 1; i++) { if (v[i] == x) { return i; 14
15 return -1; b) /** Undersöker om talen är sorterade i växande ordning. */ public static boolean issorted(int[] v) { for (int i = 0; i < v.length - 1; i++) { if (v[i] > v[i + 1]) { return false; return true; c) /** Undersöker om vektorerna v1 och v2 är lika, dvs. om de är lika långa och alla v1[i] == v2[i]. */ public static boolean equal(int[] v1, int[] v2) { if (v1.length!= v2.length) { return false; for (int i = 0; i < v1.length; i++) { if ( v1[i]!= v2[i]) { return false; return true; 5. a) 33 b) 100 c) 1 Matriser 6. Exempel på hur man snabbt kan skapa en förifylld matris att testa med: int [][] m = new int[][] {{2, 53, 87, 4,{3,33,2,90,{0,70,80,90; System.out.print(" "); //Skriv först ut kolumnrubrikerna for(int col = 0; col < m.length; col++) { System.out.print(" [" + col + "]"); System.out.println(); //Skriv ut hela matrisen for (int row = 0; row < m.length; row++) { System.out.print(" [" + row + "]"); //Först på varje rad kommer radindexet for(int col = 0; col < m.length; col++) { System.out.print(" " + m[row][col] + " "); System.out.println(); //Efter varje matris-rad kommer en ny rad
16 7. a) public class SudokuGrid { private int[][] grid; /** Skapar ett tomt Sudokurutnät. */ public SudokuGrid () { grid = new int[9][9]; /** Placerar siffran value i rutan (row,col). */ public void put(int row, int col, int value) { grid[row - 1][col - 1] = value; /** Tar bort siffran i rutan (row,col). */ public void clear(int row, int col) { grid[row - 1][col - 1] = 0; /** Tar reda på siffran i rutan (row,col), noll om rutan tom. */ public int get(int row, int col) { return grid[row - 1][col - 1]; /** Tar reda på om rutan (row,col) är tom. */ public boolean empty(int row, int col) { return grid[row - 1][col - 1] == 0; b) /** Kontrollerar om samtliga rutor är ifyllda*/ public boolean allset() { for (int r = 0; r < 9; r++) { for (int c = 0; c < 9; c++) { if (grid[r][c] == 0) { return false; return true; c) /** Kontrollerar om raden row är korrekt ifylld. */ public boolean checkrow(int row) { //För varje ifylld ruta, kolla om samma siffra finns någon annanstans for(int c = 0;c<9;c++){ if(grid[row-1][c]!= 0){ for(int c2 = c+1;c2<9;c2++){ if(grid[row-1][c2] == grid[row-1][c]){ //Vi står inte på samma ruta men vi har hittat samma värde return false; //Alla rutor kollade, inga dubletter hittade return true; Alternativ lösning:
17 /** Kontrollerar om raden row är korrekt ifylld. */ public boolean checkrow(int row) { boolean[] temp = new boolean[10]; // motsvarar siffrorna 0..9 for (int c = 0; c < 9; c++) { int digit = grid[row - 1][c]; if(digit!= 0 && temp[digit]== true){ //Rutan är ifylld och siffran har förekommit förut return false; temp[digit] = true; //Alla rutor kollade, inga dubletter hittade return true; d) public boolean checkregion(int row, int col){ boolean[] temp = new boolean[10]; // motsvarar siffrorna 0..9 //Ta reda på index för regionens övre vänstra hörn int cornerrow = ((row-1)/3)*3; int cornercol = ((col-1)/3)*3; //Loopa över 3x3 rutor for(int i = 0;i<3;i++){ int r = cornerrow+i; for(int k = 0;k<3;k++){ int c = cornercol+k; int digit = grid[r][c]; if(digit!= 0 && temp[digit]== true){ //Rutan är ifylld och siffran har förekommit förut return false; temp[digit] = true; //Alla regionens rutor kollade, inga dubletter hittade. return true; 8. /** Tar reda på elementet med index i, k. */ public double get(int i, int k) { return a[i][k]; /** Adderar matrisen m till denna matris (matriserna förutsätts vara lika stora). */ public void add(matrix m) { for (int i = 0; i < a.length; i++) { for (int k = 0; k < a[i].length; k++) { a[i][k] += m.a[i][k]; /** Beräknar spåret av matrisen, dvs summan av diagonalelementen från övre vänstra hörnet till nedre högra hörnet. */ public double trace() {
18 double sum = 0; for (int i = 0; i < a.length; i++) { sum += a[i][i]; return sum;
LUNDS TEKNISKA HÖGSKOLA EDAA20 Programmeringsteknik Institutionen för datavetenskap 2017/2018 Övning 6 1. a) int sum = 0; for (int i = 0; i < cards.size(); i++) { sum += cards.get(i).getrank(); b) int pos = 0; while (pos < cards.size() &&!(cards.get(pos).getsuit() == Card.SPADES && cards.get(pos).getrank() == 12)) { pos++; if (pos >= cards.size()) { pos = -1; Alternativ lösning: int pos = -1; for (int i = 0; i < cards.size(); i++ { if (cards.get(i).getsuit() == Card.SPADES && cards.get(i).getrank() == 12) { pos = i; break; c) Card acard = new Card(s, r); int pos = 0; while (pos < cards.size() && cards.get(pos).getrank() < acard.getrank()) { pos++; cards.add(pos, acard); 2. a) I ArrayList<Job> är Job ett typargument som talar om att det är objekt av typen Job som ska lagras i listan. b) Listan med jobb fylls på efterhand och man vet inte hur många jobb som kommer att läggas till när listan skapas. När man skapar en vektor måste man ange antal element. c) Attribut: nbr, jobs (deklarerade private i början av metoden) Parametrar: nbr i konstruktorn och j i metoden assignjob. Lokala varibler: time och i i metoden gettotaltime, b och i i metoden jobsasstrings d) Vektorn med maskiner är indata till konstruktorn. Maskin-objekten skapas och läggs in i en vektor innan konstruktorn kan anropas. 19
20 e) /* Returnerar den maskin som har minst att göra. */ private Machine machinewithleasttodo() { int min = Integer.MAX_VALUE; int minpos = -1; for (int i = 0; i < machines.length; i++) { int totaltime = machines[i].gettotaltime(); if (totaltime < min) { min = totaltime; minpos = i; return machines[minpos]; /** Fördelar jobben i listan jobs på maskinerna. Jobben är sortrade är sorterad efter avtagande tidsåtgång. */ public void makeschedule(arraylist<job> jobs) { for(int i = 0; i < machines.length; i++) { machines[i].clearjobs(); for (int i = 0; i < jobs.size(); i++) { Machine m = machinewithleasttodo(); m.assignjob(jobs.get(i)); Maskin Tid Jobb 1 16 j4 (16) 2 17 j2 (14), j7 (3) 3 17 j5 (6), j6 (5), j3 (4), j1 (2)
LUNDS TEKNISKA HÖGSKOLA EDAA20 Programmeringsteknik Institutionen för datavetenskap 2017/2018 Övning 7 Arv f) 1. a) Man anger arv med extends och anropar superklassens konstruktor med super: j public class Person { private String name; public Person(String name) { this.name = name; public class Student extends Person { private String program; public Student(String name, String program) { super(name); this.program = program; b) Observera Student- och Teacher-objekten: attributet name har ärvts från Person, men det syns inte på objekten. Nils Nilsson Bo Ek D Eva Alm CS c) 1) p = s är korrekt p får referera till Student-objekt eftersom Student är en subklass till Person, och s refererar garanterat till ett Student-objekt; 2) s = p är felaktigt p kan ju referera till andra slags objekt än Student-objekt; 3) s = t är felaktigt s får inte referera till Teacher-objekt; 4) s = (Student) p är korrekt referensen konverteras explicit till Student (men det kan bli fel under exekvering). d) s = (Student) p ger ClassCastException om p under exekvering inte refererar till ett Student-objekt (eller till ett objekt av en subklass till Student). e) super.tostring() betyder att tostring-metoden i superklassen anropas. Utskrift: Nils Nilsson Bo Ek, D Bo Ek, D Notera att samma sats, System.out.println(p.toString()), ger två olika resultat. Det beror på att Java använder dynamisk bindning för metodanrop: första gången refererar p till ett Person-objekt och Person.toString() anropas, andra gången refererar p till ett Student-objekt och Student.toString() anropas. Anmärkning: tostring anropas automatiskt när man ger ett objekt som parameter till print eller println. I stället för System.out.println(p.toString()) kan man alltså skriva System.out.println(p). 21
22 2. Det som skrivs ut börjar med en blankrad och är: AAA AAAAAA BB Abstrakta klasser och metoder 3. a) Satsen s.draw(w) går ej att kompilera. Eftersom s är deklarerad med typen Shape så söker kompilatorn i klassen Shape och uppåt i arvshierarkin efter draw. Men metoden draw finns inte där. Istället är draw implementerad i subklasserna Square och Circle. För att vi ska kunna skriva s.draw() måste det finnas en metod draw i klassen Shape. Lösningen är att deklarera draw som en abstrakt metod. public abstract class Shape {... public abstract void draw(simplewindow w); b) public class Drawing { private ArrayList<Shape> shapes; /** Skapar en tom teckning. */ public Drawing() { shapes = new ArrayList<Shape>(); /** Lägger in figuren s i teckningen. */ public void insert(shape s) { shapes.add(s); /** Ritar alla figurerna i fönstret w. */ public void draw(simplewindow w) { for (int i = 0; i < shapes.size(); i++) { shapes.get(i).draw(w);