Praktische Einführung und Programmierung
Stefan Bosse
Universität Koblenz - FB Informatik
Stefan Bosse - Algorithmen und Datenstrukturen - Modul A Einführung in Algorithmen und Datenstrukturen ::
――――┐ ┌――――――――――┐ │ │Problem │ ┌―――――――――――――┐ ┌――――――――――┐ │ ├――――――――――┼――▶│Algorithmus A├――▶│Programm A│ │ │Aufgabe │ └―――――――――――――┘ └――――――――――┘ │ Programmier-└――――――――――┘ ┌―――――――――――――┐ ┌――――――――――┐ │ sprachen ┌――――――――┤Algorithmus B├――▶│Programm B│ │ │ └――――――┬――――――┘ └―――――┬――――┘ │ ┌―――――┴――――┐ │ Messen? │ │ │Daten- │ ▼ ▼ ――――┘ │struktur 1│ ┌――――――――――――――――――――――――――――┐ └――――――――――┘ │ Komplexität / Effizienz ? │ ┌――――――――――┐ └――――――――――――――――――――――――――――┘ │Daten- │ │struktur 2│ └――――――――――┘
Stefan Bosse - Algorithmen und Datenstrukturen - Modul A Einführung in Algorithmen und Datenstrukturen :: Literatur
Algorithmen und Datenstrukturen
Thomas Ottman
Peter Widmayer
Spektrum Verlag
Algorithmen und Datenstrukturen
Eine Einführung in Java
Gunter Saake, Kai Uwe Sattler
dpunkt Verlag
Stefan Bosse - Algorithmen und Datenstrukturen - Modul A Einführung in Algorithmen und Datenstrukturen :: Historischer Überblick: Algorithmen
Das Wort Algorithmus ist ein Kunstwort aus dem Namen dieses Mathematikers und dem griechischen »arithmos« für Zahl.
Stefan Bosse - Algorithmen und Datenstrukturen - Modul A Einführung in Algorithmen und Datenstrukturen :: Historischer Überblick: Algorithmen
Auch für den Bereich der Datenstrukturen können lang zurückreichende Wurzeln gefunden werden, etwa das Indexierungssystem historischer Bibliotheken.
Stefan Bosse - Algorithmen und Datenstrukturen - Modul A Einführung in Algorithmen und Datenstrukturen :: Praktische Eigenschaften von Algorithmen
Stefan Bosse - Algorithmen und Datenstrukturen - Modul A Einführung in Algorithmen und Datenstrukturen :: Praktische Eigenschaften von Algorithmen
Algorithmen verarbeiten Daten. Daten müssen wie Algorithmen strukturiert werden. Daher der Name dieser Veranstaltung.
Stefan Bosse - Algorithmen und Datenstrukturen - Modul A Einführung in Algorithmen und Datenstrukturen :: Formale Beschreibung von Algorithmen
Ein Algorithmus beschreibt eine Abbildung:
f:E→A
mit
Aber: Nicht jede Abbildung f: E → A lässt sich durch einen Algorithmus realisieren (Berechenbarkeit!)
Stefan Bosse - Algorithmen und Datenstrukturen - Modul A Einführung in Algorithmen und Datenstrukturen :: Formale Eigenschaften von Algorithmen
Welche formalen Eigenschaften von Algorithmen werden studiert?
Stefan Bosse - Algorithmen und Datenstrukturen - Modul A Einführung in Algorithmen und Datenstrukturen :: Formale Eigenschaften von Algorithmen
Welche formalen Eigenschaften von Algorithmen werden studiert?
Die wichtigste formale Eigenschaft eines Algorithmus ist zweifellos dessen Korrektheit!
Stefan Bosse - Algorithmen und Datenstrukturen - Modul A Einführung in Algorithmen und Datenstrukturen :: Formale Eigenschaften von Algorithmen
Welche formalen Eigenschaften von Algorithmen werden studiert?
Die wichtigste formale Eigenschaft eines Algorithmus ist zweifellos dessen Korrektheit!
Aber kann die Korrektheit (d.h. Fehlerfreiheit) eines Algorithmus oder besser dessen Implementierung mit einer Programmiersprache überhaupt bewiesen werden? Uff.
Stefan Bosse - Algorithmen und Datenstrukturen - Modul A Einführung in Algorithmen und Datenstrukturen :: Formale Eigenschaften von Algorithmen
Die zweite wichtige formale Eigenschaft eines Algorithmus ist dessen Effizienz.
Wir müssen zwischen Algorithmen (also Berechungsvorschriften) und deren Implementierung mit einer Programmiersprache unterscheiden. Welche Programmiersprachen und Programmiermodelle?
Stefan Bosse - Algorithmen und Datenstrukturen - Modul A Einführung in Algorithmen und Datenstrukturen :: Programmiersprachen und Programmiermodelle
Algorithmen werden mit Programmiersprachen implementiert (Handwerkzeug)
Es gibt verschiedene Programmiermodelle und Klassen:
Stefan Bosse - Algorithmen und Datenstrukturen - Modul A Einführung in Algorithmen und Datenstrukturen :: Laufzeit und Komplexität
Die Laufzeit ist messbar, die Rechenkomplexität nur bestimmbar/ableitbar!
Rechnekomplexität bedingt auch eine Speicherkomplexität!
Stefan Bosse - Algorithmen und Datenstrukturen - Modul A Einführung in Algorithmen und Datenstrukturen :: Laufzeit und Komplexität
Beispiel statischer und dynamischer Speichebedarf
D=[1,2,3,4,5,6,7,8,9,10] // N=10, |A|=10*Bsum=0// Fall 1for(i=0;i<D.length;i++) sum+=D[i]// Fall 2function dosum(i) { if (i>0) D[i]+dosum(i-1); return D[0]}sum=dosum(D.length-1)
Wo liegen die Unterschiede in Fall 1 und 2 beim Speicherbedarf bezogen auf N?
Stefan Bosse - Algorithmen und Datenstrukturen - Modul A Einführung in Algorithmen und Datenstrukturen :: Laufzeit und Komplexität
Fall 1
Fall 2
Stefan Bosse - Algorithmen und Datenstrukturen - Modul A Einführung in Algorithmen und Datenstrukturen :: Messbarkeit von Effizienz
Nochmal wichtigste Eiegenschaften eines Algorithmus: Korrektheit und Effizienz
Man könnte beides durch Implementation des Algorithmus in einer konkreten Programmiersprache auf einem konkreten Rechner für eine Menge repräsentativ gewählter Eingaben messen.
Solche experimentell ermittelten Meßergebnisse lassen sich aber nicht oder nur schwer auf andere Implementationen und andere Rechner übertragen und sind nicht vollständig, sondern immer exemplarisch.
Stefan Bosse - Algorithmen und Datenstrukturen - Modul A Einführung in Algorithmen und Datenstrukturen :: Messbarkeit von Effizienz
Das Ziel ist, den für ein Problem besten Algorithmus zu finden und zu implementieren.
Stefan Bosse - Algorithmen und Datenstrukturen - Modul A Einführung in Algorithmen und Datenstrukturen :: Messbarkeit von Effizienz
Gegeben sei eine Folge X von N ganzen Zahlen in einem Array. Gesucht ist die maximale Summe aller Elemente in einer zusammenhängenden Teilfolge. Sie wird als maximale Teilsumme bezeichnet, jede solche Folge als maximale Teilfolge.
───────────────────────────────────────────────1 2 3 4 5 6 7 8 9 10 Index───────────────────────────────────────────────31 -41 59 26 -53 58 97 -93 -23 84 Zahlen───────────────────────────────────────────────
Für die Eingabefolge X[1::10] ist die Summe der Teilfolge X[3::7] mit Wert 187 die Lösung des Problems.
Stefan Bosse - Algorithmen und Datenstrukturen - Modul A Einführung in Algorithmen und Datenstrukturen :: Messbarkeit von Effizienz
maxtsumme = 0for (u=0;u<N;u++) { for (o=u;o<N;o++) { // bestimme die Summe der Elemente in der Teilfolge X [ u : : o ] Summe = 0; for (i=u; i<=o;i++) Summe = Summe + X[i]; // bestimme den größeren der beiden Werte Summe und maxtsumme maxtsumme = max (Summe, maxtsumme) }}
Naives Verfahren für die Suche nach der größten Teilsumme
Anzahl der Einheitsoperationen:
N−1∑u=0N−1∑o=uo∑i=u1=N(N−1+N−2+..+1)(1+2+3+..+N−1)=f(N3)
Stefan Bosse - Algorithmen und Datenstrukturen - Modul A Einführung in Algorithmen und Datenstrukturen :: Messbarkeit von Effizienz
Stefan Bosse - Algorithmen und Datenstrukturen - Modul A Einführung in Algorithmen und Datenstrukturen :: Messbarkeit von Effizienz
Jetzt folgen wir dem Divide-and-conquer-Prinzip (DaC) zur Lösung des Maximum-Subarray-Problems. Die Anwendbarkeit dieses Prinzips ergibt sich aus folgender Überlegung:
Wird eine gegebene Folge in der Mitte geteilt, so liegt die maximale Teilfolge entweder
Im letzteren Fall gilt für das in einem Teil liegende Stück der maximalen Teilfolge:
Warum Divide-and-Conquer?
Stefan Bosse - Algorithmen und Datenstrukturen - Modul A Einführung in Algorithmen und Datenstrukturen :: Messbarkeit von Effizienz
Jetzt folgen wir dem Divide-and-conquer-Prinzip (DaC) zur Lösung des Maximum-Subarray-Problems. Die Anwendbarkeit dieses Prinzips ergibt sich aus folgender Überlegung:
Wird eine gegebene Folge in der Mitte geteilt, so liegt die maximale Teilfolge entweder
Im letzteren Fall gilt für das in einem Teil liegende Stück der maximalen Teilfolge:
Warum Divide-and-Conquer?
DaC basiert auf Rekursion und rekursive Zerlegung eines Problems in kleine (elementare) Probleme.
Stefan Bosse - Algorithmen und Datenstrukturen - Modul A Einführung in Algorithmen und Datenstrukturen :: Messbarkeit von Effizienz
Wir wollen die maximale Summe von Elementen, die das linke bzw. das rechte Randelement einer Folge von Elementen enthält, kurz das linke bzw. rechte Randmaximum nennen.
Das linke Randmaximum lmax für eine Folge X[l] ... X[r] ganzer Zahlen kann man in ungefähr (r-l) Schritten (also linear) wie folgt bestimmen:
lmax = 0summe = 0for (i=l;i<=r;i++) { summe = summe + X[i] lmax = max (lmax,summe)}
Stefan Bosse - Algorithmen und Datenstrukturen - Modul A Einführung in Algorithmen und Datenstrukturen :: Messbarkeit von Effizienz
function maxtsum (X) { // f liefert eine maximale Teilsumme der Folge X ganzer Zahlen g if (length(X)==1) { a=X[0] if (a > 0) result = a else result = 0 } else { // Divide: // teile X in eine linke und eine rechte Teilfolge A und B annähernd gleicher Größe; j = floor(length(X)/2) A = slice(X,[0,j]); B=slice(X,[j+1,length(X)-1]) // Conquer: maxtinA = maxtsum (A) maxtinB = maxtsum (B) // bestimme das rechte Randmaximum rmax ( A ) der linken Teilfolge A; // bestimme das linke Randmaximum lmax ( B ) der rechten Teilfolge B; // Merge: result = max(maxtinA, maxtinB, rmax(A) + lmax (B)) } return result}
Der gesamte DaC Algorithmus zur Suche der maximalen Teilsumme
Stefan Bosse - Algorithmen und Datenstrukturen - Modul A Einführung in Algorithmen und Datenstrukturen :: Messbarkeit von Effizienz
Bezeichnet nun T(N) die Anzahl der Schritte, die erforderlich ist, um den Algorithmus maxtsum für eine Folge der Länge N auszuführen, so gilt offenbar folgende Rekursionsformel:
T(N)=2T(N2)+Const⋅N
Man erhält dann für die Größenordnung der Berechungen (also maxtsum Aufrufe) folgende asymptotische Näherung:
T(N)=f(N⋅log(N))
Stefan Bosse - Algorithmen und Datenstrukturen - Modul A Einführung in Algorithmen und Datenstrukturen :: Messbarkeit von Effizienz
Wir haben eine aufsteigend sortierte, lineare Folge von Inspektionsstellen (oder: Ereignispunkten), die Positionen 1...N der Eingabefolge.
Wir durchlaufen die Eingabe in der durch die Inspektionsstellen vorgegebenen Reihenfolge
Stefan Bosse - Algorithmen und Datenstrukturen - Modul A Einführung in Algorithmen und Datenstrukturen :: Messbarkeit von Effizienz
Prinzip des aufsteigenden Scan-line Verfahrens mit den bisMax und ScanMax Variablen
Nehmen wir nun an, daß wir bereits ein Anfangsstück der Länge l der gegebenen Folge inspiziert haben und die maximale Teilsumme bisMax sowie das rechte Randmaximum ScanMax in diesem Anfangsstück kennen.
Was ist die maximale Teilsumme, wenn man das (l+1)-te Element, sagen wir a, hinzunimmt?
Stefan Bosse - Algorithmen und Datenstrukturen - Modul A Einführung in Algorithmen und Datenstrukturen :: Messbarkeit von Effizienz
Q = [1,2,..,N] // Folge der Inspektionsstellen von links nach rechts = Folge der Positionen 1 ... N // InitialisiereScanMax = 0;bisMax = 0;while (length(Q)) { q = head(Q); Q=tail(Q) a = X[Q[q]] // update ScanMax und bisMax if ((ScanMax + a) > 0) ScanMax = ScanMax + a else ScanMax = 0; bisMax = max ( bisMax, ScanMax )}
Vollständiger Algorithmus des Scan-line Verfahrens für die Maximumsuche. Am Ende enthält dann bisMax den gewünschten Wert.
Stefan Bosse - Algorithmen und Datenstrukturen - Modul A Einführung in Algorithmen und Datenstrukturen :: Messbarkeit von Effizienz
T(N)=f(N)
Achtung: Wie betrechten bisher nur algorithmische Durchläufe von Berechnungen bie der Laufzeit. Tatsächlich muss man sich die Gesamtzahl an Rechneoperationen anschauen um eine Aussage der Effiziez und Vergleichbarkeit zu ermöglichen. Das ist vor allem bei "kleineren" N ein signifikantes Problem.
Schon kleine Änderung in der Implementierung können signifikanten Einfluss auf die Gesamtrechenzeit habem (aber nicht unbedingt auf f(N)!)
Stefan Bosse - Algorithmen und Datenstrukturen - Modul A Einführung in Algorithmen und Datenstrukturen :: Messbarkeit von Effizienz
Q = [1,2,..,N] // Folge der Inspektionsstellen von links nach rechts = Folge der Positionen 1 ... N // InitialisiereScanMax = 0;bisMax = 0;for (q=0;q<length(Q);q++) { a = X[Q[q]] // update ScanMax und bisMax if ((ScanMax + a) > 0) ScanMax = ScanMax + a else ScanMax = 0; bisMax = max ( bisMax, ScanMax )}
Version 2: Vollständiger Algorithmus des Scan-line Verfahrens für die Maximumsuche. Am Ende enthält dann bisMax den gewünschten Wert.
Stefan Bosse - Algorithmen und Datenstrukturen - Modul A Einführung in Algorithmen und Datenstrukturen :: Beweis der Korrektheit
Beispiel: Multiplikation zweier Binärzahlen a und b so dass z = a*b ist.
x = a; y = b;z = 0;while (y > 0) { if (!odd(y)) { y = y / 2; x = x + x } else { y = y - 1 z = z + x }}
Stefan Bosse - Algorithmen und Datenstrukturen - Modul A Einführung in Algorithmen und Datenstrukturen :: Beweis der Korrektheit
x y1 1 0 1 • 1 0 1 1 1 0 1 0 0 0 0 1 1 0 1───────────────── 1 0 0 0 0 0 1
Stefan Bosse - Algorithmen und Datenstrukturen - Modul A Einführung in Algorithmen und Datenstrukturen :: Beweis der Korrektheit
Um das zu zeigen, benutzen wir eine sogenannte Schleifeninvariante; das ist eine den Zustand der Rechnung charakterisierende, von den Variablen abhängende Bedingung. In unserem Fall nehmen wir die Bedingung:
P:y≥0∧z+x⋅y=a⋅b
und zeigen, daß die folgenden drei Behauptungen gelten.
Stefan Bosse - Algorithmen und Datenstrukturen - Modul A Einführung in Algorithmen und Datenstrukturen :: Beweis der Korrektheit
Nehmen wir einmal an, diese drei Behauptungen seien bereits bewiesen. Dann er-halten wir die gewünschte Aussage, daß das Programmstück terminiert und am Ende z = a • b ist, mit den folgenden Überlegungen.
Stefan Bosse - Algorithmen und Datenstrukturen - Modul A Einführung in Algorithmen und Datenstrukturen :: Beweis der Korrektheit
(y≥0∧z+xy=ab)∧(y>0)
Fall 1: [y ist gerade] Dann wird y halbiert und x verdoppelt. Es gilt also nach Ausführung der if-Anweisung {*} immer noch (y ≥ 0 und z + x • y = a • b).
Fall 2: [y ist ungerade] Dann wird y um 1 verringert und z um x erhöht und daher gilt ebenfalls nach Ausführung der if-Anweisung wieder (y ≥ 0 und z + x • y = a • b).
Stefan Bosse - Algorithmen und Datenstrukturen - Modul A Einführung in Algorithmen und Datenstrukturen :: Beweis der Korrektheit
□
Das war ein sehr einfacher Algorithmus (10 Zeilen Pseudocode). Der Linux Kernel besteht aus mehr als 10 Millionen Zeilen Programmcode. Viel Spaß beim Beweisen! Reale Programe können nicht bewiesen werden (was zu beweisen wäre).
Stefan Bosse - Algorithmen und Datenstrukturen - Modul A Einführung in Algorithmen und Datenstrukturen :: Kosten von Algorithmen
Wie effizient ist das angegebene Multiplikationsverfahren?
Zunächst ist klar, daß das Verfahren nur konstanten Speicherplatz benötigt, wenn man das Einheitskostenmaß zu-grundelegt, denn es werden nur drei Variablen zur Aufnahme beliebig großer ganzer Zahlen verwendet.
Legt man das logarithmische Kostenmaß zugrunde, ist der Speicherplatzbedarf linear von der Summe der Längen der zu multiplizierenden Zahlen abhängig.
Es macht wenig Sinn, zur Messung der Laufzeit das Einheitskostenmaß zugrunde zu legen. Denn in diesem Maß gemessen ist die Problemgröße konstant gleich 2.
Wir interessieren uns daher für die Anzahl der ausgeführten arithmetischen Operationen in Abhängigkeit von der Länge und damit der Größe der zwei zu multiplizierenden Zahlen a und b.
□ Gesamtlaufzeit von der Größenordnung O(Länge(b) • (Länge(a) + Länge(b)))
Stefan Bosse - Algorithmen und Datenstrukturen - Modul A Einführung in Algorithmen und Datenstrukturen :: Beschreibung von Algorithmen
In diesem Kurs:
Stefan Bosse - Algorithmen und Datenstrukturen - Modul A Einführung in Algorithmen und Datenstrukturen :: Beschreibung von Algorithmen
Pseudo-Js JAVA ┌――――――――――――――――――――――――――┐ ┌――――――――――――――――――――――――――┐│x={n:1} │ │public class Counter { ││function up(counter) { │ │ int n; ││ counter.n=counter.n+1 │ │ void up() { ││} │ │ n=n+1 ││function down(counter) { │ │ } ││ counter.n=counter.n-1 │ │ void down() { ││} │ │ n=n-1 ││up(x) │ │ } ││ │ │} ││ │ │Counter x=new Counter(); │└――――――――――――――――――――――――――┘ └――――――――――――――――――――――――――┘
Ein Beispiel Pseudo-Js ⇔ JAVA
Stefan Bosse - Algorithmen und Datenstrukturen - Modul A Einführung in Algorithmen und Datenstrukturen :: Pseudonotationen
Pseudocode-Notation für Algorithmen
Die eingangs genannten Bausteine sind dafür geeignet, auf der intuitiven Ebene (also nicht auf der Basis mathematischer Strenge) Algorithmen zu formulieren.
Ein Aspekt der Formulierung ist die Nutzung einer genormten, festgelegten Ausdrucksweise.
Wir werden eine derartige Ausdrucksweise kennen lernen, die die genannten Bausteine benutzt und auf einer leicht verständlichen Ebene bleibt.
Da die Formulierung der Algorithmen nahe an den Konstrukten verbreiteter Programmiersprachen ist, in denen Programme »kodiert« werden, bezeichnet man diese intuitiven Algorithmen auch als Pseudocode-Algorithmen.
Stefan Bosse - Algorithmen und Datenstrukturen - Modul A Einführung in Algorithmen und Datenstrukturen :: Pseudonotationen
A&D Dpunkt Verlag Notation für Struktogramme
Stefan Bosse - Algorithmen und Datenstrukturen - Modul A Einführung in Algorithmen und Datenstrukturen :: Pseudonotation JavaScript
Was wird benutzte:
That's all folks!
Stefan Bosse - Algorithmen und Datenstrukturen - Modul A Einführung in Algorithmen und Datenstrukturen :: Pseudonotation JavaScript
x = ε// Arithmetisch/funktionalε := a+b, a*b, a/b, a%b, a<<b, a>>b, -a, foo(a,b,c,..)// Boolesschε := a&&v, a||b, !a// Logischε := a&v, a|b, ~a
Stefan Bosse - Algorithmen und Datenstrukturen - Modul A Einführung in Algorithmen und Datenstrukturen :: Pseudonotation JavaScript
return
Anweisung.function foo(a,b,c,..) { ... return ε } x=foo(ε1,ε2,ε3,..)
Stefan Bosse - Algorithmen und Datenstrukturen - Modul A Einführung in Algorithmen und Datenstrukturen :: Pseudonotation JavaScript
Bedingte Verzweigung
if (ε) { .. }if (ε) { ..} else { .. }
Mehrfachauswahl
switch (ε) { case c1: .. break; case c2: .. break; case c3: .. break; default : ..}
Schleifen
for(i=ε;i<ε;i=ε(i)) { .. } while (ε) { .. } do { .. } while (ε)
Stefan Bosse - Algorithmen und Datenstrukturen - Modul A Einführung in Algorithmen und Datenstrukturen :: Pseudonotation JavaScript
Man unterscheidet:
Zählschleife for(start;condition;update)
mit drei integrierten Anweisungen: Einer Initialisierung (einer oder mehrere Zählvariablen), einer Schleifenbedingung die vor jedem Durchlauf getestet wird (i.A. der Zählvariable), und einer Update Anweisung die nach jedem Schleifendurchlauf ausgeführt wird (i.A. Veränderung der Zählvariable).
Abweisende Schleife while(condition)
die abhängig von der Schleifenbedingung niemals, einmal oder mehrmals den Schleifenkörper ausführt (Test vor Schleifendurchlauf).
Eine nicht abweisende Schleife do {} while(condfition)
die mindestens einmal den Schleifenkörper ausführt (Test nach jedem Schleifendurchlauf).
Stefan Bosse - Algorithmen und Datenstrukturen - Modul A Einführung in Algorithmen und Datenstrukturen :: Konkrete versa Abstrakte Datentypen
Datenstrukturen (Rekords) in JS
x = { a1 : ε, a2 : ε, ..}x.ai = ε(x.ai)
Stefan Bosse - Algorithmen und Datenstrukturen - Modul A Einführung in Algorithmen und Datenstrukturen :: Rekords versa Arrays
Rekord
x = { a:1, b:2, c:3}x.a=0sum=x.a+x.b.x.c
Array
x = [ 1, 2, 3]x[0]=0sum=x[0]+x[1]+x[2]
Stefan Bosse - Algorithmen und Datenstrukturen - Modul A Einführung in Algorithmen und Datenstrukturen :: Abstrakte Datentypen
Man unterscheidet grob zwei Klassen von Daten und Datenstrukturen:
Ein ADT ist durch (interne) Datenstrukturen und Operationen (Funktionen/Methoden) auf diesen Daten bezeichnet!