Programmieren - Java I WS 2001 Algorithmen Ein Algorithmus ist ein Verfahren zur systematischen, schrittweisen Lösung eines Problems. Er besteht aus einzelnen Anweisungen, die in einer bestimmten Reihenfolge, evtl. mehrmals ausgeführt werden müssen. Beispiele: • ärztliche Verordnung: nimm 3x täglich 15 Tropfen einer Medizin ein • Spielregeln, z.B. Mensch-ärgere-dich-nicht • Koch- und Backrezepte • Verfahren zur Addition und Multiplikation von 2 Dezimalzahlen • Näherungsverfahren zur Bestimmung der Quadratwurzel Beispiele: Algorithmen zum Test auf Primzahl Eine Primzahl ist eine ganze Zahl >1, welche nur durch sich selbst und durch den Wert 1 teilbar ist. Die Folge der Primzahlen lautet 2, 3, 5, 7, 11, 13, ... ZAHL 7 7 7 7 7 => 7 sei : 2 : 3 : 4 : 5 : 6 ist 7 teilbar? => nein teilbar? => nein teilbar? => nein teilbar? => nein teilbar? => nein eine Primzahl ZAHL sei 9 9 : 2 teilbar? => nein 9 : 3 teilbar? => ja 9 : 4 teilbar? => nein 9 : 5 teilbar? => nein usw. ... => 9 ist keine Primzahl Algorithmus: Gebe eine ZAHL ein Setze DIVTEST = 2 SOLANGE ((DIVTEST kleiner ZAHL) und (ZAHL nicht durch DIVTEST teilbar)) erhoehe DIVTEST um 1 WENN (DIVTEST gleich ZAHL) DANN Ausgabe ZAHL ist Primzahl SONST Ausgabe ZAHL ist keine Primzahl W. Süß 1 Algorithmen Programmieren - Java I WS 2001 Grundstrukturen von Algorithmen • Allgemeine Anweisungen (oder Aktionen), die ohne Einschränkung ausgeführt werden. • Bedingte Anweisungen (oder Auswahl): Wenn Programmteile nur bei bestimmten Daten ausgeführt werden, spricht man von bedingten Anweisungen. Man unterscheidet: Einfache bedingte Anweisung, bestehend aus Bedingung und Anweisung, die ausgeführt wird, wenn die Bedingung erfüllt ist. Die Bedingung ist ein Ausdruck, der als Ergebnis einen Wahrheitswert der Form wahr oder falsch liefert. Die Anweisung ist eine beliebige Anweisung (z.B. wieder eine bedingte Anweisung). Vollständige bedingte Anweisung besteht aus beiden Elementen einer bedingten Anweisung und zusätzlich einer Anweisung, die ausgeführt wird, falls die Bedingung nicht erfüllt ist. Das hat zur Folge, daß immer eine der beiden Anweisungen ausgeführt wird. Fallunterscheidung, falls es mehr als zwei Fälle gibt. Dann definiert man statt einer Bedingung, die entweder wahr oder falsch sein kann, einen sogenannten Verteiler, der mehrere Werte annehmen kann. Analog gibt es statt 2 möglichen Alternativen (Aktion 1 und 2) mehrere möglicheAlternativen (Aktion 1 ... n). • Schleifen (oder Wiederholungen), bei denen die Daten bestimmen, wie oft ein bestimmtes Programmstück durchlaufen werden soll. Schleifen bestehen i. d. R. aus 3 Teilen: Vorbehandlung, d.h. einer Initialisierung der Anfangswerte Anweisungen, die innerhalb der Schleife wiederholt ausgeführt werden. Diese müssen u.a. auch die Schleifenvariable verändern , die dann getestet werden kann. Test auf Bedingung für den Abbruch oder Fortsetzen der Schleifen anhand der Schleifenvariable. W. Süß 2 Algorithmen Programmieren - Java I WS 2001 Grundstrukturen von Algorithmen Es gibt 3 Arten von Schleifen: Zählschleifen, bei denen ein Programmabschnitt n-mal durchlaufenwird. Dabei muß die Anzahl der Schleifendurchläufe bekannt sein. (Es gibt Programmiersprachen, insbesondere Java, in deren Sprachumfang echte Zählschleifen nicht vorkommen.) Bedingte Schleifen, bei denen ein Abschnitt eines Programms solange durchlaufen wird, bis ein Testkriterium greift. Zu Beginn ist die Anzahl der Durchläufe aber unbekannt (sonst i. d. R. Zählschleife). Bedingte Schleifen unterteilt man, je nachdem, wann der Test durchgeführt wird, in: While-Schleifen, bei denen der Test vor jedem Schleifendurchlauf erfolgt. Die Ausführung der Anweisungen erfolgt, solange die Schleifenbedingung erfüllt ist. Repeat-Schleife (do-while), bei denen der Test nach jedem Schleifendurchlauf erfolgt. Das bedeutet, daß die Schleife mindestens einmal durchlaufen wird. Die Interpretation ist abhängig von der Programmiersprache: In PASCAL z.B. erfolgt die Ausführung der Anweisung, bis das Abbruchkriterium erfüllt ist. Das Abbruchkriterium dieser Schleife ist demnach die Negation der Schleifenbedingung bei der äquivalenten While-Schleife. In Java dagegen erfolgt die Ausführung der Anweisung, solange die Schleifenbedingung erfüllt ist. Die Formulierung der Schleifenbedingung ist demnach analog zur While-Schleife. W. Süß 3 Algorithmen Programmieren - Java I WS 2001 Darstellungsmethoden • Die einfachste Form, Algorithmen zu beschreiben, ist die Formulierung von Anweisungen mit Hilfe der natürlichen Sprache. Der Vorteil ist, daß ein Algorithmus ohne zusätzlichen Lernaufwand beschrieben werden kann. Der Nachteil ist, daß gleiche Sachverhalte auf beliebig viele Arten formuliert werden können. Daher ist es sinnvoll, wenigestens bestimmte Grundelemente (z.B. für Entscheidungen) in ihrer Formulierung festzulegen (siehe Tabelle). • Durch den Einsatz von Struktogrammen (z.B. das Nassi-ShneidermanDiagramm) kann die Struktur des Algorithmus, d.h. die Schachtelung der Elemente sehr übersichtlich dargestellt werden. Sie erzwingen eine strukturierte Darstellung von Algorithmen dadurch, daß sich störende Anweisungen wie z.B. Sprünge nicht realisieren lassen. Auch hier gibt es Symbole für die Darstellung von Grundelementen (siehe Tabelle). Der Nachteil von Nassi-Shneiderman-Diagrammen ist die Schwierigkeit der Darstellung sehr verschachtelter Algorithmen infolge Platzmangels. W. Süß 4 Algorithmen Programmieren - Java I WS 2001 Darstellungsmethoden • Mit Hilfe von Flußdiagrammen kann man den Ablauf eines Algorithmus recht übersichlich beschreiben. Dabei gibt es unterschiedliche Symbole für verschiedene Typen von Anweisungen, die genormt sind (DIN 66001): Allgemeine Anweisung (Aktion) Ein-/Ausgabeanweisung Anfangs-/Endmarkierung Bedingte Anweisung Diese Grundsymbole werden über Pfeile miteinander verbunden, um die Ablaufreihenfolge darzustellen. Der Nachteil besteht darin, daß es nicht für alle Anweisungsformen (z.B. Schleifen) geeignete Symbole gibt. Man kann (wie in der Tabelle) auf Nichts-Standard-Symbole ausweichen oder diese Anweisungsformen recht kompliziert mit Hilfe der angebotenen Symbole realisieren. Nachteil der Flußdiagramme: sie ermöglichen eine übersichtliche Darstellung eines Ablaufens, sie erzwingen diese aber nicht. W. Süß 5 Algorithmen Gruppe Sequenz Auswahl Natürlichsprachlich Struktogramm <Aktion 1> <Aktion 2> WENN <Bedingung> DANN <Aktion> Flußdiagramm <Aktion 1> <Aktion 1> <Aktion 2> <Aktion 2> <Bedingung> <Bed.> ja Wiederholung SOLANGE <Bedingung> <Aktion> if (Bedingung) Aktion nein <Bed.> ja <Bedingung> <Aktion 1> nein nein ja <Aktion 2> <Aktion 1> <Aktion 2> <Ver.> <Verteiler> <Kons. 1> <Kons. 1> <Aktion 1> <Aktion 1> <Kons. 1> ... <Bedingung> <K 1> <Aktion 1> <Akt. 1> * <K 2> <Akt. 2> <Bedingung> <Aktion> <Aktion> <Aktion> * <Aktion> <Bedingung> <Bedingung> <K n> ... <Akt. n> if (Bedingung) Aktion 1 else Aktion 2 switch (Verteiler) case (Konstante 1): Aktion 1 case (Konstante 2): Aktion 2 .... case (Konstante n): Aktion n while (Bedingung) Aktion do Aktion while (Bedingung) WS 2001 Algorithmen WIEDERHOLE <Aktion> SOLANGE <Bedingung> Aktion 1 Aktion 2 <Aktion> 6 FALLS <Verteiler> <Konstante 1>:<Aktion 1> <Konstante 2>:<Aktion 2> ..... <Konstante n>:<Aktion n> C-Sprachkonstrukt ja <Aktion> WENN <Bedingung> DANN <Aktion 1> SONST <Aktion 2> (*: nicht genormt) Programmieren - Java I W. Süß Unterschiedliche Darstellungsmethoden für Algorithmen und ihre Grundstrukturen Programmieren - Java I WS 2001 Beispiel: GGT Beispiel: Bestimme GGT von 24 und 15: 24:15 = 15 : 9 = 9:6= 6 :3 = 1 Rest 9 1 Rest 6 1 Rest 3 2 Rest 0 GGT = 3 Ein Algorithmus dafür in natürlichsprachlicher Form hat die folgende Gestalt: Lies a und b Falls b > a vertausche a und b Falls b > 0 Setze zahla=a und zahlb=b wiederhole: rest = zahla modulo zahlb zahla = zahlb zahlb = rest solange rest ungleich 0 Drucke "zahla ist der GGT von a und b" sonst Drucke " ungültige Eingabe" W. Süß 7 Algorithmen Programmieren - Java I WS 2001 Flußdiagramm Start GGT Lies a und b ein nein b>a ja hilf = a a=b b =hilf nein b>0 ja setze zahla = a und zahl b = b rest = zahla modulo zahlb zahla = zahlb zahlb = rest ja rest ungleich null nein Ausgabe zahl a ist GGT von a und b ungültige Eingabe Ende GGT W. Süß 8 Algorithmen Programmieren - Java I WS 2001 Struktogramm Lies a und b b>a ja hilf = a a=b b =hilf b>0 ja setze zahla = a und zahlb = b rest = zahla modulo zahlb zahla = zahlb zahlb = rest ungültige Eingabe rest ungleich null Ausgabe zahl a ist GGT von a und b W. Süß 9 Algorithmen Programmieren - Java I WS 2001 Beispiel: Zins Es soll ein Algorithmus zur Berechnung von Zinseszinsen erstellt werden. Zur Erinnerung sei das Problem hier kurz skizziert: Bei jährlicher Verzinsung für ein gegebenes Ausgangskapital K0 einem Zinssatz p erhält man Zinsen in Höhe von z = K0 * p /100. Das Gesamtkapital K1 nach einem Jahr beträgt daher: K1 = K0 * (1 + p / 100). Wenn man dieses neu erhaltene Kapital weiterverzinst, so erhält man durch Wiederholung die Zinseszinsformel für das Endkapital Kn nach n jähriger Verzinsung: Kn = K0 * (1 + p /100)n. Die Berechnung benötigt also folgende Eingabedaten: • Ausgangskapital K_0 • Zinssatz p • Verzinsungsdauer n in Jahren Der Algorithmus soll diese drei Werte einlesen, und zunächst auf Gültigkeit überprüfen, beispielsweise ist eine negative Verzinsungsdauer ungültig. Falls einer der drei Werte unzulässig ist, soll der Algorithmus mit einer qualifizierten Fehlermeldung abbrechen. Wenn alle drei Werte zulässig sind, soll der Algorithmus zunächst diese Werte ausgeben, und dann eine Tabelle folgender Form erstellen: (Beispiel p = 5%) W. Süß Jahr Zins Gesamtkapital 0 0 100 1 5 105 ... ... ... n ... ... 10 Algorithmen Programmieren - Java I WS 2001 Natürlichsprachlicher Algorithmus Start Zinseszins Lies Startkapital WENN Startkapital<0 DANN Ausgabe "Negatives Startkapital" SONST Lies Zinssatz WENN Zinssatz<0 DANN Ausgabe "Zinssatz negativ" SONST Lies Dauer WENN Dauer<0 DANN Ausgabe "Dauer negativ" SONST Kapital = Startkapital Zins = 0 Jahr = 0 SOLANGE Jahr ≤Dauer Ausgabe Jahr, Zins, Kapital Beginne neue Ausgabezeile Zins = Kapital ∗ Zinssatz/100 Kapital = Kapital + Zins Jahr = Jahr + 1 Ende Zinseszins W. Süß 11 Algorithmen Programmieren - Java I WS 2001 Struktogramm Lies Startkapital Startkapital < 0 nein ja Lies Zinssatz Zinssatz < 0 nein Lies Dauer Dauer < 0 nein ja Kapital = Startkapital Ausgabe "Dauer negativ" Ausgabe "Negativer Zinssatz" Ausgabe "Negatives Startkapital" ja Zins = 0 Jahr = 0 Jahr ≤ Dauer Ausgabe Jahr, Zins, Kapital Beginne neue Ausgabezeile Zins = Kapital ∗ Zinssatz/100 Kapital = Kapital + Zins Jahr = Jahr + 1 W. Süß 12 Algorithmen Programmieren - Java I WS 2001 Flußdiagramm Start Zinseszins Lies Startkapital K0 nein K0>=0 ja Ausgabe"Startkapital < 0" Lies Zinssatz p nein p>=0 ja Ausgabe "Zinssatz<0" Lies Verzinsungsdauer n nein Ausgabe "Dauer<0" n >=0 ja Kapital = K0 Zins = 0 Jahr ≤ n Ausgabe von Jahr, Zins, Kapital Beginne neue Zeile Zins = Kapital ∗ Zinssatz/100 Kapital = Kapital + Zins Jahr = Jahr + 1 EndeZinseszins W. Süß 13 Algorithmen Programmieren - Java I WS 2001 Schritte zur Programmentwicklung 1. Formulierung des Problems 2. Entwurf eines Lösungsalgorithmus Formulierung auf abstrakter Ebene Beachten von Strukturregeln Korrektheit des Lösungsalgorithmus prüfen Effizienzuntersuchungen 3. Implementierung, d.h. Übertragung des Lösungsalgorithmus in eine Programmiersprache. Ergebnis: ein Programm als Quellcode . 4. Übersetzen (engl.: to compile) des Programms in eine maschinennahe Sprache. Das geschieht durch den Compiler (javac). Das Ergebnis ist Bytecode. 5. Ausführen des Programms (java) W. Süß 14 Algorithmen Programmieren - Java I WS 2001 Beispiel 1. Formulierung des Problems Berechne den Quotienten zweier Zahlen a,b (d.h. a/b), falls b ≠ 0, sonst melde, daß b ein unzulässiger Wert ist. 2. Entwurf eines Lösungsalgorithmus Start Lies zwei Zahlen a und b ein WENN b ungleich 0 DANN quotient sei a / b schreibe quotient SONST schreibe "b ist ein unzulaessiger Wert" Ende ... Strukturregeln, Korrektheit, Effizienz. 3. Implementierung (Speichern als Quotient.java) import Utils; class Quotient { public static void main (String args []) { float a,b, quotient; a = Utils.inputFloat(„Gib a ein: „); b = Utils.inputFloat(„Gib b ein: „); if (b!=0) { quotient = a/b; System.out.println(„Quotient „+quotient); } else { System.out.println(b+“ ist unzulaessiger Wert“); } } } W. Süß 15 Algorithmen Programmieren - Java I WS 2001 Beispiel 4. Übersetzen: javac Quotient.java 5. Ausführen: misun3:65>java Quotient Gib a ein: 3 Gib b ein: 6 Quotient 0.5 misun3:66>java Quotient Gib a ein: 3 Gib b ein: 0 0.0 ist unzulaessiger Wert W. Süß 16 Algorithmen Programmieren - Java I WS 2001 Aufgaben Aufgabe 1 Erstelle einen Algorithmus zum Aufbau einer Temperaturtabelle von Fahrenheit (F) nach Celsius (C). Die Tabelle soll bei 0 F beginnen und bei 300 F enden. Die Abstände der Stützstellen sollen 20 F betragen. Der funktionale Zusammenhang von F und C ist durch folgende Formel gegeben: C = (5 / 9) * ( F - 32) Beispiel: Temperaturtabelle Fahrenheit I Celsius 0 I -17.8 .. 300 I 148.9 Aufgabe 2 Der Wildbestand eines Forstes umfasst 200 Stück. Die jährliche Vermehrung beträgt 10%; zum Abschuß sind im gleichen Zeitraum 15 Stück freigegeben. Wie entwickelt sich der Bestand in den nächsten Jahren? Erstelle eine Algorithmus, der den jährlichen Wildbestand ermittelt, bis dieser die Zahl 300 erreicht hat. Aufgabe 3 Entwickle einen Algorithmus, der das kleine Einmaleins in Tabellenform (10 mal 10 Tabelle) ausgibt. Aufgabe 4 Schreibe einen Algorithmus, der beliebig, viele Zahlen einliest und diese Zahlen aufsummiert. Als Abbruchkriterium verwende die Eingabe einer negativen Zahl. (Realisierung einmal mit while-Schleife und einmal mit do-while Schleife.) W. Süß 17 Algorithmen