Kurs:Algorithmen und Datenstrukturen/Vorlesung/Größter gemeinsamer Teiler
Größter gemeinsamer Teiler
BearbeitenIn diesem Kapitel wird die im vorherigen Kapitel vorgestellte Vorgehensweise zum Algorithmenentwurf am Beispiel des größten gemeinsamer Teilers gezeigt.
Hintergrundwissen
BearbeitenGegeben zwei positive natürliche Zahlen a und b, welche ist die größte positive natürliche Zahl x, so dass x sowohl a also auch b teilt und es keine positive natürliche Zahl x’ gibt, so dass x’ > x und x’ teilt sowohl a als auch b.
- Alle Variablen bezeichnen natürliche Zahlen größer 0
- Anwendungsbeispiel Kürzen: 52/32 hat 4 als ggT, mit 4 gekürzt ergibt sich 13/8
Problem definieren
BearbeitenWir betrachten (i. Allg.) hier transformationelle Probleme
Problem: ggT-Berechnung Eingabe: zwei Zahlen a,b ∈ N Ausgabe: der größte gemeinsame Teiler von a und b
Algorithmus definiert also eine Transformation auf dem gesamten, durch die Eingaben definierten Zustand, aus dem als Bedeutung dann die Werte der Ausgabevariablen ausgelesen werden.
Algorithmus entwerfen
BearbeitenVerfahren von Euklid (300 v. Chr.) für natürliche Zahlen:
"%" ist die Modulo Funktion:
ggT(46,18) = ggT(18,10) (α=2, b=18, r=10) = ggT(10,8) (α=1, b=10, r=8) = ggT(8,2) = 2 (α=1, b=8, r=2)
In Worten erklärt:
- Wie oft passt 18 in 46? → 2 mal (α)
- 2*18 ist 36, zur 46 fehlen somit noch 10 (r)
- Wie oft passt 10 in 18? → 1 mal (α)
- 1*10 ist 10, zur 18 fehlen somit noch 8 (r)
- Wie oft passt 8 in 10? → 1 mal (α)
- 1*8 ist 8, zur 10 fehlen somit noch 2 (r)
- 8 passt 0 mal in die 2, somit ist der ggT die 2
Idee: Führe die Berechnung von ggT(a,b) auf die Berechnung von ggT(b, a % b) zurück (falls b|a, ansonsten ist das Ergebnis b).
Vorbedingung: Eine Bedingung zur Ausführung des ggT(a,b) ist, dass a,b>0
Wie kann man dies sicherstellen?
- Optimistische Strategie
- Man geht vom Erfüllt sein der Bedingung aus
- z.B. Clients bekannt und zuverlässig, z.B. bei Rekursion
- Man geht vom Erfüllt sein der Bedingung aus
- Pessimistische Strategie
- Man überprüft die Bedingung bei jedem Aufruf
- z.B. Öffentliche APIs
- Man überprüft die Bedingung bei jedem Aufruf
- Möglichkeiten bei nicht erfüllten Vorbedingungen
- Ausnahmen werfen
- Parameter auf Defaultwerte setzen (mit Meldung)
- Programm nicht ausführen und Defaultwert zurückgeben
Programm erstellen
BearbeitenPseudocode
Algorithmus euklid
Eingabe: Ganze Zahlen a,b
Ausgabe: Ganze Zahl c=ggT(a,b)
Setze r = a % b;
Falls r = 0 gib b zurück;
Ansonsten gib euklid(b,r) zurück;
Rekursiv, optimistisch
public int ggT(int a, int b){
int r = a % b;
if (r == 0)!
return b;
else
return ggT(b,r);
}
Iterativ, pessimistisch – Version 1
public int ggT(int a, int b){
if (a<=0 || b<=0)
throw new ArithmeticError(“negative Daten bei ggT(“+a+“,“+b+“)“);
else {
int r = a % b;
while (r!=0) {
a = b;
b = r;
r = a % b;
}
return b;
}
}
Iterativ, pessimistisch – Version 2
public int ggT(int a, int b){
if (a<=0 || b<=0)
then throw new ArithmeticError(“negative Daten bei ggT(“+a+“,“+b+“)“);
else {
do{
int r = a % b;
a=b;
b=r;
} while (r!=0);
return a;
}
}
Algorithmenanalyse
BearbeitenIst unser ein Algorithmus ein guter Algorithmus?
- Wichtige Fragen:
– Terminiert der Algorithmus?
– Ist der Algorithmus korrekt?
– Welche Laufzeit hat der Algorithmus?
1. Theorem:
Für positive natürliche Zahlen a und b mit a > b, terminiert der Algorithmus Euklid nach endlich vielen Schritten.
Beweis:
(a) Falls b|a terminiert der Algorithmus in einem Schritt. (b) Andernfalls wird ein Parameter der Algorithmus um mindestens den Wert 1 verringert und der Algorithmus rekursiv aufgerufen. Spätestens wenn ein Parameter den Wert 1 erreicht tritt Fall (a) ein und der Algorithmus terminiert. Für endliche Eingaben bedeutet dies eine endliche Laufzeit. Was ist mit anderen Eingaben?
2. Theorem:
Der Algorithmus Euklid löst das Problem ggT.
Beweis:
Wir haben bereits festgestellt, dass für zwei positive natürliche Zahlen a, b gilt, dass ggT(a,b)=b (falls b|a) und ggT(a,b)=ggT(a%b) (falls b|a nicht gilt). Der Algorithmus Euklid vollzieht genau diese Fallunterscheidung nach.
3. Theorem:
Für positive natürliche Zahlen a und b mit a>b, benötigt der
Algorithmus Euklid maximal max{a,b} viele rekursive Aufrufe.
Beweis:
Wir haben bereits festgestellt, dass Euklid stets terminiert, dass bei jedem Aufruf ein Parameter um mindestens den Wert 1 verringert wird und dass wenn der zweite (stets kleinere) Parameter den Wert 1 hat die Rekursion spätestens endet. Damit kann es maximal max{a,b} viele rekursive Aufrufe geben.
Anmerkung:
Die obige Laufzeit ist nur eine grobe obere Abschätzung. Die tatsächliche Worst‐case‐Laufzeit ist O(log(ab)) (mehr zur O‐Notation später)
Fazit
BearbeitenWelche Strategie (optimistisch, pessimistisch) und welches Verhalten man bei nicht‐erfüllten Vorbedingungen zeigt, hängt von vielen Faktoren ab:
– Bei unkritischen oft aufzurufenden Algorithmen könnte die Überprüfung der Zulässigkeit zu viel Aufwand sein
– Bei zeitintensiven Algorithmen kann durch eine Überprüfung Zeit gespart werden
Man sollte das Verhalten seines Algorithmus im Fehlerfall aber stets gut dokumentieren!
Literatur
BearbeitenDa die Vorlesungsinhalte auf dem Buch Algorithmen und Datenstrukturen: Eine Einführung mit Java von Gunter Saake und Kai-Uwe Sattler aufbauen, empfiehlt sich dieses Buch um das hier vorgestellte Wissen zu vertiefen. Die auf dieser Seite behandelten Inhalte sind in Kapitel 8 zu finden.