Programmierungstechnik
© Günter Riedewald
Die Folien sind eine Ergänzung zur Vorlesung
und nur für den internen Gebrauch konzipiert.
Vorbemerkungen
Rolle einer Vorlesung:
- Grundstruktur für Selbststudium
- Ermöglichung der selbständigen
Nutzung der Literatur
- Hinweis auf Probleme und
Gesamtzusammenhänge
Vorbemerkungen
Rolle von Übungen:
- Ergänzung der Vorlesung durch
umfangreichere Beispiele
- Dialog von Übungsleiter und Student
zur Beseitigung von Unklarheiten
- Aktive Mitarbeit als Voraussetzung der
aktiven Auseinandersetzung mit dem
Stoff
Vorbemerkungen
Vorlesungshilfsmittel:
- Tafel
 - Schreibarbeit für beide Seiten
+ Hören-Sehen-Schreiben in
Kombination erleichtert Verständnis
und Merkfähigkeit
+ Ableitungen besser darstellbar
Vorbemerkungen
-
Folien
 +- Vermittlung von mehr Stoff
+- Schreibarbeit entfällt
- Höherer Aufwand zur Einprägung
des Stoffes
Vorbemerkungen
Multimedia
 - Hoher Entwicklungs- und
Wartungsaufwand
- Bisher kein Nachweis eines deutlich
höheren Lerneffekts
+ Darstellung dynamischer Vorgänge
Hier: Kombination von Tafel und Folien
-
Vorbemerkungen
Literaturstudium:
- Ausführliche Beschäftigung mit dem Stoff
- Andere Sichten
- Mehrmaliges Lesen:
1. Diagonal  Überblick
2. Durcharbeiten  gründliches
Verständnis
Vorbemerkungen
Prüfungen:
- Nachweis von Wissen und Fähigkeit der
aktiven Nutzung (Verstehen 
Wiedergabe  Anwendung)
- Prüfungsvorbereitung führt zur
Verknüpfung von Teilgebieten und mit
anderen Lehrgebieten
Vorbemerkungen
Abschlüsse und Bedingungen:
- Studiengang Informatik (Fachprüfung
Praktische Informatik):
1. Sem.: schriftliche Prüfung (ca. 150 min)
2. Sem.: benoteter Leistungsnachweis
3. Sem.: mündliche Prüfung (ca. 20 min)
über PT und SWT (Vor.: Benoteter
Leistungsnachweis)
Vorbemerkungen
-
Studiengang IT/TI:
1. Sem.: schriftliche Prüfung (ca. 150
min)
2. Sem.: mündliche Prüfung (ca. 30
min)
Vorbemerkungen
-
Studiengang WIN/BIN:
2. Sem.: benoteter Leistungsschein
3. Sem.: mündliche Prüfung (ca. 30
min) zu PT und SWT
Vorbemerkungen
Rolle der Theorie:
- Schnelles Veralten von Wissen zu
konkreten Systemen
- Langlebige und allgemeingültige
Erkenntnisse in der Theorie
- Theorie als Basis (Befähigung zur)
Weiterbildung
Vorbemerkungen
Theorie als Basis der Automatisierung
von Prozessen der IV
- Schnelle Einsatzbereitschaft von
Absolventen erfordert Praxiserfahrungen
- Realitätsnahe Ausbildung an HS schwer
zu verwirklichen
 Ausbildung als Mix von Theorie und
Praxis
-
Vorbemerkungen
Rolle der Theorie nach J. Nievergelt
(Informatik-Spektrum, 18(6), S. 342344, 1995)
Anwendungsmethodik
Systemrealisierung
Algorithmik
Theorie
Problemlösungen
Programmsysteme
Programmierung
abstrakte math.
Fakten
Literatur
Alagic’, S., Arbib, M.A.: The Design of WellStructured and Correct Programs, SpringerVerlag, 1978
Appelrath, H.-J., Ludewig, J.: Skriptum
Informatik - eine konventionelle Einführung,
B.G. Teubner Stuttgart, 1991
Literatur
Bauer, F.L., Goos, G.: Informatik - eine
einführende Übersicht
Heidelberger Taschenbücher, Sammlung
Informatik, Springer-Verlag, Teile 1+2, 3.
Auflage, 1982, 1984, 4. Auflage 1991
Berman, K.A., Paul, J.L.: Fundamentals of
Sequential and Parallel Algorithms, PWS
Publishing Company, 1997
Literatur
Forbrig, P.: Introduction to Programming by
Abstract Data Type
Fachbuchverlag Leipzig, 2001
Goldschlager, L., Lister, A.: Informatik - Eine
moderne Einführung, Hanser Verlag, PrenticeHall International, 3. Auflage 1990
Literatur
Hotz, G.: Einführung in die Informatik, B.G.
Teubner Stuttgart, 1990
Kröger, F.: Einführung in die Informatik Algorithmenentwicklung, Springer-Lehrbuch,
Springer-Verlag, 1991
Literatur
Myers, G.J.: The Art of Software Testing, WileyInterscience Publication 1979
oder: Methodisches Testen von Programmen,
Oldenbourg Verlag, 4. Auflage, 1991
Pomberger, G.: Softwaretechnik und Modula-2,
Hanser Verlag, 1984
Literatur
Sedgewick, R.: Algorithmen, Addison-Wesley
Publ. Company, 1992, 2002 2.Auflage
Sedgewick, R.: Algorithmen in Java
Addison-Wesley Publ. Comp., 2003
Sedgewick, R.: Algorithmen in C++
Addison-Wesley Publ. Comp., 2002
Literatur
Weitere Literatur: z. B. von den Autoren
Broy, Gruska, Kerner, Wilhelm
Siehe auch Lehrbücher zu konkreten
Programmiersprachen
Inhalt
1. Einleitung
2. Grundbegriffe
3. Algorithmenentwurf und Programmentwicklung
3.1 Einleitung
3.2 Programmierungstechniken
3.3 Techniken der Algorithmenentwicklung
(Iteration, Rekursion, nichtdeterministische
Algorithmen, Backtracking, parallele Algorithmen)
3.4 Korrektheit, Zuverlässigkeit
3.4.1 Programmteste
3.4.2 Korrektheitsbeweise (Verifikation)
3.4.2.1 Deduktive Methode
3.4.2.2 Model Checking
3.5 Datenstrukturen
3.5.1 Einleitung
3.5.2 Mathematische Grundlagen
3.5.3 Fehlerbehandlung
3.5.4 Datenstrukturen und ihre
Implementation
4. Existenz und Durchführbarkeit von
Algorithmen
4.1 Berechenbarkeit, Terminiertheit,
Durchführbarkeit
4.2 Komplexität
4.3 Nichtprozedurale Algorithmen
5. Ausgewählte Algorithmen
5.1 Sortierverfahren
5.1.1 Adressenorientiertes Sortieren
5.1.2 Assoziatives Sortieren
5.2 Suchverfahren
5.2.1 Einleitung
5.2.2 Suchalgorithmen auf der Basis von
Adressberechnungen (Hashing, perfektes
Hashing, digitale Suchbäume, Tries)
5.2.3 Assoziatives Suchen (Suchen in
geordneten Mengen)
5.2.3.1 Suchverfahren
5.2.3.2 Gewichtete Bäume
5.2.3.3 Balancierte Bäume
(gewichtsbalanciert, höhenbalanciert)
5.3 Heuristische Algorithmen
5.4 Evolutionsalgorithmen
6. Funktionales Programmieren
6.1 Funktionen in der Mathematik
6.2 Datentypen und Programmierung
Problem 1
Problem 2
Anwendung 1
Mathe.
Modell
Software
Problem n
Anwendung m
Abstraktion
Spezialisierung
Datenverarbeitung:  = (N, I), : D  D
N
Nachricht
Nachricht´

Information
Information´
I
dD
d´  D
Spezifikation
Algorithmus in
mathematischer Notation
Algorithmus in höherer
Programmierung Programmiersprache
Übersetzung
Algorithmus in
Maschinensprache
Flussbilder - Grundelemente
Verarbeitungsblock
<Anweisungsfolge>
x := x + 1
y := 0
Bedingung
nein
nein
ja
ja
x<0
Flussbilder - Grundelemente
Konnektoren
<Zahl>
<Zahl>
Gerichtete Kanten
25
25
Motto
Bevor ein Zimmermann ein Haus baut,
muss er einen Plan dafür erarbeiten.
Eine Hundehütte kann er jederzeit auch
ohne große Vorbereitung bauen.
Schrittweise Verfeinerung –
Beispiel 1
Zubereitung einer
Tasse Kaffee
Koche Wasser
Kaffee in Tasse
Wasser in Tasse
Wasser in Einschalten Warten bis
Kessel
zum Kochen
Schrittweise Verfeinerung –
Beispiel 2
Sortieren einer Folge F zu F´
Zerlegung
in F1 und F2
Sortierung
von F1 zu F1´
von F2 zu F2´
Mischen
von F1´ und
F2´ zu F´
Schrittweise Verfeinerung
Beispiel 3
program ggt( (*a,b*));
(*Vereinbarungen*)
begin
(* Eingabe a,b *)
x := a; y := b;
while y<>0 do
begin (* Verkleinerung von y; Änderung von x *)
end ;
(* Ausgabe ggt(a,b)*)
end.
Struktogramme
Verarbeitungsblock
<Anweisungen>
Lies N
Block mit Bezeichnung
<Name>
Maxberech
Struktogramme
Reihung zweier Blöcke
Lies m, k
y := m * k
Wiederholung (abweisender Zyklus)
<Bedingung>
x>0
<Anweix := x * 1
sungen>
y := y + 2
Struktogramme
Wiederholung (nichtabweisender Zyklus)
<Anweix := x – 1
sungen>
y := y + 2
<Bedingung>
x<0
Wiederholung (Zählzyklus)
v=a,e,s
i=1, 10, 2
<Anweisungen>
s := s + 1
Struktogramme
Wiederholung (ohne Bedingung)
<Anweisungen>
Alternative (einfach)
<Bedingung>
true
false
<Anw>
<Anw>
Temperaturmessung
x>0
true
z := 1
false
z := 0
Struktogramme
Fallabfrage (mehrfache Alternative)
<Ausdruck>
W1 W2 ... Wn
A1 A2 ... An
s
-1
0
1
x := 0 y := 0 z := 0
Struktogramme
Abbruchanweisung
<Name>
S1
B1
B2
true
A1
false
S1
A2
S2
Beziehungen
Dienstmodul - Kundenmodul
Datenmodul
Dienstmodul
-
-
Definitionsmodul: Datentypen, Konstanten,
Variablen
Implementationsmodul: leer
Kundenmodul
Nutzung der Daten
Beziehungen
Dienstmodul - Kundenmodul
Funktionsmodul
Dienstmodul
-
Definitionsmodul: Prozedur/Funktionsköpfe
Implementationsmodul:
Prozedur/Funktionsrümpfe
Kundenmodul
Lokale Daten und Prozedur/Funktionsaufrufe
Beziehungen
Dienstmodul - Kundenmodul
Datenkapsel
Dienstmodul
-
Definitionsmodul: Prozedur/Funktionsköpfe
Implementationsmodul:
Prozedur/Funktionsrümpfe und Daten
Kundenmodul
Prozedur/Funktionsaufrufe (keine eigenen
Daten)
Beziehungen
Dienstmodul - Kundenmodul
Abstrakter Datentyp
Dienstmodul
-
-
Definitionsmodul: Prozedur/Funktionsköpfe,
Datentyp
Implementationsmodul: Struktur des
Datentyps, Prozedur/Funktionsrümpfe
Kundenmodul
Prozedur/Funktionsaufrufe, Daten zum
Datentyp




DEFINITION MODULE Dateimanager;
(*Dateimanipulationsroutinen*)
CONST Endnr = 65535; (* groesste Kontonr*)
TYPE Kontonr = CARDINAL;



PROCEDURE AddiereWert;
(*addiert Wert des letzten Bewegungsdatensatzes zum Datensatz im
Ausgabepuffer*)



PROCEDURE SchliesseDateien;
(*schliesst alle Dateien*)



PROCEDURE AusNeuStamm;
(*schreibt Ausgabepuffer in neue Stammdatei*)





PROCEDURE EinBewegung(VAR Bewnr: Kontonr);
(*liefert einen Datensatz der Bewegungsdatei und seine Nummer*)
...
END Dateimanager.



IMPLEMENTATION MODULE Zufall;
(*Zufallszahlen nach der Kongruenzmethode*)
FROM InOut IMPORT WriteString, WriteLn, WriteCard, ReadCard;



CONST Modulus = 2345; Faktor = 3; Inkrement = 7227;
VAR Seed: CARDINAL;









PROCEDURE RandomCard(A, B: CARDINAL): CARDINAL;
VAR random: REAL;
BEGIN
Seed := (Faktor*Seed+Inkrement) MOD Modulus;
random := FLOAT(Seed)/FLOAT(Modulus);
random := random*(FLOAT(B)-FLOAT(A)+1.0)+FLOAT(A);
RETURN TRUNC(random)
END RandomCard;





BEGIN
WriteString(‘Zufallszahlen’); WriteLn; WriteString(‘Startwert?’);
ReadCard(Seed); WriteLn
END Zufall.

















DEFINITION MODULE Konserve;
TYPE tName = ARRAY [0..79] OF CHAR;
tWochentag = (Montag, Dienstag, Mittwoch, Donnerstag, Freitag,
Samstag, Sonntag);
tMonat = (Januar, Februar, Maerz, April, Mai, Juni, Juli, August,
September, Oktober, November, Dezember);
tDatum = RECORD
Tag:[1..31]; Monat: tMonat; Jahr: CARDINAL
END;
VAR Datum: tDatum;
Konto: RECORD
Name: tName; Kontonr: CARDINAL; datum: tDatum;
wert: RECORD mod: (soll, haben);
mark: CARDINAL;
pfg: CARDINAL
END;
END;
CONST MaxCard = 65535; MaxInt = 32767; MinInt = (-32767) - 1
END Konserve.











DEFINITION MODULE Stapel;
(*fuer Cardinalzahlen*)
VAR Fehler: BOOLEAN;
(*Fehler, falls versucht wird, ein Element von einem
leeren Stapel zu entnehmen oder ein Element auf
einen vollen Stapel abzulegen*)
PROCEDURE leererStapel;
(*Initialisierung eines Stapels*)
PROCEDURE push(c: CARDINAL);
(*Zahl auf einen Stapel*)
PROCEDURE pop(VAR c: CARDINAL);
(*Zahl vom Stapel*)
END Stapel.










DEFINITION MODULE ADTPuffer;
TYPE Puffer;
PROCEDURE leere(VAR R: Puffer);
PROCEDURE leer(R: Puffer): BOOLEAN;
PROCEDURE voll(R: Puffer): BOOLEAN;
PROCEDURE push(VAR R: Puffer;
El: CARDINAL);
PROCEDURE pop(VAR R: Puffer);
PROCEDURE gen(VAR R: Puffer)
END ADTPuffer.











IMPLEMENTATION MODULE ADTPuffer;
(*Ringpuffer*)
IMPORT...
FROM...
CONST G = 8; (* G-1 Groesse des Ringpuffers*)
TYPE Puffer = POINTER TO Ring;
Ring = RECORD rng: ARRAY[1..G] OF
CARDINAL;
kopf, ende: [1..G]
END;
...
END ADTPuffer.







MODULE Ablage;
...
FROM ADTPuffer IMPORT Puffer, gen, leer,
voll, push, pop;
...
VAR Ordner1, Ordner2: Puffer;
...
END Ablage.
OOP - Beispiel
CLASS Complex(x,y);
REAL x,y;
BEGIN REAL re,im;
REAL PROCEDURE RealPart;
BEGIN RealPart := re; END RealPart;
REAL PROCEDURE ImaginaryPart;
BEGIN ImaginaryPart := im; END ImaginaryPart;
PROCEDURE Add(y); REF (COMPLEX) y;
BEGIN re := re + y.RealPart;
im := im + y.ImaginaryPart; END Add;
...
re := x; im := y;
END COMPLEX;
REF (COMPLEX) C1, C2, C3;
C1 :- NEW COMPLEX(-1,1);
C2 :- NEW COMPLEX(1,-1);
C1.Add(C2);
OOP - Klassenhierarchie
Geometrisches Objekt
Farbe, Zeichne,...
Lineares Objekt 2D-Objekt
3D-Objekt
Beispiel: Türme von Hanoi
1
2
...
n-1
n
(1)
Turm ti: Bausteine 1 - i
(2)
(3)
Reihenberechnung
Eingabe x,
Anfangswerte für
Summand T und
Summe S
Berechnung
S, T
Abbruchtest
p(T,S)
erfüllt
Ausgabe
nicht erfüllt
Reihenberechnung für sin x
Eingabe x,
I:=1; T:=x; S:=0;
xq:=-x*x
|T|<
Ausgabe S
erfüllt
nicht erfüllt
S:=S+T;
T:=T*xq/((I+1)*(I+2));
I:=I+2
Vollständige Induktion




Vor.: p:N0 Boolean (Prädikat), N0 = {0,1,..}
Induktionsanfang: Zu beweisen:
p(0) = WAHR (kürzer: p(0))
Induktionsvoraussetzung: Für alle n  N0
ist zu beweisen:
p(n) = WAHR  p(n+1)= WAHR
Induktionsschluss: Für alle n  N0 gilt
p(n) = WAHR.
Allgemeine Induktion




Vor.: p: M  Boolean, M induktiv definiert
Induktionsanfang: Für die Basiselemente
xM ist zu beweisen p(x) = WAHR.
Induktionsvoraussetzung: Für alle
Konstruktoren C und alle Elemente x1,...,xnM
ist zu beweisen: p(xi) = WAHR, i=1,...,n 
p(C(x1,...,xn)) = WAHR
Induktionsschluss: Für alle Elemente xM
gilt p(x) = WAHR.
Struktogramm - Hornerschema
i := 1;
k := a1
i= 2, n+1
k := k * x + ai
Kantorovič-Baum für Polynome
a1
a2
x
*
+
a3
x
*
+
...
an+1
+
x
Labyrinth - Beispiel
1
1
2
3
4
5
6
7
2
3
4
5
6
7
Polynom: a1x4 + a2x3 + a3x2 + a4x + a5
a4
x
x
*
*
a5
a3
x
+
*
*
a2
x
+
*
*
a1
+
*
+
Paralleles Sortieren – Beispiel
Jochen Karin Franz Bernd Sepp Jim Maria Pos
Jochen 1
0
1
1
0
1
0
4
Karin 1
1
1
1
0
1
0
5
Franz 0
0
1
1
0
0
0
2
Bernd 0
0
0
1
0
0
0
1
Sepp
1
1
1
1
1
1
1
7
Jim
0
0
1
1
0
1
0
3
Maria 1
1
1
1
0
1
1
6
Korrektheit
Intuitive Vorstellungen
Formal spezifizierte
über Eigenschaften
der Software
Eigenschaften der
Software
Durch Software
realisierte
Eigenschaften
Entwicklung von „funktionstreuer“
Software



Korrekte Software:
a) Anwendung korrekter Werkzeuge auf
Spezifikation
b) Verifikation nach Softwareentwicklung
c) Softwareentwicklung gekoppelt mit
Beweisverfahren
Softwareteste zur Fehlerentdeckung (auch
fehlende Fälle)
Simulation bei Echtzeitsoftware
Aussage zu Testen
Es gibt keinen Algorithmus, der für ein
beliebiges Programm eine solche
Testdatenmenge erzeugen könnte, dass ein
korrekter Test für die Testdaten auch die
Korrektheit für beliebige andere Daten
garantieren würde.
(Beweis durch Rekursionssatz)
Testmethoden
Kriterium
Art des Testobjekts
Art der Testausführung
Kenntnisse
über Testobjekt
Komponentenart
Methoden
Durchsicht von Test lauffähiger ProgramDokumenten
me durch Ausführung
statisch
dynamisch (Abarbeitung
(Inspektion)
mit Testdaten)
Strukturtest
Funktionstest (Struktur
(bekannte
unbekannt)
Struktur)
Modultest (einzelner Modul)
Integrationstest (Modulverbindung)
Systemtest (Gesamtsystem mit BS)
Auswahl von Testdaten –
Programmbeispiel
0
(A>1)  (B=0)
ja
1 X:=X/A
3
nein
2
(A=2)  (X>1)
ja
4 X:=X+1
nein
5
6
Äquivalenzmethode
Bedingung
Normalfälle
Fehlerfälle
Daten aus
Intervall
1 (im Intervall)
2 („vor“ und
„hinter“ Intervall)
Daten sind
Anzahl
1 (erlaubte
Anzahl)
2 (zu kleine und zu
große Anzahl)
Daten einer
Menge
1 (aus Menge)
1 (nicht aus Menge)
Vor- und Nachteile von Testmethoden

Funktionales Testen:
+ unabhängig von der Implementation
+ Entwicklung der Testfälle parallel zur
Codierung
- Redundanz in den Testdaten möglich, aber
nicht ausschließbar
- evtl. werden Programmteile nicht getestet
- Definition von Überdeckungsmaßen
schwierig
Vor- und Nachteile von Testmethoden
- Fortsetzung

Strukturelles Testen:
+ wenig Redundanz in den Testdaten
+ alle Programmteile werden erreicht
- Testdatenauswahl erst nach Codierung
möglich
- ausschließlicher Test des programmierten
Verhaltens
Ein- und Ausgabeverhalten – Beispiel
{x0y0} P {x=q*y+r0ry}
Programm
Eigenschaften
Voraussetzung: x  0, y > 0, x,y ganzzahlig
q := 0; r := x;
r  0 , y > 0, x = q*y + r
WHILE r  y DO
r  y, y > 0, r  0, x = q*y + r
r := r - y; q := q + 1
r  0, y > 0, x = q*y + r
OD;
Nach der Schleife: x = q*y + r, 0  r < y
Korrektheit
{Q} P {R} bedeutet:
Wenn die Aussage Q vor der Abarbeitung des
Teilprogrammes P wahr ist und die Abarbeitung von P
terminiert, dann ist die Aussage R nach der
Abarbeitung wahr (partielle Korrektheit).
oder
Wenn die Aussage Q vor der Abarbeitung des
Teilprogrammes P wahr ist, dann terminiert die
Abarbeitung von P und die Aussage R ist wahr (totale
Korrektheit).
Axiome und Schlussregeln (Auszug)
Axiom für die Wertzuweisung
V := E (V Variable, E Ausdruck):
{P’} V := E {P} ,
wobei P’ aus P durch Ersetzen der
nichtquantifizierten Auftreten von V
durch E entsteht (P’ ist die schwächste
Vorbedingung)
Axiome und Schlussregeln (Auszug)
Verkettungsregel
{P} A1 {Q}, {Q} A2 {R}
{P} A1; A2 {R}
Regel für die while-Anweisung
{PB} A {P}
{P} while B do A od {P not B}
Axiome und Schlussregeln (Auszug)
Implikationsregeln
{P} S {Q}, Q  R
{P} S {R}
P  R, {R} S {Q}
{P} S {Q}
Pfadformeln
EFp
EGp
p
p
p
p
Pfadformeln (Fortsetzung)
AFp
AGp
p
p
p
p
p
p
p
p
p
p
Model Checking – Railroad (1)
Train
Gate
X
A
D1
I
D2
O
a
D3
E
e
Y
l, r
Controller
Z
X, Y, Z..................clocks
D1.......................distance between A and I
A, I, O, E ..............sensors
D2.......................distance between I and O
a, l, r, e..................signals
D3.......................distance between O and E
V............................speed of the train
Model Checking – Railroad (2)
Train automaton
X:=0
0
X<5
d3=D3/V e
3
1
a
0
X>2
X=D1/V
i
o
d2=D2/V
2
Model Checking – Railroad (3)
Gate automaton
Y:=0
0
Y>1 and
Y<2
1
l
0
Y<1
u
3
d
r
Y:=0
2
Model Checking – Railroad (4)
Controller automaton
Z:=0
0
Z<1
r
3
1
a
0
l
e
Z:=0
Z=1
2
Model Checking – Railroad (5)
Beispiellauf (Zugautomat):
a
i
o
e
<0, 0> ----> <1, 0> ----> <2, 2.5> ----> <3, 3> ----><0, 4>
10
12.5
13
14
a
i
o
e
----> <1, 0> ----><2, 2.5> ----> <3, 3> ----> <0, 4>
20
22.5
23
24
Betrachtungsebenen von
Datenstrukturen




Datenstrukturen als abstrakte Objekte:
Darstellung von Eigenschaften und
Wirkungsweise von Operationen
Konkrete Repräsentation
Implementation in höherer
Programmiersprache
Implementation in Maschinensprache
Vorteile der Abstraktion





Konzentration auf Wesentliches
Unabhängigkeit von Repräsentation und
Programmiersprache
Austauschbarkeit von Implementationen bei
gleicher Schnittstelle
Wiederverwendbarkeit der Implementationen
Nutzerfreundlichkeit durch Verwendung des
Problemniveaus
Algebraische Vorgehensweise der
Softwareentwicklung
Anforderungsdefinition (informal)
Formalisierung
Test, Plausibilität
Algebraische Spezifikation
(Prototyping)
Verfeinerung
Verifikation
Algorithmische Spezifikation
Transformation
Imperatives Programm
Algebra ganzer Zahlen









Trägermenge der Algebra:  = {...,-2,-1,0,1,2,...}
Operationen der Algebra: Addition, Subtraktion,
Multiplikation, Division, Vergleiche
Funktionalität (Profil) der Operationen:
_+_:  x   
_*_:  x   
_/_:  x   
_-_:  x   
_<_:  x   
( steht für Boolean)
...
Algebra ganzer Zahlen - Fortsetzung
Eigenschaften der Operationen:
 Addition, Multiplikation: kommutativ, assoziativ,
distributiv
a+b=b+a
a*b=b*a
(a + b) + c = a + (b + c)
(a * b) * c = a * (b * c)
(a + b) * c = (a * c) + (b * c)
a,b,c  
 Subtraktion als Umkehrung zur Addition
...
ADT Ganze Zahlen (Ganz)
Datensorten: INT
Operationssymbole: + - pred succ 0
(für spätere Operationen Addition, Subtraktion,
Vorgänger, Nachfolger, Konstante 0)
Funktionalität:
_+_: INT x INT  INT
_-_: INT x INT  INT
0:
 INT
Signatur (Syntax)
pred:
INT  INT
succ:
INT  INT
ADT Ganze Zahlen (Ganz) - Fortsetzung
pred(succ(x)) = x
succ(pred(x)) = x
x+0=x
x + succ(y) = succ(x + y)
x + pred(y) = pred(x + y)
x-0=x
x - succ(y) = pred(x - y)
x - pred(y) = succ(x - y)
x+y=y+x
Termgleichungen
(Semantik)
Algebra Ganze Binärzahlen




Sorte: INT
Trägermenge: {...,-11,-10,-1,0,1,10,11,...}
Operator: +
Operation: +B Addition von Binärzahlen
Operator: succ
Operation: +B 1
Operator: pred
Operation: -B 1
Termalgebra




Sorte: INT
Trägermenge: alle Terme
Operator: +
Operation: +T „Addition“ von Termen, d.h.
t1 +T t2 = t1 + t2
Operator: succ
Operation: succT(t) = succ(t)
Operator: pred
Operation: predT(t) = pred(t)
Eigenschaften von Termgleichungen
Notation: - X: t1 = t2 bezeichnet eine Termgleichung
mit der Variablenmenge X
- x: s bezeichnet eine Variable der Sorte s
Eigenschaften:
 Reflexivität:
X: t = t
 Symmetrie: X: t1 = t2  X: t1 = t2
 Transitivität: X1: t1 = t2, X2: t2 = t3
 X1  X2: t1 = t3
Eigenschaften von Termgleichungen Fortsetzung



Substituierbarkeit: X1  {xs}: t1 = t2, X2: t3 = t4,
xs: S, t3  Ts, t4  Ts  X1  X2: t5 = t6,
t5 = t1[xs/t3], t6 = t1[xs/t4]
Abstraktion: X: t1 = t2, xs: S, xs  X
 X  {xs}: t1 = t2
Konkretisierung: X  {xs}: t1 = t2, t1  ...xs...  t2,
Menge der variablenfreien Terme der Sorte s ist
nicht leer  X: t1 = t2
Strukturelle Induktion
Voraussetzungen:  Signatur mit Sortenmenge S, p
Prädikat auf den Termen von 
Induktionsschritte:
Basis: Beweis für p(t) = WAHR für alle nullstelligen
Operationssymbole und Variablen
Schritt: Beweis für
Für alle Operationssymbole , alle Terme t1,...,tn
und (t1,...,tn) gilt:
p(ti) = WAHR, i = 1,...,n  p((t1,...,tn)) = WAHR
Schlussfolgerung: p(t) = WAHR für alle Terme t
Definition eines abstrakten Datentyps






Einführung von Sorten
Einführung von Operationssymbolen
Definition der Funktionalität der
Operationssymbole
Definition der Eigenschaften der Operationen
(Termgleichungen, Termersetzungsregeln)
Schnelles Prototyping
Umsetzung (Implementation) in höhere
Programmiersprache mit Verifikation
Modulares Programmieren,
objektorientiertes Programmieren und
Theorie der Algebren im Vergleich
Modulares Programmieren
-
-
Datenkapsel:
Daten – Operationen – Import/Export
Abstrakter Datentyp:
Datentyp – Operationen – Import/Export
Beschreibung durch Definitionsmodul
(Schnittstelle) und Implementationsmodul
Modulares Programmieren,
objektorientiertes Programmieren und
Theorie der Algebren im Vergleich (Forts.)
Objektorientiertes Programmieren
-
-
Objekt:
Daten (Attribute, Instanzvariablen) –
Operationen (Methoden)
Klasse (Objektbeschreibung):
Datentypen – Operationen- Vererbung
Beschreibung durch Schnittstelle und
Implementation
Modulares Programmieren,
objektorientiertes Programmieren und
Theorie der Algebren im Vergleich (Forts.)
Theorie der Algebren
-
-
Algebra:
Trägermengen – Operationen – Import/Export
Abstrakter Datentyp:
Signatur (Sorten, Operationssymbole,
Funktionalität) – Operationseigenschaften
(Termgleichungen) – Import/Export
Fehlerbehandlung - Beispiel
Datensorte: Nat
Operationssymbole und ihre Funktionalität:
zero:
 Nat
succ:
Nat  Nat
pred:
Nat  Nat
add: Nat x Nat  Nat
mult: Nat x Nat  Nat
Fehlerbehandlung – Beispiel
(Forts.)
Termgleichungen:
pred(succ(x)) = x
add(zero, x) = x
add(succ(x), y) = succ(add(x, y))
mult(zero, x) = zero
mult(succ(x), y) = add(y, mult(x, y))
Fehlerbehandlung – Beispiel
(Forts.)
==> Ergänzung der Spezifikation:
error:
 Nat
succ(error) = error
pred(error) = error
add(error, x) = error
add(x, error) = error
mult(error, x) = error
mult(x, error) = error
pred(zero) = error
Fehlerbehandlung – Beispiel
(Forts.)
Operationssymbole:
zero:
succ:
pred:
add:
error:
safe:
 Nat
Nat  Nat
Nat  Nat
Nat x Nat  Nat
 Nat
Nat  Bool
Fehlerbehandlung – Beispiel
(Forts.)
Termgleichungen:
succ(error) = error
safe(zero) = true
safe(succ(x)) = safe(x)
safe(error) = false
pred(error) = error
pred(succ(x)) = x
pred(zero) = error
Fehlerbehandlung – Beispiel
(Forts.)
add(zero, x) = x
add(succ(x), y) = succ(add(x, y))
add(error, x) = error
mult(zero, x) = if safe(x) then zero else error fi
mult(succ(x), y) = add(y, mult(x, y))
mult(error) = error
Spezifikation eines ADT
type <Name> ==<Exportliste>
based on <Importliste>
sorts <Namenliste>
decl <Variablenliste>
constructors <kanonische Operationssymbole mit
Funktionalität>
operations <restliche Operationssymbole mit
Funktionalität>
axioms <Termgleichungen>
end of type
Beispiel – ADT BOOL
type BOOL == bool, T, F, , 
based on 
sorts bool
decl B:bool, B1:bool
constructors T:  bool; F :  bool
operations : bool  bool; __: bool x bool  bool
axioms T = F; (B)) = B; T  B = B;
F  B = F; B  B1 = B1  B
end of type
Beispiel – ADT BOOL
Abgeleitete Operationen

B  B1 = (B  B1)
B  B1 =  B  B1

B  B1 = (B  B1)  (B1  B)

Transformation arithmetischer
Ausdrücke in IPN
Voraussetzungen: zu transformierender Ausdruck
wird mit einem Endezeichen beendet und
Operatoren haben Prioritäten
 „(„ wird im Keller abgelegt
 „)“ entkellert alle Operatoren bis einschließlich
der zugehörigen öffnenden Klammer mit
anschließender Beseitigung beider Klammern
und Einfügen der Operatoren in die IPN
Transformation arithmetischer
Ausdrücke in IPN (Fortsetzung)
 Variablen und Konstanten gehen sofort in die
IPN über
 Operatoren entkellern alle Operatoren mit
größerer oder gleicher Priorität und werden
anschließend gekellert; die entkellerten
Operatoren werden der IPN hinzugefügt
 Entkellerung aller Operatoren durch
Endezeichen „!“ mit Löschen des Zeichens
Transformation arithmetischer
Ausdrücke in IPN (Fortsetzung)
Prioritäten:
1
4
7


/*
2
5
8

=
**
3
6

+-
Abstrakter Datentyp Keller – Signatur
erelement
init
push
element
stack
top
pop
erstack
Keller – Eigenschaften der
Operationen
a) Aus einem nichtleeren Keller kann nur das
zuletzt hinzugefügte Element entfernt werden.
b) Von einem nichtleeren Keller kann nur das
zuletzt hinzugefügte Element gelesen werden.
c) Im Falle eines leeren Kellers kann weder ein
Element entfernt noch gelesen werden. In
beiden Fällen erfolgt eine Fehlermeldung.
Kellerspezifikation
type Keller1 == stack, push, pop, top, init, erstack
based on ELEMENT
sorts stack
decl e: element, s: stack;
constructors init:
 stack;
push: element x stack  stack;
erstack:
 stack
operations pop: stack  stack;
top: stack  element
Kellerspezifikation (Fortsetzung)
axioms pop(push(e, s)) = s
top(push(e, s)) = e
pop(init) = erstack
top(init) = erelement
end of type
Abstrakter Datentyp Keller (erweitert) –
Signatur
max
erelement
init
push
element
top
nat
over lng
=
stack
erstack
empty
pop
bool
full
Keller – Eigenschaften der neuen
Operationen
a) lng gibt die Anzahl der Elemente eines
Kellers an, wobei der leere Keller die Anzahl 0
hat und durch jedes in den Keller
abgespeicherte Element die Anzahl um 1
vergrößert wird.
b) Ein Keller ist leer, wenn die Anzahl seiner
Elemente 0 ist. Ein Keller ist gefüllt, wenn die
Anzahl eine vorgegebene Größe max erreicht
hat.
Keller – Eigenschaften der neuen
Operationen (Fortsetzung)
c) Der Initialisierungskeller ist leer.
d) Die Abspeicherung eines Elements in einen
vollen Keller führt zu einem Fehler.
Kellerspezifikation (erweitert)
type Keller2 == stack, push, pop, top, init, erstack, full,
empty, lng, max, over
based on NAT, BOOL, ELEMENT
sorts stack
decl e:element, s:stack
constructors init:
push: element x stack
erstack:
over:
 stack;
 stack;
 stack;
 stack
Kellerspezifikation (erweitert) Fortsetzung
operations pop: stack  stack;
top: stack  element;
lng: stack  nat;
max:
 nat;
empty: stack  bool;
full:
stack  bool;
_=_: nat x nat  bool
Kellerspezifikation (erweitert) Fortsetzung
axioms push(e, s) = if full(s) then over else push(e, s) fi
pop(push(e, s)) = s
top(push(e, s)) = e
pop(init) = erstack
top(init) = erelement
lng(init) = 0
lng(push(e,s)) = lng(s) + 1
empty(init) = T
empty(push(e, s)) = F
full(s) = (lng(s) = max)
end of type
Abstrakter Datentyp Schlange – Signatur
max
erelement
insert
element
front
init
nat
over
length
=
queue
erqueue
qempty
remove
bool
qfull
Schlange – Eigenschaften der
Operationen


Eine nur initialisierte Schlange ist leer und hat
die Länge 0. Mit jedem hinzugefügten
Element wächst die Länge um 1.
Eine Schlange mit mindestens 1 Element ist
nicht leer. Eine volle Schlange hat die
maximale Länge erreicht. Es kann dann kein
Element hinzugefügt werden.
Schlange – Eigenschaften der
Operationen (Fortsetzung)



Einer leeren Schlange kann kein Element
entnommen werden.
Elemente werden bei einer nichtleeren
Schlange vorn weggenommen. Das Anfügen
von Elementen geschieht am Ende der
Schlange.
Gelesen werden kann grundsätzlich nur das
erste Element und das nur bei nichtleeren
Schlangen.
Schlange - Spezifikation
type Schlange == queue, front, insert, remove, init,
erqueue, over, qempty, qfull, length
based on NAT, BOOL, ELEMENT
sorts queue
decl e:element, q:queue
constructors
init:
 queue;
erqueue:
 queue;
over:
 queue;
insert: element x queue  queue
Schlange – Spezifikation (Forts.)
operations front: queue  element;
remove: queue  queue;
length: queue  nat;
max:
 nat;
qempty: queue  bool;
qfull:
queue  bool;
_=_: nat x nat  bool
axioms length(init) = 0
length(insert(e, q)) = length(q) + 1
Schlange – Spezifikation (Forts.)
qempty(init) = T
qempty(insert(e, q)) = F
qfull(q) = (length(q) = max)
front(init) = erelement
front(insert(e, q)) = if qempty(q) then e else front(q) fi
insert(e, q) = if qfull(q) then over else insert(e, q) fi
remove(init) = erqueue
remove(insert(e, q)) = if qempty(q) then init
else insert(e, remove(q)) fi
end of type
Abstrakter Datentyp Tabelle – Signatur

isdef
read
key
erelement
bool
delete
add, update
full
empty
element
table
size
init over ertable
=
nat
max
Abstrakter Datentyp Tabelle – Signatur
(andere Variante – unvoll.)
element
add
mentry
key
entry
table
Tabelle – Eigenschaften der
Operationen
- Eine nur initialisierte Tabelle ist leer und hat
den Umfang 0. Mit jeder Eintragung wächst
ihr Umfang um 1.
- Die Aktualisierung einer leeren Tabelle ist
ohne Effekt. Hingegen ist das Lesen einer
Eintragung aus einer leeren Tabelle ein Fehler.
- In eine gefüllte Tabelle kann keine weitere
Eintragung vorgenommen werden.
Tabelle - Spezifikation
type TABLE == key, table, read, add, update, delete,
isdef, empty, full,init, over, ertable, size
based on NAT, ELEMENT, BOOL
sorts key, table
decl k:key, l:key,t:table,e:element,f:element
constructors
init:
 table;
over:
 table;
ertable:
 table;
add: table x key x element  table
Tabelle – Spezifikation (Forts.)
operations read:
table x key  element;
update: table x key x element  table;
delete:
table x key  table;
__:
key x key  bool;
isdef:
table x key  bool;
empty:
table  bool;
full:
table  bool;
_=_:
nat x nat  bool;
size:
table  nat;
max:
 nat
Tabelle – Spezifikation (Forts.)
axioms
delete(init, k) = ertable
delete(add(t, k, e), l) = if k  l then t
else add(delete(t, l), k, e) fi
isdef(init, k) = F
isdef(add(t, k, e), l) = if k  l then T else isdef(t, l) fi
add(t, k, e) = if full(t) then over
else if isdef(t, k) then ertable
else add(t, k, e) fi fi
Tabelle – Spezifikation (Forts.)
update(init, k, e) = init
update(add(t, k, e), l, f) = if k  l then add(t, k, f)
else add(update(t, l, f), k, e) fi
read(init, k) = erelement
read(add(t, k, e), l) = if k  l then e else read(t, l) fi
size(init) = 0
size(add(t, k, e) = 1 + size(t)
empty(t) = (size(t) = 0)
full(t) = (size(t) = max)
end of type
Liste – informale Beschreibung
 Modellierung eines Karteikastens (Folge von
Karteikarten)
 Kennzeichnung der bearbeiteten Karte durch
Einschub einer Spezialkarte
(Markierungskarte) und damit Unterteilung
der Karten in Karten des vorderen und
hinteren Teils des Karteikastens
 Einfügen und Entfernen von Karten stets vor
der Markierungskarte
Liste – informale Beschreibung
(Fortsetzung)
 Verschiebung der Markierungskarte um 1
Position nach vorn oder hinten oder nach
ganz vorn bzw. ganz hinten
 Lesen der Karte vor der Markierungskarte
hinten
Markierungskarte
vorn
Liste - Signatur
max
erelement
mlist erlist over
read
init
element
list
insert
delete, first,
last, next, prev
nat
=
length
bool
empty, full,
atbeg, atend
Liste - Operationen

insert

delete

read

init
Einfügen einer Karte vor der
Markierungskarte
Entfernen der Karte vor der
Markierungskarte
Lesen der Karte vor der
Markierungskarte
Initialisierung der Kartei (nur
Markierungskarte vorhanden)
Liste – Operationen (Forts.)





first,last
Setzen der Markierungskarte auf
Anfang bzw. Ende
next, prev 1 Karte nach hinten bzw. vorn
length
Anzahl der Karteikarten
max
maximale Kartenanzahl
empty, full Ist der Karteikasten leer bzw.
voll?
atbeg,atend Ist die Markierungskarte am
Anfang bzw. Ende des Kastens?
Liste – Eigenschaften von
Operationen (Auszug)


Befindet sich die Markierungskarte am Anfang
des Kastens, so ist weder Lesen noch das
Entfernen einer Karte möglich. Die
Anwendung der prev-Operation ist dann nicht
gestattet und die first-Operation hat keine
Wirkung.
Steht die Markierungskarte am Ende des
Kastens, dann ist die next-Operation nicht
erlaubt und die last-Operation ohne Wirkung.
Liste - Signaturänderung
element
cons
seq
list
clist
nil
Beispiel – kanonischer Term
a b & c d
Kanonischer Term – alte Form
prev(prev(insert(d, insert(c, insert(b,
insert(a, init))))))
Kanonischer Term – neue Form
clist(cons(b, cons(a, nil)),
cons(c, cons(d, nil)))
Liste - Spezifikation
type LIST == list, read, insert, mlist, init, erlist, over,
delete, first, last, next, prev, length, empty, full,
atbeg, atend
based on ELEMENT, NAT, BOOL
sorts list, seq
decl e:element, f:seq, b:seq, l:list
constructors mlist:
 list;
erlist:
 list;
over:
 list;
nil:
 seq;
Liste – Spezifikation (Forts.)
cons: element x seq  seq;
clist:
seq x seq  list
operations init:
 list;
insert: element x list  list;
delete:
list  list;
first:
list  list;
last:
list  list;
next:
list  list;
prev:
list  list;
Liste – Spezifikation (Forts.)
read:
length:
empty:
full:
atbeg:
atend:
max:
_=_:
list  element;
list  nat;
list  bool;
list  bool;
list  bool;
list  bool;
 nat;
nat x nat  bool
Liste – Spezifikation (Forts.)
axioms
init = clist(nil, nil)
insert(e, clist(f, b)) = if full(clist(f, b)) then over
else clist(cons(e, f), b) fi
delete(clist(nil, b)) = erlist
delete(clist(cons(e, f), b)) = clist(f, b)
read(clist(nil, b)) = erelement
read(clist(cons(e, f), b)) = e
Liste – Spezifikation (Forts.)
last(clist(f, nil)) = clist(f, nil)
last(clist(f, cons(e, b))) = last(clist(cons(e, f), b))
first(clist(nil, b)) = clist(nil, b)
first(clist(cons(e, f), b)) = first(clist(f, cons(e, b)))
next(clist(f, nil)) = mlist
next(clist(f, cons(e, b))) = clist(cons(e, f), b)
prev(clist(nil, b)) = mlist
prev(clist(cons(e, f), b) = clist(f, cons(e, b))
length(init) = 0
Liste – Spezifikation (Forts.)
length(clist(cons(e, f), b)) = 1 + length(clist(f, b))
length(clist(nil, cons(e, b))) = 1 + length(clist(nil, b))
empty(l) = (length(l) = 0)
full(l) = (length(l) = max)
atbeg(clist(nil, b)) = T
atbeg(clist(cons(e, f), b)) = F
atend(clist(f, nil)) = T
atend(clist(f, cons(e, b))) = F
end of type
Baumdurchlaufalgorithmen
Inorder
PROCEDURE inorder(t: IN tree);
IF NOT null(t) THEN BEGIN inorder(left(t));
write(root(t));
inorder(right(t))
END
FI
END inorder
Baumdurchlaufalgorithmen
Präorder
PROCEDURE preorder(t: IN tree);
IF NOT null(t) THEN BEGIN write(root(t));
preorder(left(t));
preorder(right(t))
END
FI
END preorder
Baumdurchlaufalgorithmen
Postorder
PROCEDURE postorder(t: IN tree);
IF NOT null(t) THEN BEGIN postorder(left(t));
postorder(right(t));
write(root(t))
END
FI
END postorder
Treesort
PROCEDURE treesort(x:IN array[1..n] of Elem);
{x ist die zu sortierende Folge}
VAR t, q, help, tree, y, z:Elem; i:1..n;
{t Gesamtbaum; help und q sind Unterbäume zur
Bestimmung der Stelle, wo ein neuer Knoten
angehangen werden soll}
t := leaf(x[1]); {erstes Element wird zum Baum}
FOR i:= 2 TO n DO
{weitere Elemente werden in den Baum einsortiert}
BEGIN y := x[i];
{einzusortierendes Element}
help := t;
Treesort (Forts.)
WHILE NOT null(help) DO
{Abwärtshangeln im Baum}
q := help;
{Merken des Ausgangsknotens}
z := root(help);
{Bestimmung des Elements an der Wurzel von help}
IF keyof(y) < keyof(z) THEN help := left(help)
ELSE help := right(help)
FI
{Fortsetzung im linken oder rechten Unterbaum}
OD;
Treesort (Forts.)
IF keyof(y) < keyof(z) THEN setleft(q, leaf(y))
ELSE setright(q, leaf(y))
FI
{Anhängen eines Elements}
OD;
inorder(t);
{Durchlauf durch t in Inorder}
END treesort
Suche in einem treesort-Baum
FUNCTION find(t:IN tree; k:IN key): Boolean;
VAR p:tree; found:Boolean; x:Elem;
found := FALSE; p := t;
WHILE (NOT null(p)) AND (NOT found) DO
root(p, x);
IF k = keyof(x) THEN found := true
ELSE IF k < keyof(x) THEN p := left(p)
ELSE p := right(p)
FI
FI
OD;
find := found
END find
Binärbaum - Signatur
max
leaf
elem
setleft,setright
left, right
noden
tree
nat
=
null, maxtree
root
over, ertree, empty
cons
setroot
bool
Binärbaum - Operationen
root
setroot, setright, setleft
noden
left (right)
cons
liefert Element der Wurzel
Aktualisierung der Baumkomponenten
liefert Knotenanzahl eines
Baumes
linker (rechter) Unterbaum
wird geliefert
Konstruktion eines Baumes
aus Wurzelelement, linkem
und rechtem Unterbaum
Binärbaum – Operationen (Forts.)
leaf
null
maxtree
empty
ein Element wird zu einem
Baum, bestehend aus einem
Blatt (wird eigentlich nicht
benötigt, ergibt aber kürzere
Darstellungen)
Test auf leeren Baum
Test auf maximale
Knotenanzahl
Bauminitialisierung
Binärbaum - Spezifikation
type B-TREE == tree, root, leaf, left, right, empty,
cons, over, ertree, setroot, setleft, setright, noden,
null, maxtree
based on NAT, BOOL, ELEM
sorts tree
decl w:elem, r:tree, l:tree, e:elem, t:tree
constructors empty:
 tree;
over:
 tree;
ertree:
 tree;
cons: elem x tree x tree  tree;
Binärbaum – Spezifikation (Forts.)
leaf:
 tree
operations root:
tree  elem;
left:
tree  tree;
right:
tree  tree;
setleft: tree x tree  tree;
setright: tree x tree  tree;
setroot: tree x elem  tree;
null:
tree  bool;
maxtree:
tree  bool;
Binärbaum – Spezifikation (Forts.)
noden:
tree  nat;
max:
 nat;
_=_:
nat x nat  bool
axioms root(empty) = erelem
right(empty) = ertree
left(empty) = ertree
leaf(w) = cons(w, empty, empty)
root(cons(w, l, r)) = w
Binärbaum – Spezifikation (Forts.)
left(cons(w, l, r)) = l
right(cons(w, l, r)) = r
setleft(empty, t) = ertree
setright(empty, t) = ertree
setroot(empty, e) = ertree
setleft(cons(w, l, r), t) = cons(w, t, r)
setright(cons(w, l, r), t) = cons(w, l, t)
setroot(cons(w, l, r), e) = cons(e, l, r)
Binärbaum – Spezifikation (Forts.)
null(t) = (noden(t) = 0)
noden(empty) = 0
noden(leaf(w)) = 1
noden(cons(w, l, r)) = 1 + noden(l) + noden(r)
maxtree(t) = (noden(t) = max)
cons(w, l, r) = if noden(cons(w, l, r)) > max
then over else cons(w, l, r) fi
end of type
Beispielbaum
T
/
T1
+
a
T2
b
/
*
a
T3
c
c
right(T) = cons(/, leaf(a), leaf(c))
left(left(T)) = left(
cons(+, leaf(a), cons(*, leaf(b), leaf(c)))) = leaf(a)
Beispielbaum – Implementierung
Index
1
2
3
4
5
6
7
8
9
Wert lr
/
+
*
/
a
b
c
a
c
2
5
6
8
rr
4
3
7
9
Beispiel – Freispeicherkette
Index
1
2
3
4
5
6
7
8
9
Wert lr
6
rr
besetzter Speicher
2
7
9
nil
Anfang der Freispeicherkette
Fragen zu Algorithmen




Existiert (im mathematischen Sinn) zu einer
gegebenen Aufgabe ein Lösungsalgorithmus?
Welche Ressourcen benötigt er und ist er
überhaupt durchführbar (Komplexität)?
Wie beeinflusst ein gegebenes
Rechnersystem die effiziente Ausführung
eines Algorithmus?
In welcher Programmiersprache kann der
Algorithmus am besten notiert werden?
Church-Turing-These


Alle (existierenden) „vernünftigen“
Definitionen des Begriffs „Algorithmus“ sind
gleichwertig.
(Formale Beweise der Äquivalenz der
Formalisierungen existieren.)
Jede (neue) „vernünftige“ Definition des
Begriffs ist gleichwertig mit den obigen.
Bemerkungen



Intuitive Vorstellungen über Algorithmen lassen sich
durch Turingmaschine, Markovalgorithmen usw.
formalisieren. Ein Beweis der Äquivalenz ist allerdings
nicht möglich.
Die Formalisierungen des Algorithmenbegriffs
kommen ohne den Rechnerbegriff aus. Demzufolge
muss ein Algorithmus prinzipiell auf jedem Rechner
ausführbar sein.
Algorithmen können in Software oder Hardware
umgesetzt werden.
Fermatsche Vermutung
Stoppt der nachfolgende Algorithmus?
Eingabe n;
Für a = 1, 2, 3,...
Für b = 1, 2,..., a
Für c = 2, 3,..., a + b
Wenn an + bn = cn, dann gib a, b, c und n
aus und stoppe.
Totalitätsproblem
Gibt es einen Algorithmus, der für ein beliebiges
Programm P feststellen kann, ob P für alle
Eingaben D stoppt oder nicht stoppt?
Äquivalenzproblem
Gibt es einen Algorithmus, der für beliebige
zwei Programme feststellen kann, ob sie die
gleiche Aufgabe lösen.
Beispiel: Suchproblem
Gegeben:
endliche Folge F von Elementen einer Menge S
F = A1,..., An, Element a  S
 Gesucht: Position von a in der Folge
Algorithmus:
FUNCTION LinSu(F: IN ARRAY [1..n] OF real; a: IN real):
natural;
FOR i := 1 TO n DO IF a = F[i] THEN RETURN(i) FI OD;
RETURN(0)
END LinSu

O/Ω/Θ-Notation



g(n) = O(f(n)) bedeutet: Es existieren eine
positive Konstante M und eine Konstante n0,
so dass (n  n0) |g(n)|  M*|f(n)|.
g(n) = (f(n)) bedeutet: Es existieren eine
positive Konstante M und eine Konstante n0,
so dass (n  n0) |g(n)|  M*|f(n)|.
g(n) = (f(n)) bedeutet: Es existieren eine
positive Konstante M und eine Konstante n0,
so dass (n  n0) |f(n)|/M  |g(n)| 
M*|f(n)|.
Rechenregeln für die O-Notation
f(n) = O(f(n))
O(O(f(n))) = O(f(n))
c*O(f(n)) = O(f(n))
O(f(n))*O(g(n)) = O(f(n)*g(n))
O(f(n)*g(n)) = O(f(n))*O(g(n))
O(f(n)*g(n)) = f(n)*O(g(n))
Beispiel
Eine Operation benötige 0,000001 sec
Anzahl der
Asymptotischer Zeitbedarf bei
Eingabedaten
Komplexität
n
log2 n
n
n2
10
100
1000
10000
100000
0,000003
sec
0,000007
sec
0,00001
0,00001
sec
0,0001
sec
0,001
0,0001
sec
0,01
sec
1
sec
sec
sec
0,000013
sec
0,000017
0,01
sec
0,1
1,7
min
2,8
sec
sec
h
2n
0,001
sec
1014
Jhd.
Häufig auftretende Komplexitäten
(in wachsender Reihenfolge)
O(1) konstant
O(log n) logarithmisch
O(n)
O(n)
linear
O(n*log n)
O(n2)
quadratisch
O(nk), k konstant polynomial
O(kn), k konstant exponentiell
O(n*2n)
O(n!)
Menge M mit Halbordnung (partieller Ordnung)
R:
R  M x M, R binäre Relation auf M, wobei gilt

R ist reflexiv: (x  M) (xRx)

R ist transitiv: (x, y, z  M)
(xRy  yRz  xRz)

R ist antisymmetrisch: (x, y  M)
(xRy  yRx  x = y)
R ist eine (totale) Ordnung, wenn zusätzlich gilt:
(x, y  M) (xRy  yRx)
Sortierproblem:
Gegeben: U Universum mit Ordnung R
M = {a1,..., an}, ai  U
Gesucht: Permutation P = (p1,..., pn) von
(1, ...,n), so dass apiRapi+1, i = 1,...,n-1
Beispiel:
U = {0, 1, 2,...}, M = {5, 4, 8, 2} = {a1,...,a4}
 P = (4, 2, 1, 3), da a4  a2  a1  a3
Grad der Unsortiertheit einer Menge:
Anzahl der Inversionen der Menge
Inversion:
M = {a1,..., an}
(ai, aj), wobei ai > aj und i < j
Maximale Anzahl: (n2 – n)/2
Beispiel:
Im obigen Beispiel: (5, 4), (5, 2), (4, 2), (8, 2)
Klassifikation von Sortierverfahren:
1. Nach der Art der Elemente:
- Elementsortierung
- Schlüsselsortierung
Schlüssel Assoziierte Information Element
Argument
Wert
 Sortieren mit vollständiger
Umspeicherung der Elemente oder nur mit
Schlüsselumspeicherung (siehe auch
Implementation des ADT Tabelle)
Stabile Sortierung: relative Ordnung
zwischen zwei gleichen Schlüsseln bleibt
erhalten
Beispiel:
Eine alphabetisch geordnete Liste von
Prüfungsnoten wird nach den Noten
geordnet. Dann sind alle Namen zur
gleichen Note immer noch in alphabetischer
Reihenfolge.
2. Nach dem Speicher:
- Innere Sortierverfahren: Sortieren auf dem
Hauptspeicher
- Externe Sortierverfahren: Sortieren von
Daten auf externen Speichern unter Nutzung
innerer Verfahren für kleine Datenportionen
3. Nach der Rechnerarchitektur:
Sequentielles und paralleles Sortieren
4. Nach der zeitlichen Komplexität
5. Nach den Methoden: adressenorientiert,
assoziativ, hybrid
Adressenorientiertes Sortieren
Adressenorientiertes Sortieren
Grundalgorithmus
Voraussetzung: U = {u1,..., um} Universum,
M = {a1,..., an}, ai  U, zu sortierende Menge
Algorithmusschritte:
1) Initialisierung: Anlegen von m leeren Listen
(zugeordnet zu den Elementen des Universums)
2) Verteilung: Abarbeitung von M von links nach
rechts und Anhängen des Indexes i an die Liste j, wenn
ai = uj.
3) Verkettung: Verbindung des Endes der i. Liste mit
dem Anfang der (i+1). Liste ==> Indizes der Elemente
der sortierten Folge bezogen auf ursprüngliche Folge
Adressenorientiertes Sortieren
Beispiel
U = {0, 1, 2, 3, 4, 5, 6} = {u1,..., u7}
M = {5, 4, 3, 4, 5, 0, 2, 1} = {a1,..., a8}
Listen: Liste(Element)
1(0) 2(1) 3(2) 4(3) 5(4) 6(5) 7(6)
6
8
7
3
2
1
4
5
M sortiert:
{a6, a8, a7, a3, a2, a4, a1, a5} = {0, 1, 2, 3, 4, 4, 5, 5}
Adressenorientiertes Sortieren
Eigenschaften
Komplexität:
 Zeitlich:
- Typische Operationen: Einsortieren eines
Elements in eine Liste (c1*n), Listenverknüpfung (c2* (m – 1))
 c3* (n + m)  O(n+m)  O(n)
 Speicher: O(n*m)  O(n)
Stabilität: ja
Adressenorientiertes Sortieren
Lexikographisches Sortieren
Lexikographische Ordnung:
U = {u1,..., un}, ui Zahlen gleicher Länge
bestehend aus den Ziffern 0, 1,..., m-1
Dabei gilt: ui < uj, i < j, ui = a1...ak, uj = b1...bk
 l: (1  l  k)  (ar = br, r=1,...,l-1) 
(al < bl)
Eine analoge Definition gilt für Wörter.
Adressenorientiertes Sortieren
Lexikographisches Sortieren
Algorithmusschritte:
1) Initialisierung: Anlegen von m leeren Listen (m
Anzahl der Ziffern bzw. Buchstaben)
2) k Durchläufe:
i. Durchlauf:
 Verteilung: Zahlen (Wörter) des letzten Durchlaufs
werden gemäß i. Ziffer (Buchstaben) einer Zahl
(eines Wortes) von rechts betrachtet in die Listen
einsortiert
 Verkettung: Verbindung des Endes der i. Liste mit
dem Anfang der (i+1). Liste
Beispiel
U = {affe, alf_, duo_, elch, esel, maus, tanz, tor_, zart,
zoo_}
S = {zoo_, affe, tor_, maus, alf_}
_
a
zoo_
tor_
alf_
e
f
l
m
o
affe
maus
affe
alf_
r
s
t
u
z
maus
alf_
affe
affe
zoo_
alf_
tor_
maus
zoo_
tor_
maus
tor_
zoo_
Adressenorientiertes Sortieren
Lexikographisches Sortieren
Komplexität:
 Zeitlich: O(k * (m + n))  O(n)
 Speicher: O(n * m)  O(n)
Assoziatives Sortieren
Prinzip: Vergleich der Elemente untereinander
Grundmethode (rekursive Beschreibung):
1. Analyse: Überführung des ursprünglichen
Sortierproblems in Sortierprobleme geringeren
Umfangs
2. Rekursion: Lösung der kleineren Probleme gemäß 1.-3.
3. Synthese: Zusammensetzung der Lösungen der
kleineren Probleme zur Lösung des Gesamtproblems
Assoziatives Sortieren
Sortieren durch Einfügen (INSERTSORT)
Algorithmus (rekursive Version):
1. Analyse: Zerlegung von M = {a1,..., an} in
M1 = {a1,..., an-1} und M2 ={an}
2. Rekursion: Sortieren von M1 nach 1. - 3. mit
Ergebnis M1’
3. Synthese: Einfügen von an an die richtige
Stelle in M1’
Beispiel: Sortieren von M = {4, 5, 0, 2, 1}
Zerlegung
{4, 5, 0, 2, 1}
{4, 5, 0, 2}
{4, 5, 0}
{4, 5}
{4}
{1}
 {0, 2, 4, 5}
{2}
{0}
{5}
 {0, 1, 2, 4, 5}
 {0, 4, 5}
 {4, 5}
Einsortierung
Assoziatives Sortieren
Sortieren durch Einfügen (INSERTSORT)
Komplexität:
 Typische Operationen: Vergleich zweier


Elemente, Verschiebung eines Elements um 1
Platz
Zeitlich: O(n2)
Speicher: O(n)
Sortieren durch Einfügen (INSERTSORT)
Iterative Version
procedure insertion(a : array of integer);
var i, j, v: integer;
begin
for i := 2 to N do
begin
v := a[i]; j := i;
while a[j – 1] > v do
begin a[j] := a[j – 1]; j := j – 1 end;
a[j] := v
end
end
Sortieren durch Einfügen (INSERTSORT)
Iterative Version
Beispiel:
a0
-
-
-
-
-
-
a1
4
4
4
0
0
0
a2
5
a3
0
a4
2
a5
1
5
4
2
1
5
4
2
5
4
5
Sortieren durch Einfügen (INSERTSORT)
Eigenschaften
 Wegen der quadratischen zeitlichen Komplexität ist
es ungeeignet für große Mengen, aber sehr wohl
anwendbar für kleine.
 Ist die zu sortierende Menge gut vorsortiert, dann
sind auch große Mengen gut sortierbar (Annäherung
an minimale Komplexität).
 Es ist gut für on-line Sortierung geeignet.
 Der durch den Algorithmus zusätzlich benötigte
Speicherplatz ist unabhängig von der Größe der zu
sortierenden Menge konstant.
 Das Verfahren ist stabil.
Sortieren durch Einfügen (INSERTSORT)
Verbesserungen


Beginn der Suche der Einfügungsstelle
ca. von der Mitte der sortierten Menge
an
Beginn des Aufbaues der sortierten
Menge von der Mitte her
Sortieren durch Einfügen (INSERTSORT)
Verbesserungen
Beispiel: S = {4, 5, 0, 2, 1, 6}
Aufbau der sortierten Menge:
4
4
5
0
4
5
0
2
4
5
0 1
2
4
5
0 1
2
4
5
6
5
0
2
1
6
Assoziatives Sortieren
Sortieren durch Auswahl (SELECTSORT)
Algorithmus (rekursive Version):
1. M = {a1,..., an} wird zerlegt in M1 = {a11,...,
a1n-1} = M - M2 und M2 = {min(M)}
bzw. M2 = {max(M)}
2. Sortieren von M1 nach den Schritten 1. - 3.
mit der Ergebnismenge M1’
3. M’ = M2  M1’ bzw. M’ = M1’  M2
Sortieren durch Auswahl (SELECTSORT)
Rekursive Variante
Beispiel: Sortieren mit Minimum
{4, 5, 0, 2, 1}
Zerlegung
{4, 5, 2, 1}
{0}
{0, 1, 2, 4, 5}
{4, 5, 2}
{1}
{4, 5}
{5}
{2}
{4}
Aneinanderreihung
Sortieren durch Auswahl (SELECTSORT)
Iterative Variante
Beispiel: M = {4, 5, 0, 2, 1}
Schritt
1
2
3
4
5
Sortierte Menge
0
0
1
0
1
2
0
1
2
4
0
1
2
4
5
Restmenge
4
5
2
4
5
2
4
5
5
1
Assoziatives Sortieren
Sortieren durch Vertauschen
(BUBBLESORT)
Prinzip:
Vergleich von unmittelbar benachbarten
Elementen mit anschließender Vertauschung
bei falscher Reihenfolge
Sortieren durch Vertauschen
(BUBBLESORT)
Beispiel: M = {4, 5, 0, 2, 1, 6}
Vertauschungsschritte:
4
5
0
4
0
5
4
0
2
4
0
2
0
4
2
0
2
4
0
2
1
0
1
2
2
2
5
1
1
1
4
4
1
1
1
5
5
5
5
5
6
6
6
6
6
6
6
6
Sortieren durch Vertauschen
(BUBBLESORT)
Verbesserungen:
1. Auslassen der Vergleiche von der Stelle an,
von der im letzten Durchlauf die letzte
Vertauschung stattfand (Elemente sind
bereits in richtiger Reihenfolge)
2. Vergleich mit alternierender Richtung und
Verbesserung 1. (SHEAKSORT)
Sortieren durch Vertauschen
(BUBBLESORT)
3.
Idee von D. L. Shell (1959):
i. Sortierschritt auf der Basis des Vergleichs
von Elementen, die hi Elemente voneinander
entfernt liegen, wobei hi > hi+1, hk = 1
Empfehlung von Knuth:
hi = 3*hi+1 + 1 (..., 40, 13, 4, 1)
Sortieren durch Vertauschen
(BUBBLESORT)
Beispiel: SHELLSORT für {4, 5, 0, 2, 1, 6}
Vergleich und Vertauschung mit h1 = 4
4
5
0
2
1
6
1
5
0
2
4
6
1
5
0
2
4
6
Vergleich und Vertauschung mit h2 = 2
1
5
0
2
4
6
0
5
1
2
4
6
0
2
1
5
4
6
Vergleich und Vertauschung mit h3 = 1
0
2
1
5
4
6
0
1
2
4
5
6
Assoziatives Sortieren
Sortieren durch Mischen (MERGESORT)
Algorithmus:
1. M = {a1,..., an} wird zerlegt in M1 und M2,
die von gleicher Größe sein sollten
2. Sortieren von M1 und M2 gemäß 1. - 3.;
Ergebnismengen M1’ und M2’
3. Mischen der Mengen M1’ und M2’ zur
sortierten Menge unter Verwendung des
nachfolgenden Algorithmus’
Assoziatives Sortieren
Sortieren durch Mischen (MERGESORT)
Mischalgorithmus:
Gegeben: Sortierte Mengen M1’ und M2’
Gesucht: Sortierte Menge M’ bestehend aus den
Elementen von M1’ und M2’
Schritte:
Initialisierung von M’: M’ := 
Solange M1’ und M2’ beide nicht leer sind, führe aus:
Übernahme des kleineren der beiden ersten Elemente
von M1’ und M2’ nach M’ und Entfernung aus M1’ bzw.
M2’. Ist M1’ oder M2’ leer, dann Übernahme der anderen
Menge nach M’.
Sortieren durch Mischen (MERGESORT)
Beispiel:
Zerlegung
{4, 5, 0, 2, 1, 6}
{4, 5, 0}
{4, 5}
{4}
{2, 1, 6}
{0}
{5}
{2, 1}
{2}
{6}
{1}
Mischung:
{0, 1, 2, 4, 5, 6}
{0, 4, 5}
{4, 5}
{0}
{1, 2, 6}
{1, 2}
{6}
Assoziatives Sortieren
QUICKSORT
Verbesserung von MERGESORT zu QUICKSORT (Hoare
1961):
1. Auswahl eines Pivotelements P aus M = {a1,..., an}
und Zerlegung von M in zwei Mengen M1 und M2,
wobei M1 alle Elemente aus M enthält, die kleiner als
P sind.
2. Sortieren von M1 und M2 gemäß den Schritten 1. - 3.
mit den Ergebnismengen M1’ und M2’
3. M’ = M1’ . {P} . M2’
Beispiel:
M = {207, 095, 646, 198, 809, 376, 917, 534, 310}
Zerlegung
{207, 095, 646, 198, 809, 376, 917, 534, 310}
{376}
{207, 095, 198, 310}
{646, 809, 917, 534}
{198}
{095}
{646}
{207, 310}
{207}
{534}
{809, 917}
{809}
{310}
{917}
Verkettung
{095, 198, 207, 310, 376, 534, 646, 809, 917}
{095, 198, 207, 310}
{376}
{095} {198} {207, 310}
{207}
{310}
{534, 646, 809, 917}
{534}
{646} {809, 917}
{809}
{917}
Assoziatives Sortieren
Sortieren durch Zählen (COUNTSORT)
Prinzip:

Zu jedem Element von M = {a1,..., an} wird
festgestellt, wie viel Elemente kleiner als
dieses Element sind.

Die Anzahl der Elemente, die kleiner als ein
gegebenes Element sind, gibt die Stellung des
Elements in der sortierten Folge an.
Assoziatives Sortieren
Sortieren durch Zählen (COUNTSORT)
Beispiel:
Menge
M = {4, 5, 0, 1, 2, 6}
Kleinere
3 4 0 1 2 5
Elemente
Sortierte M´ = {0, 1, 2, 4, 5, 6}
Menge
Position
0 1 2 3 4 5
Assoziatives Sortieren
Heapsort
Vollständiger Binärbaum:


Auf jedem Niveau, bis evtl. auf das letzte,
sind alle Knoten vorhanden.
Auf dem letzten Niveau dürfen Knoten nur am
rechten Rand lückenlos fehlen.
Assoziatives Sortieren
Heapsort
Heap:
Vollständiger Binärbaum, wobei der Schlüssel
jeden Knotens größer oder gleich den
Schlüsseln der Nachfolgerknoten ist.
Lineare Darstellung eines Heaps: Anordnung
der Elemente in einem Vektor entsprechend
Baumebenen beginnend mit der 0. Ebene
Assoziatives Sortieren
Heapsort
Beispiel: Heap
1 917
2 809
4 534
5 550
3 646
6 613
8 320
Lineare Darstellung:
917 809 646 534 550 613 412 320
7 412
Assoziatives Sortieren
Heapsort
Positionsbestimmung:


Vorgänger zu Knoten j: Position j div 2
Direkte Nachfolger zu Knoten j: Positionen
2*j und 2*j + 1
Assoziatives Sortieren
Heapsort
Algorithmus:
1. Aufbau eines Heap aus den Elementen der zu
sortierenden Menge M:
Wiederholung folgender Schritte beginnend mit
einem 1-elementigen Heap
1.1 Anfügen des nächsten Elements aus M an
gegebenen Heap
1.2 Überprüfung der Heapeigenschaft mit Korrektur,
wenn nötig
2. Konstruktion der sortierten Menge M´:
Wiederholung folgender Schritte bis zur Erreichung
eines leeren Heaps:
2.1 Übernahme des Wurzelelements des Heaps nach
M´(von links nach rechts)
2.2 Ersetzen des Wurzelelements im Heap durch
letztes Heapelement (letzte Ebene, rechter Rand)
3.2 Überprüfung der Heapeigenschaft mit Korrektur,
wenn nötig
Beispiel:
M = {550, 917, 613, 320, 809, 646, 412, 534}
1. Konstruktion des Heap
550
550
550 917
550
917
Erfüllt Heapeigenschaft nicht 
917 550
917
550
917 550 613
917
550
613
Heap zu M
917 809 646 534 613 412 320
917
809
534
320
550
646
613
412
2. Konstruktion der sortierten Menge M´
Auslesen der Wurzel: 917
Ersetzen der Wurzel durch letztes Element:
320 809 646 534 550 613 412 917
320
809
534
550
646
613
412
Überprüfung der Heapeigenschaft:
809
320
534
646
550
613
412
809
550
534
320
646
613
412
Auslesen und Ersetzen der Wurzel:
412
550
534
320
646
613
412 550 646 534 320 613 809 917
Endergebnis: M´= {320, 412, 534, 550, 613, 646, 809, 917}
Hybrides Sortieren
Algorithmus:
M = {a1,..., an},
amin minimales Element, amax maximales Element von M
Schritte:
1. Unterteilung von <amin, amax+1) in m Teilintervalle
<xi, xi+1), i=0,...,m-1, x0 = amin,
xm = amax + 1
2. Verteilung der Elemente auf Intervalllisten
3. Assoziatives Sortieren in den Listen und
Listenverkettung
Beispiel:
M = {207, 095, 646, 198, 809, 376, 918, 534, 310, 209, 181, 595,
799, 694, 344, 522, 139}
xmin = 095
xmax + 1 = 919
m=8
Intervalle
<095, 198)
<198, 301)
<301, 404)
<404, 507)
<507, 610)
<610, 713)
<713, 816)
<816, 919)
Elemente
Elemente sortiert
095 181 139
207 198 209
376 310 344
 095 139 181
 198 207 209
 310 344 376
534 595 522
646 694
809 799
918




522 534 595
646 694
799 809
918
Sortierte
Menge
Suchverfahren
Suchproblem:
Ein Suchproblem ist gegeben durch
1) die Mengen U Universum (Elemente, aus denen
der Suchraum bestehen kann), A Menge der
Anfragen, X Menge der Antworten
2)
und eine Beziehung zwischen den angeführten
Mengen Q: A x 2U  X
Q(a, S) mit a  A, S  2U bezeichnet eine Antwort
aus X zu einer Anfrage a an einen Suchraum S aus
dem Universum U.
Suchverfahren
Algebraische Formulierung
Statisches Suchproblem: Der Suchraum wird
einmal aufgebaut und bleibt dann
unverändert.
Statisches
Q
X
Lexikon
init
build
insert,delete
2U
A
U
Suchverfahren
Algebraische Formulierung
Dynamisches Suchproblem: ständige Änderung
des Suchraums durch Hinzufügen und
Entfernen von Elementen
Dynamisches
Q
X
Lexikon
init
insert delete
U
A
Suchverfahren
Operationen:
init
insert
delete
build
Initialisierung des Suchraums mit einer
leeren Menge
Aufnahme eines Elements aus U in den
Suchraum
Entfernung eines Elements aus dem
Suchraum
Strukturierung des Suchraums
Suchverfahren
Typische Suchprobleme
Zugehörigkeit eines Elements zu einer Menge:
U = A beliebige Menge (nach jedem Element des U kann in S
gefragt werden), X = {true, false}, S  U

true, a  S
Q(a, S) =


false, a  S
S Wörterbuch mit der Anfrageoperation (Mitglied, member) und
im dynamischen Fall zusätzlich mit den Operationen insert
(Einfügen) und delete (Streichen, Entfernen)
Suchverfahren
Typische Suchprobleme
Minimum (Maximum) einer geordneten Menge:
U = X (potenziell jedes Element aus U kommt
in Frage), A ohne Bedeutung
Q(_, S) = min S (Q(_, S) = max S), S  U
Dynamischer Fall: Prioritätsschlange
Suchverfahren
Typische Suchprobleme
Mehrdimensionale Suchprobleme (partial
match searching):
E beliebige Menge
U = Ek Menge aller k-Tupel von Elementen aus E, k  1
A = (E  {*})k Menge aller k-Tupel, deren Elemente * oder aus
E sein können,
*E
X = 2U
Q(a, S) = {b  S| j (1  j  k)  (aj = bj  aj = *)}, S  Ek
Menge aller k-Tupel, deren Komponenten mit denen von
a = (a1,..., ak) übereinstimmen, wenn sie kein * sind
Suchverfahren
Typische Suchprobleme
Problem des nächsten Nachbarn (Postamtproblem):
A = U = E2, X = 2U, S  E2
E2 zweidimensionaler Euklidischer Raum mit Metrik 
Q(a, S) = {b  S| (c  S) 
((a, b)  (a, c)}
(Für eine Postsendung mit gegebenem Zielort
ist das nächstliegende Postamt zu bestimmen.)
Suchverfahren
Klassifizierungen
Klassifizierung der Suchalgorithmen:
1. Algorithmen mit Adressberechnung: Der Platz des
gesuchten Elements im Suchraum wird ausgehend
vom Wert des Elements berechnet.
2. Assoziative Algorithmen: Die Positionsbestimmung
geschieht durch Vergleich des gesuchten Elements
mit anderen Elementen des Suchraumes, wobei im
Universum eine Ordnung vorgegeben sein muss.
Weitere Klassifizierung: parallele Algorithmen,
sequentielle Algorithmen
Suchverfahren
Komplexitätsmaße
Voraussetzung: n Größe des Suchraumes
P(n, k) zeitliche Komplexität der Konstruktion
der Datenstruktur (Suchstruktur), in
der gesucht wird
(k-dimensionale Menge vom Umfang n)
S(n, k)
Speicherkomplexität der Suchstruktur
Q(n, k)
zeitliche Komplexität der Realisierung
einer Anfrage über der Suchstruktur
Suchverfahren
Komplexitätsmaße
U(n,k)
I(n, k)
zeitliche Komplexität jeder Aktualisierungsoperation für S
zeitliche Komplexität einer insert-
Operation im dynamischen Fall
D(n, k)
zeitliche Komplexität einer delete-
Operation im dynamischen Fall
Suchverfahren
Algorithmen mit Adressberechnungen
Verwendung eines charakteristischen Vektors
Voraussetzung: |U| = N, U = {1, 2,..., N}, N
nicht zu groß
Repräsentation von S  U durch einen
charakteristischen Vektor (Bitvektor)
A: array [1..N] of Boolean,
wobei A[i] = true genau dann, wenn das i.
Element von U in S ist
Suchverfahren unter Verwendung eines
charakteristischen Vektors
Beispiel:
U = {rot, blau, grün, gelb, schwarz},
S = (blau, gelb)
type Farbe = ...; S: array [Farbe] of Boolean
=> S[blau] = true = S[gelb],
S[rot] = S[grün] = S[schwarz] = false
rot
blau
false true
grün
gelb
schwarz
false true false
Suchverfahren
Algorithmen mit Adressberechnungen
Hashing
Voraussetzung: großes (evtl. unendliches)
Universum U und relativ kleine Menge S  U,
|S|  m
Verwendung einer Hashtabelle A[0..m-1] und
einer Hashfunktion
h: U  {0,..., m-1}
Wenn x  S, dann wird x auf A[h(x)] oder
„in der Nähe“ abgespeichert.
Suchverfahren
Hashing
Kollission: x, y  S, x  y, und h(x) = h(y)
 Abspeicherung von x und y auf
unterschiedlichen Plätzen „in der Nähe“ von
h(x); unterschiedliche Bestimmung der
„Nähe“
 Verkettung oder offene Adressierung
Suchverfahren
Hashing
1. Hashing mit Verkettung
Alle Elemente von S mit der gleichen
Hashadresse h(x) werden zu einer Kette
verbunden, deren Anfang in A[h(x)]
abgespeichert ist.
Suchverfahren
Hashing mit Verkettung
Beispiel:
U = {0, 1, 2,...}, S = (1, 3, 4, 7, 10, 17, 21},
m=3
Hashfunktion: h(x) = x mod 3
A
0
3
21
1
1
4
7
10
2
17
Suchverfahren
Hashing
2. Hashing mit offener Adressierung
Idee: Zu jedem Element x  U gehört eine
Folge von Tabellenpositionen h(x, i), i = 0,
1,... , auf denen sich x befinden könnte.
Mögliche Hashfunktion:
h(x, i) = [h1(x) + h2(x)*i] mod m
Suchverfahren
Hashing mit offener Adressierung
Beispiel:
m = 7, h1(x) = x mod 7, h2(x) = 1 + (x mod 4)
S = (3, 17, 6, 9, 15, 13, 10)
h(3, i) = [3 + 4*i] mod 7, i = 0 möglich  Abspeicherung von 3
auf A[3]
h(17, i) = [3 + 2*i] mod 7, i = 1 möglich  Abspeicherung von
17 auf A[5]
...

0
1
13 15
2
9
3
3
4
10
5
6
17 6
Suchverfahren
Hashing
3. Perfektes Hashing
Perfekte Hashfunktion:
U = {0, 1,..., N - 1}, S  U,
h: {0, 1,..., N - 1}  {0, 1,..., m-1}
h heißt perfekt, wenn für alle x, y  S, x  y, gilt
h(x)  h(y).
Eine Menge H von Hashfunktionen heißt
(N, m, n)-perfekt, wenn es für jede Teilmenge S, |S| =
n, ein h  H gibt, so dass h für S eine perfekte
Hashfunktion ist.
Suchverfahren
Perfektes Hashing
Praktische Methode (Cormack, Horspool,
Kaiserwerth):


Verwendung von zwei Tabellen:
- Tabelle D (directory)
- Tabelle T (Elementetabelle)
Aufspaltung des Suchraums S in Gruppen Si,
i=1,...,m, wobei gilt: x und y aus S gehören genau
dann in die gleiche Gruppe, wenn ihr Hashwert
gemäß primärer Hashfunktion h gleich ist

h(x,s) = a = h(y, s) bedeutet (|D| = s):
hk(e,r) ist eine sekundäre Hashfunktion für das
Auffinden der Elemente aus Sk im Abschnitt
[, +r-1] der Tabelle T, wobei
hk(x,r) = u und hk(y,r) = t , |Sk| = r
Tabelle D
Tabelle T
a
k
r


+u
x
+t
y
+r-1
Suchverfahren
Hashing
4. Digitale Suchbäume
Idee: Kombination von Hashing und Suchbaum
 Hashwert: Binärzahl
 Interpretation des Hashwertes:
- Durchlaufe den Wert von links nach rechts
bis zum Auffinden des Elements oder eines
freien Speicherplatzes zur Elementablage
- 0: gehe nach links
- 1: gehe nach rechts
Suchverfahren
Digitale Suchbäume
Beispiel: S = {s1, s2, s3, s4, s5, s6}
Hashfunktion:
i h
s1 0010
s2 1001
s3 1101
s4 0111
s5 0011
s6 1111
0010 s1
0011 s5
s2 1001
s3 1101
0111 s4
s6 1111
Suchverfahren
Hashing
5. Tries (Retrieval trees)
Tries haben eine analoge Struktur zu den digitalen
Suchbäumen mit folgenden Änderungen:
a) Die Elemente sind Blätter des Baumes.
b) Als Hashwert wird die binäre Darstellung eines
Elements verwendet.
c) Die Kanten im Baum sind mit 0 (linke Kante) oder 1
(rechte Kante) bezeichnet. Der Hashwert eines
Elements beschreibt dann eine Kantenfolge, die zum
gesuchten Element führt.
Suchverfahren
Tries
Beispiel: S = {0010, 1001, 1101, 0111, 0011, 1111}
0
0
1
1
1
0
s1
0
1
1
s5
1
0
1
s4
0
1
s2
1
1
s3
1
s6
Assoziatives Suchen
Verfahren
Voraussetzungen:
U linear geordnetes Universum (Menge mit
totaler Ordnung)
S = (x1,..., xn) mit xi  xi+1 sei im Vektor
S[1..n] abgespeichert, wobei S[i] = xi
a  U in S gesuchtes Element
Grundalgorithmus:
S
S[1]
S[unten]
S[naechster]=e
S[oben]
S[n]
Schritte:
a) Vergleiche a mit einem Element e aus S.
b) 1. e ist a  Halt
2. a < e  Suche im unteren Teil von S
3. a > e  Suche im oberen Teil von S
Erfolgloser Abbruch, wenn bei 2. bzw. 3. der jeweilige
Bereich von S nur aus einem Element besteht und
dieses Element nicht a ist.
Bestimmung des Suchabschnittes in S:
1. Initialisierung: unten := 1; oben := n;
naechster := aus [unten..oben] ausgewählter Index
(des Elements e);
2. Solange oben > unten und a  S[naechster], führe
folgende Schritte aus:
Wenn a < S[naechster], dann oben := naechster - 1,
sonst unten := naechster + 1.
naechster := aus [unten..oben] ausgewählter Index;
3. Wenn a = S[naechster], dann wurde a gefunden,
sonst ist a nicht in S.
Halt.
Der Index von e (naechster) kann durch
unterschiedliche Strategien ausgewählt werden:
a) lineare Suche: naechster := unten
b) binäre Suche: naechster := (oben + unten)/2 Intervallhalbierung
(x bedeutet: kleinste ganze Zahl größer oder gleich
x)
c) Interpolationssuche: zusätzlich werden S[0] und
S[n + 1] eingeführt
naechster := (unten - 1) +
(a - S[unten - 1])*(oben - unten + 2)/
(S[oben + 1] - S[unten - 1])
Beispiel: S = (3, 8, 12, 16, 21, 27, 32), a = 12
Binäre Suche
3
8
12
unten
16
21
naechster
naechster oben
unten + naechster
27
32
S
erster
Suchabschnitt
zweiter
Suchabschnitt
dritter
Suchabschnitt
oben
Interpolationssuche
Zusätzliche Elemente: S[0] = 0
S[8] = 37
0 3
27
8
unten
12
16
21
naechster
erster Suchabschnitt
32
oben
37
S
Binärer Suchbaum


S = (x1,..., xn) mit xi < xi+1, i=1,...,n-1
T Binärbaum mit den Knoten v1,..., vn und der
Markierungsfunktion
Label: {v1,..., vn }  S ,
wobei gilt:
vk sei die Wurzel eines beliebigen Unterbaums
Tk von T. vi bzw. vj seien beliebige Knoten im
linken bzw. rechten Unterbaum von Tk. Dann
Label(vi) < Label(vk) < Label(vj)

Suchbaum mit symmetrischer Ordnung:
- Markierung der inneren Knoten mit
Elementen aus S.
- Markierung der Blätter mit offenen
Intervallen, die alle Elemente umfassen, die
nicht im Suchbaum auftreten.
Beispiel: S = (3, 8, 12, 16, 21, 27, 32)
16
8
3
( , 3)
27
12
21
32
(3, 8)
(16, 21) (21, 27)
(8, 12) (12, 16)
(27, 32)
(32, )
Algorithmus für den Zugriff zu einem Element a
im Baum T:
1. Initialisierung: v := Wurzel von T;
2. Solange v kein Blatt ist und Label(v)  a,
wiederhole:
Ist a kleiner als Label(v), dann v := linker
Sohn von v,
sonst v := rechter Sohn von v.
3. Wenn v ein innerer Knoten ist, dann wurde a
gefunden, sonst ist a nicht im Baum
vorhanden.
Algorithmus zum Einfügen eines neuen Knotens
a mit xi0 < a < xi0+1 und S = (..., xi0, xi0+1,...):
1. Auffinden des Blattes mit der Markierung
(xi0, xi0+1)
2. Ersetzen des Blattes durch einen Baum
a
(xi0, a)
(a, xi0+1)
Assoziatives Suchen
Gewichtete Bäume
Zugriffsverteilung (0, 1, 1,..., n, n):
S = (x1,..., xn) mit x1 < x2 < ... < xn
i Wahrscheinlichkeit, dass das
Zugriffselement a identisch mit xi ist
j Wahrscheinlichkeit, dass das
Zugriffselement a im Intervall (xj, xj+1)
liegt
i + j = 1
Assoziatives Suchen
Gewichtete Bäume
Tiefe eines Baumknotens v eines Baumes T:
1. v sei die Wurzel von T: Tiefe(v, T) = 0
2. Es sei T = <w, T1,..., Tm> und v sei ein
Knoten im Teilbaum Ti:
Tiefe(v, T) = 1 + Tiefe(v, Ti)
T
T1
w
Ti v k
Tm
v
Assoziatives Suchen
Gewichtete Bäume
Gewichtete Pfadlänge PT eines Baumes T:
PT =  i*(1 + biT) +  j*ajT
biT Tiefe des Knotens xi im Baum T
ajT Tiefe des Blattes (xj, xj+1) im Baum T
Beispiel:
x3
x2
x1
(x0, x1)
1/6
1/8
1/8
1/24
x4
(x2, x3)
0
(x3, x4)
1/8
0
(x4, x5)
5/12
(x1, x2 )
0
PT = (1/24*3 + 1/8*2 + 1/8) + (1/6*3 + 1/8*2 + 5/12*2)
Assoziatives Suchen
Balancierte Bäume
1. Gewichtsbalancierte Bäume
Wurzelbalance eines Baumes T:
Voraussetzungen:
- T hat einen linken Unterbaum Tl und einen
rechten Unterbaum Tr
- |T| bedeutet die Anzahl der Blätter von T
Wurzelbalance: (T) = |Tl|/|T| = 1 - |Tr|/|T|
Assoziatives Suchen
Gewichtsbalancierte Bäume
Baum T von beschränkter Balance 
(T  BB[]):
Für jeden Unterbaum T’ von T gilt
  (T’)  1 - .
Bedeutung der Bäume aus BB[]:
Sie besitzen logarithmische Tiefe und im Mittel
logarithmische mittlere Pfadlängen
(für ¼ <   1 - 21/2/2).
Beispiel:
5/14
2/5
4/9
1/2
()
2/3
()
1/2
()
1/2
()
()
1/2
()
2/5
1/2
() () () ()
Für   1/3 ist der Baum aus BB[].
1/2
2/3
( ) 1/2
( )
()
( )
Operation Rotation nach links
1
x
y
1
y
2
x
2
a
c

b
c
1 = 1 + (1 - 1)*2
2 = 1/(1 + (1 - 1)*2)
a
b
Operation Doppelrotation nach links
1
x
2
y
1
z
x
2
y
3
a

z
3
d
b
c
1 = 1 + (1 - 1)*2*3
2 = 1/(1 + (1 - 1)*2*3)
3 = 2*(1 - 3)/(1 - 2*3)
a
b
c
d
Assoziatives Suchen
Balancierte Bäume
2. Höhenbalancierte Bäume
(a, b)-Baum:
Voraussetzungen:
a, b ganze Zahlen, a  2, b  2*a - 1
(v) Anzahl der Söhne des Knotens v
T ist ein (a, b)-Baum, wenn gilt:
1. Alle Blätter von T haben die gleiche Tiefe.
2. Alle Knoten v von T erfüllen die Bedingung (v)  b.
3. Alle Knoten v, außer der Wurzel, erfüllen die Bedingung (v)  a.
4. Die Wurzel r hat die Eigenschaft (r)  2.
Abspeicherung einer Menge S als Baum T (Mehlhorn):
1.
Die Elemente von S werden als Blätter von T von
links nach rechts in aufsteigender Ordnung
abgespeichert.
2. Jeder innere Knoten v wird mit
k1(v) : k2(v) : ...: k(v)-1
markiert, ki(v) < kj(v) für i < j und ki(v), kj(v)  U,
wobei gilt:
a) Für alle Blätter w des ersten Unterbaumes von v:
Label(w)  k1(v).
b) Für alle Blätter des (v). Unterbaumes von v:
Label(w) > k(v)-1.
c) Für die Blätter w des i. Unterbaumes von v,
1 < i < (v): ki-1(v) < Label(w)  ki(v).
Beispiel:
(2, 4)-Baum
4
2
1
7:8:9
3
7
8
9
10
a:b:c
bedeutet eine Elementeaufteilung in folgende Bereiche
a
(a, b] (b, c]
c<
Beispiel: Rebalancierung nach Einfügen
4
2
6:7:8:9
1
3
Kein (2, 4)-Baum!
6
Rebalanciert:
8
9
10
4:7
2
1
7
6
3
6
8:9
7
8
9
10
Beispiel: Rebalancierung nach Streichen
4:7
2
6
1
3
Kein (2, 4)-Baum!
Rebalanciert:
6
7
8
9
7
3
10
4:8
2
1
8:9
7
9
8
9
10
Komplexitäten
Sortieralgorithmen
Vorraussetzungen: U Universum,
S Sortiermenge, |U| = m (im endlichen Fall), |S| = n
 Adressenorientiertes Sortieren:
- Zeit: O(n + m)
- Speicher: O(n * m)
 Lexikographisches Sortieren (k
Stellenanzahl der
sortierten Wörter, m Anzahl unterschiedlicher
Zeichen):
- Zeit: O(k * (m + n))
- Speicher: O(n * m)




Insersort, Selectsort, Bubblesort:
- Zeit: O(n2)
- Speicher: O(n)
Mergesort:
- Zeit: O(n * log2 n)
- Speicher: O(n)
(2 * n)
Quicksort:
- Zeit: O(n2) , durchschnittlich ca. (n * log2 n)
- Speicher: O(n)
Countsort:
- Zeit: O(n2)
- Speicher: O(n)
(3 * n)



Hybrides Sortieren:
- Zeit: O(n * log2 n), durchschnittlich ca. (n)
- Speicher: O(n)
(2 * n)
Heapsort:
- Zeit: O(n * log2 n)
- Speicher: O(n)
Shellsort:
Zeit: O(n1,5) (hängt entscheidend von den
gewählten Abständen ab und ist schwer ermittelbar)
Ausgewählte Komplexitäten
Suchverfahren
Vorraussetzungen: U Universum, S Suchraum,
|S| = n, m Anzahl möglicher Eintragungen in einer
Hashtabelle



Charakteristischer Vektor:
Anfrage und Aktualisierung O(1)
Hashing mit Verkettung: Anfrage, Einfügen, Löschen
im schlechtesten Fall (n)
Hashing mit offener Adressierung: durchschnittliche
Suchzeit bei Belegungsfaktor  =n/m
ca. (1/)*log2 (1/(1-))







Digitale Suchbäume: O(l) mit l Anzahl der Bit, aber
durchschnittlich ca. (log2 n)
Tries: O(l) mit l Länge des Hashwertes
Binäre Suche: Anfrage O(log2 n), Einfügen und
Löschen O(n)
Binärer Suchbaum: O(T) mit T Tiefe des
Suchbaums
Interpolationssuche: O(n) , durchschnittlich
ca. (log2 log2 n)
BB[],   (1/4, 1 – 21/2/2]: O(log2 n)
(a, b)-Baum: Suche, Einfügen, Löschen O(log2 n)
Evolutionsalgorithmen
Charakterisierung:

Such- und Optimierungsstrategien nach
dem Vorbild der Evolution in der Natur

Ingenieurtechnisch ist Evolution
- ein Suchprozess im Raum genetischer
Informationen bzw. Erbanlagen
- mit dem Ziel des Findens bester
Erbanlagen

Verwendung schwacher Strategien (nicht
problemabhängig; keine spezielle
Bewertung)
Durchlauf durch den Suchraum:
Bestimmung des nächsten Suchpunktes
ausgehend von durchlaufenen Suchpunkten und
aktuellem Suchpunkt
unter Nutzung von Bewertungskriterien
Durchlaufstrategien:


Feste Strategien
Wissensbasierte Strategien
Evolutionsalgorithmen:
 Genetische Algorithmen
 Genetische Programmierung
 Evolutionsstrategien
 Evolutionäre Programmierung
Anwendungen:
 Ältere Anwendungen:
1967 Entwicklung von Spielstrategien,
Mustererkennung, Simulation lebender Zellen,
1975 Optimierung der Form von Kühlrippen,
1975 Gewichtsoptimierung eines
Stabtragwerkes

Neuere Anwendungen:
Data Mining, automatische
Programmerzeugung, Berechnung optimaler
Linsenformen, Strukturevolution neuronaler
Netze
Genetische Algorithmen
Genetische Algorithmen bilden eine Analogie
zur natürlichen Auswahl und Evolution.
Charakterisierung:
1. Wahl eines geeigneten
Kodierungsmechanismus’ für
Problemlösungen als „Chromosomen“ (i.d.R.
Bitvektoren für Individuen)
2. Mechanismus zur Erzeugung der initialen
Lösungspopulation (Generation 0)
Genetische Algorithmen
(Fortsetzung)
3. Wiederholung nachfolgender Schritte bis
zum Erreichen einer zufriedenstellenden
Bewertung oder einer Abbruchbedingung:
- Bewertung der aktuellen Population gemäß
Bewertungs- oder Fitnessfunktion
(Bewertung: Nähe zum Optimum;
Fitness: Wahrscheinlichkeit des Überlebens
und der Teilnahme an der Reproduktion 
Abbruch oder Fortsetzung mit nächstem Punkt)
Genetische Algorithmen
(Fortsetzung)
- Selektion von Subpopulationen gemäß
Heiratsschema und Erzeugung von
Nachkommen der aktuellen Generation
mittels Rekombination
- Mutation der Nachkommen
- Bestimmung der neuen Generation gemäß
Ersetzungsschema
- Aktualisierung der Abbruchbedingung
Beispiel: Problem des Handelsreisenden
Naiver Lösungsprozess: Bestimmung aller möglichen
Routen ((n-1)!) und Auswahl der kürzesten  praktisch
nicht durchführbar
Lösung durch genetischen Algorithmus:
1. Kodierung der Routen:
a) graphisch: Städte als Knoten, Reisestrecken als
bewertete Kanten
Beispiel:
C
B
A
D
E
F
b) Vektor, dessen Komponenten den direkten
Städteverbindungen entsprechen:
1 Verbindung vorhanden
0 Verbindung nicht vorhanden
Probleme:
 geschlossene Wegstrecken sind schlecht erkennbar
 schwere Realisierbarkeit vernünftiger
Rekombinations- und Mutationsoperatoren
c) Vektor S mit k Komponenten (Indizes 0,1,...,k-1), k
Anzahl der Städte: Jedem Element aus {0,1,...,k-1}
entspricht eine Stadt. Die Vektorkomponenten führen
die besuchten Städte kodiert und in der
Besuchsreihenfolge an.
Beispiel:
Zuordnung: A  0, B  1, C  2, D  3,
E  4, F  5
S für obigen Weg: (0, 1, 3, 2, 4, 5)
2. Festlegung von Bewertungs- und
Abbruchkriterien
3. Festlegung von Rekombinations- und
Auswahlstrategien
Beispiele: Rekombinationsstrategien
Kreuzung: Eltern
01001100

11001001
Kinder
01001001
11001100
Mutation: Löschen - Nachschieben - Einsetzen
8710634952 
8706349521
Genetische Programmierung
Genetische Programmierung kann als
genetische Algorithmen auf abstrakten
Syntaxbäumen von Programmen betrachtet
werden
Ziel: Es sollen Programme erzeugt werden, die
bestimmten Kriterien genügen
Vorgehensweise: siehe genetische Algorithmen
Genetische Programmierung
(Fortsetzung)
Beispiel:
Programm in LISP-Notation:
(MUL (ADD X (DIV Y 1.5)) (SUB Z 0.3))
Y/1.5
X + Y/1.5
(X + Y/1.5) * (Z - 0.3)
Z - 0.3
Genetische Programmierung
(Fortsetzung)
Abstrakter Syntaxbaum:
MUL
ADD
X
SUB
DIV
Y
Z
1.5
0.3
Algorithmusschritte:
1. Erzeugung einer initialen
Programmpopulation
2. Wiederholung folgender Schritte bis zum
Erreichen von Abbruchkriterien:
a) Bewertung der aktuellen Population 
Abbruch bzw. Fortsetzung mit b)
b) Erzeugung neuer Programme durch übliche
genetische Operationen (z.B. Austausch von
Baumteilen, Ersetzen von Baumteilen), die
auch typgesteuert sein können
c) Bestimmung der neuen Generation
Programmpopulation
Programmtest
Elternauswahl
Neue
Programme
Evolutionsstrategien
Ziel: Verbesserung von Verhalten durch
Evolution
Population:


Vektoren reeller Zahlen
Vektorkomponenten entsprechen
Verhaltensmerkmalen
Vorgehensweise: analog zu genetischen
Algorithmen
Evolutionäre Programmierung
Keine Beschränkungen für Populationen!
Erzeugung neuer Populationen durch
Mutation
Komponenten prozeduraler (imperativer)
Programmiersprachen (1)
 Ausdrucksmittel zur Darstellung des
Steuerungsflusses (Iteration, Sequenz,
Alternative, Parallelität)
 Prozedurabstraktion (Zusammenfassung von
Anweisungsfolgen zu einer, evtl.
parametrisierten, Programmeinheit, die an
verschiedenen Programmstellen aufgerufen
werden kann)
Komponenten prozeduraler (imperativer)
Programmiersprachen (2)
 Programmvariablen als Modell für Speicherplätze:
- Charakterisierung durch
Name (Bezeichnung im Programm),
Referenz (Adresse des zugeordneten
Speicherplatzes),
Wert (Inhalt des zugeordneten Speicherplatzes),
Typ (Art des Inhaltes des zugeordneten
Speicherplatzes)
Komponenten prozeduraler (imperativer)
Programmiersprachen (3)
- Möglichkeit der Wertänderung
- unterschiedliche Arten der
Parametervermittlung (z.B. Referenzaufrufe,
Werteaufrufe)
- Nebeneffekte (side effect) von Prozeduren
bei Wertänderung von nichtlokalen Variablen
Komponenten prozeduraler (imperativer)
Programmiersprachen (4)
- Möglichkeit der Mehrfachreferenz (Aliasnamen)
- Sprachkonzepte zur Speicherverwaltung (z.B.
Erzeugung und Beseitigung von Speicherplatz)
- Lebensdauer und Gültigkeitsbereiche
Lebensdauer: Dauer der Existenz eines Objekts; z.B.
während der Existenz eines Prozedurkörpers existieren
alle dort deklarierten Variablen.
Gültigkeitsbereich: gibt Zugriffsmöglichkeiten zum
Objekt an
Komponenten prozeduraler (imperativer)
Programmiersprachen (5)

Datentypkonzept:
- Datentyphierarchie
alle
elementar
aufzählbar
strukturiert
nicht aufzählbar
rekursiv endliche kartesisches Vereinigung
(Zeiger) Abbildung Produkt
(union)
(Array)
(Record)
- Typkontrollen, Typäquivalenz
Komponenten funktionaler
Sprachen





Menge einfacher Datenobjekte (z.B. Listen)
Menge vordefinierter elementarer Funktionen (z.B.
zur Listenbearbeitung)
Regeln zur Komposition von Funktionen (z.B.
Verkettung)
Bezeichnungsregeln für Funktionen im
Zusammenhang mit Deklarationen
Anwendungsoperator für Funktionen
(Funktionsaufruf)
Beispiel
% Sortierfunktion
DEF sort([]) = []
DEF sort([a|R]) = a insert sort(R)
% [a|R] bezeichnet eine Liste mit dem Kopfelement
% a und der nachfolgenden Restliste R
% Einfuegefunktion
DEF x insert [] = [x]
DEF x insert [a|R] = IF x  a THEN [x|[a|R]]
ELSE [a|(x insert R)]
FI
Sortieren von {17, 5, 7, 1}
sort([17|[5, 7, 1]])
17 insert sort([5, 7, 1])
7 insert sort([1])
sort([1|])
sort([5|7, 1])
1 insert sort([])
5 insert sort([7, 1])
1 insert []
sort([7|1])
[1]
Sortieren von {17, 5, 7, 1} (Fortsetzung)
7 insert [1] = 7 insert [1|]
17 insert [1, 5,7]
[1|7 insert []]
[1|17 insert [5, 7]]
[1|[7]] = [1, 7]
5 insert [1, 7]
[1|[5|17 insert [7]]]
[1|[5|[7|17 insert []]]]
[1|5 insert [7]]
[1|[5|7 insert []]] = [1, 5, 7]
[1|[5|[7|[17]]]] =
[1, 5, 7, 17]
Sprachelemente von Prolog
 Klausel (Hornklausel): A  B1,...,Bq.
q  0, A,
B1,...,Bq
Atome
Bedeutung:
x1,...,xk (B1’  ...  Bq’)  A’
x1,...,xk alle Variablen der Klausel
A’, B1’,...,Bq’ Aussagen, entstanden aus A, B1,...,Bq
Fakt: A. verkürzte Form von A  .
 Atom: p(t1,..., tn), p
n-stelliges Prädikatsymbol,
t1,..., tn
Terme
Sprachelemente von Prolog (Fortsetzung)

Programm: P = <p, f, r, g>
p endliche Menge von Prädikatsymbolen
f endliche Menge von Funktionssymbolen
r endliche Menge von Klauseln unter
Verwendung von p und f
g Anfrageklausel der Form
goal  B1,...,Bq. oder
?- B1,...,Bq.
Beispiel
insertsort([], []).
%Die leere Liste sortiert ergibt wiederum die
% leere Liste.
insertsort([A|R], S) :insertsort(R, SR), insert(A, SR, S).
%Ist eine Liste nicht leer, so wird erst die
% Restliste sortiert und anschliessend das
%Kopfelement in die sortierte Restliste auf
% den richtigen Platz eingefuegt.
Beispiel (Fortsetzung)
insert(X, [A|R], [A|S]) :gt(X, A), !, insert(X, R, S).
%Ist das einzufuegende Element X groesser als
% das Kopfelement der Liste, so muss es in die
% Restliste R eingefuegt werden.
insert(X, S, [X|S]).
%Ist das einzufuegende Element X kleiner oder
%gleich dem Kopfelement, so wird es als neues
%Kopfelement verwendet und die alte Liste S
% bildet die neue Restliste.
Beispiel (Fortsetzung)
Anfrage
?- insertsort([17, 5, 7, 1], S).
Systemantwort
yes
S = [1, 5, 7, 17]
Logische Programmierung mit Einschränkungen
(Constraint logic programming) - Beispiel
%Zusammenstellung einer kalorienarmen Mahlzeit
lightmeal(Vorspeise, Hauptmahlzeit, Nachspeise):I > 0, J > 0, K > 0, I + J + K <= 10,
%Die gesamte Mahlzeit darf nicht mehr als 10
%Kalorien enthalten.
vor(Vorspeise, I), haupt(Hauptmahlzeit, J),
nach(Nachspeise, K).
%Erster Parameter ist Speise, zweiter ist Kalorien
Beispiel (Fortsetzung)
%Vorspeisen
vor(rettich, 1).
vor(nudeln, 6).
%Hauptmahlzeit
haupt(H, I) :- fleisch(H, I).
haupt(H, I) :- fisch(H, I).
fleisch(bulette, 6).
fleisch(schwein, 7).
fisch(seezunge, 2).
fisch(thun, 4).
%Nachspeise
nach(obst, 2).
nach(eis, 6).
Beispiel (Fortsetzung)
Anfrage
?- lightmeal(V, H, N).
Antwort des Systems
V = rettich, H = bulette, N = obst.
Funktionales Programmieren
Funktionen in der Mathematik
Definition (Funktion, Abbildung): D und W
seien Mengen und f eine binäre,
linkseindeutige Relation f  D x W. Dann
heißt f Funktion mit dem Definitionsbereich D
und dem Wertebereich W. f bildet den
Argumentwert x  D auf den Resultatswert
y  W genau dann ab, wenn (x, y)  f
(Notation: f(x) = y. f(x) bezeichnet
demzufolge die Anwendung von f auf x.).
D  W ist der Typ (Funktionalität, Profil) von f.
f heißt partiell (total), wenn die Projektion von f
auf D eine Teilmenge von D (die Menge D) ist,
d.h. 1(f)  D (1(f) = D).
Definition (Totalisierung einer partiellen Funktion): Es
sei f eine partielle Funktion mit dem Definitionsbereich
D und dem Wertebereich W. Außerdem gelte
D = D  {} und W = W  {}. Dann ist f eine
totale Funktion mit dem Definitionsbereich D sowie
dem Wertebereich W und
 y, f(x) = y, x  D
f(x) =  , f(x) ist nicht definiert, x  D
 , x = 
Funktionales Programmieren
-Terme
Definition (-Terme): -Terme sind
1. Variablen, Konstanten , Funktionssymbole
2. Terme der Form v.l (-Abstraktion) mit
der Variablen v und dem -Term l; v heißt
gebundene Variable in l.
3. Terme der Form (m n) (-Applikation) mit
den -Termen m und n. m steht in
Funktionsposition und n in Argumentposition.
Beispiele (Infixnotation statt Präfixnotation):

(x. 1 + x)
 ((x. 1 + x) 2)  1 + 2  3

(x. ((y. ((x. x * y) 2)) x) x + y)
2*y
2*x
2 * (x + y)
Konversionen ( Reduktion,  Abstraktion):
1. Alpha-Konversion: (x. E)  E[y/x]
(Einsetzen von y anstelle von x in E;
Umbenennung von Variablen )
2. Beta-Konversion: ((x. E) F)  E[F/x]
Die Reduktion ist analog zum Ersetzen
formaler Parameter durch aktuelle Parameter
bei Prozeduraufrufen imperativer Sprachen. Zu
beachten sind Namenskonflikte, die durch den
Ersetzungsprozess entstehen können.
3. Eta-Konversion: (x. (E x))  E
Problem der Reihenfolge der Auswertung bei Reduktion:
1.
Erst Auswertung von F und dann Einsetzen
für x – applikative oder strikte Auswertung
(eager evaluation)
2.
Erst Einsetzen von F für x und anschließend
Auswertung – normalisierende Auswertung
(normal-order evaluation);
Auswertung erfolgt nur, wenn sie benötigt
wird – verzögerte Auswertung (lazy
evaluation)
Beispiel:
(((b1. (b2. IF b1 THEN b2 ELSE FALSE FI)) n  0)
t/n  0.5)
n sei 0:
Strikte Auswertung: Im zweiten Argumentterm
tritt eine Division durch 0 auf und somit kann
dieser Term nicht ausgewertet werden.
Verzögerte Auswertung:
IF n  0 THEN t/n  0.5 ELSE FALSE FI  FALSE
Diesmal wird der Term nicht benötigt und
daher nicht berechnet.
Funktionale Programmierung
Datentypen
Elementare Datentypen: z.B. int, real, bool,
string
Zusammengesetzte Datentypen: z.B. Tupel
(Untermengen kartesischer Produkte),
Verbunde (Tupel mit Selektoren), Listen
(Tupel mit Elementen vom gleichen Typ),
Funktionstypen
Ausgewählte Programmkonstrukte:
- Wertedefinition
val Identifikator = Ausdruck
Dem Identifikator wird der Ausdruck als
Bedeutung zugeordnet.
- Funktionsabstraktion
fun (Identifikator:Typ)  Ausdruck
Dies entspricht dem -Term
 Identifikator.Ausdruck,
wobei der Identifikator (Variable) zusätzlich
einen Typ bekommen hat.
- Funktionsdefinition
val Name der Funktion =
Funktionsabstraktion
oder
fun Name der Funktion
(Identifikator:Typ) = Ausdruck,
wobei
Identifikator, Typ und Ausdruck aus der
Funktionsabstraktion stammen.
Beispiele:

Typvereinbarung für Binärbäume mit real-
Zahlen als Markierungen:
datatype tree = nil
| tree of (real * tree * tree)
(Typgleichung: tree = unit + (real x tree x
tree) )
Musterbasierte Funktionsdefinition: Summe
der real-Zahlen des Baumes
fun sum(nil) = 0.0
| sum(tree(N, L, R)) = N + sum(L) +
sum(R)
1.0
-3.5
-5.7
7.7
5.7
8.0
sum(tree(1.0, tree(-3.5, tree(-5.7, nil, nil), nil),
tree(7.7, tree(5.7, nil, nil), tree(8.0, nil, nil))))
= 13.2

Einsortieren einer int-Zahl in einen Binärbaum mit
int-Zahlen als Markierungen:
datatype tree = nil
| node of (tree * int * tree)
fun insert(newitem, nil) = node(nil, newitem, nil)
| insert(newitem, node(left, olditem, right)) =
if newitem = olditem
then node(insert(newitem, left), olditem,
right)
else node(left, olditem, insert(newitem, right))

Typvereinigung von line, triangle und circle zu Figure
datatype Figure = line of (point * point)
| triangle of (point * point * point)
| circle of (point * real)
(Typgleichung: Figure = line + triangle + circle
mit
line = point x point,
triangle = point x point x point,
circle = point x real)

Parametrisierte Datentypen:
z.B.
type  pair =  * 
definiert Paare von Elementen eines beliebigen Typs
.
Datentypen
Listentyp

datatype  list = nil| cons of ( *  list)
fun hd(l:  list) =
case l of nil  ... (*Fehler*)
|cons(h,t)  h
and tl(l:  list) =
case l of nil  ... (*Fehler*)
|cons(h,t)  t
and length(l:  list) =
case l of nil  0
|cons(h,t)  1 + length(t)
Eine Liste ist eine Folge von Elementen des
gleichen Typs.
Definiert sind Funktionen zur Bestimmung des
Listenkopfs (hd), des Listenrests (tl) und ihrer
Länge (length).
(Typgleichung: -list = unit + ( x -list) )
Notation: cons(h, t) oder h::t bezeichnen
eine Liste mit dem Kopf h und dem Rest t.
Listentyp
Operationen
Beispiele:

Summe der Elemente einer Liste ganzer Zahlen
fun sum(nil) = 0
|sum(n::ns) = n + sum(ns)
 Produkt der Elemente einer Liste ganzer Zahlen
fun product(nil) = 1
| product(n::ns) = n * product(ns)
 Liste der ganzen Zahlen von m bis n ([m, n])
fun op through(m,n) =
if m  n then nil else m:: (m + 1 through n)
op bedeutet, der folgende Operator kann als Infixoperator
verwendet werden.
Currying im Beispiel:
Definition der Berechnung von bn
1. Variante (gewöhnlich):
fun power(n, b) = if n=0 then 1.0
else b*power(n-1, b)
Funktionalität: nat x integer  integer
2. Variante (Currying):
fun powerc(n) (b) = if n = 0 then 1.0
else b * powerc(n - 1) ( b)
Funktionalität: nat  (integer  integer)
Wenn val sqr = powerc(2) , dann liefert sqr das
Quadrat zu einer integer-Zahl.
Funktion als Argument im Beispiel:
1. Variante:
fun twice(f: ) = fun (x: )  f(f(x))
Funktionalität: ()  ()
twice hat als Parameter eine Funktion und liefert
selbst wieder eine Funktion. Daher könnte die vierte
Potenz so definiert werden: val fourth = twice(sqr)
2. Variante:
Definition der Verkettung zweier Funktionen:
fun op (f:  , g:  ) = fun (x:)  f(g(x))
Funktionalität: () x ()  ()
fun twice(f:) = f  f
Listentyp
Allgemeine Operationen
Filteroperationen: Alle Elemente einer Liste, die eine
gegebene Eigenschaft besitzen (ausgedrückt durch
ein Prädikat p), sollen in eine neue Liste
übernommen werden.
filter p [] = []
x:: filter p xs, wenn p x
filter p (x::xs) = 
filter p xs, sonst
Funktionalität: (  bool)  (-list  -list)
Beispiel: filter(odd) beseitigt alle geraden Zahlen
aus einer Liste ganzer Zahlen
Abbildung: Auf jedes Element einer Liste wird
die gleiche Funktion angewendet.
map f [] = []
map f (x::xs) = f x:: map f xs
Funktionalität: () (-list  -list)
Beispiel: map(sqr) liefert auf eine integerListe angewendet eine Liste der Quadrate
der Listenelemente bzw. map(odd) liefert eine
Liste logischer Werte in Abhängigkeit davon,
ob ein Listenelement ungerade (true) oder
gerade (false) war.

Faltung: Diesen Operator gibt es als rechte
und linke Faltung. Die Faltung bedeutet, dass
alle Elemente einer Liste ausgehend von
einem wählbaren Startwert durch eine
zweistellige Operation verknüpft werden, z.B.
durch Addition.
faltr f a [x1,...,xn] = f x1 (f x2 (...(f xn a)...))
f ist eine zweistellige Operation und a ist der
Startwert. Die Anwendung von f geschieht
von rechts.
Funktionalität: ()    []  
Rechte Faltung in der Sprache ML:
fun reduce(binaryop, unity) =
let fun f(nil) = unity
|f(x::xs) = binaryop(x, f(xs))
in f
end

Definition der Summe bzw. des Produkts der
Elemente einer Liste von integer-Zahlen:
reduce(op +, 0) bzw. reduce(op *, 1)
Potenziell unendlich lange Listen und
verzögerte Auswertung
Beispiel: näherungsweise Berechnung der
Quadratwurzel durch yn+1 = (yn + x/yn)/2
Lösungsidee:
 Berechnung der Elemente der unendlichen
Folge gemäß Formel
 Abbruch der Berechnung der Folge, wenn
sich zwei aufeinander folgende Elemente um
nicht mehr als  unterscheiden

Berechnung der Listenelemente:
fun approxsqrts(x) =
let fun from(approx) = approx:: from(0.5 * (approx
+ x/approx))
in from(1.0)
end

Überprüfung der Abbruchbedingung für die
ersten beiden Elemente einer Liste:
fun absolute(eps) (approx1::approx2::approxs) =
if abs(approx1 - approx2) = eps
then approx2
else absolute(eps) (approx2::approxs)

Kombination der obigen Funktionen zur
Lösungsfunktion:
val sqrt = absolute(0.0001)approxsqrts
Listenelemente werden durch approxsqrts nur
solange berechnet, wie sie für den Test
absolute(0.0001) benötigt werden.
Andere Vorgehensweise (nicht in ML-Notation):
 Verbesserung eines Näherungswertes y
gemäß Formel (für x ist die Quadratwurzel zu
berechnen):
verbessern x y = (y + x/y)/2
 Überprüfung der Abbruchbedingung für zwei
Werte x und y:
erfüllt x y = abs(y^2 - x)  eps


Berechnung eines Funktionswertes der
Funktion f mit dem Argument x in
Abhängigkeit von der Bedingung p:
 x, wenn p x
bis p f x = 
 bis p f(f x), sonst
Kombination obiger Funktionen:
wurzel x y = bis (erfüllt x) (verbessern x) y
Beispiele: Sortierfunktionen in der Sprache
OPAL
 OPAL-QUICKSORT
DEF sort() == 
DEF sort(a::R) ==
LET Small == (_ a)  R
Medium == a:: (_= a)  R
Large == (_ a)  R
IN sort(Small) :: Medium :: sort(Large)
 liefert zu einer Liste alle Elemente, die eine
bestimmte Bedingung erfüllen, in Form
einer Liste.  vertritt die leere Liste.

OPAL-INSERTSORT
DEF sort() == 
DEF sort(a :: R) == a insert sort(R)
FUN insert:  x seq[]  seq[]
DEF x insert  == x :: 
DEF x insert (a :: R) ==
IF x  a THEN x :: (a :: R) ELSE a :: (x insert R) FI

Beispiel