3.3 Übungen

Duke als Boxer

3.3.1 Übung: Schleifenterminierung

Welche der folgenden Schleifen terminieren?
    int i = 1, j = 1;
    do {
      i = i + j;
      j++;
    } while (i < 200);
b)  
    int i = 1, j = 20;
    while (i + j < i) {
      i = i + 2;
      j--;
    }
c)  
    int i = 1, j = 20;
    while (i + j > i) {
      i = i + 2;
      j--;
    }
d)  
    int i = 100, j = 27;
    while (i != j) {
      i = i / 2;
      j = j / 3;
    }

3.3.2 Übung: Ziffern einer Zahl

Schreiben Sie ein Java-Programm, das eine positive ganze Zahl n einliest und
feststellt, aus wie vielen Ziffern sie besteht.

Hilfestellung:

Einlesen von Zahlenwerten beim Starten von der Kommandozeile als Option wie zum Beispiel:

$ java Main 17 19

erfolgt durch Einlesen von Zeichenketten und Umwandlung in Zahlen. Anbei ein Rahmenprogramm welches das Problem löst:

public class Main {
    public static void main(String[] args) {
    int firstArg=0;
    int stellen=0;
    if (args.length > 0) {
        try {
            firstArg = Integer.parseInt(args[0]);
        } catch (NumberFormatException e) {
            System.err.println("Argument muss Ganzzahl sein");
            System.exit(1);
            }
        System.out.println("Die Zahl firstArg = " + firstArg + " wurde eingelesen");
        // Implementierung gehört hierher
        System.out.println(" Die Zahl " + firstArg + " hat " + stellen + " Stellen!");
    }
}

Eine andere Möglichkeit besteht darin, dass man das Programm startet und bei Bedarf eine Eingabe von der Konsole anfordert.

Achten Sie hier auf die fettgedruckte Importanweisung der Klasse Scanner. Sie ist notwendig um die Klasse zu benutzen:

import java.util.Scanner;
public class Eingabe {
    public static void main(String[] args) {
        Scanner eingabe = new Scanner(System.in);
        System.out.print("Geben Sie die erste Zahl ein: ");
        int zahl1 = eingabe.nextInt();
        System.out.print("Geben Sie die zweite Zahl ein: ");
        int zahl2 = eingabe.nextInt();
        System.out.println("Ergebnis: " + zahl1);
        System.out.println("Ergebnis: " + zahl2);
    }
}

Das Programm Eingabe kann man auf der Konsole wie folgt bedienen:

$ java Eingabe
Geben Sie die erste Zahl ein: 34
Geben Sie die zweite Zahl ein: 56
Ergebnis: 34
Ergebnis: 56 

Am einfachsten ist es die Eingaben in der ersten Zeile des Programmes hart zu belegen...

3.3.3 Übung: Quersumme

Schreiben Sie ein Java-Programm, das die Quersumme einer positiven ganzen Zahl berechnet und ausgibt.

Beispiel: Zahl 4711 --> Quersumme 13.

3.3.4 Übung: Zahlenstatistik

Schreiben Sie ein Java-Programm, das eine Zahlenfolge liest und ihren
größten und kleinsten Wert sowie ihren Mittelwert berechnet und ausgibt.

Tipp: Die Wertebereiche für die Zahlen sind Ihnen freigestellt. Der Durchschnittswert sollte korrekt sein

Hilfestellung:

Einlesen eines Feldes (Arrays) von der Kommandozeile

package s1.block3;
public class Zahlenstatistik {
    public static void main(String[] args) {
        int feld[];
        if (args.length > 0) {
            feld = new int[args.length];
            try {
                for (int i=0;i<args.length;i++) {
                    feld[i] = Integer.parseInt(args[i]);
                    // Einlesen der Kommandozeilenargumente und umwandeln in Ganzzahlen
                    }
            } catch (NumberFormatException e) {
                System.err.println("Argument muss Ganzzahl sein");
                System.exit(1);
                }
        // Ab hier steht das Feld mit allen Werten zur Verfügung
    }
}

3.3.5 Übung: Primfaktorzerlegung

Schreiben Sie ein Java-Programm, das eine positive ganze Zahl n einliest und in ihre Primfaktoren zerlegt.
Beispiel:
  • Die Zahl 100 besteht aus den Primfaktoren 2, 2, 5, 5;
  • die Zahl 252 aus den Primfaktoren 2, 2 , 3, 3, 7.

Option: Optimieren sie Ihr Programm auf die kürzeste Laufzeit. Verwenden Sie hierzu den Nanotimer von JDK 6.0 wie folgt:

package s1.block3;
public class Primzahlzerlegung {
    public static void main(String[] args) {
        int firstArg = 0;
        int p=0;
        long time;
        time= System.nanoTime();
        if (args.length > 0) {
            try {
                p = Integer.parseInt(args[0]);
            } catch (NumberFormatException e) {
                System.err.println("Argument muss Ganzzahl sein");
                System.exit(1);
                }
            System.out.println("Eingelesene Zahl: " + p);
        }
    // Die Eingabe der Kommandozeile liegt als Variable p vor.
    // Implementierung ...
    time= System.nanoTime() - time;
    System.out.println("Zeit in m: "+ time);
    }
}

Überlegungen:

  • Welche Zeit wird hier gemessen?
  • Was hat ausser dem Algorithmus noch Einfluss auf die Ausführungsgeschwindigkeit?
  • Sind Ihre Messungen wiederholbar?
  • Welche Risiken hat eine Optimierung des Algorithmus?
  • Wie wichtig ist die Schnelligkeit eines Programms?

3.3.6 Übung: Codevereinfachung

Vereinfachen Sie folgende Codestücke:
 
a)  
// Annahme: j >= 0
    i = 0;
    while (i != j) i++;
b)  
  while (a < b) {
      c = a;
      a = b;
      b = c;
    }

3.3.7 Übung: Wochentagberechnung

Lesen Sie ein Datum in Form dreier Zahlen für den Tag, den Monat und das Jahr sowie eine weitere Zahl zwischen 0 und 6 ein, die den Wochentag (Sonntag bis Samstag) des 1. Januars dieses Jahres darstellt. Berechnen Sie den Wochentag des eingelesenen Datums und geben Sie diesen aus. Sie können davon ausgehen, dass die Eingaben korrekt sind. Berücksichtigen Sie auch Schaltjahre.

3.3.8 Übung: Überlaufprüfung

Lesen Sie zwei 32 Bit Ganzahlen (int) a und b ein und prüfen Sie, ob bei ihrer Addition ein Überlauf stattfindet, also eine Summe entstehen würde, die größer als 231 - 1 oder kleiner als  -231   ist.

3.3.9 Übung: Schnitt zweier Linien

Lesen Sie die Endpunkte zweier horizontaler oder vertikaler Linien in Form ihrer x- und y-Koordinaten ein und prüfen Sie, ob sich die beiden Linien schneiden. Die beiden Linien befinden sich in einem zweidimensionalen kartesischen System:

Diagramm zu Schneiden zweier Linien

Hinweis: Wenn es einen Schnittpunkt gibt ist er (c,b)

3.3.10 Übung: Codevereinfachung

Vereinfachen Sie folgende Codestücke:

a)  

    if (b == 0)
      a = 2 * c;
    else
      if (c != 0)
        a = a * b + 2 * c;
      else
        a = a * b;

b)  

    if (x < 0 && y < 0)
      a = x * y;
    else
      if (x < 0)
        a = x * (-y);
      else
        if (y > 0)
          a = (-x) * (-y);
        else
          a = x * (-y);

3.3.11 Übung: Dreiecksbestimmung

Schreiben Sie ein Java-Programm, das die Seitenlängen eines Dreiecks einliest und prüft, ob es ein

  • gleichseitiges
  • gleichschenkeliges
  • rechtwinkeliges
  • sonstiges gültiges
  • ungültiges Dreieck ist.

Ein Dreieck ist ungültig, wenn die Summe zweier Seitenlängen kleiner oder gleich der dritten Seitenlänge ist. Beachten Sie, dass ein Dreieck sowohl rechtwinkelig als auch gleichschenkelig sein kann!

3.3.12 Übung: Sortieren

Schreiben Sie ein Java-Programm, das 3 Zahlen a, b und c einliest und sie in sortierter Reihenfolge wieder ausgibt. Im Rahmenprogramm muss die letzte Zeile durch einen Sortieralgorithmus und Ausgaben ersetzt werden.

public class Sortieren {
   public static void main(String[] args) {
       int a = 0;
       int b = 0;
       int c = 0;

      if (args.length > 2 ) {
         try {
            a = Integer.parseInt(args[0]);
            b = Integer.parseInt(args[1]);
            c = Integer.parseInt(args[2]);
         } catch (NumberFormatException e) {
            System.err.println("Argument muss Ganzzahl sein");
            System.exit(1);
         }
      }
      System.out.println("Eingelesene Werte: " + a + ", " + b + ", " + c);

      System.out.println("Anstatt dieser Zeile muss ein Sortieralgorithmus implementiert werden...";
   }
}

3.3.13 Übung: Plausibilitätsprüfung

Lesen Sie ein Datum in Form dreier Zahlen für den Tag, den Monat und das Jahr ein. Prüfen Sie, ob es sich um ein gültiges Datum handelt. Berücksichtigen Sie auch Schaltjahre.

Hinweis: Gregorianischer Kalender: Ein Jahr ist ein Schaltjahr, wenn es durch 4 teilbar ist. Jahre, die durch 100, aber nicht durch 400 teilbar sind, sind keine Schaltjahre.
Vorsicht: In der Musterlösung werden Felder verwendet. Die sind noch nicht vorgestellt worden, sie machen es aber deutlich leichter...

3.3.14 Übung: Textverschlüsselung

Schon im alten Rom verschlüsselte man Nachrichten. Ein einfaches Verschlüsselungsverfahren ist von Julius Cäsar überliefert. Es verschiebt jeden Buchstaben der Nachricht um einen fixen Wert n. Ist n gleich 2, so wird 'A' auf 'C', 'B' auf 'D' und 'Z' auf 'B' verschoben. Ziffern und Sonderzeichen werden nicht verschoben. Schreiben Sie ein Programm, das eine Zahl n und einen beliebigen Text liest und ihn nach obigem Verfahren verschlüsselt wieder ausgibt.

3.3.15 Übung: Verzweigungen

Schreiben Sie ein Java-Programm, das drei Werte x, y und z einliest und prüft, ob

  • x, y und z nicht lauter gleiche Werte enthalten,
  • x, y und z lauter verschiedene Werte enthalten,
  • mindestens zwei Werte gleich sind.

3.3.16 Übung: Häufigkeit von Zeichen

Schreiben Sie ein Programm, das einen Text liest und die Häufigkeit der darinvorkommenden Zeichen berechnet. Geben Sie die Zeichenhäufigkeit als Histogramm aus. Beispiel:

a ****
b **
c ********
...

 Hinweis: Dieses Programm setzt Kenntnisse von Feldern vorraus die erst später behandelt werden

3.3.17 Übung: Weckzeiten implementieren

Implementieren Sie zwei logische Tests für die Kontrolle der Weckzeit einer Uhr.

Diese Aufgabe baut auf der Übung zur Implementierung einer analogen Uhr auf.

Sie benötigen 3 Klassen für diese Aufgabe die alle im gleichen Verzeichnis stehen müssen:

  • Klasse Zeiger (Lösung von 2.4.11) oder Ihre eigene Implementierung. Diese Klasse muss nicht modifiziert werden.
  • Klasse WeckerUhr (weiter unten). Die Klasse muss nicht modifiziert werden. Die Klasse enthält die main() Methode. Es muss immer diese Klasse (java WeckerUhr) zum Starten der Anwendung verwendet werden!
  • Klasse Weckzeit: Diese Klasse muss in der Übung modifiziert werden. Die Vorlage der Klasse ist bereits übersetzbasr und ausführbar.

Es reicht die Klasse WeckerUhr zu übersetzen. Die beiden anderen Klassen werden automatisch rekursiv mitübersetzt.

Nach dem Starten der Anwendung mit java WeckerUhr erscheint das folgende Fenster:

Weckeruhr im normalen Zustand

Uhr im normalen Zustand

Weckeruhr beim Klingeln

Uhr beim Klingeln (roter pulsierender Kreis)

Erste Aufgabe: Kontrolle der Wertebereiche

Die Klasse Weckzeit enthält eine Methode korrekteWeckzeit(int h, int m, int s). Diese Methode prüft die Eingaben des GUI auf korrekte Wertebereiche. Das Ergebnis wird in einer boolschen Variablen result gespeichert. Die Vorlage liefert bei allen Eingaben false. Belegen Sie die Variable so, dass vernünftige Werte akzeptiert werden.

Fragen:

  • Was sind vernünftige Werte für Stunde (h), Minute(m), Sekunde(s)?
  • Welche logische Verknüpfung muss man nutzen wenn alle Werte im korrekten Bereich sein sollen?

Der Erfolg Ihrer Implementierung können Sie daran erkennen, dass die Eingaben des GUI nach dem klicken des OK Knopfs in das Anzeigenfeld übernommen worden sind.

Zweite Aufgabe: Bestimmen der richtigen Zeitpunkte zum Wecken

Das Lösen der ersten Teilaufgabe ist eine Voraussetzung für den zweiten Teil (Ihr Wecker funktioniert sonst nur Mittags und um Mitternacht...)

Das Hauptprogramm der Klasse WeckerUhr ruft in der aktuellen Implementierung viermal pro Sekunde die Methode klingeln() auf um zu kontrollieren ob der Wecker klingeln soll. Ändern Sie die Referenzimplementierung derart, dass nur nach der eingebenen Weckzeit für eine bestimmte Periode geklingelt wird.

Die zu modifizierende Referenzimplementierung:

result = (aktS%10 == 0);

lässt den Wecker bei allen Sekundenwerten die durch 10 teilbar sind für eine Sekunde klingeln. 

Die Variablen aktH, aktM, aktS enthalten die aktuelle Zeit. Die Variablen wzh, wzm, wzs enthalten die Weckzeit.

Fragen:

  • Wie lange soll der Wecker klingeln?
  • (Zur Verfeinerung) Wie kann man gewährleisten, dass der Wecker auch um 11:59:50 für 15 Sekunden klingelt?

Klasse Weckzeit

package s1.block3;
public class Weckzeit {
    int wzh = 0; // Weckzeit in Stunden
    int wzm = 0; // Weckzeit in Minuten
    int wzs = 0; // Weckzeit in Sekunden
    public void setzeWeckzeit(int hh, int mm, int ss) {
        if (korrekteWeckzeit(hh,mm,ss)) {
            wzh = hh;
            wzm = mm;
            wzs = ss;
        }
    }
    public boolean korrekteWeckzeit(int h, int m, int s) {
        boolean result;
        // benutzen die Variablen h,m,s um eine gültige Zeit zu bestimmen
        result = false;
        return result;
    }
    public boolean klingeln(int aktH, int aktM, int aktS) {
        boolean result;
        // benutzen die Variablen der aktuellen Zeit aktH (Stunde),
        // aktM (Minute), aktS (Sekunde) und die Weckzeit wzmh, wzm, wzs
        // um zu bestimmern ob der Wecker klingeln soll
        // Verbessern Sie diese Zuweisung
        // In der aktuellen Implementieren klingelt der Wecker
        // alle 10 Sekunden für 1 Sekunde
        result = (aktS%10 == 0);
    return result;
    }
}

Klasse WeckerUhr

package s1.block3;
/*
 * Zeichnen einer analogen Uhr in einem JFrame
 */
import java.awt.*;
import java.awt.event.*;
import java.util.Calendar;
import javax.swing.*;
/**
 *
 * @author sschneid
 */
public class WeckerUhr extends JPanel {

int sekunde = 0;
int minute = 0;
int stunde = 0;
boolean klingeln = false;
String tzString; // aktuelle Zeitzone
int initialHeight;
float zoom = 1;
boolean an = false;
JFrame hf; // Das Fenster der Anwendung
Container myPane;
JTextField h,m,s;
JButton eingabe;
Weckzeit wz;
int klingelRadius = 0;
/**
* Konstruktor der Klasse. Er initialisiert die Grafik
*/
public WeckerUhr() {
wz = new Weckzeit();
hf = new JFrame("Uhr");
h = new JTextField(2);
m = new JTextField(2);
s = new JTextField(2);
eingabe = new JButton("OK");
eingabe.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
int stunde, minute, sekunde;
try {
stunde = Integer.parseInt(h.getText());
minute = Integer.parseInt(m.getText());
sekunde = Integer.parseInt(s.getText());
}
catch (NumberFormatException ex) {
// Es wurde keine korrekte Zahl eingegeben
stunde = -100;
minute = -100;
sekunde= -100;
}
wz.setzeWeckzeit(stunde,minute,sekunde);
}
});
// Beenden der Anwendung bei Schließen des Fenster
hf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Aufbau des Contentpanes
myPane = hf.getContentPane();
myPane.add(this, BorderLayout.CENTER);
JPanel wzPanel = new JPanel(new GridLayout(1,0));
wzPanel.add(new JLabel("hh:mm:ss"));
wzPanel.add(h);
wzPanel.add(m);
wzPanel.add(s);
wzPanel.add(eingabe);
myPane.add(wzPanel,BorderLayout.SOUTH);
// Erzeuge einen Menüeintrag zum Beenden des Programms
JMenuBar jmb = new JMenuBar();
JMenu jm = new JMenu("Datei");
JMenuItem exitItem = new JMenuItem("Beenden");
exitItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
jm.add(exitItem);
jmb.add(jm);
hf.setJMenuBar(jmb);
hf.pack();
// Das JFrame sichtbar machen
// Gewünschte Größe setzen
// 1. Parameter: horizontale Größe in Pixel
// 2. Parameter: vertikale Größe in Pixel
hf.setSize(2 * Zeiger.maxRadius + 80,
2 * Zeiger.maxRadius + 130);
hf.setVisible(true);
hf.setAlwaysOnTop(true);
initialHeight = getHeight();
}
/**
* Hauptprogramm der Anwendung. Es werden keine Eingabeparameter benötigt
* @param args dieser Parameter wird nicht ausgewertet
*/
public static void main(String[] args) {
WeckerUhr dieUhr = new WeckerUhr();
dieUhr.tickTack();

}
/**
* Diese Methode verwaltet den Zeitgeber-thread. Dieser Thread belegt
* die statischen Variablen der Uhrzeit neu
*/
public void tickTack() {
try {
boolean blinken = false;
while (true) {
Thread.sleep(250); // Schlafe x Millisekunden
// Hole Systemzeit und belege statische Variablen
Calendar call = Calendar.getInstance();
tzString = call.getTimeZone().getDisplayName();
sekunde = call.get(Calendar.SECOND);
minute = call.get(Calendar.MINUTE);
stunde = call.get(Calendar.HOUR);
klingeln = wz.klingeln(stunde,minute,sekunde);
if (blinken){
klingelRadius=100;
}
else {
klingelRadius=30;
}
blinken = !blinken;
repaint();
}
} catch (InterruptedException e) {
System.out.println(
"Die Anwendung wird wegen einer Ausnahme beendet");
}
}
/**
* Überladene Paintmethode. Sie führt alle Zeichenoperationen im Panel aus
* @param g vom Laufzeitsystem übergebenes Graphikobjekt.
*/
@Override
public void paint(Graphics g) {
   super.paint(g);
   zoom = (float)getHeight()/(float)initialHeight;
   int maxRadius = Zeiger.maxRadius;
   int xCenter = (int)(maxRadius*zoom) + 40;
   int yCenter = (int)(maxRadius*zoom) + 20;
   float fontSize = g.getFont().getSize2D();
   int charCenterOffSet = (int)(fontSize/2);
   String timeString = stunde + ":" + minute + ":" + sekunde
      + " " + tzString;
   String klingelString;
   klingelString = wz.wzh +":"+wz.wzm + ":" +wz.wzs +" klingeln";
   if (klingeln) {
      g.setColor(Color.red);
      g.fillOval(xCenter-((int)(zoom*klingelRadius/2)),
         yCenter-((int)(zoom*klingelRadius/2)),
         (int)(klingelRadius*zoom),
         (int)(klingelRadius*zoom));
   }
   // Zeichne Uhrenhintergrung und Koordinatensystem
   g.setFont(g.getFont().deriveFont(fontSize));
   g.setColor(Color.BLACK); // Farbe
   g.drawArc(xCenter - 5, yCenter - 5, 10, 10, 0, 360);
   g.drawLine(xCenter, yCenter, xCenter + 40, yCenter);
   g.drawLine(xCenter, yCenter, xCenter, yCenter + 40);
   g.drawString("X", (int)(xCenter + 45*zoom),
   yCenter + +charCenterOffSet);
   g.drawString("Y", xCenter - charCenterOffSet,
      (int)(yCenter + 55*zoom));
   g.drawString("12",xCenter - charCenterOffSet,
      (int)(yCenter - maxRadius*zoom));
   g.drawString("3", (int)(xCenter + maxRadius*zoom),
      yCenter + charCenterOffSet);
   g.drawString("6", xCenter - charCenterOffSet,
      (int)(yCenter + 2*charCenterOffSet+maxRadius*zoom));
   g.drawString("9", (int)(xCenter - maxRadius*zoom - charCenterOffSet),
      yCenter + charCenterOffSet);
   // Zeichne aktuelle Zeit zum Debuggen
   g.drawString(timeString, 0,
      (int)(yCenter + maxRadius*zoom));
   // Zeichne Weckzeit zum Debuggen
   g.drawString(klingelString, 0, (int)(yCenter + maxRadius*zoom + 25));
   // Zeichne Stundenzeiger
   g.setColor(Color.BLACK);
   g.drawLine(xCenter, yCenter,
   (int)(xCenter + Zeiger.stundeX(stunde)*zoom),
   (int)(yCenter + Zeiger.stundeY(stunde)*zoom));
   g.drawString("h["
      + Zeiger.stundeX(stunde)
      + "," + Zeiger.stundeY(stunde) + "]",
      0, (int)(yCenter + maxRadius*zoom - (3*fontSize)));
   // Zeichne Minutenzeiger
   g.setColor(Color.RED);
   g.drawLine(xCenter, yCenter,
      (int)(xCenter + Zeiger.minuteX(minute)*zoom),
      (int)(yCenter + Zeiger.minuteY(minute)*zoom));
   g.drawString("m["
         + Zeiger.minuteX(minute) + ","
         + Zeiger.minuteY(minute) + "]", 0,
      (int)(yCenter + maxRadius*zoom - (2*fontSize)));
   // Zeichne Sekundenzeiger
   g.setColor(Color.BLUE);
   g.drawLine(xCenter, yCenter,
      (int)(xCenter + Zeiger.sekundeX(sekunde)*zoom),
      (int)(yCenter + Zeiger.sekundeY(sekunde)*zoom-fontSize));
   g.drawString("s["
         + Zeiger.sekundeX(sekunde) + ","
         + Zeiger.sekundeY(sekunde) + "]", 0,
      (int)(yCenter + maxRadius*zoom - fontSize));
   }
}

Anonymous (not verified)

Thu, 11/09/2017 - 12:11

die Zahl 252 aus den Primfaktoren 3, 3, 4, 7.
4 ist keine Primzahl hier müsste 2x die 2 hin