}
Programmeringsteknik för D
LÖSNINGSFÖRSLAG TILL ÖVNINGAR }
EDA016
Övning 1
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 resul- tatet. 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än- da 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:
2 nbrA
5 nbrB
och efter tredje, fjärde respektive femte tilldelningssatsen:
2 nbrA
5 nbrB
20 nbrC
4 nbrA
5 nbrB
20 nbrC
4 nbrA
5 nbrB
0 nbrC
3. a) Parentesen runt c + d i tilldelningssatsen int e = ... är onödig. Om den uteläm- nas 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
i katalog med samma namn som paketet. Nedan finns koden som är given, i mer klipp-och- klistra-vänlig form utan radnummer:
package greeting;
public class Hello {
public static void main(String[] args) {
String name = javax.swing.JOptionPane.showInputDialog("What name?");
javax.swing.JOptionPane.showMessageDialog(null, "Hello " + name);
} }
package greeting;
import se.lth.cs.pt.window.SimpleWindow;
public class WindowApp {
public static void main(String[] args) {
SimpleWindow w = new SimpleWindow(200, 200, "App");
w.setLineColor(java.awt.Color.PINK);
w.moveTo(100,100);
w.writeText("Hello Pink Panter!");
while (true) {
w.waitForMouseClick();
w.lineTo(w.getMouseX(), w.getMouseY());
w.writeText("Hello Pink Panter!");
} } }
package greeting;
import se.lth.cs.pt.window.SimpleWindow;
import java.awt.Color;
/**
* A collection of greeting methods.
*/
public class Greet { /**
* Asks for a name and then greets politely.
*/
public static void swingGreeting(){
String name = javax.swing.JOptionPane.showInputDialog("What name?");
javax.swing.JOptionPane.showMessageDialog(null, "Hello " + name);
} /**
* Greeting of pink creature. Allows user to spam click but not too far down.
* Each click is awarded one point.
*
* @param color the color of the greeting
* @return the number of points earned
*/
public static int panterGreeting(Color color){
SimpleWindow w = new SimpleWindow(200, 200, "App");
w.setLineColor(color);
w.moveTo(100,100);
w.writeText("Hello Pink Panter!");
int points = 0;
while (w.getMouseY() < 180) { w.waitForMouseClick();
points = points + 1; //earn a point for each click w.lineTo(w.getMouseX(), w.getMouseY());
w.writeText("Your hello-points: " + points);
}
return points;
} }
package greeting;
/** A polite Greetings App. */
public class GreetApp { /** Starts the App. */
public static void main(String[] args) { Greet.swingGreeting();
int pts = Greet.panterGreeting(java.awt.Color.PINK);
System.out.println("You earned " + pts + " points!");
} }
1. 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);
} }
2. 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");
3. Följande ritas:
4. public class ErrorTest {
public static void main(String[] args) {
SimpleWindow w = new SimpleWindow(600, 600, "ErrorTest"); // parameter Square sq = new Square(100, 200, 50); // deklaration
while (sq.getX() < 300) { // parentes sq.draw(w);
sq.move(10, 10);
} } }
5. a) Efter satsen sq2 = sq1 refererar båda referensvariablerna till samma objekt:
20 30 40 x y side sq1
sq2
b) Satsen sq1 = null sätter referensvariabeln till null – objektet som variabeln refererar till påverkas inte:
20 30 40 x y side null
sq1 sq2
6. Variablerna sq1 och sq2 innehåller samma värde efter andra tilldelninssatsen:
47540 47540
x y side sq1
30 40 20 5200 5204
...
...
...
47540 47544 47548
...
sq2
1. 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);
} }
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;
...
2. a) y = Math.sin(20 * Math.PI / 180);
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);
3. (int) Math.round(x) 4. 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. public class AverageTemperature {
public static void main (String[] args) { double sum = 0;
Scanner scan = new Scanner(System.in);
for (int i = 0; i < 30; i++) {
double temperature = scan.nextDouble();
sum = sum + temperature;
}
double averageTemperature = sum / 30;
System.out.println("Medeltemperatur: " + averageTemperature + " grader");
} }
6. 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);
7. 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.");
} }
8. a) a > 5 b) a > 2 c) a <= 2
d) a <= 2 || a >= 9 e) a >= 0 && a <= 10
f) ready g) !ready
1. public class Car {
private String nbr; // registreringnummer private Person owner; // ä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;
} }
2. Minnessituation:
"ABC123"
nbr owner p
c1 c2
"XYZ789"
owner
"Bo Ek"
name
"Eva Alm"
name
3. 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. */
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;
} }
4. 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 punktno- tation. 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).
5. 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);
} } }
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);
} } }
6. public class CollatzSequence {
public static void main(String[] args) {
System.out.println("Skriv startvärdet i talföljden (a0)");
Scanner scan = new Scanner(System.in);
int a = scan.nextInt();
System.out.println(a);
int length = 1;
while (a != 1) { if (a % 2 == 0) {
a = a / 2;
} else {
a = 3 * a + 1;
}
System.out.println(a);
length = length + 1;
}
System.out.println("Antal tal = " + length);
}
Övning 6
1. a) /** 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;
}
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;
}
2. a) 33 b) 100
c) 1
3. I remove flyttas det sista elementet i apartments-vektorn till ”hålet” där det borttagna elementet fanns. Det går bra att göra så, eftersom ordningen mellan elementen inte har någon betydelse. I countApartments görs två genomgångar av vektorn: först en för att hitta det maximala antalet rum, sedan en för att registrera antalet rum.
12
public Register(int maxSize) {
apartments = new Apartment[maxSize];
n = 0;
}
public void add(Apartment a) { apartments[n] = a;
n++;
}
public void remove(int id) { int i = 0;
while (i < n && apartments[i].getId() != id) { i++;
}
if (i < n) {
apartments[i] = apartments[n - 1];
n--;
} }
public int[] countApartments() { int max = 0;
for (int i = 0; i < n; i++) {
if (apartments[i].getNbrOfRooms() > max) { max = apartments[i].getNbrOfRooms();
} }
int[] count = new int[max];
for (int i = 0; i < n; i++) {
int rooms = apartments[i].getNbrOfRooms();
if (rooms > 0) {
count[rooms - 1]++;
} }
return count;
Övning 7
1. public class Experiment { private Die die1;
private Die die2;
/** Skapar ett experiment där tärningarna d1 och d2 kastas */
public Experiment(Die d1, Die d2) { die1 = d1;
die2 = d2;
}
/** Kastar tärningarna n gånger, räknar antalet gånger summan blev 2, 3, 4, ..., 11, 12. Returnerar antalen i en vektor */
public int[] makeExperiment(int n) { int[] result = new int[11];
for (int i = 0; i < n; i++) {
int index = die1.roll() + die2.roll() - 2;
result[index]++;
}
return result;
} }
2. /** Returnerar en vektor med antal olika siffror av varje sort som behövs för nummer mellan start och stop där intervallet mellan numren är interval. */
public int[] nbrDigits(int start, int stop, int interval) { int[] digits = new int[10];
for (int i = start; i <= stop; i = i + interval) { int nbr = i;
while (nbr != 0){
digits[nbr % 10]++;
nbr = nbr / 10;
} }
return digits;
}
14
for (int i = 0; i < towns.length; i++) { towns[i].setVisited(false);
}
int startPos = 0;
while (!towns[startPos].getName().equals[startTown)) { startPos++;
}
Town current = towns[startPos];
System.out.println(current.getName());
current.setVisited(true);
for (int i = 1; i < towns.length; i++) { current = getNearest(current);
System.out.println(current.getName());
current.setVisited(true);
} }
/* Tar reda på den obesökta stad som ligger närmast staden t. */
private Town getNearest(Town t) { double minDist = Double.MAX_VALUE;
Town nearest = null;
for (int i = 0; i < towns.length; i++) {
if (towns[i] != t && !towns[i].isVisited() &&
towns[i].getDistanceTo(t) < minDist) { minDist = towns[i].getDistanceTo(t);
nearest = towns[i];
} }
return nearest;
}
Övning 8
1. /** 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() { double sum = 0;
for (int i = 0; i < a.length; i++) { sum += a[i][i];
}
return sum;
}
2. /** 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;
}
3. /** 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();
}
16
for (int i = 0; i < plainText.length(); i++) { char plainChar = plainText.charAt(i);
int codeNbr = plainChar + rand.nextInt(256);
if (codeNbr >= 256) {
codeNbr = codeNbr - 256;
}
char codeChar = (char) codeNbr;
sb.append(codeChar);
}
return sb.toString();
}
Beräkningen av det krypterade tecknet har för tydlighets skull delats upp i flera steg. Man kan också göra så här:
char codeChar = (char) ((plainText.charAt(i) + rand.nextInt(256)) % 256);
Övning 9
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. public class PhoneDirectory {
private ArrayList<Person> persons; // personerna i katalogen /** Skapar en tom telefonkatalog. */
public PhoneDirectory() {
persons = new ArrayList<Person>();
}
/* Tar reda på personen med namnet name. Returnerar null om ingen sådan person finns. */
private Person findPerson(String name) { for (int i = 0; i < persons.size(); i++) {
if (persons.get(i).getName().equals(name)) { return persons.get(i);
18
/** Lägger in en person med namnet name och telefonnumret nbr (om personen inte redan finns i katalogen). Om personen lagts in ska true returneras, annars false. */
public boolean insert(String name, String nbr) { if (findPerson(name) == null) {
persons.add(new Person(name, nbr));
return true;
} else {
return false;
} }
/** Tar bort personen med namnet name ur registret. */
public void delete(String name) {
for (int i = 0; i < persons.size(); i++) { if (persons.get(i).getName().equals(name)) {
persons.remove(i);
} } }
/** Tar reda på telefonnumret till personen med namnet name. Om personen inte finns i katalogen returneras null. */
public String findNbr(String name) { Person p = findPerson(name);
if (p != null) {
return p.getPhoneNbr();
} else {
return null;
} }
/** Returnerar en lista med namnen på de personer vars namn börjar med strängen s. */
ArrayList<String> startsWith(String s) {
ArrayList<String> list = new ArrayList<String>();
for (int i = 0; i < persons.size(); i++) {
if (persons.get(i).getName().startsWith(s)) { list.add(persons.get(i).getName());
} }
return list;
}
/** Returnerar en sträng som representerar telefonkatalogen.
Strängen innehåller personens namn och telefonnummer med radslutstecken mellan de olika personernas uppgifter.
Om telefonkatalogen är tom ska en tom sträng returneras. */
public String toString() { if (persons.size() == 0) {
return "";
}
StringBuilder sb = new StringBuilder();
sb.append(persons.get(0).getName());
sb.append(’ ’);
sb.append(’\n’);
sb.append(persons.get(i).getName());
sb.append(’ ’);
sb.append(persons.get(i).getPhoneNbr());
}
return sb.toString();
} }
1. a) Man anger arv med extends och anropar superklassens konstruktor med super:
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.
D Bo Ek Nils Nilsson
CS Eva Alm
c) 1) p = s är korrekt — p får referera till Student-objekt eftersom Student är en sub- klass 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 — sfå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 re- fererar 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).
2. public static void partition(int[] v, Condition cond) { int first = 0;
while (first < v.length && cond.evaluate(v[first])) { first++;
}
for (int i = first + 1; i < v.length; i++) { if (cond.evaluate(v[i])) {
int temp = v[i];
v[i] = v[first];
v[first] = temp;
first++;
} } }
Anmärkning: metoden fungerar även utan den inledande while-satsen.
1. Metoden behöver två parametrar: vektorn som ska sorteras och antalet tal. Metoden för alla sina indata via parametrarna och bör därför vara en statisk metod.
public static void sort(int[] sequence, int n) { for (int i = 1; i < n; i++) {
int nbr = sequence[i];
int k = i - 1;
while (k >= 0 && sequence[k] > nbr) { sequence[k + 1] = sequence[k];
k--;
}
sequence[k + 1] = nbr;
} }
2. När referenser förs över som parametrar används värdeanrop, precis som för alla typer av parametrar. Men det är värdet av referensen som kopieras till metoden — det skapas inte någon kopia av objektet. I metoden use kommer alltså variabeln pa att referera till samma objekt som a, och när man utför pa.set(10) så ändras innehållet i objektet.
Utskrift (kommentarerna inom parentes skrivs inte ut):
value = 5 (före anropet av use) value = 5 (första print i use) value = 10 (andra print i use) value = 10 (efter anropet av use)
3. Satsen pa = new A(10) i use medför att den formella parametern pa sätts att referera till ett nytt objekt. Variabeln a påverkas inte. När man lämnar use så försvinner alla parametrar och lokala variabler — det medför att objektet med value = 10 inte längre kan nås och att det kommer att tas bort av skräpsamlaren.
Utskrift:
value = 5 value = 5 value = 10 value = 5