3. Ablaufsteuerung, Kontrollstrukturen
3. Ablaufsteuerung, Kontrollstrukturen Stefan Schneider Sun, 06/20/2010 - 15:51- 7468 views
3.1 Verzweigungen und Vergleichsoperationen
3.1 Verzweigungen und VergleichsoperationenDurch Verzweigungen können im Ablauffluß des Programmes verschiedene Fälle geprüft werden und man kann abhängig davon unterschiedliche Anweisungen ausführen.
Befehlsblöcke
Java erlaubt das Zusammenfassen von Javabefehlen durch Blöcke. Blöcke werden geschweiften Klammern beschrieben.
Für Blöcke gilt
- Im Block deklarierte Variablen sind nur innerhalb des Blocks, nach der Deklaration benutzbar
- Befehle innerhalb eines Blocks müssen mit Semikolon getrennt werden
- Auch der letzte Befehl in einem Block muss mit Semikolon abgeschlossen werden
- Blöcke können geschachtelt werden
Beispiel
{ int i = 1; i++; int j = i*2; }
Tipp: Systematisches Einrücken und Klammern die genau übereinander stehen helfen sehr bei der Lesbarkeit
Einfachverzweigung (if, if else)
Eine Einfachverzweigung wird in Java mit dem Schlüsselwort if eingeleitet. Anschließend folgt eine Bedingung in runden Klammern. Ist die Bedingung erfüllt, wird die folgende Anweisung bzw. der Anweisungsblock in geschweiften Klammern ausgeführt. Hierdurch ergibt sich die folgende Syntax:
if (Bedingung) Anweisung;
oder
if (Bedingung) {Anweisung(en);}
Ist die Bedingung nicht erfüllt wird die Anweisung ausgelassen und der normale Ausführungsfluß wird wieder aufgenommen. Ein Beispiel hierfür ist:
int x = 8; if (x > 5) System.out.println("Wert x = " + x + " ist größer als 5"); System.out.println ("Wert x = " + x);
Hier ergeben sich die Ausgaben:
Wert x = 8 ist größer als 5 Wert x = 8
da die bedingte Anweisung sowie die letzte Anweisung durchlaufen wird.
UML Darstellung in Aktivitätsdiagrammen
if Bedingung ohne else Klausel kann man die geschweiften Klammer bei einer einzelnen Anweisung weglassen.
Entweder-oder Kontrollfluss mit dem Schlüsselwort else
Es gibt auch die Möglichkeit eines entweder-oder Kontrollflusses mit Hilfe des Schlüsselworts else:
if (Bedingung) {Anweisung(en);} else {Anweisung(en);};
Hier wird der eine oder der andere Block von Anweisungen ausgeführt.
Ein Beispiel:
int x = 8; int y = 0; if (x > 5) { System.out.println("Wert x = " + x + " ist größer als 5"); y = x; } else { System.out.println("Wert x = " + x + " ist kleiner oder gleich 5"); y = -x; } System.out.println ("Wert x = " + x );
UML Darstellung in Aktivitätsdiagrammen
if Anweisungen lassen sich schachteln um komplexe Bedingungen prüfen zu können. Anbei ein Beispiel:
int a = 5; int b = 10; int maximum =0; if (a > b) // Äussere if Bedingung if (a > 0) { maximum = a;} // Innere if Bedingung else { maximum = 0; } //innere else Bedingung System.out.println ("Wert maximum = " + maximum "); |
Im oben gezeigten Beispiel gibt es eine else Bedingung von der es nicht offensichtlich ist zu welchem if Block sie gehört.
else-Regel |
---|
Ein else-Block gehört immer zum direkt vorhergehenden if-Block |
Tipp: Der Quellcode wird bei geschachtelten if Bedingungen schnell unübersichtlich und fehleranfällig.
Verwenden Sie besser die im Folgenden vorgestellte switch Bedingung um komplexe Abfragen zu implementieren.
Mehrfachverzweigung (switch-case)
Eine Alternative zu if-else Anweisungen ist die switch-case Anweisung. Sie erlaubt eine sehr viel übersichtlichere Programmierung wenn es bei einem ganzzahligen Ausdruck mehr als zwei Alternativen gibt.
Im einfachen Fall sieht eine switch-case Anwendung wie folgt aus:
int wochentag; ... switch (wochentag) { case 7: System.out.println("Sonntag"); break; case 6: System.out.println("Samstag"); break; case 5: case 4: case 3: case 2: case 1: System.out.println("Wochentag"); break; default: System.out.println("Fehler"); } |
int wochentag; ... switch (wochentag) { case 7: System.out.println("Sonntag"); break; case 6: System.out.println("Samstag"); break; case 5: case 4: case 3: case 2: case 1: System.out.println("Wochentag"); break; default: System.out.println("Kein gültiger Wochentag!"); }
Besonderheiten der switch-case Anweisung
- Der zu prüfende Ausdruck muss bestimmten Typen genügen:
- byte, short, int, char, enum, String. (Die Unterstützung von String ist neu seit JDK 7, siehe JSR 334, Projekt Coin)
- Die einzelnen Fälle (cases) werden nicht mit geschweiften Klammern geklammert
- Das Schlüsselwort break dient zum Rücksprung aus einem Fall. Der nächste Fall wird mit abgearbeitet wenn es weggelassen wird!
- Es können mehrere Fälle mit Doppelpunkt aufgeführt werden. Der darauf folgende Block wird dann für alle Fälle abgearbeitet.
- Das Schlüsselwort default erlaubt einen Ausführungsblock anzugeben, der ausgeführt wird wenn kein anderer Fall zum Zuge kam
- Der Wert in einem Fall (case) muss eine Konstante sein.
Allgemeine Form:
... switch (Ausdruck) { case konstante1: Anweisung(en); break; ... case konstante2: case konstante3: ... case konstanteN: Anweisung(en); break; default: Anweisung(en); break; }
Beispiel mit unterschiedlichen Break-Anweisungen
int wochentag; ... switch (wochentag) { case 7: System.out.println("Sonntag"); break; case 6: System.out.println("Samstag"); case 5: case 4: case 3: case 2: case 1: System.out.println("Wochentag"); break; default: System.out.println("Fehler"); } |
- 14423 views
Fehlende break; - Anweisung
Fehlt die break;-Anweisung, werden die folgenden Blöcke ohne Fallüberprüfung ausgeführt? Im UML-Diagramm ("Beispiel mit untersch. Break-Anweisungen) ist dargestellt, dass im case 6: automatisch auch die cases 5-1: angenommen werden und somit "Samstag" UND "Wochentag" gedruckt werden würden.
Ist das tatsächlich der Fall, oder werden die folgenden Cases trotz fehlender break-Anweisung zumindest geprüft? Das "der nächste Fall wird mitabgearbeitet" ist etwas undeutlich formuliert.
Besten Dank
- Log in to post comments
Gut beobachtet
Ja, fehlt ein break, läuft das Programm einfach weiter. Zur Formulierung muss ich erst nochmal nachdenken.
- Log in to post comments
Einfach ausprobieren in der JS-Konsole (mit: console.log)
wochentag=6
switch (wochentag) {
case 7:
console.log("Sonntag");
break;
case 6:
console.log("Samstag");
case 5: case 4: case 3: case 2: case 1:
console.log("Wochentag");
break;
default:
console.log("Fehler");
}
=>
Samstag
Wochentag
- Log in to post comments
break-Schlüsselwort nach default
Im Bsp unter "Besonderheiten der switch-case Anweisung" wird die default-Anweisung mit einem "break;" beendet, im "Beispiel mit unterschiedlichen Break-Anweisungen" jedoch ohne.
Unterliegt beides der korrekten Syntax?
Gruß.
- Log in to post comments
Bei Ihrem Beispiel mit…
Bei Ihrem Beispiel mit verschachtelten if und else Strukturen ist bei dem System.out.println("Wert maximum: " + maximum"); hinter dem letzten Maximum noch ein Anführungszeichen, welches gelöscht werden muss.
- Log in to post comments
3.2 Schleifen und Felder
3.2 Schleifen und FelderSchleifen erlauben die Wiederholungen von Einzelanweisung. Schleifen bestehen typischerweise aus den folgenden Komponenten
- einen Schleifenrumpf mit den auszuführenden Anweisungen
- einem Kopf oder Fuß mit einer Ausführungsbedingung
- oft einer Laufvariablen mit der die Durchläufe kontrolliert werden
Die while Schleife
Die while Schleife überprüft vor dem Schleifeneintritt ob die Ausführungsbedingung (noch) erfüllt ist. Sie enthält die Schleifenbedingung im Kopf der Schleife.
Die Syntax der while Schleife ist die folgende:
while ( Bedingung) { Anweisung ; } oder while ( Bedingung) Anweisung; Beispiel: Arithmetische Summe 1+2+3+4+5 int i = 1; int summe= 0; while (i<=5) { summe = summe + i; i++; } |
Die do-while-Schleife
Die do-while-Schleife überprüft nach dem ersten Schleifendurchlauf ob die Ausführungsbedingung erfüllt ist. Sie enthält die Schleifenbedingung im Fuß der Schleife. Die Syntax der do-while Schleife ist die folgende: do { Anweisung ; } while ( Bedingung ); oder do Anweisung; while ( Bedingung ); Beispiel: Beende Schleife wenn Wert durch 3 ohne Rest teilt int i = 9; int j = 0; // Zählt Schleifendurchläufe do { j++; i--; } while (i%3 != 0); Die Schleife wird dreimal durchlaufen. |
Regel:
- Die while Schleife ist eine abweisende Schleife: Sie wird nicht notwendigerweise durchlaufen.
- Die do-while ist eine nicht abweisende Schleife: Sie wird mindestens einmal durchlaufen.
Diese Unterscheidung ist in verschiedenen Bereichen wichtig
- Variablen werden bei einer abweisenden Schleife eventuell nicht belegt
- Es wird manchmal in der Qualitätssicherung gefordert, dass alle Zeilen eines Programmes duchlaufen werden. Bei abweisenden Schleifen muss man unter Umständen bei der Implementierung der Testabdeckung mehr investieren.
Die for-Schleife
Die for-Schleife überprüft die Schleifenbedingung vor dem Eintritt in die Schleife.
Ihre Syntax ist die anspruchsvollste der drei Schleifenarten:
for (Initialiserung; Bedingung; Veränderung) {Anweisung ;}
oder
for (Initialiserung; Bedingung; Veränderung) Anweisung;
Der Kopf der for-Schleife besteht aus den folgenden drei Teilen:
- Initialisierungsteil: Laufvariable und Startwert werden festgelegt.
- Bedingungsteil: Wird der Wert der Bedingung unwahr (false) wird die Schleife verlassen oder nicht betreten. Ansonsten wird sie weiter fortgesetzt.
- Veränderungsteil: Nach jedem Durchlauf der Schleife wird die Laufvariable entsprechen verändert (Typischerweise inkrementiert oder dekrementiert).
Beispiel einer einfachen for-Schleife
Im folgenden Beispiel wird die for-Schleife "b mal" durchlaufen. Durch das Aufaddieren der Variablen a wird eine Multiplikation von positiven Zahlen ausgeführt.
Ist b gleich Null oder negativ wird die Schleife nicht durchlaufen.
Geschachtelte Schleifen
Oft ist es notwendig Schleifen zu schachteln. Dies kommt oft bei mehrdimensionalen Datenstrukturen vor bei denen jedes Feld bearbeitet werden muss. Bei jedem Durchlauf der äusseren Schleife wird die innere aufgerufen, die ihre eigenen Durchläufe komplett bei jedem Durchlauf der äusseren Schleife durchführt. Anbei ein Beispiel einer naiven Multiplikation die auf Inkrementieren beruht:
class MultiplizierenNaiv { public static void main(String[] args) { int a = 5; int b = 10; int result = 0; for (int i = 1; i <= a; i++) { System.out.println("Äussere Schleife i = " + i); for (int j = 1; j <= b; j++) { System.out.println("Innere Schleife j = " + j); result++; } } System.out.println(a +"*"+b+" = "+result); } }
Geschachtelte Schleifen sind sehr mächtig und sie haben ein viel größeres Potential Rechnerleistung zu binden. Die Aufwände bei zwei geschachtelten Schleifen können quadratisch steigen im Vergleich zum linearen Aufwand einer einfachen Schleife. Generell gilt, dass eine teure Anweisung in einer Schleife n-mal statt einmal durchlaufen werden kann. Es ist daher wichtig auf die folgenden Dinge zu achten:
- Lassen Sie alle Anweisungen die man vor oder nach der Schleife ausführen kann aus dem Schleifenblock draussen
- Definieren und Initialisieren Sie Variablen wenn möglich ausserhalb der Schleife und verwenden Sie die Variablen wieder. Die Variable muss sonst jedes mal neu angelegt und wieder gelöscht werden.
- Verzichten Sie auf unnötige Schleifendurchläufe
- Seien Sie vorsichtig bei mehrfach geschachtelten Schleifen. Die Anzahl der Durchläufe kann theoretisch sehr schnell, sehr groß werden. Eine dreifach geschachtelte Schleife mit jeweils 1000 Durchläufen wird eine Milliarde mal ausgeführt!
Sprunganweisungen und Schleifenabbrüche mit continue und break Schlüsselwörtern
Java verfügt über zwei Möglichkeiten Schleifen in der Mitte von Ausführungsblöcken zu verlassen. Diese Programmiertechnik sollte man normalerweise vermeiden.
In manchen Fällen ist sie jedoch nützlich. Schleifenabbrüche werden durch die beiden folgenden Schlüsselwörter gesteuert:
Die break Anweisung ist schon vom switch Befehl her bekannt. Mit ihr kann man auch eine if Bedingung beenden. Beispiel einer continue Anweisung: ... for (int i=0; i<= 100; i++) { if (i%2 == 0) continue; System.out.println("Die Zahl " + i + " ist ungerade"); } Bei geraden Zahlen wird die Druckanweisung nach der if Anweisung nicht mehr ausgeführt. Die Schleifen werden jedoch alle durchlaufen. |
Beispiel einer break-Anweisung:
... for (int i=1; i<= 100; i++) { if (i== 32) break; System.out.println("Die Zahl " + i + " wurde bearbeitet"); } Die Zahlen von 1 bis 31 werden ausgedruckt. Anschließend wird die Schleife abgebrochen. Die break und continue Anweisungen beziehen sich immer auf die nächst äussere Schleife. Mit Hilfe von Labels (Marken) kann man auch über mehrere geschachtelte Schleifen nach aussen springen. |
Verlassen von Blöcken mit Hilfe von Sprungzielen (Label)
Java erlaubt das Benennen von Blöcken mit Hilfe von "Labeln" (Marken). Mit ihnen kann man mit einer break-Anweisung beliebig viele Blöcke auf einmal verlassen.
Das folgende Beispiel zeigt wie man zum Label "Label1" springt um beide Schleifen auf einmal zu verlassen:
class MultiplizierenNaivLabel { public static void main(String[] args) { int a = 5; int b = 10; int result = 0; Label1: for (int i = 1; i <= a; i++) { System.out.println("Äussere Schleife i = " + i); for (int j = 1; j <= b; j++) { System.out.println("Innere Schleife j = " + j); if ((i == 3) && (j == 3)) break Label1; result++; } } System.out.println(a +"*"+b+" = "+result); System.out.println("Dieses Ergebnis ist falsch..."); } }
Endlosenschleifen
Endlosenschleifen sind Schleifen die nicht terminieren. Ein Programm mit einer Endlosschleife sieht aus wie ein "hängendes" Programm. Es bindet jedoch sehr wahrscheinlich (mindestens) einen physikalischen Prozessor vollständig! Anbei einige Beispiele mehr oder weniger leicht zu erkennende Endloschleifen: while ( true) { /* Anweisung(en) */ } ... for ( ; ; ) { /* Anweisung(en) */ } ... int i=10; while (i>5) i++; ... int i=0; while ( i!=99) {i++; i++;} Der Übersetzer erkennt diverse einfache Endlosschleifen und meldet die darauf folgende Codezeile als "unreachable code". |
Trivia: Welcher Obsthändler hat die Adresse 1 Infinite Loop, Cupertino, CA 95014?
|
Felder (Arrays), Einführung
Die folgende Kurzüberblick von Feldern ist notwendig um die Übungen zu den Kontrollstrukturen zu lösen. Felder werden später noch einmal aufgegriffen und genauer behandelt.
Felder sind Datenbehälter mit einer oder mehreren Dimensionen um eine Anzahl primitive Datentypen gleichen Typs aufzunehmen.
Man kann auf die einzelnen Feldelemente wahlfrei, also direkt mit Hilfe eines Index zugreifen. Java benutzt rechteckige Klammern [] um auf einzelne Elemente eines Feldes zuzugreifen.
Initialisieren und Deklarieren von Feldern
Felder sind im Gegensatz zu Variablen mit primitiven Datentyp Objekte. Dies bedeutet, dass die die Variable nur aus einer Referenz besteht. Das Feld selbst muss dynamisch angelegt werden. Hierfür gibt es eine Reihe von Gründen.
- Der Übersetzer kann nicht wissen wie groß ein Feld werden kann
- Man kann mit einer Feldvariablen dynamisch neue Felder verwalten
- Felder können sehr groß sein. Es ist oft klüger das Feld erst anzulegen wenn man es benötigt und die Größe kennt.
Die Deklaration von Feldern geschieht wie folgt:
int[] x; // Anlegen einer Referenz, es ist noch keine Größe vorgeben, // es können noch keine Feldelemente benutzt werden< double[] y; // Anlegen einer Referenz, es ist noch keine Größe vorgeben, //es können noch keine Feldelemente benutzt werden
Um das eigentliche Feld anzulegen muss der new Operator verwendet werden wie für reguläre Objekte auch um den Speicher zu allozieren. Dies geschieht wie folgt:
int [] x; x = new int[4]; double[] y; y = new double[200];
Jetzt zeigt x auf 4 Datenbehälter für Ganzzahlen. Der Zugriff auf die vier Elemente erfolgt über einen Index im Bereich von 0 (erster Wert) bis 3.
Zugriff auf Felder
Das Feld kann nun wie folgt belegt und bearbeitet werden:
int [] x = new int[4]; x[0] = 99; x[1] = 88; x[2] = x[0]+x[1]; x[3] = x[0]*x[1];
Bestimmen der Länge eines Feldes
...geschieht mit dem Attribut .length. Hier ein Beispiel:
int[] x; int groesse; ... groesse=x.length;
Erweiterte for Schleife (enhanced for-loop)
Seit Java 5 ist es möglich mit der for Schleife Felder komfortabler abzuarbeiten. Man kann mit einer Laufvariable alle Elemente des gegeben Feldes abarbeiten. Wie zum Beispiel:
int [] xxx = { 11, 22, 33, 44, 55}; for ( int position : xxx) // für Element auf Position position in xxx[] System.out.println("Wert: " + position);
Wird das folgende Ergebnis liefern:
Wert: 11 Wert: 22 Wert: 33 Wert: 44 Wert: 55
Die Oracle Java Dokumentation erklärt die Einsatzmöglichkeiten und Grenzen der "enhanced for-loop".
- 16667 views
Endlosschleife
"int i = 10
while (i > 5 ) i++;"
fehlen nach der Bedingung nicht die { }?
Also {i++;} ?
- Log in to post comments
Nein
Das wurde hier in Syntax nicht vollständig korrekt dargestellt.
Die allgemeine Regel für Programmierblöcke ist: Man darf anstatt mehrerer Befehle in einem Block mit geschweiften Klammern immer auch einen einzelnen Befehl ohne geschweifte Klammer schreiben.
Die Syntax müßte wohl als regulärer Ausdruck so aussehen:
while (bedingung) [{ anweisung; {anweisung;}} , anweisung; ]
- Log in to post comments
Bestimmen der Länge eines Feldes
Sollte es nicht heißen
groesse = x.length(); statt groesse = x.length; ?
lg
- Log in to post comments
length ist keine Methode, das Feld ist keine Klasse
das ist ein Spezialfall. Felder sind keine Klassen und haben keine Methoden. length ist ein Attribut welches alle Felder besitzen.
Man kann das auch mal selbst in eine Entwicklungsumgebung eintippen und schauen was passiert...
- Log in to post comments
Mag sein, dass das ein…
Mag sein, dass das ein Erbsenzähler Problem ist, allerdings wird unter dem Punkt 'Bestimmen der Länge eines Feldes' beschrieben, dass die Länge mit der .length()-Methode bestimmt wird.
Sollte hier nicht length-Attribut stehen?
- Log in to post comments
for Schleife
Im Beispiel einer einfachen for Schleife steht, dass sie b mal durchlaufen wird, jedoch ist die Bedingung der for Schleife i
- Log in to post comments
3.2.1 Schleifentransformationen
3.2.1 SchleifentransformationenDie drei Java Schleifentypen sind für unterschiedliche Zwecke entwickelt worden. Man Sie jedoch ineinander Überführen.
Hier sind einige Regeln
While Schleife in Do-While Schleife überführen
von While Schleife | zu do-While Schleife | |
---|---|---|
Java |
while (Bedingung) {Block A } |
do if (Bedingung) { Block A } while ( Bedingung ) |
UML |
Do-While Schleife in While Schleife überführen
Eine Do-While Schleife führt einen Block mindestens einmal aus. Man kann Sie in eine While Schleife tranformieren in dem man den Block kopiert und voran stellt.
Vorsicht: Durch das duplizieren des Codes wird der Code schlechter wartbar!
von Do-While Schleife | zu While Schleife | |
---|---|---|
Java |
do Block A while ( Bedingung ) |
Block A while (Bedingung) {Block A } |
UML |
For-Schleife in eine While Schleife überführen
von For-Schleife | zu While Schleife | |
---|---|---|
Java |
for (Initialiserung; Bedingung; Veränderung) {Block A} |
Initialisierung while (Bedingung) { Block A; Veränderung } |
While Schleife in For-Schleife überführen
While Schleifen kan man recht einfach in For-Schleifen überführen.
von While-Schleife | zu For-Schleife | |
---|---|---|
Java |
while (Bedingung) { Block A;} |
for (; Bedingung;) {Block A} |
Eine solche Überführung wird aber recht selten angewendet, da der Initialisierungsanteil und die Veränderung der for Schleife irgendwo im Block A verborgen sind.
Do-While Schleife in For-Schleife überführen
Do-While Schleifen kan man auch recht einfach in For-Schleifen überführen.
von While-Schleife | zu For-Schleife | |
---|---|---|
Java |
do { Block A;} while (Bedingung) |
Block A; for (; Bedingung;) {Block A;} |
Eine solche Überführung wird aber recht selten angewendet, da der Initialisierungsanteil und die Veränderung der for Schleife irgendwo im Block A verborgen sind.
- 3916 views
Semikolon
Hallo,
muss bei der Transformation von der For Schleife zu der While Schleife hinter die Initialisierung ein Semikolon?
Und mir ist aufgefallen, dass bei der letzten Transformation die Begriffe in der Tabelle nicht stimmen.Es handelt sich um eine Transformation von einer Do While Schleife zu einer For Schleife, aber in der Tabelle steht von einer While Schliefe zu einer While Schleife.
Mit freundlichen Grüßen!
- Log in to post comments
3.3 Übungen
3.3 Übungen
3.3.1 Übung: SchleifenterminierungWelche der folgenden Schleifen terminieren?
|
int i = 1, j = 1; do { i = i + j; j++; } while (i < 200);
int i = 1, j = 20; while (i + j < i) { i = i + 2; j--; }
int i = 1, j = 20; while (i + j > i) { i = i + 2; j--; }
int i = 100, j = 27; while (i != j) { i = i / 2; j = j / 3; }
3.3.2 Übung: Ziffern einer Zahl
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
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
- 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
// Annahme: j >= 0 i = 0; while (i != j) i++;
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:
Hinweis: Wenn es einen Schnittpunkt gibt ist er (c,b)
3.3.10 Übung: Codevereinfachung
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:
Uhr im normalen Zustand |
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)); } }
- 13767 views
Primfaktorzerlegung
die Zahl 252 aus den Primfaktoren 3, 3, 4, 7.
4 ist keine Primzahl hier müsste 2x die 2 hin
- Log in to post comments
3.4 Lösungen
3.4 Lösungen3.4.1 Schleifenterminierung
int i = 1, j = 1; do { i = i + j; j++; } while (i < 200);
int i = 1, j = 20; while (i + j < i) { i = i + 2; j--; }
int i = 1, j = 20; while (i + j > i) { i = i + 2; j--; }
int i = 100, j = 27; while (i != j) { i = i / 2; j = j / 3; }
3.4.2 Ziffern einer Zahl
public class Main { public static void main(String[] args) { int firstArg = 0; int stellen = 0; int a; 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"); a = firstArg; while (a !=0) { stellen++; a/=10; } } System.out.println(" Die Zahl " + firstArg + " hat " + stellen + " Stellen!"); } }
3.4.3 Quersumme
package s1.block3; public class Quersumme { public static void main(String[] args) { int firstArg = 0; int querSumme = 0; int a; 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 + " wurde eingelesen"); a = firstArg; while (a !=0) { querSumme+= a%10; a/=10; } System.out.println("Die Zahl " + firstArg + " hat die Quersumme " + querSumme + "!"); } } }
3.4.4 Zahlenstatistik
package s1.block3; public class Zahlenstatistik { public static void main(String[] args) { int feld[]; int min = Integer.MAX_VALUE; int max = Integer.MIN_VALUE; float average = 0; if (args.length > 0) { feld = new int[args.length]; try { for (int i=0;i<args.length;i++) { feld[i] = Integer.parseInt(args[i]); if (feld[i] < min) {min=feld[i];} if (feld[i] > max) {max=feld[i];} average += feld[i]; } } catch (NumberFormatException e) { System.err.println("Argument muss Ganzzahl sein"); System.exit(1); } average= average/(float)args.length; System.out.println("Anzahl eingelesene Werte: " + args.length); System.out.println("Kleinster Wert: " + min); System.out.println("Größter Wert: " + max); System.out.println("Durchschnitt: " + average); } } }
3.4.5 Primzahlzerlegung
package s1.block3; public class Primzahlzerlegung { public static void main(String[] args) { int firstArg = 0; int p=1; 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); while (p>1) { for (int i=2; i<= p; i++) { while (p%i == 0) { System.out.println("Primfaktor: " + i); p /= i; } } } } time= System.nanoTime() - time; System.out.println("Zeit in m: "+ time); } }
Optimiert:
// Gute Kandidaten // 2^30-1 = 1073741823 // 2^31-1 = 2147483647 public class Main { public static void Primzahlzerlegung(String[] args) { int firstArg = 0; long p = 1; 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); } long i = 2; System.out.println("Eingelesene Zahl: " + p); while ((p > 1) && (i <= p)) { if (p % i == 0) { System.out.println("Primfaktor: " + i); p /= i; i = 2; } else { if (i > Math.sqrt(p)) { // Beende Suche wenn Wurzel von P erreicht i = p; } else { i++; } } } } time = System.nanoTime() - time; System.out.println("Zeit in m: " + time); } }
3.4.6 Codevereinfachung
a.)
// Annahme: j >= 0 i = j;
a = (a<b) ? b : a; b = (a<b) ? a : b; c = (a<b) ? a : c;
3.4.7 Wochentagberechnung
Hier wurde nur der julianische Kalender implementiert nicht der (aktuelle) gregorianische Kalender.
Hier wurden Felder verwendet, die noch nicht vorgestellt wurden.
package s1.block3; public class WochentagBerechnung { public static void main(String[] args) { int monatOffSet[] = new int[13]; int tag = 0; int monat = 0; int jahr=0; int wochentag0101startJahr= 6; int jahresOffSet; // Bedeutung siehe Feld tagText String[] tagText = {"Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"}; int wochentag; int startJahr = 2010; int anzSchaltJahre; if (args.length > 1 ) { try { tag = Integer.parseInt(args[0]); monat = Integer.parseInt(args[1]); jahr = Integer.parseInt(args[2]); wochentag0101startJahr = Integer.parseInt(args[3]); } catch (NumberFormatException e) { System.err.println("Argument muss Ganzzahl sein"); System.exit(1); } monatOffSet[1] = 0; monatOffSet[2] = (monatOffSet[1]+31)%7; monatOffSet[3] = (monatOffSet[2]+28)%7; monatOffSet[4] = (monatOffSet[3]+31)%7; monatOffSet[5] = (monatOffSet[4]+30)%7; monatOffSet[6] = (monatOffSet[5]+31)%7; monatOffSet[7] = (monatOffSet[6]+30)%7; monatOffSet[8] = (monatOffSet[7]+31)%7; monatOffSet[9] = (monatOffSet[8]+31)%7; monatOffSet[10] = (monatOffSet[9]+30)%7; monatOffSet[11] = (monatOffSet[10]+31)%7; monatOffSet[12] = (monatOffSet[11]+30)%7; jahresOffSet = (monatOffSet[12]+31)%7; if (monat>2) anzSchaltJahre=jahr/4-startJahr/4; else anzSchaltJahre=(jahr-1)/4-startJahr/4; wochentag = (monatOffSet[monat] + tag - 1 + wochentag0101startJahr + (jahr-startJahr)*jahresOffSet + anzSchaltJahre )%7; System.out.println ("Der 1.1."+ startJahr+" war ein " + tagText[wochentag0101startJahr]); System.out.println ("Der "+ tag + "."+monat+"."+jahr+ " ist ein " + tagText[wochentag]); // Optional: Datumsbestimmung mit Hilfe der Java Infrastruktur Calendar myCal = new GregorianCalendar(jahr,monat+1,tag); System.out.println ("Gregorianischer Java Kalender:"); System.out.println ("Der " + tag + "." + monat + "." + jahr+ " ist ein " + tagText[myCal.get(Calendar.DAY_OF_WEEK)]); } } }
3.4.8 Überlauf
Bei der Addition von Ganzzahlen gibt es keine Überlaufsprüfung.
package s1.block3; public class Ueberlauf { public static void main(String[] args) { int a = 0; int b = 0; int result; if (args.length > 1 ) { try { a = Integer.parseInt(args[0]); b = Integer.parseInt(args[1]); } catch (NumberFormatException e) { System.err.println("Argument muss Ganzzahl sein"); System.exit(1); } } System.out.println("Eingelesene Werte: " + a + ", " + b); result = a + b; if ((result < a) || (result < b)) System.out.println("Überlauf!"); else System.out.println(a + " + " + b + " = " + result); } }
3.4.9 Schnitt zweier Linien
Eingabereihenfolge der Parameter ist: a1, a2, b ,c , d1, d2
package s1.block3; public class GeradenSchnitt { public static void main(String[] args) { double a1 = 0.0; double a2 = 0.0; double b = 0.0; double c = 0.0; double d1 = 0.0; double d2 = 0.0; double tmp; if (args.length > 5) { try { a1 = Double.parseDouble(args[0]); a2 = Double.parseDouble(args[1]); b = Double.parseDouble(args[2]); c = Double.parseDouble(args[3]); d1 = Double.parseDouble(args[4]); d2 = Double.parseDouble(args[5]); } catch (NumberFormatException e) { System.err.println("Argument muss Fließkommazahl sein"); System.exit(1); } } System.out.println("Linie 1: (" + a1 + "," + b + ") bis (" + a2 + "," + b + ")"); System.out.println("Linie 2: (" + c + "," + d1 + ") bis (" + c + "," + d2 + ")"); // Schnittpunkt ist (c,b) // Sortieren von a1, a2 . if (a1 > a2) { tmp = a1; a1 = a2; a2 = tmp;} // Sortieren von d1, d2 . if (d1 > d2) { tmp = d1; d1 = d2; d2 = tmp; } System.out.println("Nach sortieren..."); System.out.println("Linie 1: (" + a1 + "," + b + ") bis (" + a2 + "," + b + ")"); System.out.println("Linie 2: (" + c + "," + d1 + ") bis (" + c + "," + d2 + ")"); if ((a1 <= c) && (c <= a2) && (d1 <= b) && (b <= a2)) System.out.println("Die beiden Strecken schneiden sich"); else System.out.println("Die beiden Strecken schneiden sich nicht"); } }
Beispielläufe
java s1.block3.GeradenSchnitt 3.1 8.2 4.0 5.2 11.1 4.9 Linie 1: (3.1,4.0) bis (8.2,4.0) Linie 2: (5.2,11.1) bis (5.2,4.9) Nach sortieren... Linie 1: (3.1,4.0) bis (8.2,4.0) Linie 2: (5.2,4.9) bis (5.2,11.1) Die beiden Strecken schneiden sich nicht java block3.GeradenSchnitt 3.1 8.2 6.0 5.2 11.1 4.9 Linie 1: (3.1,6.0) bis (8.2,6.0) Linie 2: (5.2,11.1) bis (5.2,4.9) Nach sortieren... Linie 1: (3.1,6.0) bis (8.2,6.0) Linie 2: (5.2,4.9) bis (5.2,11.1) Die beiden Strecken schneiden sich
3.4.10 Codevereinfachung
a)
a = a * b + 2 * c;
b)
x<0 | x>=0 | |
---|---|---|
y<0 | a=x*y | a=x*(-y) |
y>=0 | a = x*(-y) | a=(-x)*(-y) |
y = ((x<0) && (y<0)) ? y : -y; x = ((y>=0) && (x>=0))? -x : x; a = x * y;;
3.4.11 Dreiecksbestimmung
package s1.block3; public class Dreiecksvergleich { public static void main(String[] args) { float x[] = new float[3]; int j; if (args.length > 2 ) { try { float a; for (int i=0; i <3; i++) { x[i] = Float.parseFloat(args[i]); j=i; // Sortiere Eingabe in steigender Reihenfolge while (j>0) if (x[j] < x[j-1]) { a = x[j-1]; x[j-1] = x[j]; x[j]= a; j--; } else j=0; } } catch (NumberFormatException e) { System.err.println("Argument muss Fließkommazahl sein"); System.exit(1); } System.out.println("Eingebene Werte: " + x[0] + "; " + x[1] + "; " + x[2]); // Die folgenden Vergleiche verlassen sich darauf, dass das Feld // aufsteigend sortiert ist. if (x[0]+x[1]<=x[2]) System.out.println("Dreieck ist ungültig"); else if (x[0] == x[2]) System.out.println("Dreieck ist gleichseitig (und gleichschenkelig)"); else { if ((x[0] == x[1]) || (x[1] == x[2])) System.out.println("Dreieck ist gleichschenkelig (nicht gleichseitig)"); if (x[0]*x[0]+x[1]*x[1]==x[2]*x[2]) System.out.println("Dreieck ist rechtwinklig"); } } } }
3.4.12 Sortieren
package s1.block3; 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); // alle Moeglichkeiten testen if ((a <= b) && (b<=c)) System.out.println("Sortierte Werte: " + a + ", " + b + ", " + c); else if ( (a <= c) && (c <= b) ) System.out.println("Sortierte Werte: " + a + ", " + c + ", " + b); else if ( (b <= a) && (a <= c) ) System.out.println("Sortierte Werte: " + b + ", " + a + ", " + c); else if ( (b <= c) && (c <= a) ) System.out.println("Sortierte Werte: " + b + ", " + c + ", " + a); else if ( (c <= a) && (a <= b) ) System.out.println("Sortierte Werte: " + c + ", " + a + ", " + b); else if ( (c <= b) && (b <= a) ) System.out.println("Sortierte Werte: " + c + ", " + b + ", " + a); } }
3.4.13 Plausibilitätsprüfung
package s1.block3; public class Plausibilitaetspruefung { public static void main(String[] args) { int monatTage[] = {0, 31, 28, 31, 30, 31, 30,
int tag = 0; int monat = 0; int jahr = 0; if (args.length > 2 ) { try { tag = Integer.parseInt(args[0]); monat = Integer.parseInt(args[1]); jahr = Integer.parseInt(args[2]); } catch (NumberFormatException e) { System.err.println("Argument muss Ganzzahl sein"); System.exit(1); } System.out.println("Eingabe ist: " + tag + "." + monat + "." + jahr); if ((monat>0) && (monat < 13) && (tag>0)) if (monatTage[monat] >= tag) System.out.println("Datum ist gültig"); else if ((monat == 2) && (tag == 29) && (jahr%4 == 0) && ((jahr%100 !=0) || (jahr%400==0)) ) System.out.println("Datum ist gültig (Schalttag)"); else System.out.println("Datum ist ungültig"); } } }
3.4.14 Textverschlüsselung
Die vorgestellte Lösung ist eine naive, aber in diesem Fall korrekte Lösung da hier der implementierte Wert eines Zeichen im Vordergrund steht und nicht die Bedeutung des Zeichens.
Sie basiert auf der naiven Annahme, dass die den Zeichen (Buchstaben) zugeordnete Zahlenwerte der Sortierreihenfolge der Buchstaben entspricht. Diese Annahme ist für lateinische Zeichensätze meißten, mehr oder weniger richtig. Im Allgemeinen sollte man bei Programmentwicklung an die Internationalisierung denken. Hier gilt:
- Die lexikografische Ordnung (Sortierreihenfolge) ist länderabhängig und hängt von der Landeseinstellung (locale, Codepage) der eingestellten Umgebung ab.
- Beispiel: Die Buchstaben ß, ö, Ö, ü etc haben in Unicode oder ISO 8852 Werte die nicht der deutschen lexikographischen Ordnung entsprechen.
- Die von Java verwendete Unicodecodierung erlaubt die Codierung der meisten Zeichen der Welt gleichzeitig. Die Sortierreihenfolge ist hier nicht garantiert.
- Beispiel: Es gibt Zeichen die in der japanischen sowie in der chinesichen Sprache verwendet werden. Diese Zeichen sind identisch, haben jedoch eine unterschiedliche Bedeutung. Sie werden daher in China und Japan unterschieldlich sortiert.
package s1.block3; public class Textverschluesselung { public static void main(String[] args) { String myText = ""; int offSet = 0; char c; if (args.length > 1 ) { offSet = Integer.parseInt(args[0]); myText = args[1]; } System.out.println("Eingabe: <<" + myText + ">>, Verschiebung: " + offSet); System.out.print("Ausgabe: <<"); offSet = offSet%26; // Bei 26 Buchstaben kann der Versatz nur module 26 sein for (int i=0;i < myText.length(); i++) { // Lese jeden Wert der Zeichenkette aus und erhöhe den Zähler im Feld c = myText.charAt(i); if ((c>='A') && (c<='Z')) { c = (char)(c + offSet); if (c > 'Z') c-=(char)26; //Ziehe vom Ergebnis 26 ab da es jenseits von "Z" liegt. System.out.print(c); } } System.out.println(">>"); } }
3.4.15 Verzweigung
package s1.block3; public class Verzweigung { public static void main(String[] args) { int x[] = new int[3]; if (args.length > 2 ) { try { for (int i=0; i<3; i++) x[i]= Integer.parseInt(args[i]); } catch (NumberFormatException e) { System.err.println("Argument muss Ganzzahl sein"); System.exit(1); } } System.out.println("Eingabe: " + x[0] +", " + x[1] + ", "+ x[2]); if ((x[0]==x[1]) && (x[1]==x[2])) System.out.println("Alle Werte sind gleich."); if ((x[0]==x[1]) || (x[1]==x[2]) || (x[0]==x[2])) System.out.println("Mindestens zwei Werte sind gleich."); if ((x[0]!=x[1]) && (x[1]!=x[2]) && (x[0]!=x[2])) System.out.println("Alle Werte sind verschieden."); } }
3.4.16 Häufigkeit von Zeichen
package s1.block3; public class Haeufigkeitzeichen { public static void main(String[] args) { String myText=""; char c; int histogram[] = new int[Character.MAX_VALUE]; if (args.length > 0 ) { myText=args[0]; } System.out.println("Eingabe: <<" + myText + ">>"); for (int i=0;i < myText.length(); i++) { // Lese jeden Wert der Zeichenkette aus und erhöhe den Zähler im Feld c = myText.charAt(i); histogram[c]++; } for (int i=0; i < Character.MAX_VALUE; i++) if (histogram[i]!= 0) { // Wichtig: unterdrücke alle leeren Einträge. // Das Feld hat ~65000 Zellen! System.out.print((char)i + ": "); for (int j=0; j< histogram[i]; j++) System.out.print('*'); System.out.println(); } } }
3.4.17 Weckzeiten implementieren
package s1.block3; public class WeckzeitLoesung { 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 = ((h>=0) && (h<=12 && (m>=0) && (m<=59)&& (s>=0) && (s<=59))); 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 // Bestimme aktuelle Zeit in Sekunden int aktZeit = aktH*3600 + aktM*60+aktS; // Bestimme Weckzeit in Sekunden int weckZeit = wzh *3600 + wzm *60+wzs; // Ist die aktuelle Zeit größer aber nicht größer als 10 Sekunden? result = (aktZeit-weckZeit>=0) && (aktZeit-weckZeit<10); return result; }
}
- 8601 views
3.5 Lernziele
3.5 Lernziele
Am Ende dieses Blocks können Sie:
|
Lernzielkontrolle
Sie sind in der Lage die folgenden Fragen zur Ablaufsteuerung und die Frage aus der Übung 3.3.1 Schleifenterminierung zu beantworten.
Feedback
- 4727 views