3.4 Lösungen

3.4.1 Schleifenterminierung

Welche der folgenden Schleifen terminieren?
 
a)  Terminiert
    int i = 1, j = 1;
    do {
      i = i + j;
      j++;
    } while (i < 200);
b)  Terminiert: Schleife wird nicht durchlaufen
    int i = 1, j = 20;
    while (i + j < i) {
      i = i + 2;
      j--;
    }
c)  Terminiert
    int i = 1, j = 20;
    while (i + j > i) {
      i = i + 2;
      j--;
    }
d)  Terminiert
    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;
b)  
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)

Wahrheitstafel
  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,
                             31, 31, 30, 31, 30, 13};

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;
    }

}