Está en la página 1de 124

1 2

Inhaltsüberblick

0. Einführung
Programmstrukturen
Vorlesung 1. Algorithmen
Paradigmen, Analyse
Algorithmen und Datenstrukturen 2. Datenstrukturen
(PI.ADS.AD.VO) Allgemeiner Überblick
3 Stunden / 4 ECTS Punkte 3. Listen
Lineare Speicherstrukturen, Stack, Queue
4. Bäume
Ao. Univ.-Prof. Dipl.-Ing. Dr. Erich Schikuta Suchstrukturen
Institut für Knowledge and Business Engineering 5. Vektoren
Fakultät für Informatik, Universität Wien Sortieren, Hashing
SS 2007 6. Graphen
Traversierungs- und Optimierungsalgorithmen
VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

3 4

Literatur Danksagung

R. Sedgewick, Algorithmen in C++ (Teil 1-4), Addison Wesley, Für Mitarbeit und Durchsicht der Folien geht mein
3. überarbeitete Auflage, 2002 besonderer Dank an Helmut Wanek, Clemens
Thomas H. Cormen, Charles E. Leiserson, and Ronald L. Bruckmann und Martin Polaschek
Rivest, Introduction to Algorithms, published by MIT Press
and McGraw-Hill. (First published in 1990.) Mein weiterer Dank geht an zahlreiche Studierende
Jim Gray, Vortrag: Parallel Database Systems der letzten Jahre, die im Rahmen ihrer Übungen die
Analyzing LOTS of Data, Microsoft Research, 1997 Basis für einige der dynamischen Beispiele der VO
E. Schikuta, Folien zur Vorlesung, lieferten.
Algorithmen und Datenstrukturen 1,
SS 2006

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


5 6

0.1 Was ist Informatik ?

Die Wissenschaft der Informatik umfasst alle Modelle (Methoden,


Kapitel 0: Verfahren, Konzepte, etc.), die dazu dienen eine gegebene
Eingabe in eine beliebige Ausgabe zu verwandeln
Einführung

Input Output
Informatik

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

7 8

Modelle der Informatik Beispiele für Modelle

Kochrezept als Folge von Anweisungen


Amerikanischer Wildreis
Modelle Computerprogramm 1 Tasse ergibt 3 Portionen
der Reis gründlich waschen
Spielregeln 1 Tasse Reis in 3 Tassen kochendes Wasser geben
Input Informatik
Bedienungsanleitung Output kurz aufkochen lassen
...
Kochrezept bei schwacher Hitze 25 min bedeckt dünsten
Reis abdecken, salzen, mit Gabel auflockern
restliche Flüssigkeit verdampfen
Informatik
Beschreibung von Ursache-Wirkungs-
Zusammenhängen
Weißes Licht erhält man, wenn man rotes,
grünes und blaues Licht mischt
VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta
9 10

0.2 Algorithmus Algorithmus - Eigenschaften (1)

Unter Algorithmus versteht man die schrittweise Eingangswerte/Ausgabewerte


EW sind vor, AW nach der Ausführung bekannt
Vorschrift zur Berechnung gesuchter aus
Eindeutigkeit
gegebenen Größen, in der jeder Schritt aus einer Jeder Schritt der Ausführung muß eindeutig sein, keine
Anzahl eindeutig ausführbarer Operationen und Mehrdeutigkeiten möglich
einer Angabe über den nächsten Schritt besteht. Endlichkeit
Statisch: mit endlich vielen Zeichen formulierbar
Dynamisch: in endlich vielen Schritten beendbar
Ursprung Vollständigkeit
Algorithmus ≈ Berechnungsvorschrift sollte vollständig sein, sollte alle möglichen Fälle behandeln
Ben Musa Al-Chwarizmi (usbekischer Mathematiker um Korrektheit
825), erstes Buch über Algebra sollte das gewünschte Ergebnis liefern

arithmos ... griechisches Wort für Zahl Granularität der Operationen


Spezifikationsgenauigkeit der einzelnen Beschreibungselemente

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

11 12

„Paradigmen“ und Darstellung Das logikbasierte Paradigma

Paradigma ein Programm besteht aus Regeln und Fakten


Wenn es regnet, nehme ich den Schirm.
„ ... Das, was den Mitgliedern einer wissenschaftlichen Gemeinschaft Wenn ich zerstreut bin, vergesse ich den Schirm unterwegs.
gemeinsam ist ... eine Konstellation von Meinungen, Wertungen Wenn ich zerstreut bin, grüße ich Bekannte nicht.
und Methoden...“ (Thomas Kuhn 1976) Regeln Wenn ich nicht zerstreut bin, grüße ich Bekannte.
Wenn es regnet und ich meinen Schirm unterwegs vergesse, werde ich
Algorithmen können auf ganz unterschiedliche Art konzipiert nass.
werden („Paradigmen“): Wenn es schwül ist, bin ich zerstreut.
Es ist schwül.
prozedural versus funktional versus logik-basiert Fakten Es regnet.
orthogonal dazu objektorientiert (OO) Anfrage: werde ich nass? – Antwort: ja.
Ableitbare Fakten: Ich nehme den Schirm. – Ich bin zerstreut. – Ich vergesse
auf eine bestimmte Art konzipierte Algorithmen können auf den Schirm unterwegs. – Ich werde nass. – Ich grüße Bekannte nicht.
ganz unterschiedliche Art ausgedrückt werden ein Problem: Widersprüche zwischen den Regeln
(Darstellung): Beispiel (nicht ganz ernst zu nehmen, aber illustrativ): Meta-Regel
Regel 1: Der Chef hat recht.
natürlichsprachlich, in einer Programmiersprache, … Regel 2: Stimmt dies ausnahmsweise nicht, so findet Regel 1 Anwendung.

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


13 14

Das funktionale Paradigma Das prozedurale Paradigma

Beispiel: Cäsar-Verschlüsselung ≈ imperatives Paradigma


„Nimm jeweils den im Alphabet drittfolgenden Buchstaben“
„Pfadfinder-Geländespiel“:
CAESAR
↓↓↓↓↓↓
jedes Vorkommen von 'A' Geh zur alten Höhle
FDHVDU kann durch 'D' ersetzt werden Merk dir, wieviele Fichten davor stehen
Das Programm ist nur aus Funktionen (Abbildungen) im Geh den Weg weiter bis zur Gabelung
Zähle die Fichten, die du hier siehst, dazu
mathematischen Sinn aufgebaut. Jedes Vorkommen eines Wenn du insgesamt fünf Fichten gezählt hast, geh den linken Weg
Funktionsaufrufes kann durch das Funktionsergebnis ersetzt weiter;
werden. Funktionen haben keine Seiteneffekte; es gibt keine wenn sieben, dann den rechten
Variablen. n=0 → 1
Beispiel: Fakultätsfunktion n! = {
n > 0 → n · (n – 1)!
Der Lösungsweg ist durch eine Folge von Anweisungen
vorgegeben
3! » 3·(3-1)! » 3·2! » 3·2·(2-1)! » 3·2·1! » 3·2·1·(1-1)! » 3·2·1·0! » 3·2·1·1 » 6
» hier: „kann ersetzt werden durch“ Anweisungen können Werte in Variablen zwischenspeichern,
lesen und verändern

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

15 16

0.3 Algorithmendarstellung Darstellung – graphisch

Ablaufdiagramm = Flussdiagramm Struktogramm


Wie man einen Algorithmus darstellen kann, hängt Anweisungen stehen in Knoten Anweisungen stehen in Blöcken
vom gewählten Paradigma ab! Kontrollfluss: gerichtete Kanten Kontrollfluss: Form, Struktur der Blöcke

Für das prozedurale Paradigma bieten sich Start summe = 0

insbesondere an: summe = 0


n>0? n>0
Graphisch
JA NEIN summe = summe + n
Ablaufdiagramme summe =
summe + n n=n–1
Struktogramme drucke drucke summe
summe
Pseudocode n=n–1
Künstliche Programmiersprachenderivate Ende

Stilisierte Prosa Pro: leicht erfassbar, Standardnotation, auch dem Anwender verständlich (Diskussionsbasis)
Con: große Programme unüberschaubar, schwierig direkt in Programmiersprache umsetzbar, schwer
Programmiersprachen editierbar, automatische Codegenerierung eher beschränkt (meist nur Prozedurköpfe)
VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta
17 18

Darstellung – Pseudocode Darstellung – Programmiersprache

Programmiersprachenderivate Stilisierte Prosa Kenneth E. Iverson, 1979


Anlehnung an eine Programmier- Beschreibung der schrittweisen “Notation as a Tool of Thought”
sprache (z. B. Pascal, MODULA-2); Ausführung
Ziel, eine der natürlichen Sprache Inventor of APL
möglichst nahe Kunstsprache zu
schaffen (standardisierte Darstellung!) int summe = 0;
while(n > 0) {
begin comment Das ist ALGOL; Schritt 1:Initialisiere. summe += n;
integer n,i,summe; Setze summe auf 0. n--;
read(n); Schritt 2:Abarbeitung der Schleife. }
summe := 0; Solange n größer als 0,
for i := n step -1 until 1 addiere n zu summe, cout << summe;
do summe := summe + i; ziehe 1 von n ab.
print(summe) Schritt 3:Ausgabe.
end Drucke summe.

Pro: Programmiersprache sehr ähnlich, direkte Umsetzung einfach Pro: (fast) direkt ausführbar
Con: ähnliche Komplexität wie Programmiersprache, für den Anwender oft schwer verständlich Con: komplex, für Entwurf nur sehr beschränkt einsetzbar

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

19 20

Programmiersprachen-„Paradigmen“ Programmiersprachen-Gruppen
Damit ein Computer ein Problem lösen kann, müssen wir ihm Generation Typ der Vertreter
Programmiersprache
den Algorithmus in Form eines Programms, das in einer
„erste“ Maschinensprachen Binär- und Hexadezimal-Programmierung
Programmiersprache geschrieben ist, präsentieren
„zweite“ Maschinenorientierte OS/370 Assembler, 2650 Assembler,
Sprachen (Assembler) 8080 Assembler
„dritte“ Problemorientierte Sprachen FORTRAN, COBOL, Pascal, MODULA-2, C
Klassifikation von Programmiersprachen: Programmiersprachen- „vierte“ Datenbanksprachen SQL, Natural-2
„Paradigmen“ „fünfte“ Sprachen der KI Lisp, PROLOG

prozedural versus funktional versus logik-basiert ? Objektorientierte Sprachen Smalltalk


? Hybride Sprachen C++
sequentiell versus parallel
prozedural versus funktional versus logik-basiert
typisiert versus untypisiert (fließender Übergang) sequentiell versus parallel
typisiert versus untypisiert (fließender Übergang)
orthogonal dazu: objektorientiert
orthogonal dazu: objektorientiert

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


21 22

0.4 Programmstrukturen Sequenz, Zuweisung

Elemente einer prozeduralen Programmiersprache


Die Wertzuweisung ist eine Anweisung
Aktion 1 j ← 1
Die Sequenz von Anweisungen ist eine Anweisung
Die Entscheidung ist eine Anweisung
Aktion 2 j ← j + 1
Die Iteration ist eine Anweisung

Satz (Böhm / Jacopini 1966): j = 1;


j = j + 1;
Jedes durch einen Computer ausführbare Programm Aktion 1
(berechenbare Funktion) kann durch eine Kombination oder
dieser 4 Elemente berechnet werden Aktion 2
j = 1;
j++;

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

23 24

Verzweigung while - Schleife

Aktionsblock wird solange


wiederholt, wie die nein
ja nein
j > n Bedingung (Eintritts- while j < n
bedingung) gilt
ja nein ja
?
j ← 0 j ← i while (Bedingung true)
nein
j ← j + 1
ja

Aktion

Bedingung if (j > n)
erfüllt ?
JA NEIN j = 0; while (j < n)
Eintrittsbedingung
else j = j + 1;
Teil 1 Teil 2 j = i;
Anweisung(en),
Schleifenblock

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


25 26

Iteration oder Schleife Funktion / Prozedur (1)

Anweisung wird abhängig von einer Bedingung Abgeschlossene algorithmische Einheiten


wiederholt ausgeführt bestehen aus Sequenzen, Verzweigungen, Schleifen
Verschiedene Schleifenformen in Gebrauch
und Funktions-/Prozeduraufrufen
Beispiel: while-Form
Anweisung wird solange Funktion
wiederholt, wie die
Eingangswerte, genau ein Ausgangswert
Bedingung erfüllt ist NEIN
Bedingung
(Eintrittsbedingung)
erfüllt? Prozedur
JA nur Eingangswerte
Eintrittsbedingung beide können über Parameterliste Werte zurückliefern
Anweisung
Anweisung

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

27 28

Funktion/Prozedur (2) 0.5 Rekursion

Ein Objekt heißt rekursiv, wenn es durch sich selbst


Funktion Prozedur definiert ist, oder sich selbst (teilweise) enthält.

void sum(int n) {
int sum(int n) {
int summe = 0;
Beispiele:
int summe = 0;
while(n > 0) { while(n > 0) { Fernseher Mathematik
summe += n; summe += n; (Definition der Fakultät)
n--; n--;
} } n = 0 → 1
return summe; printf(“%d\n”, summe); n! = 
} } n > 0 → n ⋅ ( n − 1) !

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


29 30

Rekursive Programmteile Direkte Rekursion

Eine Prozedur/Funktion heißt rekursiv, wenn sie sich Berechnung der Fakultät
in der Folge ihrer Abarbeitung selbst referenziert. // Berechnung von n! für n>=0
int fakultaet(int n) {
if(n == 0) rekursiver
return(1);
Eine Prozedur/Funktion P heißt direkt rekursiv, wenn else
Aufruf

sie sich explizit selbst aufruft. Hingegen ist P indirekt return(n * fakultaet(n-1));
rekursiv, wenn sie den Aufruf einer anderen }

Prozedur/Funktion enthält, die ihrerseits wieder P


Berechnung der Fibonacci Zahlen
(direkt oder indirekt) aufruft.
// Berechnung der Fibonacci Zahlen
int fibonacci(int n) {
if(n <= 1) return 1;
return fibonacci(n-1) + fibonacci(n-2);
}

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

31 32

Direkte Rekursion, Beispiel Indirekte Rekursion


int fkt(int n) {
Berechnung von 3! if(n == 0) Definition eines Ausdrucks (expression) in MODULA-2
Aufruf: fkt(3) ⇒ 6
return(1);
else (Ausschnitt)
return(n*fkt(n-1));
}

Expr ::= SimpleExpr [RelOp SimpleExpr]


fkt(3) fkt(2) fkt(1) fkt(0)
SimpleExpr ::= [SignOp] Term [AddOp Term]
n==0
3*fkt(2) 2*fkt(1) 1*fkt(0) Term ::= Factor {MulOp Factor}

return return return return(1) Factor ::= ‘(‘ Expr ‘)’ | NOT Factor | Value
(3*2) (2*1) (1*1)

3*2*1*1 2*1*1

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


33 34

indirekte Rekursion, Beispiel Charakteristik rek. Lösungsansätze

Ableitung des Ausdrucks: 3 * ( 4 + 5 ) Eigenschaften


Expr
Expr ::= SimpleExpr [RelOp SimpleExpr] Ziel ist die schrittweise Entwicklung der Lösung ausgehend
SimpleExpr ::= [SignOp] Term [AddOp Term] von einem bzw. zurückführend auf einen Fixpunkt (eine
SimpleExpr Term ::= Factor {MulOp Factor}
Factor ::= ‘(‘ Expr ‘)’ | NOT Factor | Value
Ausgangslösung)
Term Vorteile
Factor MulOp Factor knapper und prägnanter Lösungsweg
oft Ansatz direkt aus der Problemdefinition ableitbar
Value * ( Expr )
Programm einfacher lesbar
3 SimpleExpr Nachteile
Term + Term Programme können fehlerhafter sein
Value Value logische Fehler schwerer zu finden
mögliche Verlangsamung der Programme
4 5
Programm schwerer lesbar (vergl. Vorteile!)

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

35 36

Rekursiver Ansatz Kriterien

Drei Kriterien
Verringern des Problemgrades
Ein Problem der Größe n wird in eine endliche Anzahl von Abbruchkriterium
Problemen zerlegt, deren Größe kleiner n ist.
if(n == 0) return(1);
Abbruchkriterium
else
Spezifikation einer zu erreichenden Programmsituation, bei der das return(n*fakultaet(n-1));
Programm die rekursiven Aufrufe beendet.
Konstruktion Zerlegung der
Konstruktion des Endergebnisses des Problemgröße
Das Endergebnis sukkzessiv (meist beim rekursiven Aufstieg) aus Endergebnisses
den Teilergebnissen zusammensetzen.

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


37 38

Was nehmen wir mit?

Algorithmus
Darstellung
Programmstrukturen Kapitel 1:
Rekursion
Algorithmen

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

39 40

1.1 Motivation Algorithmen zu Problemstellungen finden!

Algorithmen Aufgabe: “Summe der ganzen Zahlen bis n”


Verfahrensvorschriften, Anweisungsfolgen, Straight-forward solution: “Aufsummieren der einzelnen
Vorgangsmodellierungen, beschriebene Lösungswege Werte zwischen 1 und n” n
summe ← ∑ i
i ←1
Ziele
Realisierung (C/C++ Programm)
Algorithmen zu Problemstellungen finden!
Lösungsansätze finden, „konstruieren“ int sum(int n) {
2. „Gute“ Algorithmen finden! int i, summe = 0;
for(i=1; i<=n; i++)
“bessere” Algorithmen
summe += i;
schneller, vollständiger, korrekter, ... return summe;
“leistungsfähigere” Datenstrukturen }
kompakter, effizienter, flexibler, ...
Vergleiche mit anderem Programmieransatz, z.B. for- statt
Generell: Ersparnis an Rechenzeit und/oder Speicherplatz while-Schleife! ⇒ alternativer Programmierstil (Warum?)

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


41 42

Alternative Realisierung (1) Alternative Realisierung (2)

Zwei Alternativen 2. Alternativer Lösungsweg


1. Alternativer Programmierstil Wahl eines anderen Problemlösungsweges, z.B.
Problemlösungsansatz beibehalten, aber Gauß´sche Summenformel
programmiertechnische Umsetzung überarbeiten
n
n ⋅ (n + 1)
Beispiel:
Achtung! ∑i =
i =1 2
Schleifenform (siehe oben) Was ist bei einem
Rekursion statt Iteration Aufruf n<0 zu
beachten? Umsetzung
int sum(int n) {
int sum(int n) {
if(n == 0) return 0;
if(n == 1) return 1; return (n*(n+1))/2;
else }
return n+sum(n-1);
}

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

43 44

„Gute“ Algorithmen finden! Was ist gut? Oder vielleicht besser?

Vergleich der Laufzeiten Problem: Laufzeitenvergleich führt nur zu punktueller


Summenberechnung, 100000 Wiederholungen, CPU: 200 MHz Pentium
Qualitätsbestimmung
100
Laufzeit, Speicherplatzverbrauch
Abhängig von
10
Computer
Betriebssystem
Gauß Compiler, ...
1
for, while

for, while (Opt.)


Ziel: Methodik für generellen Qualitätsvergleich
0,1
Rekursion zwischen Algorithmen
Unabhängig von äußeren Einflüssen
0,01
100 1000 10000

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


45 46

1.2 Algorithmen-Paradigmen 1.2.1 Greedy (1)

Generelle Techniken zur Lösung großer Klassen von In jedem Schritt des Algorithmus wird die Möglichkeit
Problemstellungen gewählt, die unmittelbar (lokal) den optimalen
Greedy algorithms (kleinsten bzw. größten) Wert bezüglich der
“gefräßiger, gieriger” Ansatz, Wahl des lokalen Optimums Zielfunktion liefert. Dabei wird die globale Sicht auf
das Endziel vernachlässigt.
Divide-and-conquer algorithms
schrittweise Zerlegen des Problems der Größe n in kleiner
Teilprobleme Vorteil:
Dynamic programming Effizienter Problemlösungsweg, oft sehr schnell, kann in
vielen Fällen relativ gute Lösung finden
dynamischer sukkzessiver Aufbau der Lösung aus schon
berechneten Teillösungen Nachteil:
Findet oft keine optimale Lösung

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

47 48

Greedy (2) Greedy (3)

Beispiel: Münzwechselmaschine DOCH


“Wechsle den Betrag von 18.- in eine möglichst kleine Problem bei kleiner Änderung der Problemstellung:
Anzahl von Münzen der Größe 10.-, 5.- und 1.-”
5.- è 6.-
greedy Ansatz:
Münzwerte 10.-, 6.- , 1.-
wähle größte Münze
kleiner als Betrag
d.h.: 18.- - 10.- = 8.- •
gib die Münze aus greedy Ansatz liefert optimal wäre aber 3 x 6.-
8.- - 5.- = 3.- •
subtrahiere ihren 18.- - 10.- = 8.- • 18.- - 6.- = 12.- ‘
3.- - 1.- = 2.- Œ
Wert vom Betrag 8.- - 6.- = 2.- ‘ 12.- - 6.- = 6.- ‘
2.- - 1.- = 1.- Œ
2.- - 1.- = 1.- Œ 6.- - 6.- = 0 ‘
wiederhole solange 1.- - 1.- = 0 Œ
bis Differenz gleich 0 1.- - 1.- = 0 Œ ⇒ 3 Münzen
⇒ 4 Münzen
Lösung für diese Problemstellung nicht nur “gut”
sondern sogar optimal!

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


49 50

1.2.2 Divide-and-conquer (1) Divide-and-conquer (2)

Ausgehend von einer generellen Abstraktion wird das Verschiedene Ansätze


Problem iterativ verfeinert, bis Lösungen für Problem size division
vereinfachte Teilprobleme gefunden wurden, aus Zerlegung eines Problems der Größe n in eine endliche
welchen eine Gesamtlösung konstruiert werden Anzahl von Teilproblemen kleiner n
kann. Step division
Aufteilen einer Aufgabe in eine Sequenz (Folge) von
individuellen Teilaufgaben
Case division
Diese Vorgangsweise wird auch oft mit “stepwise Identifikation von Spezialfällen zu einem generellen Problem
refinement” oder “top-down approach” bezeichnet ab einer gewissen Abstraktionsstufe

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

51 52

Problem size division Step division

Durch Zerlegung Verringerung der Problemgröße, d.h. Idee: Straßenkehrer-Philisophie:


P(n) ⇒ k*P(m), “Atemzug - Besenstrich - Schritt”
wobei k, m < n Beispiel
Gehaltserhöhung
Binäre Suche Suche Zahl 7
Suche eine Zahl x in der (aufsteigend) sortierten
Folge z1,z2,..,zn (allgemein: zl,zl+1,..,zr mit l=1, r=n) 1 3 4 6 7 8 10 Bestimme Mitarbeiter
und ermittle ihre Position i Finde eindeutige Identifikation Speichere Information
Zerlegung: k = 1 und m ≈ n/2 7 8 10 Suche im Datenbestand
Lösche alte Datensatz
Trivial: finde mittleren Index m = (l+r)÷2 Stelle aktuelles Gehalt fest
Füge neuen Datensatz ein
Falls zm=x Ergebnis m, sonst 7 Ändere auf neues Gehalt
Falls x<zm suche x im Bereich zl,z2,..,zm-1 Speichere Information
sonst suche x im Bereich zm+1,zm+2,..,zr Vermerke Änderungsvorgang

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


53 54

Case division 1.2.3 Dynamic Programming (1)

Ansatz: Identifikation von Fallunterscheidungen im Problem


Problemdatenbereich Oft ist eine Teilung des Originalproblems in eine ‘kleine’
Beispiel Anzahl von Teilproblemen nicht möglich, sondern führt zu
Berechnung der Lösungen zu einer quadratischen Gleichung
einem exponentiellen Algorithmus.
Man weiß aber, es gibt aber nur eine polynomiale Zahl von
Teilproblemen.
az + bz + c = 0
2

b 1 2
1 Idee
z1, 2 = −( )± q ,q = b 2 − 4ac nicht Start von Problemgröße n und Aufteilung bis Größe 1,
2a 2a
SONDERN

if q > 0, 2 reelle Wurzeln Start mit Lösung für Problemgröße 1, Kombination der
q = 0, reelle Doppellösu ng berechneten Teillösungen bis eine Lösung für
q < 0, Paar komplexer Wurzeln Problemgröße n erreicht wurde.

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

55 56

Dynamic Programming (2) Dynamic Programming (3)

Beispiel: Berechnung der Fibonacci Zahlen Lösungsweg


int fib(int n) { Beginn mit Berechnung für fib(0), Anlegen einer
if(n <= 1) return 1; Tabelle aller berechneten Werte und Konstruktion der
return fib(n-1) + fib(n-2)
}
neuen Werte aus den berechneten Tabelleneinträgen.
fib(4) Berechnungsrichtung
fib(3) fib(2) fib ( 0 ) fib ( 1 ) fib ( 2 ) … fib ( n )
1 1 2 … fib ( n - 2 ) + fib ( n - 1 )
fib(2) fib(1) fib(1) fib(0) fib(2) 2x berechnet
fib(1) 3x berechnet
fib(0) 2x berechnet Werte werden aus der
fib(1) fib(0) 1 1 1 Beachte Tabelle entnommen
Verbesserung der Laufzeit
1 1
ABER
Problem: Wiederholte Lösung eines Teilproblems
zusätzlicher Speicherplatzbedarf
VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta
57 58

1.3 Analyse u. Bewertung von Algorithmen Analogie: Auto

Ziel ist objektive Bewertung von Algorithmen Spezifische Kriterien


Kriterien: Auswahl
Effektivität Sitzplätze
Ist das Problem lösbar, ist der Ansatz umsetzbar in ein Programm? CW-Wert
Hubraum
Korrektheit
Leistung
Macht der Algorithmus was er soll?
Termination
Hält der Algorithmus an, besitzt er eine endliche Ausführungszeit? Höchstgeschwindigkeit Beschleunigung
Komplexität Statistische Kennzahlen
Wie strukturiert ist der Algorithmus ⇒ Strukturkomplexität? Beurteilungsmöglichkeit, Klassifikationsmöglichkeit
Wie schnell ist der Algorithmus ⇒ Laufzeitkompexität? Sportwagen, Lastwagen, Familienlimousine, ...

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

59 60

Bewertung von Programmen 1.3.1 Effektivität

Beipiel Sortierprogramm Prinzip


Korrektheit Algorithmus kann als lauffähiges Computerprogramm
Effektivität
void selection(Element v[], int n) { formuliert werden.
int i, j, min;
effective ⇒ it does work
for(i = 0; i < n; i++) {
min = i; Problem
for(j = i+1; j < n; j++)
if(v[j] < v[min]) min = j;
Formulierung
Laufzeit swap(v[min], v[i]); Transformation der Problembeschreibung in einen
} exekutierbaren Algorithmus
}
Struktur
Termination
Ich will, brauche, So
muß haben ... geht
Klassfikation
das!
schnell, korrekt, wartbar, problemüberdeckend, endlich, …

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


61 62

1.3.2 Korrektheit Formales Testen

Produziert der Algorithmus das gewünschte Mathematisch orientierte Verifikationstechniken


Ergebnis? erlauben es, die Korrektheit von Programmstücken
Zwei Vorgangsweisen möglich in Abhängigkeit von Bedingungen an die
Testen Eingabedaten (Prämissen) zu beweisen
Formales Testen McCarthy, Naur, Floyd, Hoare, Knuth, Dijkstra, etc.

Testen zwingt den Entwickler Entwurfsentscheidungen noch einmal


Vollständiges Austesten meist nicht möglich nachzuvollziehen und hilft beim Auffinden logischer Fehler
Statistischer Ansatz meist verfolgt, z.B. Pfadüberdeckung Algorithmus muss verstanden werden
(Strukturelle Komplexität) je größer ein Programmsystem, umso schwieriger die
Bestenfalls „Falsifizierung“ erreichbar Verifikation (in der Praxis kaum von Bedeutung)
Es können nur Fehler gefunden werden, aber es kann keine
Korrektheit bewiesen werden
Beweisansatz abhängig vom Problem

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

63 64

Mathematischer Beweis Verifikation

Vollständige Induktion Programm-Verifikation


Beispiel: Gauß´sche Summenformel verschiedene Ansätze
“Rückwärtsbeweis”:
Ind. Anfang Strukturierter Ansatz, beruht auf Prädikatentransformation
für n = 1 → 1*2/2 = 1 ü Überprüfung, ob die Voraussetzungen (weakest
Ind. Voraussetzung preconditions, wp) an die Eingabedaten garantieren, dass
n
n ⋅ ( n + 1)
∑i =
i =1 2
(1+2+…+n-1) = (n-1)*n/2
Ind. Schluss
das Programm in einem Zustand terminiert, der das
gewünschte Programmziel erfüllt.
(1+2+…+n-1)+n = (n-1)n/2 +n =
= ((n-1)n +2n)/2 = (n2-n+2n)/2 = Man bezeichnet diese Programmziel, welches die Aufgabe
= n(n+1)/2 ü des Programms beschreibt, als Korrektheitsbedingung
Hierzu darf das Programm nur aus einfachen Zuweisungen,
Vergleichen, while-Form Schleifen und Anweisungsfolgen
bestehen. Alle anderen Konstrukte müssen übersetzt werden.
VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta
65 66

Verifikation - Beispiel 1.3.3 Termination (1)

Beispiel Rückwärtsbeweis Frage: Hält der Algorithmus an, d.h. besitzt er eine
n
Korrektheitsbedingung : s = ∑ i
i =1 endliche Ausführungszeit?
int sum(int n) { (I) Schleifeninvariante SI
int s = 0; i −1
SI: ( s = ∑ j ) ∧ (i ≤ n + 1)
Falls nicht klar, oft folgende Technik einsetzbar:
j =1
i = 1;
while(i <= n) {
(1) SI ∧ ¬Bed ⇒ KB Man finde eine Größe oder eine Eigenschaft des
i −1 i −1 n

s = s + i; s = (∑ j ) ∧ (i ≤ n + 1) ∧ (i > n) ⇒ s = ( ∑ j ) ∧ (i = n + 1) ⇒ s = ∑ j ⇒ KB
j =1 j =1 j =1
Algorithmus der die folgenden 3 Charakteristiken
i = i + 1; (2) SI ∧ Bed ⇒ wp ( Schleifenblock | SI )
i −1 i
erfüllt:
} wp ( s = s + i | wp (i = i + 1 | ( s = ∑ j ) ∧ (i ≤ n + 1))) ⇒ wp ( s = s + i | ( s = ∑ j ) ∧
j =1 j =1
Eine 1-1 Abbildung dieser Größe auf die ganzen Zahlen
return s; i i −1
∧ (i ≤ n + 1))⇒ ( s + i = ∑ j ) ∧ (i ≤ n + 1) ⇒ ( s = ∑ j ) ∧ (i ≤ n + 1) ≡ SI kann aufgestellt werden.
} j =1 j =1

(II) Rest des Programms Diese Größe ist positiv.


1−1
wp ( s = 0 | wp (i = 1 | SI )) ⇒ wp ( s = 0 | ( s = ∑ j ) ∧ (1 ≤ n + 1)) ⇒ Die Größe nimmt während der Ausführung des Algorithmus
j =1
0 kontinuierlich ab (dekrementiert).
⇒ (0 = ∑ j ) ∧ ( 0 ≤ n ) ⇒ n≥0
j =1

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

67 68

Termination (2) 1.3.4 Strukturelle Komplexität

Idee: Bewertende Aussage über den strukturellen Aufbau des


Programms und der Programmteile untereinander, d.h.
Die gefundene Größe besitzt bei Algorithmusbeginn Bewertung des Programmierstils interne Attribute
einen vorgegebenen positiven Startwert, der sich Allgemein angenommen, dass Programmierstil mit den zu erwartenden
kontinuierlich verringert. Da die Größe nie negativ Softwarewartungskosten korreliert.
werden kann, folgt, dass der Algorithmus Aussagen über die Qualität eines Softwareproduktes (externe
terminieren muss, bevor die Größe kleiner 0 ist. Attribute)
Fehleranfälligkeit Annahme:
Größe n Termination interne Attribute sind mit externen
bevor n < 0 Wartungsaufwand
Attributen korreliert!
Beispiel: int sum(int n) {
Kosten
if(n <= 0) return 0;
if(n == 1) return 1; These
Dekrement
else komplexes Programm ⇒ hohe Kosten
return n+sum(n-1); klares Programm ⇒ geringere Kosten
}

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


69 70

Grundsatz Softwaremetriken

Ziel Metriken (Maßzahlen) zu finden, die den Aufbau,


„When you can measure what you are speaking about Struktur, Stil eines Moduls (Programmstücks)
and express in numbers you know something about bewerten und vergleichen lassen.
it, but when you cannot measure it, when you Anforderungen
cannot express it in numbers, your knowledge is of a Gültigkeit
meager and unsatisfactory kind.“ Misst tatsächlich was es vorgibt zu messen
Einfachheit
Resultate sind einfach verständlich und interpretierbar
Lord Kelvin Sensitivität
Reagiert ausreichend auf unterschiedliche Ausprägungen
Robustheit
Reagiert nicht auf im Zusammenhang uninteressante Eigenschaften

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

71 72

Messung der strukturellen Komplexität Zusammenhang Kupplung und Kohäsion

Intra-modulare Komplexität Kupplung


Beschreibt die Komplexität eines einzelnen SW Moduls Misst Komplexität der Beziehungen zwischen Moduln
Modul Komplexität (intern) Kohäsion
LOC, Line-of-codes (simpel)
Misst Informationsfluss von und nach Außen abhängig von
NCSS, non commenting source statements
der Modulgröße
McCabe (zyklomatische Komplexität), …
Kohäsion (extern)
Meist Beziehung zwischen Kupplung und Kohäsion
Henry-Kafura Metrik (Informationsfluss), …
Inter-modulare Komplexität
Beschreibt Komplexität zwischen Moduln
Kupplung
Starke Kupplung Schwache Kupplung
Fenton und Melton, …
Schwache Kohäsion Starke Kohäsion
VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta
73 74
1.3.4.1 Intra-modulare Komplexität –
Metrik von McCabe
Programmbeispiel

0: private sub foo (a as integer) 1


Die Metrik von McCabe ist ein Maß zur Beurteilung der
1: while a < limit do
Modul Komplexität 3
2: process_1 a
Basiert auf der zyklomatischen Komplexität V: liefert die 3: if bar(a) then 5 4
Anzahl der unabhängigen Pfade in einem Programmgraph 4: process_2 a
Region2
Bei einem unabhängigen Pfad wird mindestens eine 'neue' Kante im 5: elseif mumble(a) then 6 7
Programmablaufplan beschritten. Region3
6: process_3 a
Erfahrungswerte für die zyklomatische Komplexität 7: else
Region1
9
V(G) Einschätzung im Normalfall 8: process_4 a
9: end if 10
Region4
<5 einfach 10: end while
Basis Menge
11
5-10 normal 11: end sub Pfad 1: 1 Details
Pfad 2: 1,3,4,10,1,11 Kanten = 11
> 10 komplex, sollte restrukturiert werden Pfad 3: 1,3,5,6,9,10,1,11 Knoten = 9
Pfad 4: 1,3,5,7,9,10,1,11 Bedingungsknoten = 3
> 20 schwer verständlich, wahrscheinlich fehlerhaft
VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

75 76
1.3.4.2 Intra-modulare Komplexität –
Zyklomatische Komplexität Henry-Kafura Metrik

Mehrere Berechnungsmöglichkeiten Maß zur Bestimmung der Kohäsion


1. Die Anzahl der Regionen im Programmgraph G Beschreibt die funktionale Stärke des Moduls; zu welchem
2. V(G) = E - N + 2 (E = Anz. d. Kanten, N = Anz. d. Knoten) Grad die Modulkomponenten dieselbe Aufgabe erfüllen
3. V(G) = P + 1 (P = Anzahl der binären Bedingungsknoten) Metrik von Sallie Henry and Dennis Kafura
Zyklomatische Komplexität des Beispiels Basiert auf Zusammenhang zwischen Modulkomplexität und
1. Regionen = 4 Verbindungskomplexität zwischen Moduln
2. V(G) = 11 - 9 + 2 = 4 Maß für Modulkomplexität
3. V(G) = 3 + 1 = 4 LOC
In unserem Beispiel ist die magische Zahl 4, d.h. NCSS
„einfaches“ Programm (Metrik McCabe < 5) McCabe

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


77 78

Verbindungskomplexität Anwendung

Quantifizierung des lesenden und verändernden Zugriffs des Von Henry und Kafura auf Unix Code angewendet
Moduls auf die Umgebung FAN- Annahme: Zusammenhang zwischen Komplexität und
Zählt die Datenflüsse zwischen Moduln IN Änderungshäufigkeit (Fehlerkorrektur) einer Prozedur
FAN-INm: „Anzahl der Module die m verwenden“ 165 Prozeduren untersucht, Patch-Information aus
genauer: Anzahl der Datenflüsse, die im Modul m Modul Newsgroups
terminieren + Anzahl der Datenstrukturen, aus Annahme bestätigt:
FAN-
denen der Modul m Daten ausliest
OUT Änderungen nehmen mit
FAN-OUTm: „Anzahl der Module die m verwendet“ Komplexitätsklasse zu
genauer: Anzahl der Datenflüsse, die vom Modul m ausgehen + Anzahl
der Datenstrukturen, die der Modul m verändert Probleme HK
Henry-Kafura Formel Abh. vom Datenfluss, bei
Cim * (FAN-INm * FAN-OUTm)2
einem FAN = 0, gesamt 0
Cim … Modulkomplexität (z.B. LOC, McCabe, …)
auch bei hoher Modul-
komplexität
Wiederverwendbarkeit wird durch hohen FAN Wert „bestraft“
VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

79 80
1.3.4.3 Inter-modulare Komplexität –
Fenton und Melton Metrik
Berechnung der Kupplung

Maß zur Bestimmung der Kupplung Fenton-Maß für die Kupplung zwischen 2 Moduln
Kupplung misst die Unabhängigkeit zwischen Moduln c(x,y) = i + n/(n+1)
Globale Kupplung eines Programms wird abgeleitet aus den
Kupplungswerten zwischen allen möglichen Modulpaaren i ist der schlechteste Kupplungstyp zwischen Modul x und y
n ist die Anzahl der „Kupplungen“ vom Typ i
Kupplungstypen
Binäre Relationen definiert auf Paaren von Moduln x, y
Nach dem Grad der „Unerwünschtheit“ geordnet
Maß C(S) für die globale Kupplung eines Systems S
0. No coupling: keine Kommunikation zwischen x und y
1. Data coupling: Kommunikation über Parameter (Daten) bestehend aus n Moduln D 1, … , Dn
2. Stamp coupling: akzeptieren selben Record-Typ als Parameter C(S) = Median der Menge der Kupplungswerte aller
3. Control coupling: Kommunikation über Parameter (Kontrolle) Modulpaare
4. Common coupling: Zugriff auf selbe globale Datenstruktur
5. Content coupling: x greift direkt auf interne Struktur von y zu (ändert
Daten, Anweisungen)

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


81 82

1.3.5 Laufzeitkomplexität Summe-Beispiel: simpler Ansatz

Aussagen über das Laufzeitverhalten von Algorithmen int sum(int n) Zeit in msec
Gemessene Zeiten im
in Abhängigkeit von der Problemgröße int s = 0; T1 ⇒ 0.1 Programm
int i = 1; T2 ⇒ 0.1
Ziel while(i <= n) { T3 ⇒ 0.3
Algorithmen zu vergleichen s = s + i; T4 ⇒ 0.1 1000,0

i = i + 1;} T5 ⇒ 0.1
Ansatz return s; T6 ⇒ 0.1 100,0

Messen der Ausführungszeit der einzelnen Anweisungen } 10,0


Bestimmen, wie oft jede Anweisung beim Programmablauf Berechnung der Laufzeit Laufzeit

ausgeführt wird fsum(n) =T1+T2+n*(T3+T4+T5)+T3+T6 1,0


10 100 1000
Summe berechnen fsum(10) = 0.1+0.1+10*(0.3+0.1+0.1)+0.3+0.1 = 5.6
fsum(100) = 0.1+0.1+100*(0.3+0.1+0.1)+0.3+0.1 = 50.6
Problem fsum(1000) = 0.1+0.1+1000*(0.3+0.1+0.1)+0.3+0.1 = 500.6
Ausführungszeiten abhängig von Maschinen- bzw. System- fsum(n) = 0.6 + n*(0.5)
architektur, Übersetzungsqualität des Compilers, etc.
VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

83 84

Probleme des simplen Ansatzes Ordnungsnotation

Entspricht einem Ansatz des „Ausprobierens“ Grundprinzip


Nur punktuell möglich Die exakten Werte der Ausführungszeiten sind
bestimmte Problemgröße, Datenverteilung uninteressant!

Sonderfälle problematisch Ordnungsnotation


Man möchte Aussagen treffen (siehe Ziel), dass Algorithmus
Systemabhängig A grob gesehen gleich schnell wie Algorithmus B ist.
Hardware, Prozessor, ... Durch Beschreiben der Laufzeiten von A und B über Funktionen f(n)
Betriebssysteme, Compiler, Bibliotheken, ... und g(n) wird diese Fragestellung auf Vergleich dieser Funktionen
zurückgeführt.
Lastabhängig
Man betrachtet das asymptotische Wachstum der
Frage schwer zu beantworten, ob „graduelle“ oder Ausführungszeiten der Algorithmen bei wachsender
„grundsätzliche“ Verbesserung erreichbar Problemgröße n.
VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta
85 86

Big - O / Ω / Θ - Notation Summen-Beispiel

Big-O-Notation: Eine Funktion f(n) heißt von der Ordnung Laufzeitschätzung: fsum(n) =T1+T2+n*(T3+T4+T5)+T3+T6 reale Werte, in der
O(g(n)), wenn zwei Konstanten c0 und n0 existieren, sodass Messung: T1=0.1, T2=0.1, T3=0.3, T4=0.1, T5=0.1, T6=0.1 Implementierung
f(n) ≤ c0g(n) für alle n > n0. ergibt fsum(n) =0.6+n*(0.5) gemessen
liefert eine Obergrenze für die Wachstumsrate von Funktionen g(n)=n ⇒ Untergrenze: 0.1*g(n) Obergrenze: h(n)=1*g(n)
1000
f∈O(g), wenn f höchstens so schnell wie g wächst.
z.B.: 17n2 ∈ O(n2), 17n2 ∈ O(2n) eine von vielen
n
Big-Ω-Notation: Eine Funktion f(n) heißt von der Ordnung möglichen
0.6 0.5 . n 500
Ω(g(n)), wenn zwei Konstanten c0 und n0 existieren, sodass Grenzen
0.1 . n

f(n) ≥ c0g(n) für alle n > n0.


liefert eine Untergrenze für die Wachstumsrate von Funktionen 0
0 200 400 600 800 1000
f∈O(g), wenn f mindestens so schnell wie g wächst. n

z.B.: 17n2 ∈ Ω (n2), 2n ∈ Ω(n2), n37 ∈ Ω(n2) daraus folgt bezüglich der Ordnung des Algorithmus
- Notation: Das Laufzeitverhalten ist Θ(n) falls gilt: f(n)=O(n) und fsum(n) ∈ O(n) und weiters fsum(n) ∈ Ω(n), d.h. fsum(n) ∈ Θ(n).
Die daraus für unser Beispiel ableitbare Aussage lautet, dass die Laufzeit des
f(n)=Ω(n) (beschreibt das Laufzeitverhalten exakt) Algorithmus direkt proportional zur Problemgröße n ist

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

87 88

Laufzeitvergleich (1) Laufzeitvergleich (2)


1000
Laufzeitenvergleich Beschreibung des Laufzeitverhaltens
Annahme vorgegebene 800
durch obere O(n) und untere Schranke Ω(n)
n
Problemgröße und n . log ( n ) 600 z.B.: T(n) = 1.5n2 + 5n - 200 ⇒ O(n2), da n2 ≤ T(n) ≤ 2n2
unterschiedliches n
2
6
400 1 10
Laufzeitverhalten n
3

200
5
3 8 10
Ordnung Laufzeit n
0
0 20 40 60 80 100

2
2. n
n
5
100 6 10
log n 1.2 x 10 -5sec
√n 3.2 x 10 -4 sec 2
80 1.5. n 5. n 200
5
n 0.1 sec n
4 10
2
60 n
n log n 1.2 sec n

n √n 31.6 sec log ( n )


40 n
2 10
5

n2 2.8 h
20
n3 31.7 a 0
0 0 200 400 600 800 1000
2n über 1 Jahrhundert 0 200 400 600 800 1000

n n

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


89 90

Analyseansatz Praktische Laufzeitanalyse

Prinzipien der mathematischen Analyse Ignoriere konstante Faktoren


Definition der Problemgröße n Konstante Werte werden auf den Faktor 1 reduziert, d.h.
Finden eines geeigneten Problemparameters der die Problem-größe T(n) = 13 * n ⇒ O(n)
beschreibt. Dieser charakterisiert die Belastung (= f(n)) T(n) = log2 (n) ⇒ O(log(n)), da logx(n) = loga(n) / loga(x)
worst-case versus average-case Merke nur höchste Potenz
worst-case: Verhalten im schlechtesten Fall, maximal zu erwartender Ignoriere alle anderen Potenzen außer der höchsten
Aufwand
T(n) = n2 - n + 1 ⇒ O(n2)
average-case: ∅−Verhalten, Erwartungswert des Aufwandes
Laufzeitanalyse über O(n) und Ω(n) oft schwierig zu bestimmen Daher in Kombination:
Ignoriere konstante Faktoren T(n) = 13*n2 + 47*n – 11*log2(n) + 50000 ⇒ O(n2)
Merke nur höchste Potenzen

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

91 92

Beispiel: Laufzeitanalyse ‘Bubblesort’ Rekurrenzen

void bubble(Element v[], int n) { Einfache Rekursion


int i, j; Problemgröße n T1 Einige wichtige Rekurrenzen
for(i = n-1; i >= 1; i--) T2 int sum(int n) {
for(j = 1; j <= i; j++) T3 if(n <= 0) return 0; T1 T(n) = T(n-1)+n ⇒
if(n == 1) return 1; T2 ⇒ T(n) = n*(n+1)/2 = O(n2)
if(v[j-1] > v[j]) T4
return n + sum(n-1); T3+T(n-1)
swap(v[j-1], v[j]); T5 T(n) = T(n/2)+1 ⇒ T(n) = ld n = O(log n)
}
} Rekurrenzgleichung
Annahme Informeller Ansatz: finden T(n) = T(n/2)+n ⇒ T(n) = 2*n = O(n)
T1 = ... T5 = T(n) = T1+T2+T3+T(n-1)
=1 T(n) = T1 + (n-1)*(T2 + (n-1)*(T3+T4 +T5)) T(n) = T(n-1) + 1 T(0)=T(1)=1 T(n) = 2*T(n/2)+n ⇒
⇒ T(n) = n*ld n = O(n*log n)
T(n) = 1+(n-1)*(1+(n-1)*(1+1+1)) = 3n2-5n-3 T(n) = T(n-2) + 1 + 1
… T(n) = 2*T(n/2)+1 ⇒ T(n) = 2*n = O(n)
Ignoriere konstante Faktoren
worst-case = T(n) = 1 + … + 1 + 1
T(n) = n2-n-1
best-case = n
Merke höchste Potenz
T(n) = O(n2) = Ω(n2) = Θ(n2) average case T(n) = O(n)

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


93 94
1.3.6 Laufzeitanalyse von rekursiven
Algorithmische Lücke
Programmen
Eine algorithmische Lücke für ein Problem existiert, falls für die bekannten Die Laufzeitanalyse von rekursiven Programmen ist
problemlösenden Algorithmen A gilt, dass ihr Aufwand größer als der
ableitbare Lösungsaufwand für das Problem P ist. Ziel: meist nicht-trivial
die algorithmische
O(A) dient zur Beschreibung des Algorithmus
Lücke zu schließen,
Bis jetzt nur taxativ gelöst
Ω(P) dient zur Beschreibung des Problems d.h. Ω(P) = O(A)
Ω(P) ≤ O(A)
Laufzeitverhalten eines rekursiven Programms lässt
Probleme Algorithmen
Palt Pneu algorithmische Aneu Aalt
sich durch eine Rekurrenz beschreiben
Lücke
Beispiel: Mergesort
Θ(1) if n = 1
T ( n) = 
Geschlossene Lücke
Ω(n) Ω(n log n) Aufwand O(n2) O(n3)
2T ( n / 2) + Θ( n) if n > 1
Suchen in sortierter Sequenz, T(A) = log(n) wobei folgende Lösung angegeben wurde
Sortieren, T(A) = n*log(n) T ( n) = Θ(n log n)
Offene Lücke
Graphenisomorphie, T(Anaiv) aus O( |V|! )

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

95 96

Lösungsansätze Master Theorem

Wir betrachten unterschiedliche Lösungsansätze „Kochrezept“ zur Bestimmung des Laufzeitverhaltens


Substitutionsmethode Vereinfachte Form (generelle Version Cormen et al. pp. 62)
Erraten einer asymptotischen Grenze und Beweis dieser Es seien a ≥ 1, b ≥ 1 und c ≥ 0 Konstante
Grenze durch Induktion T(n) ist definiert durch aT(n/b) + Θ(nc)
Iterationsmethode wobei n/b entweder n/b oder n/b ist
Umwandlung der Rekurrenz in eine Summe und Anwendung T(n) besitzt dann den folgenden asymptotischen
von Techniken zur Grenzwertberechnung von Summen
Grenzwert
Mastermethode Fall 1: wenn c < logba dann T(n) = Θ(nlog a) b

Liefert Grenzen für Rekurrenzen der Form Fall 2: wenn c = logba dann T(n) = Θ(nc log n)
T(n) = aT(n/b) + f(n), wobei a ≥ 1, b > 1 und f(n) ist eine
Fall 3: wenn c > logba dann T(n) = Θ(nc)
gegebene Funktion

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


97 98

Beispiel Weitere Beispiele

Binäres Suchen Fall 1: wenn c < logba dann T(n) = Θ(nlogba)


int bs (int x, int z[], int l, int r) { Fall 2: wenn c = logba dann T(n) = Θ(nc log n)
if (l > r) // Schwelle, kein Element vorhanden Beispiel: Mergesort Fall 3: wenn c > logba dann T(n) = Θ(nc)
T(n) = 2T(n/2) + n = 2T(n/2) + Θ(n)
return -1; // 0 verboten, da gültiger Indexwert!
else {
int m = (l + r) / 2; a = 2, b = 2, c = 1
if (x == z[m])
return m;
// gefunden!
Fall 2, da c = logba ⇒ 1 = log22, ergibt T(n) = Θ(n log n)
else if (x < z[m]) Beispiel: T(n) = 4T(n/2) + n = 4T(n/2) + Θ(n)
return bs(x, z, l, m-1);
else // x > z[m] a = 4, b = 2, c = 1
return bs(x, z, m+1, r); Fall 1: wenn c < logba dann T(n) = Θ(nlogba) Fall 1, da c < logba ⇒ 1 < log24, ergibt T(n) = Θ(nlog 4) = 2

} Fall 2: wenn c = logba dann T(n) = Θ(nc log n)


} Fall 3: wenn c > logba dann T(n) = Θ(nc)
Θ(n2)
Beispiel: T(n) = T(n/2) + n = T(n/2) + Θ(n)
Laufzeit: T(n) = T(n/2) + 1 = T(n/2) + Θ(1) a = 1, b = 2, c = 1
a = 1, b = 2, c = 0
Fall 2, da c = logba ⇒ 0 = log21, ergibt T(n) = Θ(log n) Fall 3, da c > logba ⇒ 1 > log21, ergibt T(n) = Θ(n1) = Θ(n)
VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

99 100

Was nehmen wir mit?

Algorithmenparadigmen
Greedy, Divide and Conquer, Dynamic Programming
Analyse und Bewertung von Algorithmen Kapitel 2:
Effektivität, Korrektheit, Termination
Datenstrukturen
Strukturkomplexität
McCabe, Henry-Kafura, Fenton
Laufzeitkomplexität
Ordnungsnotation, Algorithmische Lücke, Master Theorem

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


101 102

2.1 Situation Magnetische Platten sind billiger als Papier


Jim Gray, 97

Datenstrukturen (Datenbanken) speichern ALLE Daten Dateischrank: cabinet (4 drawer) 250$


paper (24,000 sheets) 250$
The Old World: The New World: space (2x3 @ 10$/ft2) 180$
Millionen von Objekten Milliarden von Objekten total 700$
100-Byte Objekte Große Objekte (1MB) 3 ¢/sheet
People
Platte: disk (4 GB =) 500$
ASCII: 2 m pages
Name Address
David NY
Paperless office
(100x cheaper) 0.025 ¢/sheet
People
Mike Berk Library of congress online
Name Address Papers Picture Voice All information online
Won Austin
David NY
entertainment Image: 200 k pages
publishing
Mike Berk business (10x cheaper) .25 ¢/sheet
Information Network,
Won Austin
Knowledge Navigator, Conclusio: Speichere alles auf Platten
Information at your fingertips

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

103 104

Moore’s Law Beispiele (1)

XXX verdoppelt sich alle 18 Monate Magellan Projekt


60% Steigerung pro Jahr Satellit umkreiste die Venus, Radarabtastung
Micro Prozessor Geschwindigkeit zur Oberflächendarstellung
Chip Dichte Sandte 3 Terabyte Daten
Magnetische Platten Dichte Rendering der Daten benötigt 13 Gigabyte / sec
Kommunikationsbandbreite 1GB Zur Zeit technisch nicht durchführbar!
128MB
WAN Bandbreite 1 chip memory size
Wettervorhersage
8MB
nähert sich LAN ( 2 MB to 32 MB)
Zirkulationsmodelle der Atmosphäre und der Ozeane
1MB
128KB 1000 Jahre Simulation, 150 km2 Auflösung,
0.2 simulierte Jahre / Maschinenstunde
8KB
1970 1980 1990 2000 Ein Durchlauf auf Intel Touchstone Delta 57 Wochen
bits: 1K 4K 16 64K 256K 1M 4M 16M64 256M
K M 40 MB Daten /Simulationsminute = 20 Terabytes

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


105 106

Beispiele (2)

CERNs Herausforderung: Datagrid Detector Online Readout


Neuer Beschleuniger LHC multi-level trigger
mit 4 Detektoren filter out background
Large Hadron Collider, 14 TeV reduce data volume
Ziele: Suche nach Higgs Boson
und Graviton (et al.) 40 M
26,7 km Umfang
Hz
Start 2007 leve (40
100 Meter tief l1- T
B/se
Ziele 7 spec c)
leve 5 KH ial h
Weltweiter Zugriff auf die Daten l2 - z (75 ardwa
CERN und Regional Centers (Europa, Asien, Amerika) 5 K embedde GB/sec) re
Hz dp
2000 Benutzer leve (5 GB/ rocesso
l3- sec) rs
Riesige Datenvolumen 10 P
(100 0 Hz Cs
Daten Semantik M B/se
data c)
Performance und throughput offli record
ne a ing &
naly
sis
VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

107 108

Gigantische Datenmengen Größe: Was ist ein Petabyte?

Charakteristische Größen (geschätzt) 1 Petabyte = 2 hoch 50, i.e.


(1,125,899,906,842,624) bytes ∼ 1015 bytes
1-6 (vielleicht 100 ?) Petabyte / Jahr
Zeitraum 15 bis 20 Jahre 1,000,000,000,000 business letters 150,000 miles of bookshelf
10500 Knoten 100,000,000,000 book pages 15,000 miles of bookshelf
50,000,000,000 FAX images 7,000 miles of bookshelf
2.1 Petabyte Platten Platz 10,000,000,000 TV pictures (mpeg) 10,000 days of video
340 Gigabyte IO Bandbreite 4,000,000 LandSat images
Tapes ???
Library of Congress (in ASCII)
enthält 0.025 Petabyte

Aktuelle und zukünftige Projekte generieren weit mehr Daten


Auf uns warten Exa-, Zeta-, Yotta Byte !!!
VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta
109 110

Geschwindigkeit: Speicherzugriffszeiten
2.2 Motivation
Wie weit sind die Daten entfernt ?

SternbildAndromdeda
Andromeda Beispiel: 100 Telefonnummern zu verwalten
10 9 Tape /Optical 2,000 Years Ein „Haufen“ Zettel mit Namen und Nummern
Robot
Finden einer Telefonnummern durch sequentielle Suche
benötigt im Durchschnitt 50 „Zugriffe“
Clock Ticks

106 Disk Pluto 2 Years


Zettel nach dem Namen sortiert
Suche durch binäres Aufteilen („in die Mitte, Schlüssel-
vergleich und dann links oder rechts davon weitersuchen“)
100 Memory
Sacramento
Linz 1.5 hr Ungefähr ld 100 ≈ 7 Zugriffe

10 On Board Cache This Campus 10 min Rolodex


2 On Chip Cache This Room Zettel sortiert, in Ordnern und mit Namensindex
1 Registers My Head 1 min Ziel mit einem (1!) Zugriff gewünschte Nummer

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

111 112

Ziele Datenstrukturen

Information “effizient” zu verwalten! Erfüllung dieser Ziele führte zur Entwicklung von

Was bedeutet “effizient”? Datenstrukturen


Quantitative Ziele
Zugriffszeit Datenstrukturen dienen zur Verwaltung großer Mengen
schnelles Einfügen, Verändern, Löschen, ... (d.i. “Bearbeiten” im ähnlicher Objekte
weitesten Sinn) der Daten Unterschiedliche Datenstrukturen dienen zur Verwaltung
Speicherplatz unterschiedlicher Objekte, die durch unterschiedliche
kompaktes Speichern der Information Eigenschaften charakterisiert sind, daraus folgt:
Qualitative Ziele Für unterschiedliche Problemstellungen unterschiedliche
Unterstützung spezifischer Zugriffsarten auf Eigenschaften bzw. Datenstrukturen!
Charakteristiken der Daten

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


113 114

Beispiel: Telefonbuchverwaltung 2.3 Überblick

Suche in einem Telefonbuch mit 2000000 Einträgen Alle bekannten Datenorganisationsformen bauen auf
Annahme: Zugriff auf einen Datensatz in 0,01 ms
einigen wenigen einfachen Techniken auf
Ansätze (Zeit für einen Zugriff)
Sequentielles Suchen (im Mittel 1000000 * 0,01 ms = 10 s) Sequentielle Techniken
Baumstruktur (ungefähr ld 2000000 * 0,01 = 0,21 ms) Listen
Hashverwaltung (1 Zugriff = 0,01 ms)
Stack, Queue
Zugriffzeit im Verhältnis zur Dateigröße
10000
Baumstrukturen
1000
Binärer Baum, B+-Baum,
100 Sequentiell Priority Queue
10
Baumstruktur Hashverfahren
1

0,1
Hashverfahren Dictionary, Hash Tabelle,
0,01
Kollisionsverfahren
1 10 100 1000 10000 100000 1000000

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

115 116

Liste Spezielle Listen

Eine Liste (list) dient zur Verwaltung einer beliebig Stack (Keller)
Anzahl von Elementen eines einheitlichen Typs. Elemente werden nach dem LIFO (last-in, first-out) Prinzip
Die Elemente werden in einer Sequenz angeordnet, die sich verwaltet
(meist) aus der Eintragereihenfolge ableiten lässt Anwendungen: Kellerautomaten, Speicherverwaltung,
(ungeordnet). Evaluationsordnung

Der Aufwand des Zugriffes auf ein einzelnes Element ist Queue (Schlange)
abhängig von der Position in der Sequenz. Elemente werden nach dem FIFO (first-in, first-out) Prinzip
verwaltet
... Anwendungen: Warteschlangen, Bufferverwaltung,
Prozessmanagement, Stoffwechsel
Kopf Ende
Anwendungen
sequentielle Datenbestände, große Datenmengen, externe
Speicherung
VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta
117 118

Baum Spezielle Bäume

Der Baum (tree) stellt eine Generalisierung der Liste Binärer Baum
auf eine 2-dimensionale Datenstruktur dar. Knoten haben max. 2 Nachfolger, Hauptspeicherverwaltung
besteht aus Knoten und Kanten Binärer Suchbaum
Exponentieller Zusammenhang zwischen Tiefe des Baumes geordneter binärer Baum, Werteverwaltung
und Anzahl der Knoten Heap
Anwendungen: allgemeine Schlüsselverwaltung, Haupt- und ungeordneter binärer Baum, Warteschlangen
Externspeichermanagement B+-Baum
balanzierter Mehrwegbaum, Externspeicherverwaltung,
Datenbanksysteme
Trie
Prefix-Baum, Zeichenkettenverwaltung, Wörterbücher

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

119 120

Vektor Spezielle Vektoren

Ein Vektor (vector, Feld) verwaltet eine fix Hash Tabelle


vorgegebene Anzahl von Elementen eines Der Index eines Elements wird aus dem Element selbst
einheitlichen Typs. berechnet (über eine Hashfunktion h(x))
Zugriff auf ein Element über einen ganzzahligen Index (die Anwendungen: Verwaltung von Tabellen (Compilertables,
Position im Vektor) Namenslisten, …), bedingt Externspeicher-Management
Aufwand des Zugriffes für alle Elemente konstant Dictionary
Der Index eines Elementes kann beliebigen Typ haben und
x0 x1 x2 … xn-1 xn wird mit dem Element gemeinsam gespeichert
Anwendungen: Verwaltung komplexer (zusammengesetzter)
Informationen, Zuordnungslisten
Anwendungen
Verwaltung fix vorgegebener Anreihungen, Strings, math.
Konzepte

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


121 122

Vergleichskriterien Informeller Vergleich

Dynamik Datenstruktur Stärken Schwächen


Datenverwaltung Liste dynamisch linearer Aufwand der
beliebige Datenmenge Operationen
Einfügen, Löschen
klares Modell simples Modell
Datenmenge
geringer Speicherplatz
beliebige oder fixe Anzahl von Elementen
Baum dynamisch Balanzierungsalgorithmen
Aufwand beliebige Datenmenge aufwendigerer
Laufzeit der Operationen logarithmischer Aufwand der Speicherplatzverbrauch
Speicherplatzverbrauch Operationen komplexes Modell
Vektor dynamisch oft fixe Datenmenge
Modell direkter Elementzugriff eingeschränkte
Operationenumfang konstanter Aufwand der Operationen
Operationen

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

123 124

Was nehmen wir mit?

Datenorganisation
Effizienz
Quantität - Qualität Kapitel 3:
Datenstrukturen
Typen Listen
Vergleichskriterien

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


125 126

3.1 Definition Listen Abstraktion

Eine (lineare) Liste ist eine Datenstruktur zur Datenstrukturen stellen eine Abstraktion eines
Verwaltung einer beliebig großen Anzahl von Vorstellungsmodells dar
Elementen eines einheitlichen Typs. Begriff des „abstrakten Datentyps“ ADT
Der Zugriff auf die einzelnen Elemente einer (simplen) Liste Sagt nichts über die physische Realisierung am
ist nur vom Kopf (Head) aus möglich. Computer aus
Das Ende der Liste wird auch als Tail bezeichnet. Verschiedene Realisierungen denkbar!
Die Elemente werden in einer Sequenz angeordnet, die sich Realisierung oft abhängig von Problemstellung,
(meist) aus der Eintragereihenfolge ableiten läßt Programmierumgebung, Zielsetzungen, ...
(ungeordnet).
Mögliches Vorstellungsmodell Liste
... „Perlenschnur“, Perlen werden an einem Ende aufgefädelt
Kopf Ende
VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

127 128

Liste Methoden auf Listen

Definition: Einfügen
Eine Liste L ist eine geordnete Menge von Elementen Element am Kopf einfügen

L = (x1, x2, …, xn) Zugriff


Kopfelement bestimmen
andere
Löschen
Die Länge einer Liste ist gegeben durch Operationen denkbar
Kopfelement entfernen siehe später!
|L| = |(x1, x2, …, xn)| = n
Erzeugen
Eine leere Liste hat die Länge 0. Liste neu anlegen
Längenbestimmung
Das i-te Element einer Liste L wird mit L[i] bezeichnet, daher Anzahl der Elemente bestimmen
gilt 1 ≤ i ≤ |L| Inklusionstest
Test, ob Element enthalten ist

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


129 130

Methode Einfügen Methode Zugriff

Methode ‘Add’
Methode ‘FirstElement’
Einfügen eines Elementes a am Kopf einer Liste L, d.h.
L = (x1, x2, …, xn), x0
Zugriff über das Kopfelement (x1, das erste Listen-
element) auf die Liste , d.h.
Vorstellungsmodell
L = (x1, x2, …, xn)
Add(L, x0) Vorstellungsmodell „Perlenschnur“:
„Perlenschnur“: Perle betrachten
Perle auffädeln FirstElement(L) → x1 und Eigenschaften
L = (x0, x1, …, xn)
Fehler falls Liste leer feststellen
x0
x1 x2 ... xn
x1 x2 ... xn

x1
x0 x1 x2 ... xn liefert den Wert des Elements, NICHT das Listenelement !

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

131 132

Methode Löschen Methode Erzeugen

Methode ‘RemoveFirst’ Methode ‘Constructor'


Löscht das Kopfelement (x1, das erste Listenelement) Erzeugt eine neue Liste, die leer ist, d.h. keine Elemente
aus der Liste L, d.h. enthält und daher die Länge 0 hat,
L = (x1, x2, …, xn), mit |L| = n Constructor() → L, mit |L| = 0
Vorstellungsmodell
Vorstellungsmodell
„Perlenschnur“:
„Perlenschnur“:
RemoveFirst(L) Perlenschnur
Perle abziehen
∅ vorbereiten
L = (x2 …, xn), mit |L| = n-1

x1 x2 x3 ... xn

x2 x3 ... xn

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


133 134

Methode Längenbestimmung Methode Inklusionstest

Methode ‘Length’ Methode ‘Member’


Bestimmt die Anzahl der Elemente der Liste L, d.h. Überprüft, ob ein gegebenes Element a in der Liste L
L = (x1, x2, …, xn), mit |L| = n enthalten ist, d.h.
L = (x1, x2, …, xn)
Length(L) → n Vorstellungsmodell
Member(L, a) → [true, false] „Perlenschnur“:
true …∃ i | 1 ≤ i ≤ |L| ∧ a = xi Perle mit
x1 x2 ... xn false … sonst spezifischer
Eigenschaft suchen

Vorstellungsmodell
n „Perlenschnur“: x1 ... a ... xn
liefert den ganzzahligen Wert n Anzahl Perlen
bestimmen
true
VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

135 136

Klasse Listen 3.2 Implementierung von Listen

Deklaration C++, Klasse Speichertypen


Contiguous memory 22200
typedef … ItemType; 22208
zur Verwendung in 22216
… 22224
der Klassen Def., 22232
class List { 22240
besserer Ansatz
public: 22248
mit C++ Templates 22256
List(); // Constructor 22264
void Add(itemType a); Scattered (Linked) memory
ItemType FirstElement(); 22200
22208
void RemoveFirst(); 22216
22224
int Length(); 22232
int Member(itemType a); 22240
22248
} 22256
22264

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


137 138

Memory Typen C++ Konstrukt: Feld

Contiguous memory Contiguous memory


Physisch zusammenhängender Speicherplatzbereich, äußerst starr, da Ein Feld bzw. Array ist einer Anreihung einer fixen Anzahl
beim Anlegen die endgültige Größe fixiert wird.
von Elementen des gleichen Typs.
Verwaltung über das System.
Der Zugriff auf ein einzelnes Feldelement erfolgt über eine Index (die
Datenstrukturen auf der Basis von contiguous memory können nur eine
relative Position im Feld). Der Index startet oBdA mit 0 und endet
begrenzte Anzahl von Elementen aufnehmen.
mit Anzahl-1.

Scattered (Linked) memory Vereinbarung Zugriff


Physisch verteilter Speicherbereich, sehr flexibel, da die Ausdehnung <ETyp> <Feldname>’[‘<EZahl>’]’ <Feldname>‘[‘index’]’
dynamisch angepaßt werden kann. z.B.: z.B.:
Verwaltung über das Programm. double x[10]; x[0] = 3.1415 * r * r;
Datenstrukturen können beliebig groß werden. int a[10000]; a[9999] = 0;
char name[25];

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

139 140

C++ Konstrukt: Dynamische Objekte C++ Konstrukt: Dynamische Objekte

Scattered memory Erzeugung bzw. Zerstörung Achtung:


new … erzeugt ein neues Objekt p = 0 // erlaubt,
Dynamische Objekte // Initialisierung
delete … zerstört ein existierendes Objekt
Objekte die zur Laufzeit des z.B.: p = 4711 // verboten
Programmes durch double * p = new double; // Adressmanipulation
double x = 3.14159; * p = 3.14159;
Programmanweisungen 22208
double* p = &x; p ≡ 22200
erzeugt und für die 3.14159
// & liefert Adr. von x 22208
Speicherplatz angelegt wird. alter, undefinierter Wert
cout << *p; delete p;
Diese Objekte besitzen keinen 22208
// * deref. Ptr., d.h. p ≡ 22200
Namen und werden über sog. 3.14159
// druckt 3.14159
Zeiger (Pointer) verwaltet. Operatoren vom System freigegeben
Zeiger bzw. Pointer & ... liefert die Adresse des Objekts
x ≡ 22192 3.14158
Eine Variable, die die Adresse * ... dereferenziert den Zeiger und liefert den Inhalt der ref. Objektes
p ≡ 22200 22192
eines Objekts (Adressoperator -> ... Zugriff auf eine Strukturkomponente über einen Zeiger,
‘&’) enthält
d.h. x->y entspricht (*x).y

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


141 142
Liste - statisch -
3.2.1 Liste - statisch - Struktur
Erzeugen - Zerstören - Einfügen
Statische Implementation - contiguous memory Erzeugen,
Speichern der Elemente in einem Feld begrenzter Länge List::List() {p = 0;}

Zerstören
typedef int ItemType; list List::~List() {p = 0;}
class List { 0 Einfügen
private: 1 void List::Add(ItemType a) {
p 2
ItemType list[8]; if(p < 8) {
3
// Datenstruktur list[p] = a;
4
int p; p++;
5
// nächste freie Position 6 }
7 else cout << "Error-add\n";

}
} Länge = 8

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

143 144
Liste - statisch -
Liste - statisch - Zugriff - Löschen
Länge - Inklusionstest
Zugriff Länge,
int List::Length() {
ItemType List::FirstElement() {
return p;
if(p > 0) return list[p-1]; }
else cout << "Error-first\n";
}
Inklusionstest
int List::Member(ItemType a) {

Löschen int i = 0;
while(i < p && list[i] != a) i++;
void List::RemoveFirst() { if(i < p) return 1;
if(p > 0) p--; else return 0;
else cout << "Error-remove\n"; }
}

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


145 146

3.2.2 Liste - dynamisch - Struktur (1) Rekursive Datenstruktur

Dynamische Implementation - linked memory Eine Datenstruktur heißt rekursiv oder zirkulär, wenn
Dynamisch erweiterbare Liste unbegrenzter Länge sie sich in ihrer Definition selbst referenziert
typedef int ItemType; Basismodell für dynamisch erweiterbare Datenstrukturen
class List {
Liste
public:
class Element{
class Element { // Elementklasse
InfoType Info;
ItemType value;
Element* next; Element* Next;
}; }
Adr. 0 kenzeichnet
Element* head; // DS Kopf Baum
Ende der Liste
… class Node {
} Element
value next KeyType Key;
head 0 Node* LeftChild;
Node* RightChild;
}
VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

147 148
Liste - dynamisch -
Liste - dynamisch - Einfügen
Erzeugen - Zerstören
Einfügen Erzeugen, Löschen
void List::Add(ItemType a) { List::List() { head = 0;}
Element* help;
help = new Element; List::~List() {
help->next = head; Element* help;
help->value = a; Typischerweise while(head != 0) {
head = help; am Kopf der Liste help = head;
} head = head->next;
delete help;
help
} Anfang
Vor dem Einfügen 1. Durchlauf
} 2. Durchlauf
head
head
0
0

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


149 150

Liste - dynamisch - Zugriff Liste - dynamisch - Löschen

Zugriff Löschen
void List::RemoveFirst() {
ItemType List::FirstElement() { if(head != 0) {
if(head != 0) Element* help;
return head->value; help = head;
else head = head->next;
cout << "Error-first\n"; delete help;
} } else cout << "Error-remove\n";
}

Vor dem Löschen

head
0

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

151 152

Liste - dynamisch - Länge Liste - dynamisch - Inklusionstest

Länge Inklusionstest
int List::Length() { int List::Member(ItemType a) {
Element* help = head; Element* help = head;
int length = 0; while(help != 0 && help->value != a)
while(help != 0) { help = help->next;
length++; Checkpoint if(help != 0) return 1;
help = help->next; else return 0;
} }
Anfang, length: 0
return length; 1. Durchlauf length: 1
} 2. Durchlauf length: 2 help
help 3. Durchlauf length: 3

head
head x y z 0
0 ?

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


153 154

Liste - Traversieren 3.3 Stack

Sequentielles Abarbeiten einer Liste, Besuchen aller Elemente Der Stack (Kellerspeicher) ist ein Spezialfall der Liste, die die
head help Elemente nach dem LIFO (last-in, first-out) Prinzip verwaltet
0

Idee des Stacks: Man kann nur auf das oberste, zuletzt
1. Initialisieren des Hilfszeigers daraufgelegte Element zugreifen (vergleiche Buchstapel,
help = head; Holzstoß, ...)Anwendungen: Kellerautomaten, Speicherverwaltung,
help
HP-Taschenrechner (UPN), ...
head 0
Das Verhalten des Stacks lässt sich über seine (recht
2. Weitersetzen des Hilfszeigers (Position) einfachen) Operationen beschreiben
help = help -> next;
help
push: Element am Stack ablegen
head 0
top: Auf oberstes Element des Stacks zugreifen
pop: Element vom Stack entfernen
3. Abfrage auf Listenende (und Suchkriterium)
isEmpty: Test auf leeren Stack
while ( help != 0 && … ) { … }
help 0

head ?

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

155 156

Methoden auf Stacks Stack als Liste

Methode ‘Push’ 0
Stack ist eine spezielle Liste, daher können die Stack-
Element wird auf dem Stack 1
operationen durch Listenoperationen ausgedrückt
abgelegt (an oberster 2 werden.
Position). Push(S,a) ⇒ Add(S,a)
Methode ‘Top’ 0 Top(S) ⇒ FirstElement(S)
Liefert den Inhalte des 0 Pop(S) ⇒ RemoveFirst(S)
1
obersten Elementes des
2
Stacks. IsStackEmpty(S) ⇒
wenn Length(S) = 0 return true
Methode ‘Pop’ 0
sonst false
Oberstes Element des 1
Stacks wird entfernt. 2

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


157 158

3.4 Queue Methoden auf Queue

Die Queue (Warteschlange) ist ein Spezialfall der Liste, die die
Elemente nach dem FIFO (first-in, first-out) Prinzip verwaltet 0
Methode ‘Enqueue’
1
Idee: Die Elemente werden hintereinander angereiht, wobei nur am Element wird am Ende der
2
Ende der Liste Elemente angefügt und vom Anfang der Liste Queue abgelegt (an
weggenommen werden können
Anwendungen: Warteschlangen, Bufferverwaltung, letzter Position)
Stoffwechsel, Prozessmanagement, … 0
Methode ‘Front’
Einfache Operationen 1
Enqueue Liefert den Inhalte des 2
Element am Ende der Queue ablegen ersten Elementes der 2
Front Queue
Erstes Element der Queue zugreifen
Dequeue Methode ‘Dequeue’ 0
Erstes Element aus der Queue entfernen 1
IsQueueEmpty
Erstes Element der Queue
2
Test auf leere Queue wird entfernt

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

159 160

Queue als Liste Front(Q)

Queue ist ebenfalls eine spezielle Liste, daher Front(Q)


ItemType e; // Hilfselement
sollten alle Queueoperationen auch durch List L; // Hilfsliste
Listenoperationen ausgedrückt werden können. int n = Q.Length();
for (int i = 1; i <= n - 1; i++) {
L.Add(Q.FirstElement());
Enqueue(Q,a) ⇒ Add(S,a) Q.RemoveFirst();
Q L
Front(Q) ⇒ ? Nicht trivial !
}
e = Q.FirstElement();
Dequeue(Q) ⇒ ? n = L.Length();
for (i = 1; i <= n; i++) {
Q.Add(L.FirstElement());
Möglichkeit (umständlich!)
L.RemoveFirst();
Zugriff auf das erste Queueelement (letzte in der Liste) durch }
iteratives Entfernen aller Elemente und gleichzeitigen Aufbau return e;
einer ‘gestürzten’ Hilfsliste. Danach Vorgang umkehren.

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


161 162

Dequeue Zugriff auf beliebiges Listenelement

Dequeue(Q) Besser: Einführen einer neuen Listenoperation


List L; Methode ‘AccessElement’
int l = Q.Length(); Zugriff auf ein beliebiges Listenelement über die Position in der
for (int i = 1; i <= n - 1; i++) { Liste, d.h.
L.Add(Q.FirstElement()); L = (x1, …, xn), i
Q.RemoveFirst();
} AccessElement(L, i) → xi
Q.RemoveFirst(); Fehler falls Position nicht definiert
int n = L.Length(); i
for (i = 1; i <= n; i++) {
x1 x2 ... xn
Q.Add(L.FirstElement());
L.RemoveFirst();
} xi
C++-Methode: ItemType AccessElement(position i);

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

163 164

Methode AccessElement Queue als Liste (2. Versuch)

ItemType List::AccessElement(int pos) { Neuerlicher Definitionsansatz mit zusätzlicher


Element* act = head;
Listenoperation etwas einfacher, aber ...
int actpos = 1;

while(actpos < pos) { Enqueue(Q,a) ⇒ Add(Q,a)
act = act->next; Front(Q) ⇒ AccessElement(Q,Length(Q))
actpos++;
Dequeue(Q) ⇒ ?
}
return act->value; RemoveElement(Q, Length(Q))
} Möglichkeit:
Analog zu positionsbezogener Zugriffsfunktion eine
positionsbezogene Teilungsfunktion entwerfen, die eine
Liste an einer vorgegebener Stelle in 2 Teillisten zerlegt.

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


165 166

Löschen eines beliebigen Listenelements Methode RemoveElement


void List::RemoveElement(int pos) {
Methode ‘RemoveElement’ Element* pred, * act;
Löschen eines beliebiges Listenelement über die Position int actpos = 2;
in der Liste, d.h. if(pos == 1) RemoveFirst();
erstes Element
else {
L = (x1, …, xi-1, xi, xi+1, … , xn), i
pred = head;
act = head->next;
RemoveElement(L, i) → L while(act != 0 && actpos < pos) {
Fehler falls Position nicht definiert pred = act;
Üblicherweise 2 act = act->next; 2 Hilfszeiger
Hilfszeiger auf
Erstes Element L = (x1, …, xi-1, xi+1, … , xn), i aktuelles und
actpos++;
(1. Pos.) Spezialfall vorhergehendes }
Element if(act == 0) return;
pred act
pred->next = act->next;
head delete act;
0 }
Position: i-1 i i+1 }

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

167 168

Methode AddElement Stack - Queue Klasse

Analog auch AddElement mgl.: Einfügen an beliebiger Stelle C++ Klassen Deklaration (Skizze)
void List::AddElement(ItemType a, int pos) {
Element* pred, * act;
int actpos = 2; Stack Queue
if(pos == 1) Add(a); erstes Element class Stack { class Queue {
else {
pred = head; … …
act = head->next; public: public:
while(act != 0 && actpos < pos) { Stack(); Queue();
pred = act; bool Push(ItemType a); bool Enqueue(ItemType a);
act = act->next; 2 Hilfszeiger ItemType Top(); ItemType Front();
actpos++;
} bool Pop(); bool Dequeue();
pred->next = new Element; bool IsStackEmpty(); bool IsQueueEmpty();
pred->next->value = a; } }
pred->next->next = act;
}
}

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


169 170
Aufwandsvergleich "unserer" Listen
Vergleich "unserer" Datenstrukturen
Implementationen
Generelle Unterscheidung zwischen statischer und Liste Liste Liste Liste
dynamischer Realisierung statisch dynamisch statisch dynamisch

statische R.: contigous memory, Felder Speicherplatz O(n) O(n) AccessElement O(1) O(n)
dynamische R.: dynamic memory, dynamische Objekte Konstruktor O(1) O(1) RemoveElement O(n) O(n)
Destruktor O(1) O(n) AddElement O(n) O(n)
Datenverwaltung
Add O(1) O(1)
Einfügen und Löschen wird unterstützt
FirstElement O(1) O(1)
Datenmenge RemoveFirst O(1) O(1)
statische R.: beschränkt, abhängig von der Feldgröße Length O(1) O(n)
dynamische R.: unbeschränkt Member O(n) O(n)
abhängig von der Größe des vorhandenen Speicherplatzes
Achtung: Eigentlicher Aufwand O(n)
eher simple Modelle in Add und RemoveFirst versteckt

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

171 172
Aufwandsvergleich "unserer" Stack - Queue
3.5 Spezielle Listen
Implementationen
Stack Stack Queue Queue Doubly Linked List
statisch dynamisch statisch dynamisch
doppelt verkettet Liste
Speicherplatz O(n) O(n) Speicherplatz O(n) O(n)
Circular List
Konstruktor O(1) O(1) Konstruktor O(1) O(1)
Zirkulär verkettete Liste
Destruktor O(1) O(n) Destruktor O(1) O(n)
Push O(1) O(1) Enqueue O(1) O(1) Ordered List
Pop O(1) O(1) Dequeue O(1) O(n) Geordnete Liste
Top O(1) O(1) Front O(1) O(n) Double Ended List
IsStackEmpty O(1) O(1) IsQueueEmpty O(1) O(1) Doppelköpfige Liste

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


173 174

Doubly Linked List Circular List

Doppelt verkettete Liste Zirkulär verkettete Liste


Zeiger des letzten Element verweist wieder auf das erste
x1 x2 x3 x4
Element
jedes Element besitzt 2 Zeiger, wobei der eine auf das Ring Buffer
vorhergehende und der andere auf das nachfolgende Vorsicht beim Eintragen und Löschen des ersten Elementes!
Element zeigt
Basis-Operationen einfach
x1
class Node { x2
KeyType Key; Pred Key Succ x5
Node* Pred;
x3
Node* Succ;
x4
}

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

175 176

Ordered List Double Ended List

Geordnete Liste Liste mit 2 “Köpfen”


Elemente werden entsprechend ihres Wertes in die Liste an Jede Liste besitzt 2 Zeiger, die zum Kopf und zum Ende der
spezifischer Stelle eingetragen Liste zeigen
Meist der Größe nach geordnet Vereinfacht das Einfügen am Kopf und am Ende der Liste
Eintragen an spezifischer Stelle, die erst gefunden werden
muß → Traversieren

Tail
2 4 9 17 Head x1 x2 x3 x4

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


177 178

Was nehmen wir mit?

Listen
Operationen
Speicherung Kapitel 4:
Contigous - Scattered memory
Stack – Queue Bäume
Vergleich
Spezielle Listen
Doubly Linked List
Circular List
Ordered List
Double Ended List
VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

179 180

4.1 Definition Bäume Beispiel Bäume

Ein Baum (tree) ist ein spezieller Graph, der eine Prozessorfamilien
8080
hierarchische Struktur über eine Menge von 8085 8086 8088 68000
Objekten definiert 80186 80286 68020
Spezialfall
80386 Liste
Intuitives Vorstellungsmodell - Nicht-lineare Datenstruktur 68030
80486 68040
Anwendungen Pentium
Repräsentieren Wissen, Darstellung von Strukturen, Abbildung von
Zugriffspfaden, Analyse hierarchischer Zusammenhänge, ... Stammbaum
Gaea

Cronus Phoebe Ocean

Zeus Poseidon Demeter Pluto Iapetus

Persephone Apollo Atlas Prometheus

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


181 182

Definition Bäume (1) Komponenten

Ein Baum besteht aus einer Menge von Knoten, die Die Wurzel ist der einzige Knoten mit nur
durch gerichtete Kanten verbunden sind wegführenden Kanten
Ein Pfad oder Weg ist eine Liste sich unterscheidender Knoten, Knoten von denen keine Kanten wegführen heißen
wobei aufeinander folgende Knoten durch eine Kante Blatt (leaf)
verbunden sind Wurzel
Pfad/Weg von der
Knoten, in die Kanten Wurzel zum Blatt
Es gibt genau einen Pfad der 2 Knoten miteinander
hinein- und von denen Knoten (interner)
verbindet und jeder Knoten hat nur einen direkten
Kanten wegführen,
Vorgänger; alle Vorgänger sind von ihm selbst
heißen interne Knoten
verschieden (definierende Eigenschaft eines Baumes)
Ein Baum enthält daher keine Kreise, d.i. ein Pfad bei dem der
Kante
Startknoten gleich dem Endknoten ist
Blatt

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

183 184

Gültige und ungültige Bäume Definition Bäume (1)

Gültige Bäume Jeder Knoten (mit Ausnahme der Wurzel) hat genau einen
Knoten über sich, den man als Elternknoten oder
übergeordneten Knoten bezeichnet
Die Knoten direkt unterhalb eines Knotens heißen Kindknoten
oder untergeordnete Knoten
Transitive Eltern werden als Vorgänger bzw. transitive Kinder
als Nachfolger bezeichnet
Ungültige Bäume Vorgänger
Räumlich nebeneinander- Elternknoten,
liegende Knoten auf Adjazenter Knoten
übergeordneter Knoten

derselben Tiefe heißen Nachbarknoten


adjazent oder Nachbarn us k Kindknoten,
Fo
untergeordneter Knoten

Nachfolger

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


185 186

Rekursive Baum Definition Länge, Höhe, Tiefe

Ein einzelner Knoten ohne Kanten ist ein Baum Die Länge eines Weges zwischen 2 Knoten entspricht
Seien T1, …, Tk (k > 0) Bäume ohne gemeinsame Knoten. Die der Anzahl der Kanten auf dem Weg zwischen den
Wurzeln dieser Bäume seien r1, …, rk. Ein Baum T0 mit der beiden Knoten
Wurzel r0 besteht aus den Knoten und Kanten der Bäume T 1,
…, Tk und neuen Kanten von r0 zu den Knoten r1, …, rk Die Höhe eines Knoten ist die Länge des längsten
Der Knoten r0 ist dann Weges von diesem Knoten zu den erreichbaren
r r r
die neue Wurzel
1
... T
2 k

k
Blättern
T
und T1, …, Tk sind T
1

2 Die Tiefe eines Knoten ist die Länge des Weges zur
Unterbäume von T0 r 0
Wurzel
r1 r2 rk
Die Höhe eines Baumes entspricht der Höhe der
ri … Wurzel des Baumes i
... Tk Wurzel
T1
Ti… Unterbaum i
T2

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

187 188

Länge, Höhe, Tiefe grafisch Beispiel Parse Tree

Parsierungsbäume (parse trees) analysieren Anweisungen bzw.


Programme einer Programmiersprache bezüglich einer
Tiefe gegebenen Grammatik
(depth) Eine Grammatik definiert Regeln, wie und aus welchen
Elementen eine Programmiersprache aufgebaut ist
<stmt> Nonterminal Symbole
(werden aufgelöst)
Beispiel: C++ (Ausschnitt) if, ident Terminalsymbole
Höhe (nicht mehr aufgelöst)
<stmt> ::= <select-stmt> | <expr> ::=, | Grammatiksymbolik
(height)
<select-stmt> ::= if ( <expr> ) <stmt> else <stmt>
<expr> ::= <relational-expr> | <assign-expr> | ident
<relational-expr> ::= <expr> < <expr>
<assign-expr> ::= ident = <expr>

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


189 190

Beispiel Parse Tree (2) Spezielle Bäume

if (a < b) max = b else max = a Bäume (trees)


<stmt> ::= <select-stmt> | <expr>
<select-stmt> ::= if ( <expr> ) <stmt> else <stmt>
<stmt> <expr> ::= <relational-expr> | <assign-expr> | ident
<relational-expr> ::= <expr> < <expr>
<select-stmt> <assign-expr> ::= ident = <expr> ungeordnete Bäume geordnete Bäume
if ( <expr> ) <stmt> else <stmt> (unordered trees) (ordered trees)

<relational-expr> <expr> <expr>

<expr> < <expr> <assign-expr> <assign-expr> binäre Bäume Mehrweg Bäume


(binary trees) (multiway trees)
ident ident ident = <expr> ident = <expr>

a b max ident max ident Die Ordnung bezieht sich auf die Position der Knoten im
Baum (Knoten A links von Knoten B) und nicht auf die
b a Werte der Knotenelemente

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

191 192

4.2 Binäre Bäume Binäre Bäume - Eigenschaften

Binäre Bäume sind geordnete Bäume, in denen jeder Häufiger Einsatz in Algorithmen
Knoten maximal 2 Kinder hat und die Ordnung der Effiziente Manipulationsalgorithmen
Knoten mit links und rechts festgelegt ist Zusammenhang zw. Anzahl der Elemente und der Höhe

Binärer Baum mit 2 Kindern


Höhe 0 Höhe 1 Höhe 2
Binärer Baum mit rechtem Kind (right child) 1 Knoten 3 Knoten 7 Knoten
1 Blatt 2 Blätter 4 Blätter
In jeder neuen Ebene wird im optimalen Fall die Anzahl der
Binärer Baum mit linkem Kind (left child)
Blätter verdoppelt
Entartung möglich: Jeder Knoten hat
Binärer Baum ohne Kind (Blatt)
genau ein Kind → entspricht linearer Liste
VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta
193 194

Formen binärer Bäume Voller binärer Baum

Leerer binärer Baum Full binary tree


Binärer Baum ohne Knoten Jeder Knoten im Baum hat keine oder genau 2 Kinder.
Voller binärer Baum Mit anderen Worten, kein Knoten besitzt nur 1 Kind
Jeder Knoten hat keine oder 2 Kinder
Perfekter binärer Baum
Ein voller binärer Baum bei dem alle Blätter dieselbe Tiefe besitzen
Kompletter binärer Baum
Ein perfekter binärer Baum mit der Ausnahme, dass die Blattebene nicht
vollständig, dafür aber von links nach rechts, gefüllt ist
Höhen-balanzierter binärer Baum
Für jeden Knoten ist der Unterschied der Höhe des linken und rechten
Kindes maximal 1

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

195 196

Perfekter binärer Baum Eigenschaften des perfekten binären Baumes

Perfect binary tree Eigenschaften


Ein voller binärer Baum (alle Knoten haben keine oder Frage: welche Höhe h muss ein perfekter binärer Baum
genau 2 Kinder) bei dem alle Blätter dieselbe Tiefe haben um n Blätter zu besitzen
besitzen. In jeder Ebene Verdoppelung, d.h. 2h = n
h * log 2 = log n
h = log2 n = ld n
Ein perfekter binärer Baum der Höhe h besitzt 2h+1-1 Knoten
davon sind 2h Blätter
Beweis mit vollständiger Induktion
Zusammenhang zwischen Knoten/Blätter und Höhe:
wichtigste O(n) Knoten/Blätter : O(log n) Höhe
Eigenschaft
von Bäumen
VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta
197 198

Kompletter binärer Baum Höhen-balanzierter binärer Baum

Complete binary tree Height-balanced binary tree


Ein kompletter binärer Baum ist ein perfekter binärer Baum Für jeden Knoten ist der Unterschied der Höhe des linken
mit der Ausnahme, dass die Blattebene nicht vollständig, und rechten Kindes maximal 1
dafür aber von links nach rechts, gefüllt ist Dies garantiert, dass lokal für jedes Kind die Balanzierungs-
eigenschaft relativ gut erfüllt ist, global aber die gesamten
Baumdifferenzen größer sein können → einfachere Algorithmen

Eigenschaft
Ein kompletter binärer Baum mit n Knoten hat eine Höhe von
maximal h = log2 n

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

199 200

Baum Traversierung Expression Tree

Traversieren eines Baumes bezeichnet das Systematische Auswertung eines mathematischen Ausdrucks
systematische Besuchen aller seiner Knoten Ein mathematischer Ausdruck kann in Form eines Expression
Unterschiedliche Methoden unterscheiden sich in der Trees angegeben werden
+
Reihenfolge der besuchten Knoten
(20 / 5) + 3
/ 3
Mögliche Reihenfolgen
A, B, C A 20 5

B, A, C
B, C, A Blätter repräsentieren Operanden (Zahlenwerte), interne Knoten
B C Operatoren
… Baumdarstellung erspart Klammernnotation

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


201 202

Traversierungsalgorithmus Preorder Traversierung

Traversierungsalgorithmen bestehen prinzipiell aus 3 Algorithmus


verschiedenen Schritten preorder(node) {
if(node != 0) { Beispiel
Bearbeiten eines Knotens (process node)
process(node)
Rekursiv besuchen und bearbeiten des linken Kindes (visit left child) 20/5+3
preorder(left child)
Rekursiv besuchen und bearbeiten des rechten Kindes (visit right child) preorder(right child) + A
}
Durch unterschiedliches Anordnen der 3 Schritte B
} / 3 E
unterschiedliche Reihenfolgen
Besucht die Knoten im Baum in Prefix-
3 Bearbeitungsreihenfolgen interessant Notation-Reihenfolge C 20 5 D
Preorder Traversierung (Operator, Operand 1, Operand 2)
Postorder Traversierung Faustregel
Process-Reihenfolge: ABCDE
Inorder Traversierung Knoten bearbeiten beim 1. Besuch
Notation-Reihenfolge: + / 20 5 3
Anwendung
LISP, Assembler

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

203 204

Postorder Traversierung Inorder Traversierung

Algorithmus Algorithmus
postorder(node) { inorder(node) {
if(node != 0) { if(node != 0) {
postorder(left child)
Beispiel Beispiel
inorder(left child)
postorder(right child) 20/5+3 20/5+3
process(node)
process(node) + A + A
inorder(right child)
}
} }
B / 3 E } B / 3 E
Postfix-Notation-Reihenfolge
(Operand1, Operand2, Operator) Infix-Notation-Reihenfolge
C 20 5 D (Operand1, Operator, Operand2) C 20 5 D
Faustregel
Knoten bearbeiten beim letzten Faustregel
Besuch Knoten bearbeiten beim 2. oder letzten
Anwendung Process-Reihenfolge: CDBEA Besuch Process-Reihenfolge: CBDAE
Invers Polish Notation, HP Notation-Reihenfolge: 20 5 / 3 + Notation-Reihenfolge: 20 / 5 + 3
Anwendung
Taschenrechner, FORTH
einfacher algebraischer Taschen-
rechner (ohne Klammern)

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


205 206

4.3 Binäre Suchbäume Schlüsseleigenschaft im BST

In einem Binärbaum besitzt jeder (interne) Knoten eine Für jeden internen Knoten gilt, dass alle Werte der
linke und eine rechte Verbindung, die auf einen Nachfolger im linken Unterbaum kleiner (oder
Binärbaum oder einen externen Knoten verweist gleich) dem Knotenwert und die Werte der
Verbindungen zu externen Knoten heißen Nullverbindungen, Nachfolger im rechten Unterbaum größer als der
externe Knoten besitzen keine weiteren Verbindungen Knotenwert sind Interne
Knoten
Ein binärer Suchbaum (binary search tree, BST) ist ein 12
Binärbaum, bei dem jeder interne Knoten einen Externe Knoten
<= > Repräsentieren quasi die
Schlüssel besitzt 10 15 Datenspeicher (enthalten nur
mehr Schlüssel und Daten,
externe Knoten besitzen keine Schlüssel keine Zeiger auf Nachfolger),
3 11 21 z.B. Seiten auf der Platte
Auf den Schlüsseln ist eine lineare Ordnung “<“ definiert Bei Hauptspeicherstrukturen
meist vernachlässigbar
Wenn x und y verschieden sind, so gilt x<y oder y<x; ist x<y und
werden im Weiteren grafisch oft nur
y<z, dann gilt auch x<z mehr durch einen Strich dargestellt

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

207 208

Eigenschaften binärer Suchbäume Operationen

Verwaltung beliebig großer Datenbestände Erstellen


dynamische Struktur Erzeugen eines leeren Suchbaumes
Einfügen
Effiziente Administration Einfügen eines Elementes in den Baum unter Berücksichtigung der
Aufwand proportional zur Höhe des Baumes und nicht zur Ordnungseigenschaft
Anzahl der Elemente Suche
Einfügen, Zugriff und Löschen im Durchschnitt von O(log n) Test auf Inklusion
Signifikante Verbesserung im Vergleich zum linearen Löschen
Aufwand (O(n)) bei Liste Entfernen eines Elementes aus dem Baum unter Erhaltung der
Zugriff auf Elemente in sortierter Reihenfolge durch inorder Ordnungseigenschaft
Traversierung Ausgabe
Ausgabe aller Elemente in sortierter Reihenfolge
...
VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta
209 210

Klassendefinition Suchen in einem binären Baum


typedef int ItemType;
Beim Suchen eines Schlüssels wird ein Pfad von der Wurzel
class SearchTree {
class node { Einfachheitshalber in
public: node alles
public
abwärts verfolgt
ItemType info; Bei jedem internen Knoten wird der Schlüssel x mit dem Suchschlüssel s
node * leftchild, * rightchild;
node(ItemType x, node * l, node * r) {info=x; leftchild=l; rightchild=r;} verglichen
};
typedef node * link;
Falls x = s liegt ein Treffer vor, falls s <= x suche im linken Teilbaum,
link root; sonst im rechten
void AddI(ItemType);
void AddR(link&, ItemType); Wenn man einen externen Knoten erreicht, war die Suche erfolglos
bool MemberI(ItemType);
bool MemberR(link, ItemType);
void PrintR(link, int); node
Erfolgreiche Suche (z.B. 11) Erfolglose Suche (z.B. 13)
public:
SearchTree(){root = 0;}
void Add(ItemType);
leftchild info rightchild
12 12
int Delete(ItemType);
bool Member(ItemType); 7 15 7 15
void Print();
}; 3 11 21 3 11 21

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

211 212

Suche (iterativ) Suche (rekursiv)


bool SearchTree::MemberI(ItemType a) { bool SearchTree::MemberR(link h, ItemType a) {
if(root) { if(!h) return false;
link current = root; Aufruf: else {
while(current) { SearchTree t; if(a == h->info) return true;
if(current->info == a) return true; …
if(a < current->info)
if(a < h->info)
t.Member(7); return MemberR(h->leftchild, a);
current = current->leftchild;
else else
current = current->rightchild; Verzweigung auf return MemberR(h->rightchild, a);
}
root->leftchild, }
} }
return false; da root->info > a
(d.I. 12 > 7) bool SearchTree::Member(ItemType a) {
}
return MemberR(root, a);
bool SearchTree::Member(ItemType a) {
}
return MemberI(a); 12
} Aufruf:
SearchTree t;
7 15 …
t.Member(7);
return true, da root->info == a (gefunden!)

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


213 214

Einfügen in einem binären Suchbaum Einfügen (iterativ)

Das Einfügen entspricht einer erfolglosen Suche Ähnlich dem Einfügen in eine Liste (2 Hilfszeiger)
void SearchTree::AddI(ItemType a) {
(wobei gleiche Schlüssel übergangen werden) und if(root) { Aufruf:
link current = root; Hilfszeiger: SearchTree t;
dem Anfügen eines neuen Knotens an der link child;
while(1) {
current, child …
t.Add(7);
Nullverbindung wo die Suche endet (anstelle des if(a <= current->info) {
child = current->leftchild;
externen Knotens) if(!child) {current->leftchild = new node(a, 0, 0); return;}
} else {
child = current->rightchild;
Einfügen 13 if(!child) {current->rightchild = new node(a, 0, 0); return;}
}
Suche Knoten anfügen current = child;
}
12 12 } else {
root = new node(a, 0, 0); current
7 15 7 15 return; child
}
3 11 21 3 11 13 21 } 12
void SearchTree::Add(ItemType a) {
AddI(a); 7 15
}

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

215 216

Einfügen (rekursiv) Traversieren

void SearchTree::AddR(link& h, ItemType a) { void SearchTree::PrintR(link h, int n) {


if(!h) {h = new node(a, 0, 0); return;} if(!h) return;
Inorder
if(a <= h->info) PrintR(h->rightchild, n+2);
Traversierung
AddR(h->leftchild, a); Man beachte die Verwendung for(int i = 0; i < n; i++) cout << " ";
else eines Referenzparameters cout << h->info << endl;
AddR(h->rightchild, a); (link&), erspart die 2 PrintR(h->leftchild, n+2);
Hilfszeiger
} }
void SearchTree::Add(ItemType a) { void SearchTree::Print() {
AddR(root, a); PrintR(root, 0);
} } Gibt Baum um 90 Grad gegen den
Aufruf Aufruf Uhrzeigersinn verdreht aus
SearchTree t; SearchTree t;
… …
t.Add(7); t.Print();

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


217 218

Löschen in einem binären Baum Löschen (2)

Der Löschvorgang unterscheidet 3 Fälle Fall 1


Löschen von internen Knoten mit Löschen von Knoten 3 durch Ersetzen des linken Kindzeigers von Knoten
7 durch eine Nullverbindung (externer Knoten)
(1) keinem (2) einem (3) zwei
internen Knoten als Kinder 12 12
7 15 7 15

3 11 21 11 21

Fälle 1 und 2 sind einfach durch Anhängen des Fall 2


verbleibenden Teilbaums an den Elternknoten des zu Löschen von Knoten 15 durch Einhängen des Knoten 21 als rechtes
löschenden Knotens zu lösen. Kind von 12
12 12
Für Fall 3 muss ein geeigneter Ersatzknoten gefunden
7 15 7 21
werden. Hierzu eignen sich entweder der kleinste im
rechten (Inorder Nachfolger) oder der größte im linken 11 21 11
Teilbaum (Inorder Vorgänger)
VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

219 220

Löschen (3) Laufzeit

Fall 3 12 Erwartungswert der Einfüge- und Suchoperationen bei n


7 15 zufälligen Schlüsselwerten ist ungefähr 1,39 ld n
3 11 21 Im ungünstigsten Fall kann der Aufwand zu ungefähr n
Im Falle des Löschens von 12 eignen sich als Ersatz die Knoten mit den Werten 11
Operationen „entarten“
(größte im linken) oder 15 (der kleinste im rechten Teilbaum). Beispiele für ungünstige Suchbäume
Dies resultiert in 2 möglichen Bäumen:
11 15
3 3
7 15 7 21
7 21
3 21 3 11
11 7
Somit muss der Löschvorgang für Fall 3 in zwei Teile zerlegt werden: 12 15
1. Finden eines geeigneten Ersatzknotens
15 11
2. Ersetzen des zu löschenden Knotens (was wiederum aus dem Entfernen
des Ersatzknotens aus seiner ursprünglichen Position (entspricht Fall 1 21 12
oder 2) und dem Einhängen an der neuen Stelle besteht)

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


221 222

Analyse binärer Suchbaum 4.4 Höhenbalanzierter binärer Baum

Datenverwaltung Höhenbalanziert (bekannt!): Für jeden Knoten ist der Unter-


unterstützt Einfügen und Löschen schied der Höhe des linken und rechten Kindes maximal 1
Datenmenge Geeignete Algorithmen für Einfügen und Löschen erhalten die
Balanzierungseigenschaft und vermeiden dadurch die „Entartung“ der
unbeschränkt
Laufzeit zu O(n) und garantieren O(log n)
Modelle
Hauptspeicherorientiert
Unterstützung komplexer Operationen
Bereichsabfragen, Sortierreihenfolge
Laufzeit Speicherplatz O(n)
Konstruktor O(1)
Zugriff O(log n)
Einfügen O(log n)
Bitte beachten:
beträchtlicher konstanter
Löschen O(log n)
Aufwand ist notwendig!
Sortierreihenfolge O(n)

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

223 224

AVL Bäume Einfügen in einen AVL Baum

AVL Bäume sind höhenbalanzierte binäre Suchbäume Das Einfügen verläuft analog zum Einfügen im binären
Adelson-Velski und Landau, 1962 Suchbaum
5 46
4 46

4 46 Einfügen 54
Beispiel 2 17 4 78
2 17 3 78
Höhen sind neben den
Knoten angegeben 2 17 3 78
1 32 3 50 1 88
Anmerkung: externe Knoten 0 1 32 2 50 1 88
nicht vergessen, sie haben die 1 32 2 50 1 88
Höhe 0! Problem: die Balanzierungs- 1 48 62 2
0 0 1 48 62 1 eigenschaft kann durch das
Einfügen verletzt werden
1 48 62 1 d.h. Korrektur notwendig
1 54
0 00 0

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


225 226

Rotationen Einfügen Beispiel

Balanzierungskorrektur durch Knotenrotationen


2 generelle Fälle (einfach und doppelt) zu unterscheiden 5 46
Jeweils 2 weitere symmetrische Fälle 4 46
C C 2 17 4 78
Fall 1 Fall 2
B eigentlich A 2 17 3 62
1
T4 T4 1 32 3 50 88 Doppelte
A B Rotation
T3 T1
T4 1 32 2 50 2 78
B 1
48 62 2
T1 T2 T2 T3 1 1 1
A C
Einfache
T1 48 54 T3 88
Doppelte Rotation
Rotation 1 54 T3
1. Schritt produziert T1 T2 T4
T1 T2 T3 T4 Fall 1, danach
T2
einfache Rotation
VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

227 228

Einfache Rotationen Doppelte Rotationen

Nach Einfügen eines Elementes ( ) Baum nicht mehr balanziert Die doppelte Ausgangspunkt Zwischenphase Ergebnis
Rotation besteht
Durch Symmetrie 2 einfache Rotationsfälle zu unterscheiden eigentlich aus 2 A RL-Rotation A RL-Rotation
1.Phase: 2.Phase: B
„Fall“ Bestimmung einfachen LL Rotation RR Rotation
B A Rotationen C B
1. Ausgehend vom A C
Die RL Rotation B C
LL-Fall A B Knoten, bei dem die
aus einer LL
LL-Rotation Balanzierung verletzt
ist, überprüft man, Rotation des
rechten 1 1 2 2 3
3 1 welcher Teilbaum 2 3 4 3 1 4
2 2 länger ist (L oder R). Subbaumes und
1 3 4
danach einer RR
2. Danach beim Rotation des
Kindknoten im nicht C LR-Rotation C LR-Rotation
gesamten Baumes 2.Phase:
A B balanzierten Teilbaum der nicht balanziert
1.Phase: B
feststellen, welcher A RR Rotation B LL Rotation
ist
B A weiterer (Sub)- A C
RR-Fall RR-Rotation Teilbaum länger ist (L (die LR Rotation B A
oder R) (bei gleicher funktioniert
1 3 Länge einfacher Fall) entsprechend
umgekehrt) 4 3 4 2 3
2 3 1 2 1 3 2 1 4
2
1

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


229 230

Beispiel Einfügen im AVL Baum Beispiel Einfügen im AVL Baum (2)


4
Einfügereihenfolge: 4,5,7,2,1,3,6 5 4
3 1
3
4 4 5 3 unbal. 2 7 LR Rot. 2 5 6…
4, 5
2 bal. 1 2 0 0
bal. 7 unbal. 0 2 RR Rot.
5 5 4 7 …
simpel 1 4 1 3 7
0 1 0 0 1 0
7
3
0 0
0 0

4
4 4
5 5 4
2 3
3 1 5 … unbal. RL Rot. 2 6
4 7 4 7 2 5

simpel
1 unbal. 2 0 0 0 LL Rot. 2 7 1 1 0 2
2 1 3 7 1 3 5 7
2
1 0
1 4 0 0 0 0
1 1 0
0 0 6
0 0

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

231 232

Löschen im AVL Baum Beispiel Löschen im AVL Baum

Das Löschen funktioniert analog zum Löschen im Löschreihenfolge: 4,8,6,5,2,1,7


5 5 5
binären Suchbaum
4 8 6
Gelöschte Knoten können zu nicht balanzierten 3 8 LL Rot. 2 8 simpel 2 7 RR Rot.

Bäumen führen
2 4 7 10 1 3 7 10 1 3 6 10
Lösung durch Rotationen analog zum Einfügen Beim Löschen Fall 3
oBdA Ersatzknoten =
Eine (Lösch) Rotation kann aber die Balanzierung eines 1 6 9 11 6 9 11 größter links 9 11
anderen Knoten verletzen 5 3 7 7 10
5 2 1 7
Daher kann ein Löschvorgang eine Serie von Rotationen simpel RL Rot. simpel RR Rot.
2 10 2 10 3 10 3 10 3 11
auslösen um Unbalanziertheiten vom Löschort bis zur
Wurzel aufzulösen 1 3 7 11 1 7 11 1 9 11 9 11 9
Die ist unterschiedlich zum Einfügen, wo mit einer Rotation
die Unbalanziertheit behoben werden kann 9 9
VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta
233 234

Analyse AVL Baum 4.5

Datenverwaltung Mehrwegbäume sind Bäume mit Knoten, die mehr als


unterstützt Einfügen und Löschen
2 Kinder besitzen können
Datenmenge
unbeschränkt Intervallbasierten Suchdatenstrukturen
Modelle k1 k2 ... km-1 km
Hauptspeicherorientiert p0 p1 pm-1 pm
Unterstützung komplexer Operationen x < k1 k1 ≤ x < k2 km-1 ≤ x < km km ≤ x
Bereichsabfragen, Sortierreihenfolge Knoten besteht aus einer Menge von m Schlüsselwerten k1, k2,
Laufzeit Heuristische Analyse (Wirth 79) …, km und m+1 Verweisen (Kanten) p0, p2, …, pm, sodass für
Speicherplatz O(n) zeigt, dass eine Rotation bei jeder alle Schlüssel xj im Unterbaum, der durch pi referenziert wird,
2-ten Einfügeoperationen und nur
Rotation O(1)
bei jeder 5-ten Löschoperation gilt ki ≤ xj < ki+1 (Schlüssel liegen im Intervall [ki, ki+1[).
Zugriff O(log n)
vorkommt Beispiel 11 37
Einfügen O(log n)
Die Höhe eines AVL-Baumes mit n Interne Knoten
3 9 13 39 41 53
Löschen O(log n) Knoten ist ≤ 1.45 log n, d.h. höchstens
Sortierreihenfolge O(n) 45 % größer als erforderlich. Externe Knoten
VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

235 236

Suchen im Mehrwegbaum 2-3-4 Bäume

Ähnlich zur Suche im binären Suchbaum Ein 2-3-4 Baum ist ein Mehrwegbaum mit den
Bei jedem internen Knoten mit Schlüsseln k 1, k2, …, km und folgenden 2 Eigenschaften
Verbindungen p0, p1, … , pm Größeneigenschaft: jeder Knoten hat mindestens 2 und
Suchschlüssel s = ki (i = 1, …, m): Suche erfolgreich maximal 4 Kinder
S ≤ k1: fortsetzen im Unterbaum p0
Tiefeneigenschaft: alle externe Knoten besitzen dieselbe
ki ≤ s < ki+1: fortsetzen im Unterbaum pi
Tiefe
s > km: fortsetzen im Unterbaum pm
Falls man einen externen Knoten erreicht: Suche erfolglos Abhängig von der Anzahl der Kinder heißt ein interner
Knoten 2-Knoten, 3-Knoten oder 4-Knoten
Beispiel: Suche 50
11 37
11 37
3 9 13 39 45 53
3 9 13 39 45 53
50

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


237 238

Höhe eines 2-3-4 Baumes Einfügen in einen 2-3-4 Baum

Satz: Ein 2-3-4 Baum, der n interne Knoten speichert, Ein neuer Schlüssel s wird im Elternknoten v des externen
hat eine Höhe von O(log n) Knotens eingefügt, den man bei der Suche nach s erreicht
hat
Beweis Die Tiefeneigenschaft des Baumes wird erhalten, aber es wird
Die Höhe des 2-3-4 Baumes mit n internen Knoten sei h möglicherweise die Größeneigenschaft verletzt
Da es mindestens 2i interne Knoten auf den Tiefen i = 0, … , Ein (Knoten-) Überlauf ist möglich (es entsteht ein 5-Knoten)
h-1 gibt und keine internen Knoten auf Tiefe h, gilt Beispiel: Einfügen von 30 erzeugt Überlauf
n ≥ 1 + 2 + 4 + … + 2h-1 = 2h – 1 11 24
v
Daher gilt h ≤ log2 (n + 1) Knoten Tiefe 3 9 13 27 32 35
1 0 5-Knoten
11 24
2 1 v
2h-1 h-1 3 9 13 27 30 32 35

0 h
VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

239 240

Überlauf und Split Löschen

Ein Überlauf (Overflow) bei einem 5-Knoten v wird durch eine Der Löschvorgang wird auf den Fall reduziert, wo der
Split Operation aufgelöst zu löschende Schlüsselwert in einem internen
Die Kinder von v seien v1, … , v5 und die Schlüssel von v seien k1, … , k4
Knoten mit externen Knotenkindern liegt
Knoten v wird durch die Knoten v´ und v´´ ersetzt, wobei
v´ ein 3-Knoten mit den Schlüsseln k 1 und k2 und Kindern v1, v2 und v3, Andernfalls wird der Schlüsselwert mit seinem Inorder
v´´ ein 2-Knoten mit Schlüssel k 4 und Kindern v4 und v5 ist Nachfolger (oder Inorder Vorgänger) ersetzt
Schlüssel k3 wird in den Elternknoten u von v eingefügt (dadurch kann
eine neue Wurzel entstehen)
Analog Fall 3 binäre Suchbäume
Ein Überlauf kann an die Vorgänger von u propagiert werden Beispiel Löschen Schlüssel 24
u u 11 24 11 27
11 24 11 24 32
v v´ v´´ 3 9 13 27 32 35 3 9 13 32 35
3 9 13 27 30 32 35 3 9 13 27 30 35

v1 v2 v3 v4 v5 v1 v2 v3 v4 v5
VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta
241 242

Unterlauf Verschmelzen im 2-3-4 Baum

Durch das Löschen eines Schlüssels in einem Knoten v kann Fall 1: Verschmelzen von Knoten
es zu einem Unterlauf (underflow) kommen Bedingung: Alle adjazenten Knoten (benachbarte Knoten
Knoten v degeneriert zu einem 1-Knoten mit einem Kind und keinem auf derselben Tiefe) zum unterlaufenden Knoten v sind 2-
Schlüssel
11 27 Knoten
v
Man verschmilzt v mit einem/dem adjazenten Nachbarn w
3 9 13
und verschiebt den nicht mehr benötigten Schlüssel vom
Elternknoten u zu dem verschmolzenen Knoten v´
Bei einem Unterlauf kann man 2 Fälle unterscheiden Das Verschmelzen kann den Unterlauf zum Elternknoten
Fall 1: Verschmelzen propagieren
Benachbarte Knoten werden zu einem erlaubten Knoten verschmolzen u u
Fall 2: Verschieben 11 27 11
Schlüsselwerte und entsprechende Kinder werden zwischen Knoten w v v´
3 9 13 3 9 13 27
verschoben

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

243 244

Verschieben im 2-3-4 Baum Analyse 2-3-4 Baum

Fall 2: Verschieben von Schlüsseln Datenverwaltung


Einfügen und Löschen unterstützt
Bedingung: Ein adjazenter Knoten (benachbarter Knoten auf
Datenmenge
derselben Tiefe) w zum unterlaufenden Knoten v ist ein
unbeschränkt
3-Knoten oder 4-Knoten
Modelle
Man verschiebt ein Kind von w nach v Hauptspeicherorientiert
Man verschiebt einen Schlüssel von u nach v Unterstützung komplexer Operationen
Man verschiebt einen Schlüssel von w nach u Bereichsabfragen, Sortierreihenfolge
Laufzeit
Nach dem Verschieben ist der Unterlauf behoben Speicherplatz O(n)
Verschmelzen, Verschieben O(1)
u u Zugriff O(log n)
11 27 11 20
Einfügen O(log n)
w v w v
3 9 13 20 3 9 13 27 Löschen O(log n)
Sortierreihenfolge O(n)

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


245 246

Vergleich der Baumvarianten 4.6 Externspeicherverwaltung

Ziel
Baumhöhe + Erstellen eines Schlüsselbaumes für eine große Anzahl von
Balanzierungs-
Baumvariante Aufwand der Methode
Operationen
form Elementen

Allgemeiner Im Zufall, Gesetz


Problem
Abhängig von
Binärer Durchschnitt
der Eingabe
der großen Hauptspeicher zu klein
Suchbaum log(n) Zahlen
Lösung
Speicherung der Knoten auf dem Externspeicher (Platte)
AVL-Baum log(n) höhenbalanziert Rotationen
Hauptspeicher
Split, 01001010010101
2-3-4 Baum log(n) perfektbalanziert Verschmelzen, 11101101101010
Verschieben 01010101011101
... Platte

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

247 248

Plattenzugriffe Seitenverwaltung

Ansatz Lösung
Referenzieren eines Knotens entspricht Zugriff auf die Platte Zerlegung des binären Baumes in Teilbäume, diese in
Bei Aufbau eines binären Schlüsselbaumes für eine eine sog. Seiten (pages) speichern
Datenmenge von z.B. einer Million Elementen ist die
durchschnittliche Baumhöhe log2106 ≈ 20, d.h. 20 Suchschritte →
20 Plattenzugriffe
Dilemma
Unterschied Aufwand Platten- zu Hauptzugriff Faktor
100000, milli- zu nano-Sekunden (z.B. 5ms – 60 ns)
Jeder Suchschritt benötigt einen Plattenzugriff ⇒ hoher
⇒ Mehrwegbaum (multiway-tree)
Aufwand an Rechenzeit
Bei 100 Knoten pro Seite für 1 Million Elemente nur mehr log 100106 = 3
Seitenzugriffe
Im schlimmsten Fall (lineare Entartung) aber immer noch 10 4 Zugriffe (10 6 / 100)

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


249 250

Seitenverwaltung (2) Indexstruktur

Knoten entsprechen Seiten (Blöcke) Indexstruktur besteht aus Schlüsselteil (Index) und
besitzen eine Größe, Seitengröße (Anzahl der enthaltenen Einträge bzw. Datenteil
Speichergröße in Bytes)
repräsentieren die Transfereinheit zwischen Haupt- und Externspeicher Graphische Struktur
Zur Effizienzsteigerung des Transfers wird die Größe der Seiten an die
Blockgröße der Speichertransfereiheiten des Betriebssystems
angepaßt (Unit of Paging/Swapping)
Index

Hauptspeicher schreiben Externspeicher Daten


Seiten Index
ermöglicht den effizienten Zugriff auf die Daten
... ...
Disk
Daten
lesen
enthalten die gespeicherte Information (vergleiche externe Knoten)

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

251 252

Knotenarten 4.7 B+-Baum

2 Knotenarten Höhenbalanzierter (perfektbalanzierter) Mehrwegbaum


Indexknoten Eigenschaften
Erlauben effizienten Zugriff auf die externe Knoten Externspeicher-Datenstruktur
Definieren die Intervallbereiche der Elemente, die im zugeordneten Eine der häufigsten Datenstrukturen in Datenbanksystemen
Teilbaum gespeichert sind. Dynamische Datenstruktur (Einfügen und Löschen)
realisiert durch interne Knoten Algorithmen für Einfügen und Löschen erhalten die
Externe Knoten Balanzierungseigenschaft
Enthalten die zu verwaltende Information Garantiert einen begrenzten (worst-case) Aufwand für Zugriff,
Einfügen und Löschen
realisiert durch Blattknoten
Der Aufwand für die Operationen Zugriff, Einfügen und Löschen ist
Beispiel bedingt durch die Baumstruktur maximal von der Ordnung log n
11 25 37 Indexknoten (O(log n)).
Besteht aus Index und Daten
3 9 11 25 26 37 Externe Knoten Der Weg zu allen Daten ist gleich lang

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


253 254

Definition B+-Baum Beispiel B+-Baum

B+-Baum der Ordnung k B+-Baum der Ordnung 2


Anmerkung: Im
alle Blattknoten haben die gleiche Tiefe (gleiche Weglänge weiteren werden
Indexknoten grün
zur Wurzel) und externe Knoten
11 23 35 weiß dargestellt
die Wurzel ist entweder ein Blatt oder hat mindestens 2
Kinder
jeder (interne) Knoten besitzt mindestens k und maximal 2k 1 3 8 11 17 19 21 23 25 30 35 37 46
Schlüsselwerte, daher mindestens k+1 und maximal 2k+1
Kinder Jeder Indexknoten hat mindestens 2 und maximal 4 Grenzwerte
Für jeden in einem Knoten referenzierten Unterbaum gilt, dass die in und folglich mindestens 3 und maximal 5 Kinder
ihm gespeicherten Elemente kleiner als die Elemente im rechten Ausnahme ist die Wurzel
und größer als die Elemente im linken Unterbaum sind. Die
Intervallgrenzen werden durch die Schlüsselwerte bestimmt.
Die Größe der externen Knoten ist eigentlich durch die Ordnung
nicht definiert, wird aber üblicherweise in der Literatur
gleichgesetzt
VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

255 256

Suche B+-Baum Einfügen (1)

11 23 35 Fall 1: Einfügen Element 26


Platz im externen Knoten vorhanden, einfaches Einfügen
1 3 8 11 17 19 21 23 25 30 35 37 46

Suchen Element 17 Element 27


11 23 35
11 23 35 11 23 35
11 ≤ x < 23 23 ≤ x < 35
1 3 8 11 17 19 21 23 25 30 35 37 46
11 17 19 21 23 25 30

enthalten nicht enthalten ?


Aufwand der Suche
11 23 35
Höhe eine B+-Baumes der Ordnung k mit Datenblockgröße
b (mind. b, max 2b Elemente) ist maximal log k+1(n/b).
Warum?
Bereichsabfrage möglich 1 3 8 11 17 19 21 23 25 26 30 35 37 46
Suche alle Element im Breich [Untergrenze, Obergrenze]
VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta
257 258

B+-Baum Einfügen (2) B+-Baum Einfügen (3)

Fall 2: Einfügen Element 28 Fall 3: Einfügen Element 18


Kein Platz mehr im externen Knoten (Überlauf, Overflow), Kein Platz mehr im Knoten und kein Platz mehr im
externer Knoten muss geteilt werden ⇒ Split darüberliegenden Indexknoten, Indexknoten muss
gesplittet werden
11 23 35 neue
28
Grenze
23 25 26
23 25 26 30 Splitten 11 23 28 35
28 30

11 17 19 21 28 30
11 23 28 35
1 3 8 23 25 26 35 37 46

11 17 19 21 28 30
1 3 8 23 25 26 35 37 46

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

259 260

B+-Baum Einfügen (4) B+-Baum Einfügen (5)

Beim Splitten eines Indexknoten wird das mittlere Der resultierende Baum hat folgendes Aussehen
Indexelement im darüberliegenden Indexknoten 23
eingetragen. Falls der nicht existiert (Wurzelsplit), wird eine
neue Wurzel erzeugt 11 19 28 35

1 3 8 23 25 26
11 17 18 28 30
19 21 35 37 46
11 23 28 35
23 Unterscheidung des Splits für externe und interne Knoten
19 Externe Knoten: 2k+1 Elemente werden auf 2 benachbarte externe Knoten aufgeteilt
Interne Knoten: 2k+1 Indexelemente (Schlüsselwerte) werden auf 2 benachbarte
11 17 18 11 19 Indexknoten zu je k Elemente aufgeteilt, das mittlere Indexelement wird in die
19 21 darüberliegende Indexebene eingetragen.
28 35
Falls keine darüberliegende Ebene existiert, wird eine neue Wurzel erzeugt, der
Baum wächst um eine Ebene (“Baum wächst von den Blättern zur Wurzel”),
der Zugriffsweg zu den Daten erhöht sich um 1.
VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta
261 262

B+-Baum Löschen (1) B+-Baum Löschen (2)

Fall 1: Entfernen von Element 46 Fall 2: Entfernen von Element 37


Externer Knoten nach Löschen nicht unterbesetzt Externer Knoten nach dem Löschen unterbesetzt
23 23
11 19 28 35 11 19 28 35
1 3 8 23 25 26
1 3 8 23 25 26
11 17 18 28 30
11 17 18 28 30
19 21 35 37 46
19 21 35 37
Element wird einfach aus verschmelzen
dem externen Knoten Element wird entfernt, ist Knoten unterbesetzt ( Underflow), Elementanzahl < k
23 entfernt Umgekehrter Vorgang zum Split ⇒ benachbarte Knoten werden verschmolzen
11 19 28 35 (merge)
28
1 3 8 23 25 26 Interner Knoten unterbesetzt, muss
11 17 18 28 30 23 25 26 ebenfalls mit Nachbarn
19 21 35 37 verschmolzen werden.
28 30 35

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

263 264

B+-Baum Löschen (3) B+-Baum Löschen (4)

Das Verschmelzen kann zur Verringerung der Anmerkung


Das Verschmelzen zweier Knoten kann zu einem Überlauf (analog
Baumhöhe führen, 2 Knoten werden zur neuen Einfügen) des neuen Knoten führen, was einen nachfolgenden Split
Wurzel verschmolzen, alte Wurzel wird entfernt. notwendig macht.
Beispiel: (Baumausschnitt)
Löschen von 19 Verschmelzen - Überlauf Splitten
11 19 23 28
... 19 ... ... 21 ... ... 18 ...
11 17 18 23 25 26
1 3 8 19 21 28 30 35 11 16 17 18 11 16 17 18 21 11 16 17

19 21 18 21
Diese (Verschmelzen-Splitten) Sequenz erzeugt eine besseren Aufteilung der
Datensätze zwischen benachbarten Knoten. Dies wird auch hier (siehe 2-3-4
Baum, eigentlich fälschlicherweise) als Datensatzverschiebung (shift)
bezeichnet.
VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta
265 266

Datenblockverkettung Analyse B+ - Baum

In der Praxis werden die Datenblöcke linear verkettet, um Datenverwaltung


einen effizienten, sequentiellen Zugriff in der Einfügen und Löschen unterstützt
Sortierreihenfolge der gespeicherten Elemente zu
ermöglichen
Datenmenge
unbeschränkt
abhängig von der Größe des vorhandenen Speicherplatzes
11 19 23 28
Modelle
11 17 18 23 25 26 Externspeicherorientiert
1 3 8 19 21 28 30 35
Unterstützung komplexer Operationen
Bereichsabfragen, Sortierreihenfolge

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

267 268

Analyse B+ - Baum (2) 4.8 Trie

Ein Trie ist ein digitaler Suchbaum


Speicherplatz O(n) Dient zur Speicherung von Strings (Verwaltung von
Split, Verschmelzen O(1) Wörterbüchern, Telefonbüchern, Spellcheckern, etc.)
Bezeichnung wird abgeleitet von “retrieval”, wird aber wie “try”
Zugriff O(log n) ausgesprochen
Einfügen O(log n) Bei k Buchstaben ein “k+1-ary Tree”, wobei jeder Knoten
durch eine Tabelle mit k+1 Kanten auf Kinder repräsentiert
Löschen O(log n)
wird.
Sortierreihenfolge O(n)
A B C D E ... Y Z $

Bitte beachten: Ordnung des Baumes ist konstanter Faktor!


Spezialformen
Patricia Tree, de la Briandais Tree
VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta
269 270

Beispiel Trie Patricia Trie

Trie Practical Algorithm to Retrieve Information Coded in


TEN Alphanumeric
THE Ziel ist die Komprimierung des Tries
THEN
THIN P S T W PSTW
THIS
TIN I I E H I I PIN SING EHI WIN
SING N N N E I N N
PIN $ G $ $ N N S $ $ TEN E I TIN
WIN
$ $ $ $ N $ N S
Einfügen

THEN THE THIN THIS


Suchen
VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

271 272

de la Briandais Trie Analyse Trie

Listen-Repräsentation eines Tries Datenverwaltung


Einfügen und Löschen unterstützt
statt der Tabellen im Knoten lineare Liste Struktur des Tries unabhängig von der Einfügereihenfolge
Knoten besteht aus 2 Kinderkomponenten
Datenmenge
Nächster Wert - Nächster Level unbeschränkt
P S T W
Modelle
Hauptspeicherorientiert
I I E H I I Unterstützung komplexer Operationen
Bereichsabfragen, Sortierreihenfolge
N N N E I N N Laufzeit
Bei der exakten
Speicherplatz O(n)
Berechnung ist die Basis
$ G $ N $ N S $ $ Zugriff O(log n) des Logarithmus von der
Einfügen O(log n) Kardinalität der
Zeichenmenge, z.B. 26
$ $ $ $ Löschen O(log n) (Grossbuchstaben), 2
Sortierreihenfolge O(n) (Bitstrings)

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


273 274

4.9 Priority Queues Operationen

Datenstruktur zum wiederholten Construct


Finden und Entfernen des Elementes Erzeugen einer leeren Priority Queue
mit dem kleinsten (bzw. größten) IsEmpty
Schlüsselwert aus einer Menge Abfrage auf leere Priority Queue
Anwendungen
Insert
Simulationssysteme (Schlüsselwerte repräsentieren
Exekutionszeiten von Ereignissen) Einfügen eines Elementes
Prozessverwaltung (Prioritäten der Prozesse) FindMinimum
Numerische Berechnungen (Schlüsselwerte entsprechen den
Rechenfehlern, wobei zuerst die großen beseitigt werden)
Zurückgeben des kleinsten Elementes
Grundlage für eine Reihe komplexer Algorithmen (Graphentheorie, DeleteMinimum
Filekompression, etc.)
Löschen des kleinsten Elementes
Anmerkung: Im folgenden betrachten wir o.B.d.A. nur Priority
Queues die den Zugriff auf die kleinsten Elemente
unterstützen
VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

275 276

Implementationsansätze Priority Queue als Baumstruktur

Ungeordnete Liste Balanzierte Schlüsselbäume


Elemente werden beliebig in die Liste eingetragen (Aufwand Einfügen im balanzierten Schlüsselbaum vom Aufwand
O(1)). O(log n)
Beim Zugriff bzw. Löschen des ‘kleinsten’ Elementes muss Zugriff realisieren durch Verfolgen des äußersten linken
die Liste abgesucht werden Aufwand → O(n). Weges im Baum (zum kleinsten Element) → Aufwand
Geordnete Liste O(log n)
Elemente werden in der Reihenfolge ihrer Größe
eingetragen (Aufwand O(n)). Günstigste Realisierung über
Zugriff bzw. Löschen konstanter Aufwand → O(1) ungeordnete, komplette Schlüsselbäume
Problem mit der Eigenschaft, dass für alle Knoten die Schlüsselwerte
Aufwand O(n) schwer zu vermeiden. ihrer Nachfolger größer (oder kleiner) sind

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


277 278

Ungeordneter, kompletter Schlüsselbaum Heap Datenstruktur

Wertemenge 3 Realisierung eines Heaps effizient durch ein Feld


3 6 5 10 9 11 Die n Schlüsselwerte des Heaps können als Folge von
6 5 Elementen x0, x1, x2, … xn-1 interpretiert werden, wobei
die Position der einzelnen Knotenwerte im Feld durch
folgende Regel bestimmt wird:
10 9 11 Wurzel in Position 0, die Kinder des Knotens i werden an Position
2i+1 und 2i+2 gespeichert.
Heap
Beispiel 3 0
Binärer kompletter Baum
Wert jedes Knotens ist kleiner (größer) oder gleich den Werten seiner
Nachfolgerknoten 6 5
1 2 3 6 5 10 9 11
Wurzel enthält kleinstes (größtes) Element
0 1 2 3 4 5
Anordnung der Unterbäume bez. Ihrer Wurzel undefiniert (ungeordneter
Baum) 10 9 11
3 4 5

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

279 280

Zugriff Klasse Priority Queue

Zugriff auf das kleinste Element mit konstanten class PQ {


Aufwand: O(1) int *a, N;
public:
→ Wurzel = erstes Element im Feld. PQ(int max) { a = new int[max]; N = -1; }
~PQ() { delete[] a; }
3
int FindMinimum(){ return a[0]; }
6 5 int IsEmpty() { return (N == -1); }
void Insert(int);
int DeleteMinimum();
10 9 11

};
3 6 5 10 9 11
0 1 2 3 4 5

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


281 282

Einfügen in einen Heap Methode Insert

Neues Element an der letzten Stelle im Feld eintragen void PQ::Insert(int v) {


int child, parent;
Überprüfen, ob die Heap Eigenschaft erfüllt ist
a[++N] = v;
Wenn nicht, mit Elternknoten vertauschen und solange child = N;
wiederholen bis erfüllt parent = (child - 1)/2;
Eintragen von 4 while(child != parent) {
(an der letzten Stelle im Feld) Aufwand: O(log n) if(a[parent] > a[child]) {
Heap Eigenschaft nicht swap(a[parent], a[child]);
erfüllt, daher mit Elternknoten jetzt child = parent;
3 vertauschen 3 ok! parent = (parent - 1)/2;
} else break; // to stop the loop
6 5 6 4
}
}
10 9 11 4 10 9 11 5

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

283 284

Löschen aus einen Heap Methode DeleteMinimum

Wurzel mit äußerst rechten Blattknoten tauschen, diesen int PQ::DeleteMinimum() {


Blattknoten löschen, Wurzel in den Baum sinken lassen (mit int parent = 0, child = 1;
int v = a[0];
kleinerem Kindknoten vertauschen), bis Heap Eigenschaft
a[0] = a[N];
gilt. Aufwand: O(log n) N--;
3 5 while(child <= N) {
vertauschen
if(a[child] > a[child+1]) child++;
6 4 6 4 if(a[child] < a[parent]) {
swap(a[parent], a[child]);
10 9 11 5 10 9 11 3 parent = child;
löschen child = 2*child + 1;
5 vertauschen, 4
sinken lassen ok! } else break; // to stop the loop
6 4 6 5 }
return v;
10 9 11 10 9 11 }

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


285 286

Analyse Heap Heaps und Heaps

Datenverwaltung Bitte zu unterscheiden! Der Begriff Heap wird in der


Einfügen und Löschen unterstützt Informatik zur Bezeichnung verschiedener Konzepte
Datenmenge verwendet
unbeschränkt
Heap als Datenstruktur zur Speicherung von Priority Queues
Modelle
Heap als Speicherbereich zur Verwaltung (vom Benutzer
Hauptspeicherorientiert
selbst verwalteter) dynamisch allozierter Speicherbereiche
Nur simple Operationen
Heap als Speicherform in Datenbanken
Laufzeit
Speicherplatz O(n) Der Heap stellt eine
Zugriff (Minimum/Maximum) O(1) effiziente
Basisdatenstruktur für
Einfügen O(log n) viele weitere darauf
Löschen O(log n) aufbauende
Datenstrukturen dar

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

287 288

Was nehmen wir mit?

Baumstrukturen
Notation
spez. Eigenschaften, von O(n) auf O(log n)
Kapitel 5:
Suchbäume
Binäre Suchbäume Vektoren
AVL-Bäume
2-3-4 Bäume
B+-Baum
Balanzierung
Trie
Priority Queues
Heap
VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta
289 290

5 Vektoren 5.1 Dictionary

Ein Vektor (Feld, array) verwaltet eine fix vorgegebene Ein Dictionary ist eine Datenstruktur, die nur die
Anzahl von Elementen eines einheitlichen Typs. einfachen Operationen des Einfügens, Löschens
Zugriff auf ein Element über einen ganzzahligen Index (die und der Suche zur Verfügung stellt.
Position im Vektor) Ein Elemente im Dictionay besteht meist aus einem
Aufwand des Zugriffes für alle Elemente konstant Schlüssel- (key) und einem Informationsteil (info).
Beispiele sind
Wörterbücher, Namenslisten, Bestandslisten, etc.
x0 x1 x2 … xn-2 Xn-1 Vektoren sind zur Realisierung von Dictionaries gut geeignet
Struktur
Methoden
key0 key1 key2 Keyn-1
Hashing: Datenorganisationsform …
Sortieren: Datenreorganisationsmethoden info0 info1 info2 Infon-1

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

291 292

Beispiele Operationen

Wörterbuch Construct
(Ausschnitt) Erzeugen eines leeren Dictionary
Schlüssel Information IsEmpty
computable berechenbar
computation Berechnung Abfrage auf leeres Dictionary
compute (be)rechnen
computer Rechenautomat
Insert
Einfügen eines Elementes
Bestandsliste Delete
Schlüssel Information
1 CPU
Löschen eines Elementes
4
17
Bildschirm
Tastatur
LookUp
25 Maus Abfrage eines Elementes über seinen Schlüssel und liefern
der Information
VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta
293 294

Klasse Dictionary 5.2 Hashing

class Dictionary {
Hashing ist eine Methode Elemente in einer Tabelle
private:
node { KeyType Key; InfoType Info; }; direkt zu adressieren, in dem ihre Schlüsselwerte
node *Dict; durch arithmetische Transformationen direkt in
int NumberElements; Tabellenadressen (Indizes) übersetzt werden
public:
Dictionary(int max) { Mit anderen Worten, der Index (die Position in der Tabelle)
Dict = new node[max]; eines Elements wird aus dem Schlüsselwert des Elements
NumberElements = 0; selbst berechnet.
} Schlüssel → Adresse (Index) Tabelle
~Dictionary() { delete Dict; } 0
1
void Insert(KeyType k, InfoType I); 2
3
4
void Delete(KeyType k); Transformation 5
Schlüssel 6
InfoType LookUp(KeyType k); ...
};
m-1

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

295 296

Hashing, allgemein Hashfunktion

Ansatz Gewünschte Eigenschaften


Menge K von n Schlüsseln {k0, k1, …, kn-1} Einfach und schnell zu berechnen.
Hashtabelle T der Größe m Elemente werden gleichmäßig in der Tabelle verteilt.
Randbedingung: n >> m Alle Positionen in der Tabelle werden mit gleicher
(Anzahl der möglichen Schlüsselwerte viel größer als Plätze in der Tabelle) Wahrscheinlichkeit berechnet.
Transformation Beispiele
Hash-Funktion h Modulo Bildung, Schlüssel mod m
Man sollte darauf achten, daß m eine Primzahl ist, sonst kann es
h: K → {0, 1, … m-1} bei Schlüsseltransformationen (Strings) zu Clusterbildungen
Für jedes j soll der Schlüssel k j an der Stelle h(kj) in der (Anhäufungen) durch gemeinsame Teiler kommen.
Tabelle gespeichert werden. Der Wert h(K) wird als Hash- Bitstring-Interpretation
Wert von K bezeichnet. Teile aus der binären Repräsentation des Schlüsselwertes
Wahl der Hashfunktion (eigentlich) beliebig! werden als Hashwert herangezogen.
Transformationstabellen
VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta
297 298

Beispiel Hashing Kollision

Bestandsliste Datensätze Eine Kollision tritt auf, wenn zwei oder mehrere
Größe der Liste 7 Schlüssel Information Schlüsselwerte auf dieselbe Tabellenposition
Hashfunktion h(k) = k mod 7
1 CPU abgebildet (gehasht) werden.
4 Bildschirm
17 Tastatur
25 Maus

0
1 mod 7 = 1 1 1 CPU Dies bedeutet, daß für 2 Schlüssel ki, kj, mit ki ≠ kj,
2 gilt h(ki) = h(kj).
17 mod 7 = 3 3 17 Tastatur
4 Bildschirm Diese Situation ist aber zu erwarten, da es viel mehr mögliche
4 mod 7 = 4 4
Schlüssel als Tabellenplätze gibt (n >> m als Randbedingung).
5
? 6 Die Hashfunktion h ist i.a. nicht injektiv, d.h. aus h(x)=h(y) folgt nicht
notwendigerweise x=y.
25 mod 7 = 4 → Position in der Tabelle schon besetzt
Kollision
VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

299 300

Kollisionsbehandlung 5.2.1 Separate Chaining

Eine Kollision löst eine notwendige Kollisions- Beim Separate (Simple) Chaining wird die Kollisions-
behandlung aus. behandlung mit linearen Listen bewerkstelligt.
Kollidierende Schlüsselwerte werden in einer linearen
Überlaufkette (Liste) ausgehend vom ursprünglich
gehashten Tabellenplatz gespeichert.
D.h., für den kollidierenden Schlüsselwert muß ein Beispiel:
Wichtig: Element am
Kopf der Liste
Ausweichsplatz gefunden werden. 0
h(k) = k mod 7 einfügen, da sonst
Maßnahmen zur Kollisionsbehandlung sind meist recht aufwendig der Aufwand gegen
1 1 CPU
und beeinträchtigen die Effizienz von Hashverfahren. O(n) wachsen kann!
2

der Kollisionspfad ist definiert durch die Ausweichplätze aller 3 17 Tastatur


4
Elemente, die auf den gleichen Platz "ge-hasht" wurden 39 Drucker 25 Maus
5
Wir betrachten nun 2 simple Kollisionsbehandlungen 6 4 Bildschirm

Separate Chaining und Double Hashing Der Eintrag des Elementes (39, Drucker) führt zu einer Verlängerung der Überlaufkette.

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


301 302

5.2.2 Double Hashing Linear Probing

Beim Double Hashing wird bei Kollision eine zweite, Spezialfall des Double Hashing
von h unabhängige, Hashfunktion zur Bestimmung Kollisionsbehandlung: Man verwendet den nächsten
einer alternativen Position verwendet. freien Platz
Überlauf auf Position a0 = h(k) Bei Erreichen des Tabellenendes sucht man am
Bestimmung einer alternativen Position mit Kollisionsfunktion Tabellenanfang weiter
g : K → {1, … m-1}, z.B. ai+1 = (ai + g(k)) mod m Hashfuktionen: a0 = h(k), ai+1 = (ai + g(k)) mod m
Beispiel K … Kollision g(k) = 1
0 0
h(k) = k mod 7
g(k) = letzte Ziffer von k mal 3 1 1 CPU Beispiel 1 1 CPU

K 2 39 Drucker 2
a0 = 25 mod 7 = 4 25 mod 7 = 4 K
a1 = (4 + (5*3)) mod 7 = 5 3 17 Tastatur (4+1) mod 7 = 5 3 17 Tastatur
4 4 Bildschirm 4 4 Bildschirm
a0 = 39 mod 7 = 4 K 39 mod 7 = 4 K
5 25 Maus 5 25 Maus
a1 = (4 + (9*3)) mod 7 = 3 K (4+1) mod 7 = 5 K
6 6 39 Drucker
a2 = (3 + (9*3)) mod 7 = 2 (5+1) mod 7 = 6

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

303 304

Suchen und Löschen in Hashtabellen Eigenschaften

Suchen Generell für Hashverfahren


Solange eine Zieladresse durch ein Element belegt ist, und + Aufwand beim Zugriff auf ein Element im besten Fall konstant, O(1),
der gesuchte Schlüsselwert noch nicht gefunden wurde, einfache Evaluation der Hashfunktion.
muß über den Kollisionspfad weitergesucht werden. - Kollisionsbehandlung aufwendig, volle Hashtabelle führt zu vielen
Kollisionen, daher (Faustregel) nie über 70% füllen.
Separate Chaining: Verfolgen der linearen Liste
- Kein Zugriff in Sortierreihenfolge.
Double Hashing: Aufsuchen aller möglichen Plätze der Kollisionsfkt.
Separate Chaining
Löschen
+ Dynamische Datenstruktur, beliebig viele Elemente.
Separate Chaining: Entfernen des Listenelements - Speicherplatzaufwendig (zusätzliche Zeigervariable).
Double Hashing: Positionen, an denen ein Element gelöscht
Double Hashing
wurde, müssen gegebenenfalls mit einem speziellen Wert
+ Optimale Speicherplatzausnützung.
(“wiederfrei”) markiert werden, damit der entsprechende
- Statische Datenstruktur, Tabellengröße vorgegeben.
Kollisionspfad für die restlichen Elemente nicht
- Kollisionbehandlung komplex, „wiederfrei“ Markierung beim Löschen.
unterbrochen wird.
VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta
305 306

Analyse Hashing Analyse Hashing (2)

Datenverwaltung
Einfügen und Löschen unterstützt
Speicherplatz O(1)
gültig nur für
Datenmenge reines
Konstruktor O(1)
beschränkt Hashverfahren
abhängig von der Größe der vorhandenen Hashtabelle Zugriff O(1) ohne Kollisions-
behandlung
Modelle Einfügen O(1)
Hauptspeicherorientiert Löschen O(1)
Unterstützung simpler Operationen
keine Bereichsabfragen, keine Sortierreihenfolge

Bitte beachten: Aufwand von Hashing stark abhängig vom


Kollisionsverfahren, geht aber oft gegen O(n)

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

307 308

5.3 Dynamische Hash-Verfahren Hash-Funktionen Schema

Dynamischen Hash-Verfahren versuchen im Falle von Simpler Ansatz


Kollisionen die ursprüngliche Hashtabelle zu |addri+1| = 2 * |addri|
erweitern h(x) ist eine Hash-Funktion
Anlegen von Überlaufbereichen (z.B. lineare Listen) hi(x) seien die i „least significant bits“ von h(x)
Vergrößerung des Primärbereichs (ursprüngliche Tabelle) Somit gilt Wert h(x) binär h 2(x) h3(x)
Erfordert Modifikation der Hash-Funktion 7 7 00111 11=3 111=7
hi+1(x) = hi(x) oder
Ansatz: Familien von Hash-Funktionen 8 8 01000 00=0 000=0
h1: K → addr1
hi+1(x) = hi(x) + 2i 9 9 01001 01=1 001=1
... Beispiel: 10 10 01010 10=2 010=2

hn: K → addrn addr2 = 0 .. 3, 13 13 01101 01=1 101=5

Wobei |addr1| < |addr2| < ... < |addrn| addr3 = 0 .. 7, 14 14 01110 10=2 110=6

Ziel: Wechsel von addri auf addri+1 erfordert minimale Reorganisation h(x) = x 23 23 10111 11=3 111=7
der Hash-Tabelle (d.h. Umspeichern von Daten minimieren) 4 Adresswechsel 26 26 11010 10=2 010=2

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


309 310

Dynamische Hashverfahren 5.3.1 Linear Hashing

„Two-Disk-Access“ Prinzip W. Litwin 1980


Finden eines Schlüssel mit maximal 2 Platten Zugriffen Organisation der Elemente in Blöcken (Buckets)
Hashverfahren für externe Speichermedien Analog zu B-Bäumen
Linear Hashing Blockgröße b
Verzeichnisloses Hashverfahren Idee
Primärbereiche, Überlaufbereiche
Bei Überlauf eines Blocks (Splitting) wird der Primär- und
Extendible Hashing Überlaufbereich um jeweils einen Block erweitert
Verzeichnis mit binärer Expansion
Primärbereich durch Hinzufügen eines Blocks am Ende der
Primärbereiche
Hash-Tabelle
Bounded Index Size Extendible Hashing
Überlaufbereich durch lineare Liste
Verzeichnis mit beschränkter Größe
Binäre Expansion der Blöcke

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

311 312

Splitting und Suche Einfügen

Splitting wird „Runden“-weise durchgeführt Einfügen


Eine Runde endet, wenn alle ursprünglichen N Blocks (für Suche Block (hd oder hd+1)
Runde R) gesplittet worden sind Falls Block voll
Blocks 0 bis NextToSplit-1 sind schon gesplittet Füge Element in einen Überlaufblock
Nächster Block zum Splitten ist definiert durch Index NextToSplit Neues Element in der linearen Liste
Aktuelle Rundennummer ist definiert durch d Splitte Block NextToSplit und erhöhe NextToSplit um 1
Suche d=2, NextToSplit=1, b=3 Beispiel: Einfügen von 6 (=000110)
d=2, NextToSplit=2, b=3
Suche nach Wert x 000 8 2=000010 d=2, NextToSplit=1, b=3
8=001000 2=000010 000 8
a = hd(x); 01 17 25 000 8
17=010001 8=001000 001 17 25
if(a < NextToSplit) a = hd+1(x); 10 34 50 2 25=011001 01 17 25 17=010001 10 34 50 2 6
11 28=011100 10 34 50 2 25=011001
34=100010 28=011100
11
100 28 11
50=110010 34=100010 100 28
100 28
50=110010 101

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


313 314

Beispiel: linear Hashing Bemerkungen

Aktuelle hi(x) = h3(x) Einfügen: 16, 13, 21, 37 Die Rundennummer d wird erhöht, wenn das Splitting einmal
d=3, NextToSplit=0, b=3 d=3, NextToSplit=0, b=3 d=3, NextToSplit=1, b=3 durch ist, d.h.
000 8 000 8 16 0000 16 if(NextToSplit == 2d) { d++; NextToSplit=0; }
001 17 25 001 17 25 001 17 25 Expansionspolitik
010 34 50 2 010 34 50 2 010 34 50 2
Bei jedem Überlauf Splitten nicht wirklich sinnvoll
011 011 Split 011
28 28 28 Salzberg schlägt vor Expansion durchzuführen, wenn seit der letzten
100 100 100
5 5 13 21 5 13 21 Expansion genau L * b Datensätze eingefügt wurden
101 101 101
110 110 110 L ist definiert durch den Belegungsfaktor, d.h
111 55 111 55 111 55 L = Rohdatenvolumen / Volumen der Datenstruktur
1000 8 Lange Überlaufketten werden in jedem Fall vermieden
2=000010 28=011100 16=010000
5=000101 34=100010 13=001101 37 In der Praxis keine linearen Adressräume sondern Aufteilen des
8=001000 50=110010 21=010101 Primärbereiches auf mehrere Hash Dateien pro Platte
17=010001 55=110111 37=100101 37
25=011001 Überlaufblock Zuordnungssystem über Verwaltungsblöcke

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

315 316

5.3.2 Extendible Hashing Struktur und Suche

Hash-Verfahren mit Index Eigenschaften


d=2, b=4
R. Fagin, J. Nievergelt, N. Pippenger and H.R. Strong, 1979 Jeder Indexeintrag referenziert genau Index T
einen Datenblock 14 8 10 26
Idee Jeder Datenblock wird von genau 2k mit k 00
1

Wenn Primärbereich zu klein wird, Vergrößerung durch aus N0 Indexeinträgen referenziert 01


9 13
Verdopplung Die Anzahl der Indexeinträge, die den 10 2
Block referenzieren ist im Block lokal 11
Primärbereich wird über Index T verwaltet bekannt 7 31 23 2
Bei Überlauf eines Blocks Split dieses Blocks und Wird durch eine lokale Tiefe t verwaltet
(Gegensatz globale Tiefe d für die
Verwaltung des Blocks durch Verdoppeln des Index 7=00111 14=01110
gesamte Hash-Tabelle) 8=01000 23=10111 Lokale
Index ist viel kleiner als die Datei, daher Verdoppeln viel günstiger Anzahl der den Block referenzierenden 9=01001 26=11010 Tiefe
Keine Überlaufbereiche Verzeichniseinträge entspricht 2d-t 10=01010 31=11111
13=01101
Suche
Element x im Block T[hd(x)]

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


317 318

Einfügen Einfügen Fall 1: t < d

Zwei Fälle zu unterscheiden falls ein Block überläuft Versuch den Split ohne Indexexpansion durchzuführen
t < d: mehrere Indexeinträge referenzieren diesen Block Neuen Datenblock anfordern
Aufteilung der Daten des überlaufenden Blocks nach ht+1
t = d: ein Indexeintrag referenziert diesen Block
t = t + 1 für alten und neuen Datenblock
Fall 1: t < d Falls Split wieder zu einem Überlauf führt, wiederholen
Einfügen von 6 d=2, b=4 Einfügen von 6 (=00110)
7=00111
6=00110 8=01000
14 8 10 26 1 9=01001 d=2, b=4 d=2, b=4 8
Fall 2: t = d 00 10=01010
14 8 10 26 2
01 13=01101 1
Einfügen von 15, 19 10 9 13 2
14=01110 00 00
14 6 10 26
23=10111 01 01 2
15=01111 11 26=11010 9 13
10 2 10
19=10011 7 31 23 31=11111 9 13 2
2 11 11
7 31 23 2
7 31 23 2

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

319 320

Einfügen Fall 2: t = d Einfügen Fall 2: t = d (2)

Erfordert eine Indexexpansion (Verdoppelung) Jetzt Fall 1 7=00111


Neuen Speicherbereich für 2d zusätzliche Referenzen anfordern 15=01111
Für jedes T[x], für das gilt x ≥ 2d: T[x] = T[x-2d] 19=10011
23=10111
d = d+1 31=11111
Danach Rückführung auf Fall 1 d=3, b=4 d=3, b=4
d=3, b=4
Einfügen von 15 und 19 8 8
8 000 2 000 2
d=2, b=4 000 2
8 2
001
9 13
001
9 13
001 010 2 010 2
9 13 2
00 010 011 011
9 13
01 2 Index- 011 100 14 6 10 26 2 100 14 6 10 26 2
expansion 100 14 6 10 26 2
10 101 101
14 6 10 26 2 101 7 31 23 15 19 19
11 110 2 110 3
110 7 31 23 15 2
7 31 23 15 111 111
2 111 7 31 23 15 3

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


321 322

Problem des Indexwachstums Kommentare

Indexexpansion kann scheitern, mehrfache Verdoppelungen Löschen leerer Blöcke nicht einfach
d=1, b=4 Verschmelzung mit ihren Split-Buddies („Split-Images“)
16 8 28 32 8=001000
d=3, b=4
0 1
9=001001 Analog für Indexverkleinerung
1 13=001101 16 8 56 32
9 13 1 16=010000 000
3 Falls Index im Hauptspeicher gehalten werden kann,
28=011100
001 nur ein externer Zugriff notwendig
32=100000
Einfügen 56 9 13
56=111000 010
1 Im worst case exponentielles Indexwachstum
d=2, b=4 011
56 100 Typisch bei clustered data (Daten sind nicht gleichverteilt)
16 8 28 32 28
00 2 101 3 Daher Speicherplatzbedarf für Index im worst case nicht
01
9 13
110 akzeptierbar
10 1 111 Index normalerweise im Hauptspeicher
11 2
Problem der Blockung des Index auf der Platte
2
1. Indexexpansion 2. Indexexpansion Keine garantierte Mindestauslastung
VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

323 324

Analyse 5.3.3 Bounded Index Size Extendible Hashing

Analyse komplex Ansatz durch


Es lässt sich zeigen, dass Extendible Hashing zur Primärbereich (analog zu Extendible Hashing)
Speicherung einer Datei mit n Datensätzen und einer Index mit beschränkter Größe
Blockgröße von b Datensätzen ungefähr 1.44*(n/b) Blöcke Binäre Expansion der Datenbereiche
benötigt
(1 Block, 2, 4, ... Blöcke)
Das Verzeichnis hat durchschnittlich für gleichverteilte
Datensätze n1+1/b/b Einträge
Versucht dem Unvermögen des Extendible Hashings,
den Index auf der Platte unterzubringen, mit einer
Großer Vorteil falls das Verzeichnis in den
speziellen Indexstruktur zu begegnen
Hauptspeicher passt, nur ein Plattenzugriff auf einen
Datensatz notwendig

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


325 326

Struktur Beispiel BISEH

Index besteht aus x Bereichen b=2 (Blockgröße), x=4 (Indexbereiche), y=4 (Einträge pro IB)
Ein Bereich enthält y Einträge der Form <z, ptr> wobei
ptr ist eine Adresse auf einen Plattenblock 64 225 67 155
z gibt die Anzahl der Verdoppelungen der entspr. Datenbereiche
d.h. ptr ist die Adresse eines Datenbereichs mit 2z Plattenblöcken 00 01 10 11
x und y sind Potenzen von 2 00 0 0 0
Hash-Werte werden gezont interpretiert, z.B. 01 255 = 1111 11 11
10 0 0 200 = 1100 10 00
16 Indexbereiche (x=16), 32 Einträge pro Indexbereich (y=32), 4 Blöcke 56 = 0011 10 00
11 0 0 0
in jedem Datenbereich 64 = 0100 00 00
Hash-Signatur für den 0. Block der vom 20. Eintrag im Indexbereich 10 155 = 1001 10 11
referenziert wird 205 255 67 = 0100 00 11
10. Indexbereich 12
0110 00 10100 1010 200 56 12 = 0000 11 00
205 = 1100 11 01
0. Plattenblock 20. Eintrag im IB 10 225 = 1110 00 01

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

327 328

Beispiel BISEH (2) Beispiel BISEH (2)

Einfügen von 128 und 144, im ersten Versuch erfolgreich Einfügen von 95 und 31, erst im zweiten Versuch erfolgreich

64 128 0 64 128
144 1 225 67 155 144 225 67 155
255 = 1111 11 11
255 = 1111 11 11 200 = 1100 10 00
on
n si 00 01 10 11 200 = 1100 10 00 00 01 10 11 56 = 0011 10 00
pa 1 0 0 56 = 0011 10 00 1 0 0 64 = 0100 00 00
Ex 64 = 0100 00 00 155 = 1001 10 11
0 0 155 = 1001 10 11 0 0 67 = 0100 00 11
67 = 0100 00 11 12 = 0000 11 00
0 0 0 0 0 2
12 = 0000 11 00 205 = 1100 11 01
205 = 1100 11 01 225 = 1110 00 01
225 = 1110 00 01 00 128 = 1000 00 00
12 205 255 12 205
144 = 1001 00 00
200 56 128 = 1000 00 00 200 56 95 31 01
144 = 1001 00 00 10
95 = 0101 11 11
255 11 31 = 0001 11 11

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


329 330

Allgemeiner Vergleich von Hash- zu Index-Verfahren 5.4 Sortierverfahren

Punkte, die zu beachten sind: Das Sortieren von Elementen (Werten, Datensätzen,
Kosten der periodischen Reorganisation etc.) stellt in der Praxis der EDV eines der
Häufigkeit von Einfügen und Löschen wichtigsten und aufwendigsten Probleme dar.
Es existieren hunderte Sortieralgorithmen in den
Average Case versus Worst Case Aufwand verschiedensten Varianten für unterschiedlichste
Erwartete Abfrage Typen Anwendungsfälle.
Hashing ist generell besser bei exakten Schlüsselabfragen Hauptspeicher - Externspeicher
Sequentiell - Parallel
Indexstrukturen sind bei Bereichsabfragen vorzuziehen
Insitu - Exsitu
Stable - Unstable
...
Sortierverfahren gehören zu den am umfangreichsten
analysierten und verfeinerten Algorithmen in der Informatik.
VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

331 332

Kriterien für die Auswahl von Sortierverfahren Sortierverfahren

Hauptspeicher - Externspeicher Aufgabe


Kann der Algorithmus nur Daten im Hauptspeicher oder auch Files Ein Vektor der Größe n der Form V[0], V[1], …, V[n-1] ist zu sortieren.
(Dateien) oder Bänder auf dem Externspeicher (Platte, Lexikographische Ordnung auf den Elementen.
Bandstation) sortieren? Nach dem Sortieren soll gelten: V[0] ≤ V[1] ≤ … ≤ V[n-1].
Insitu - Exsitu Elementare (Simple) Verfahren (Auswahl)
Kommt das Sortierverfahren mit ursprünglichen Datenbereich aus Selection Sort
(insitu) oder braucht es zusätzlichen Speicherplatz (exsitu)?
Bubble Sort
Worst Case - Average Case Verfeinerte („Intelligentere“) Verfahren (Auswahl)
Ist das (asymptotische) Laufzeitverhalten des Sortierverfahrens
Quicksort
immer gleich oder kann es bei speziellen Fällen “entarten”
(schneller oder langsamer werden)? Mergesort
Heapsort
Stable - Unstable
Wenn mehrere Datensätze denselben Schlüsselwert haben, bleibt
dann die ursprüngliche Reihenfolge nach dem Sortieren erhalten?

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


333 334

Klasse Vector 5.4.1 Selection Sort

class Vector {
Selection Sort oder Minimumsuche
int *a, size;
public: Finde das kleinste Element im Vektor und vertausche es mit
Vector(int max) { a = new int[max]; size = max; } dem Element an der ersten Stelle. Wiederhole diesen
~Vector() { delete[] a; } Vorgang für alle noch nicht sortierten Elemente.
void Selectionsort();
void Bubblesort();
void Quicksort();
Swap
void Mergesort(); Das Vertauschen (Swap) zweier Elemente (int) stellt einen
zentralen Vorgang beim Sortieren dar.
int Length();
void swap(int &x, int &y) {
private:
int help = x;
void quicksort(int, int);
void mergesort(int, int); x = y;
void swap(int&, int&); y = help;
}; }

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

335 336

Selection Sort, Beispiel Selection Sort, Algorithmus

Beispiel Algorithmus
v[0] v[1] v[2] v[3] v[4] v[5]
n=6 P E V A K S
void Vector::Selectionsort() {
swap(v[0], v[3])
int n = Length();
P E V A K S
int i, j, min;
A E V P K S --- for(i = 0; i < n; i++) {
min = i;
A E V P K S swap(v[2], v[4])
for(j = i+1; j < n; j++)
A E K P V S --- if(a[j] < a[min]) min = j;
swap(a[min], a[i]);
A E K P V S swap(v[4], v[5])
}
A E K P S V }

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


337 338

Selection Sort, Eigenschaften 5.4.2 Bubble Sort

Eigenschaften Bubble Sort


Hauptspeicheralgorithmus Wiederholtes Durchlaufen des Vektors.
Insitu Algorithmus Wenn 2 benachbarte Elemente aus der Ordnung sind
sortiert im eigenen Datenbereich, braucht nur eine temporäre (größeres vor kleinerem), vertausche (swap) sie.
Variable, konstanter Speicherplatzverbrauch
Aufwand Dadurch wird beim ersten Durchlauf das größte Element an die
generell O(n2) letzte Stelle gesetzt, beim 2. Durchlauf das 2.größte an die
vorletzte Stelle, usw. Die Elemente steigen wie Blasen (bubbles)
auf.

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

339 340

Bubble Sort, Beispiel Bubble Sort, Algorithmus

Beispiel Algorithmus
v[0] v[1] v[2] v[3] v[4] v[5]
n=6 P E V A K S

swaps: void Vector::Bubblesort() {


P E V A K S P-E, V-A, int n = Length();
V-K, V-S
int i, j;
E P A K S V P-A, P-K
for(i = n-1; i >= 1; i--)
E A K P S V E-A for(j = 1; j <= i; j++)
A E K P S V
if(a[j-1] > a[j])
swap(a[j-1], a[j]);
A E K P S V
}
A E K P S V

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


341 342

Bubble Sort, Eigenschaften 5.4.3 Quicksort

Eigenschaften Quicksort (Hoare 1962)


Hauptspeicheralgorithmus Der Vektor wird im Bezug auf ein frei wählbares
Insitu Algorithmus Pivotelement durch Umordnen der Vektorelemente in 2
sortiert im eigenen Datenbereich, braucht nur eine temporäre Teile geteilt, sodaß alle Elemente links vom Pivotelement
Variable, konstanter Speicherplatzverbrauch kleiner und alle Elemente rechts größer sind. divide-
Aufwand Die beiden Teilvektoren werden unabhängig and-
conquer
generell O(n2) voneinander wieder mit quicksort
Eigenschaft
(rekursiv) sortiert.
Das Pivotelement steht dadurch auf seinem endgültigen Platz. Es
bleiben daher nur mehr n-1 Element (in den beiden Teile) zu
sortieren (Verringerung der Problemgröße)
Beruht auf dem “divide-and-conquer” Ansatz.

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

343 344

Pivotelement umordnen Pivotelement umordnen (2)

Beliebiges Element als Pivotelement wählen


E P V A K N B
(im u.a. Bsp. linkes Element im Vektor, auch zufällige Wahl oder Median
aus 3 zufälligen üblich) B E V A K N B P

Pivotelement von links bzw. rechts in den Vektor ‘hineinsinken’ T E B A K N V P

lassen, E B P A K N V
d.h. jeweils sequentiell von links mit allen kleineren Elementen, von E B A P K N V
rechts mit allen größeren vertauschen.
E B A K P N V
Bei Blockierung, d.h. links kleineres und rechts größeres
Element, diese beiden Elemente vertauschen B E B A K N P V

Pivotelement E B A K N P V

P E V A K N B
von links hineinsinken E umgeordnete Elemente
von rechts hineinsinken B blockierende Elemente
von links hineinsinken von rechts hineinsinken
B,T Blockierung u. Tausch P Pivotelement

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


345 346

Quicksort, Rekursion Quicksort, Algorithmus


void Vector::Quicksort() {
quicksort(0, Length()-1);
v[0] v[1] v[2] v[3] v[4] v[5] v[6]
}
n=7 P E V A K N B void Vector::quicksort(int l, int r) {
Pivot: P int i, j; int pivot;
swaps: P-E, V-B, P-B, P-A, P-K, P-N if(r > l) {
E B A K N P V pivot = a[l]; i = l; j = r+1;
Pivot: E Pivot: V for(;;) {
swaps: E-B, E-A swaps: - while(a[++i] < pivot) if (i == r) break;
B A E K N V while(a[--j] > pivot);
Pivot: B Pivot: K if(i >= j) break;
swaps: B-A swaps: - swap(a[i], a[j]);
A B K N }
Pivot: A Pivot: N swap(a[j], a[l]);
swaps: - swaps: - quicksort(l, j-1);
A N quicksort(j+1, r);
}
A B E K N P V }

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

347 348

Quicksort, Eigenschaften 5.4.4 Mergesort

Hauptspeicheralgorithmus Mergesort (???, 1938)


Insitu Algorithmus Der zu sortierende Vektor wird rekursiv in Teilvektoren
sortiert im eigenen Datenbereich, braucht nur temporäre Hilfsvariable halber Länge geteilt, bis die (trivialen, skalaren) Vektoren
(Stack), konstanter Speicherplatzverbrauch aus einem einzigen Element bestehen.
Aufwand Danach werden jeweils 2 Teilvektoren zu einem doppelt so
Im Durchschnitt O(n*log(n)) großen Vektor gemerged (sortiert).
Kann zu O(n2) entarten Beim Mergen werden sukkzessive die ersten beiden Element der
Beispiel: Vektor ist vorsortiert und als Pivotelement wird immer das erste Vektoren verglichen und das kleinere in den neuen Vektor
oder letzte Vektorelement gewählt
übertragen, bis alle Elemente im neuen Vektor sortiert gespeichert
Empfindlich auf unvorsichtige Wahl des Pivotelements sind.
Stabilität nicht einfach realisierbar Das Mergen wird solange wiederholt, bis in der letzten Phase 2
Vektoren der Länge n/2 zu einem sortierten Vektor der Länge n
Rekursiver Algorithmus verschmelzen.
Komplex zu realisieren, wenn Rekursion nicht zur Verfügung steht
“divide-and-conquer” Ansatz.
VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta
349 350

Merging Mergesort, Rekursion

Merging zweier Vektoren


trivialer Fall n=4
5 1 v[0] v[1] v[2] v[3]
P E V A

1, 5 P E V A
Zerlegungs-
phase
P E V A
allgemeiner Fall

E P A V Merge-
1, 4, 5, 7, 9, 11, 12, 14 2, 3, 6, 8, 10, 13, 15 phase
A E P V

1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

351 352

Mergesort, Algorithmus Mergesort, Eigenschaften


void Vector::Mergesort() {
mergesort(0, Length()-1);
Eigenschaften
} Hauptspeicheralgorithmus, aber auch als
void Vector::mergesort(int l, int r) { Externspeicheralgorithmus verwendbar.
int i, j, k, m;
Extern Sortieren: statt Teilphase wird oft vorgegebene
Vector help(r-l+1);
Datenaufteilung genommen, oder nur soweit geteilt, bis sich
if(r > l) {
Teilvektor (Datei) im Hauptspeicher sortieren lässt.
m = (r+l)/2;
mergesort(l, m); Exsitu Algorithmus
mergesort(m+1, r); braucht einen zweiten ebenso großen Hilfsvektor zum Umspeichern
for(i=m+1; i>l; i--) help.a[i-1] = a[i-1];
Aufwand
for(j=m; j<r; j++) help.a[r+m-j] = a[j+1];
for(k=l; k<=r; k++) Generell O(n*log(n))
a[k]=(help.a[i]<help.a[j])?help.a[i++]:help.a[j--]; Braucht doppelten Speicherplatz
} Rekursiver Algorithmus
}
Komplex zu realisieren, wenn Rekursion nicht zur Verfügung steht.

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


353 354

5.4.5 Heapsort Heapsort (modifizierter Ansatz)

Eine Heap (Priority Queue) kann Basis zum Sortieren Kombination der beiden Arrays, Vermeidung von
bilden (Williams 1964): doppeltem Speicherplatz
1. ein Element nach dem anderen in einen Heap einfügen
6 9 11 10
2. sukzessive das kleinste bzw. größte Element entfernt 0 1 2 3 4 5 6 9 11 10 5 3
die Element werden in aufsteigender bzw. absteigender Ordnung 3 5 0 1 2 3 4 5
geliefert
1. 3
2. 5 6 ...
Heap-Eigenschaft umdrehen: Wert jedes Knotens ist
0 0 0
größer oder gleich den Werten seiner Kinderknoten
6 5 6 11 9 11
1 2 1 2 1 2 3 11
0 0
10 9 11 10 9 10
3 4 5 3 4 3 6 5
1 2 9 10 11 9 10 3 6 5
1 2
0 1 2 3 4 5
3 6 5 10 9 11 5 6 11 10 9 6 9 11 10
10 9 11
0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 3 4 5 3 6 5
3 3 5 3 5 6 9 10 11 3 4 5

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

355 356

Beispiel: buildheap Beispiel: heapsort

Wertemenge 9 Idee: Heap-Eigenschaft


0 11 Idee: Maximum "löschen" und am
erzeugen; für Blattknoten 0
9 6 5 10 3 11 freiwerdenden Platz sichern
trivialerweise erfüllt
6 5 10 9
1 2 Nr. 2 erster zu prüfender 1 2
10
0
9
0
Knoten, 11 passt nicht, in
9 6 5 10 3 11 Baum sinken lassen, d.h.
10 3 11 6 3 5 6 9 6 3
0 1 2 3 4 5 3 4 5 5 mit 11 tauschen 3 4 5 1 2 1 2

9 9 11 11 10 9 6 3 5 5 3 5
0 0 0 3 4 3
0 1 2 3 4 5
10 6 9 5 3 11 9 6 3 5 10 11
6 11 10 11 10 9 0 1 2 3 4 5 0 1 2 3 4 5
1 2 1 2 1 2

10 3 5 6 3 5 6 3 5 6 5 3
3 4 5 3 4 5 3 4 5 0 0 0
Wert 6 (Nr. 1) passt nicht, in Nr. 0 (9) in Baum sinken. Heap-Eigenschaft erfüllt! 5 3 3
Teilbaum sinken lassen, d.h. 1 2 1
mit größerem der Nachfolger 11 10 9 6 3 5
vertauschen, d.h. 6 mit 10 0 1 2 3 4 5 6 5 3 9 10 11 5 3 6 9 10 11 3 5 6 9 10 11
0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


357 358

Heapsort Algorithmus (1) Heapsort Algorithmus (2)

void Vector::Heapsort() { void Vector::heapify(int i, int heapsize) {


int heapsize = Length(); int left = 2*i + 1;
int right = 2*i + 2;
BuildMaxheap();
int largest;
for(int i = Length()-1; i >= 1; i--) { if (left < heapsize && a[left] > a[i])
swap(a[0], a[i]); largest = left;
heapsize--; else
heapify(0, heapsize); largest = i;
} if (right < heapsize && a[right] > a[largest])
} largest = right;
if (largest != i) {
swap(a[i], a[largest]);
void Vector::BuildMaxheap() { heapify(largest, heapsize);
for(int i = Length()/2 - 1; i >= 0; i--) }
heapify(i, Length()); }
}
VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

359 360

Eigenschaften der komplexen Verfahren Laufzeitvergleich der Verfahren

Quicksort 500
Entartung zu O(n2) möglich 400
Wahl des Pivotelements!

Sekunden
300
Mergesort
immer Laufzeit O( n * log(n) ) 200

doppelter Speicherplatz notwendig 100


Heapsort 0
keinen der obigen Nachteile 2500 3000 3500 4000 4500 5000
aber höherer konstanter Aufwand Vektorgröße

Bubble Sort Selection Sort Quicksort


Mergesort Heapsort

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


361 362

Comparison Sort Verfahren Entscheidungsbaum

Man nennt diese bekannten Verfahren Vergleichende Betrachtung der Vergleichenden Sortierverfahren
Sortierverfahren (Comparison sort) durch Entscheidungsbäume
Die Reihenfolge der Elemente wird dadurch bestimmt, dass Der Entscheidungsbaum enthält alle möglichen Vergleiche
die Elemente miteinander verglichen werden
eines Sortierverfahrens um eine beliebige Sequenz einer
Nur Vergleiche der Form xi < xj,, xi ≤ xj, ... angewendet
vorgegebenen Länge zu sortieren
Diese Algorithmen zeigen als günstigste Laufzeit eine
Die Blattknoten repräsentieren alle möglichen Permutationen der
Ordnung von O(n log n), d.h. wir konnten bis jetzt als Eingabe Sequenz
untere Grenze Ω(n log n) feststellen
Die Wege von der Wurzel zu den Blättern definieren die
Vermutung: Das Problem des Sortierens durch notwendigen Vergleiche um die entsprechenden
Vergleichen der Elemente lässt sich mit Ω(n log n) Permutationen zu erreichen
beschreiben
Falls gültig ⇒ Algorithmische Lücke geschlossen, da
Ω(P) = O(A)
VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

363 364

Beispiel Entscheidungsbaum Beweis: Untere Grenze für den worst case

Entscheidungsbaum für 3 Elemente Wir ignorieren Swappen, Administrationsoperationen, etc.


d.h. 3! = 6 mögliche Permutationen der Eingabe Elemente Die Anzahl der Blätter im Entscheidungsbaum ist n!
< x1 ,x2 ,x3 > Die Anzahl der Blätter in einem binären Baum ist ≤ 2h
x1:x2 daher
2 h ≥ n!
x2:x3 x1:x3
h ≥ lg(n!)
n n
Stirlingsche Näherung n! = 2πn ( ) n (1 + θ (1 / n)) > ( ) n
1,2,3 x1:x3 2,1,3 x2:x3 e e
n
h > lg( ) n = n lg n − n lg e d.h. Algorithmische Lücke für
e Vergleichende Sortierverfahren
1,3,2 3,1,2 2,3,1 3,2,1 h = Ω(n lg n) geschlossen

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


365 366

5.5 Sortieren in linearer Zeit 5.5.1 Counting Sort

Sortierverfahren, die nicht auf dem Vergleich zweier 1954 Erstmals verwendet von Harold H.Seward MIT
Werte beruhen, können eine Eingabe Sequenz in Thesis „Information Sorting in the Application of
linearer Zeit sortieren Electronic Digital Computers to Bussiness
Erreichen die Ordnung O(n) Operations“ als Grundlage für Radix Sort.
Beispiele 1956 Erstmals publiziert von E.H. Fried
Counting Sort 1960 unter dem Namen Mathsort von W. Feurzeig.
Radix Sort
Bucket Sort

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

367 368

Counting Sort Counting Sort (2)

Bedingung Erweiterung
Die zu sortierenden n Elemente sind Integer Werte im Die Elemente stammen aus dem Bereich [1..k] und es gibt
Bereich 0 bis k keine doppelten Werte
Falls k von der Ordnung n ist (k = O(n)) benötigt das Frage: wie können wir den ersten Ansatz erweitern?
Sortierverfahren O(n) Allgemeiner Fall
Ansatz Die Elemente sind aus dem Bereich [1..k], Doppelte sind
Gegeben sei eine exakte Permutation erlaubt

5 8 4 2 7 1 6 3 Idee des Counting Sort


Bestimme für jedes Element x die Anzahl der Elemente
Jedes Element wird einfach auf die Position seines Wertes kleiner als x im Vektor, verwende diese Information um
in einem Zielvektor gestellt das Element x auf seine Position im Ergebnisvektor zu
platzieren
VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta
369 370

Counting Sort Algorithmus Counting Sort Beispiel

Eingangsvektor A, Ergebnisvektor B, Hilfsvektor C 1: A 3 6 4 1 3 4 1 4 3: B 1 4


for(i=1; i<=k; i++) 2. D.
C[i] = 0; C 2 0 2 3 0 1 C 1 2 4 6 7 8
for(j=1; j<=length(A); j++) 1: C[i] enthält die Anzahl der
Elemente gleich i, i = 1,2,...,k
C[A[j]] = C[A[j]] + 1;
2: C 2 2 4 7 7 8 3: B 1 4 4
for(i=2; i<=k; i++) 2: C[i] enthält die Anzahl der 3. D.
C[i] = C[i] + C[i-1]; Elemente kleiner oder gleich i
C 1 2 4 5 7 8
for (j=length(A); j>=1; j--) {
3: Jedes Element wird an seine 3: B 4
B[C[A[j]]] = A[j];
korrekte Position platziert 1. Durchlauf
C[A[j]] = C[A[j]] – 1; Falls alle Element A[j] unterschiedlich 3:
C 2 2 4 6 7 8 B 1 1 3 3 4 4 4 6
sind ist die korrekte Position in C[A[j]], Ende
} da Elemente gleich sein können wird
der Wert C[A[j]] um 1 verringert

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

371 372

Counting Sort Analyse 5.5.2 Radix Sort


for(i=1; i<=k; i++)
C[i] = 0;
O(k) Radixsort betrachtet die Struktur der Schlüsselwerte
for(j=1; j<=length(A); j++) Die Schlüsselwerte der Länge b werden in einem
C[A[j]] = C[A[j]] + 1; O(n) Zahlensystem der Basis M dargestellt (M ist der Radix)
for(i=2; i<=k; i++)
C[i] = C[i] + C[i-1]; O(k) z.B. M=2, die Schlüssel werden binär dargestellt, b = 4
for (j=length(A); j>=1; j--) { 8 4 2 1 Gewicht
B[C[A[j]]] = A[j];
C[A[j]] = C[A[j]] – 1; O(n) 9= 1 0 0 1 b=4
} 3 2 1 0 Stelle #
Daraus folgt, dass der Gesamtaufwand O(n + k) ist
In der Praxis haben wir sehr oft k = O(n), wodurch wir einen realen Aufwand
Es werden Schlüssel sortiert, indem ihre einzelnen
von O(n) erreichen Bits an derselben Bit Position miteinander
Man beachte, dass kein Vergleich zwischen Werten stattgefunden hat, sondern verglichen werden
die Werte der Elemente zur Platzierung verwendet wurden (vergl. Hashing)
Counting Sort ist ein stabiles Sortierverfahren
Das Prinzip lässt sich auch auf alphanumerische Strings
Garantiert durch letzte Schleife, die von hinten nach vorne arbeitet erweitern

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


373 374

Radix Sort Algorithmus Binärer Quicksort

Allgemeiner Algorithmus Sehr altes Verfahren


for(Index i läuft über alle b Stellen) {
1929 erstmals für maschinelles Sortieren von
sortiere Schlüsselwerte mit einem (stabilen)
Sortierverfahren bezüglich Stelle i Lochkarten.
} 1954 H.H. Seward [MIT R-232 (1954), p25-28 ]
Richtung des Indexlaufs, Stabilität eigenständig und ausführlich: P.Hildebrandt , H. Isbitz,
Von links nach rechts H. Rising, J. Schwartz
d.h. for(int i=b-1; i>=0; i--) { ... } [JACM 6 (1959), 156-163]
Führt zum Binären Quicksort (Radix Exchange Sort) 1 Jahr vor Quicksort
Von rechts nach links und stabiles Sortierverfahren
d.h. for(int i=0; i<b; i++) { ... }

Führt zum LSD-Radixsort (Straight Radix Sort)

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

375 376

Binärer Quicksort Idee Binärer Quicksort Partition

Idee Aufteilung der Datensätze durch insitu Ansatz ähnlich


Betrachte Stellen von links nach rechts des Partitionierens beim Quicksort
1. Sortiere Datensätze bezogen auf das betrachtete Bit do {
scan top-down to find key starting with 1;
2. Teile die Datensätze in M unabhängige, der Größe nach
scan bottom-up to find key starting with 0;
geordnete, Gruppen und sortiere rekursiv die M Gruppen
exchange keys;
wobei die schon betrachteten Bits ignoriert werden
} while (not all indices visited)
Beispiel
Beispiel
01 00 Scan
1 1. 0 2. 0 0 1. 0 1 ... vom 1 0 0
1 0 Anfang 1 1 0
0 1 10 10 0 0 1
1 1 Scan 1 1 1
11 10 vom
0 1 10 11 Ende
0 1 1

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


377 378

Binärer Quicksort für Dezimalzahlen Binärer Quicksort Eigenschaften

Anzahl der Gruppen M ist 10 Binärer Quicksort verwendet im Durchschnitt


Zahlenwerte 0 bis 9 ungefähr N log N Bitvergleiche
log N (Kodierung des Zahlenwerts) = konstanter Faktor
016
015 N = Unsicherheit in der Zahlendarstellung
0 3 2 0 3 2
2 2 4 0 1 6 015 016 Gut geeignet für kleine Zahlen
0 1 6 0 1 5 032 031
0 3 1 Benötigt relativ weniger Speicher als andere Lineare
0 1 5 031
032 Sortierverfahren
0 3 1
169 123
1 6 9 123
1 2 3
123
169
Es ist ein Instabiles Sortierverfahren
169
2 5 2 224 Ähnlich dem Quicksort nur für positive ganze Zahlen
252 224 224
252 252

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

379 380

LSD-Radixsort Was bedeutet „stabil“

Idee Bei Binärem Quicksort Bei einem stabilen Sortierverfahren wird die relative
von links nach rechts!
Betrachte Bits von rechts nach links Reihenfolge von gleichen Schlüsseln nicht verändert
LSD … „least significant digit“ Beispiel
Sortiere Datensätze stabil (!) bezogen auf das betrachtete Bit 0 1 0 0 1 0
Erster Durchgang von letztem Beispiel 0 0 0 0 0 0
Zu sortierende Bits pro Durchlauf
Die relative Reihenfolge der 1 0 1 1 0 0
0 0 1 1 1 0
Schlüssel die mit 0 enden
0 1 0 0 1 0 0 0 0 0 0 0 1 1 1 1 0 1
0 0 0 0 0 0 1 0 0 0 0 1 bleibt unverändert, dasselbe 0 1 1 0 0 1
1 0 1 1 0 0 1 0 1 0 1 0 gilt für die Schlüssel, die mit 1 0 0 1 1 1
0 0 1 1 1 0 0 0 1 0 1 1 1 enden 1 1 0 0 1 1
1 1 1 1 0 1 0 1 0 1 0 0
0 1 1 0 0 1 1 1 0 1 0 1 Stabilität garantiert Korrektheit des Algorithmus
1 0 0 1 1 1 1 1 1 1 1 0 Mögliches Verfahren: Counting Sort
1 1 0 0 1 1 0 1 1 1 1 1

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


381 382

LSD-Radixsort für Dezimalzahlen Analyse von Radix Sort

Anzahl der Gruppen M ist 10 Sortieren von n Zahlen, Schlüssellänge b


for(Index i läuft über alle b Stellen) {
Ziffern 0 bis 9 sortiere n Schlüsselwerte mit einem (stabilen)
Sortierverfahren bezüglich Stelle i
}

0 3 2 0 3 1 0 1 5 0 1 5
Bei der Anwendung eines Sortierverfahrens mit der Laufzeit
2 2 4 0 3 2 0 1 6 0 1 6 O(n) (wie z.B. Partitionierung bei Radix Exchange Sort,
0 1 6 2 5 2 1 2 3 0 3 1 Counting Sort bei Straight Radix Sort) ist daher die Ordnung
0 1 5 1 2 3 2 2 4 0 3 2 von Radix Sort O(bn)
0 3 1 2 2 4 0 3 1 1 2 3 Counting Sort ist kein insitu Verfahren, daher doppelter Speicherplatz
1 6 9 0 1 5 0 3 2 1 6 9 notwendig, führt in der Praxis zum Einsatz von O(n log n) Verfahren
1 2 3 0 1 6 2 5 2 2 2 4 Wenn man b als Konstante betrachtet kommt man auf O(n)
2 5 2 1 6 9 1 6 9 2 5 2 Bei Zahlenbereich von m Werten Darstellung am Computer mit b =
log(m) Stellen, da aber Wertebereich am Computer begrenzt, Ansatz
b konstant akzeptierbar

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

383 384

5.5.3 Bucket Sort Bucket Sort Beispiel

Annahme über die n Eingabe Elemente, dass sie Eingabe Vektor A der Größe 10
Bucket Vektor B verwaltet Elemente über lineare Listen
gleichmäßig über das Intervall [0,1) verteilt sind
Bucket B[i] enhält die Werte des Intervalls [i/10, (i+1)/10)
Idee
Teile das Intervall [0,1) in n gleichgroße Teil-Intervalle .78 0
(Buckets) und verteile die n Eingabe Elemente auf die .17 1 .12 .17
.39 2 .21 .23 .26
Buckets .39
.26 3
Da die Elemente gleichmäßig verteilt sind, fallen nur wenige .72 4
Elemente in das gleiche Bucket .94 5
Sortiere die Elemente pro Bucket mit Selection Sort .21 6 .68
.12 7 .72 .78
Besuche die Buckets entlang des Intervalls und gib die
.23 8
sortierten Elemente aus .68 9 .94

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


385 386

Bucket Sort Algorithmus Analyse Bucket Sort

n = length(A); Alle Anweisungen außer Sortieren sind von der Ordnung O(n)
Analyse des Sortierens
for(i=1; i<=n; i++)
ni bezeichnet die Zufallszahl der Elemente pro Bucket
insert A[i] into list B[n*A[i]]; Selection Sort läuft in O(n2) Zeit, d.h. die erwartete Zeit zum Sortieren
eines Buckets ist E[O(n2)] = O(E[n2]), da alle Buckets zu sortieren ist
for(i=0; i<n; i++) n −1 n −1

∑ O( E[ni2 ]) = O(∑ E[ni2 ]) ⇒ O(1)


sort list B[i] with insertion sort; i =0 i =0
Um den Ausdruck zu berechnen
Concatenate the lists B[0], B[1], ..., Verteilung der Zufallsvariable ni bestimmen
B[n-1] together in order Es gibt n Elemente mit n Buckets, d.h. die Wahrschein-
lichkeit eines Elements in eine Bucket zu fallen ist p = 1/n
ni folgt der Binomial-Verteilung
E[ni] = n*p = 1 und Var [ni] = n*p*(1-p) = 1 – 1/n
Da E[ni2] = Var[ni] + E2[ni] = 1 – 1/n + 12 = 2 – 1/n = Θ(1)
Daraus folgt, dass der Aufwand für Bucket Sort O(n) ist

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

387 388

5.6 Externes Sortieren Eigenschaften von Bändern

Externes Sortieren bezeichnet alle Sortierverfahren, Bändern entsprechen allgemein Sequenzen


die nicht ausschließlich im Hauptspeicher ablaufen Die Datenelemente sind hintereinander angeordnet
Diese Verfahren benötigen sekundäre (Platten) oder tertiäre
(Bänder) Speichermedien und man kann auf sie nur sequentiell lesend und
Üblicherweise versteht man darunter Verfahren, die schreibend zugreifen
Bändern einsetzen Verwaltung elementweise oder blockweise (ein Block
Grund für externe Verfahren sind zu sortierende umfasst mehrere gemeinsam verwaltete Elemente)
Datenmengen, die nicht mehr vollständig in den Es ist nicht möglich auf ein beliebiges Element ohne
Hauptspeicher passen Aufwand O(n) zuzugreifen
In der Praxis häufig anzutreffen Bänder können üblicherweise von beiden Seite gelesen und
Ziel ist die Anzahl der Transfers zwischen geschrieben werden bzw. von einem Ende zum anderen
gespult werden
Hauptspeicher und Externspeicher zu minimieren

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


389 390

Strategie für externes Sortieren Merging

Klassisches „Sortieren durch Mischen“ Ansatz analog zu Mergesort im Hauptspeicher


Seit den 50er Jahren im Einsatz Statt Hauptspeicherfeld eben Band
Soviel Daten wie möglich in den Hauptspeicher laden Merging zweier Sequenzen
Diese Daten im Hauptspeicher sortieren
5 1
Sortierte Daten (Run) auf externes Speichermedium
simpler Fall
schreiben
1, 5
Ein Run ist eine geordnete Teil-Sequenz der urspr.
Datenelemente
1, 4, 5, 7, 9, 11, 12, 14 2, 3, 6, 8, 10, 13, 15
Runs über den Hauptspeicher zu größeren Runs
zusammenmischen (Merging) allgemeiner Fall

1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

391 392

5.6.1 Balanced Multiway Merging Algorithmus

Idee Bilden initaler Runs durch Sortieren der Daten im


Anfänglicher Verteilungsdurchgang Hauptspeicher und gleichmäßiges Verteilen auf P
Mehrere Mehrweg Mischdurchgänge Output Bänder
Annahme Alternieren der Bänder
N zu sortierende Datensätze auf externem Gerät d.h. Input wird Output und vice cersa
Platz für M Datensätze im Hauptspeicher Solange
2 P externe Geräte (Bänder) zur Verfügung Merging der „Runs“ von den Input auf die Output Bänder
P Inputbänder und alternieren der Bänder
P Outputbänder
bis EIN sortierter Run entsteht
Input auf Band 0, anderen Bänder 1, 2, …, 2P – 1
Ziel: sortiertes Ergebnis auf Band 0

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


393 394

Balanced Multiway Merging Beispiel Balanced Multiway Merging Analyse

Dreiweg Mischen, P = 3 Durch Hardwareparameter (langsames Band) Anzahl


der Banddurchläufe interessant
Band 0 A S O R T I N G A N DM E RG I NG E X AM P L E *
N ... Anzahl der Elemente
Band 3 A O S * DMN * A E X * M ... Größe des Hauptspeichers
Band 4 I R T * E G R * L MP *
Band 5 AGN * G I N * E * Jeder Sortier-Durchlauf erzeugt N/M sortierte Runs
Daher bei p-Weg Merging braucht man ungefähr
Band 0 A A G I NO R S T *
Im Beispiel muss noch
logP(N/M) Durchläufe
Band 1 D E GG I MN N R *
einmal Band 3 auf Band 0 Jeder Durchlauf verringert die Anzahl der Durchläufe um
Band 2 A E E L MP X * (Ziel) kopiert werden Faktor P
Band 3 A A A D E E E GGG I I L MMN N NO P R R S T X * Beispiel: Zu sortierende Datei 200 GB, Hauptspeicher 1 GB,
Sortieren benötigt 5 Durchläufe

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

395 396

Organisation im Hauptspeicher 5.6.2 Replacement Selection

Organisation der Elemente im Hauptspeicher über Elemente im Hauptspeicher werden über eine Priority
Priority Queue (z.B. Heap) Queue der Größe p verwaltet (sortiert)
Kleinstes Element (nächstes zu Mergen) ist direkt PQ wird mit den kleinsten Elementen der p Runs gefüllt
zugreifbar Das kleinste Element der PQ wird auf das Output Band
geschrieben und das nächste Element nachgeschoben
Einfügen eines neuen Elementes vom Band von der
Die PQ Eigenschaft wird mit einer heapify Funktion erhalten
Ordnung O(log M)
M beschreibt die Größe des zur Verfügung stehenden Beispiel
Hauptspeichers Im Hauptspeicher sind nur die kleinsten
A O S Elemente der Runs, (dargestellt werden
Erlaubt auch das Erzeugen von sortierten Runs die aber die ganzen Runs (zur Erklärung))
viel größer sind als der Hauptspeicher Realisierung über Pointer auf die echten
I R T A G N Runs = indirekter Heap

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


397 398

Erzeugung von initialen Runs Erzeugung von initialen Runs Beispiel

Idee ist den ungeordneten Input durch eine große PQ ASORTINGEXAMPLE


durchzuschleusen Heap der Größe 5
Das kleinste Element rausschreiben und das nächste Element A I N O
in die PQ aufzunehmen R O R O R O R G
(falls notwendig) die PQ Bedingung wiederherstellen (heapify) S T S T S T S T
Spezielle Situation falls ein Element kleiner als das letzte
R S T X
geschrieben ist
Kann nicht mehr Teil des Runs werden, wird markiert und als größer als
S G T G X G A G
alle Elemente des aktuellen Runs behandelt E T E X E A E M
Dieses Element beginnt einen neuen Run A E E Erzeugt 2 Runs:
E G L G L G AINORSTX
Es lässt sich zeigen, dass Runs, die mit Replacement Selection
P M P M P M AEEGLMP
erzeugt wurden ungefähr 2 Mal so groß wie die PQ sind

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

399 400

5.6.3 Polyphase Merging Polyphase Merging Beispiel

Nachteil des Balanced Multiway Merging ist die relativ


Band 0 AOR S T I N AGN D EMR GIN
große Anzahl von benötigten Bändern
Band 1 EGX AMP EL Initiale Runs
Ansatz mit P Bändern und 1 Output Band benötigt zwar durch
weniger Bänder aber exzessives Kopieren Band 2
Replacement
Output Band muss wieder auf P Bänder aufgeteilt werden Selection erzeugt
Band 0 D EMR GI N
Idee des Polyphase Merging Band 1
Verteile die mit Replacement Selection erzeugten initialen
Band 2 A E GOR S T X A I MN P AEG L N
Runs ungleichmäßig über die Bänder (ein Band bleibt
leer) Band 0
Führe ein Merging-until-empty durch Band 1 A D E E GMO R R S T X A G I I MN N P
Merging bis ein Band leer ist, welches das neue Output Band wird
Band 2 A EG L N

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


401 402

Eigenschaften Was nehmen wir mit?

Diese „Merge-until-empty“ Strategie kann auf beliebige Dictionary


Bandzahlen (> 2) angewendet werden Hashing
Analyse ist kompliziert Statische und dynamische Verfahren
Unterschied zwischen Balanced Multiway Sorting und Sortieren
Polyphase Merging eher gering
Klassische Verfahren O(n2) und O(n log n)
Polyphase Merging nur für geringe Bandzahlen (p < 9)
Lineare Verfahren O(n)
besser als BMS
Dient eher zum Verringern der Bandzahlen
Externes Sortieren

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

403 404

Graphen

Graphen sind eine dominierende Datenstruktur in der


Informatik
Kapitel 6: Viele Probleme der Informatik lassen sich durch Graphen
beschreiben und über Graphenalgorithmen lösen
Graphen
Ungerichteter Graph

Gerichteter Graph

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


405 406

Graphen-Beispiele 6.1 Ungerichteter Graph

Ortsverbindungen Ein ungerichteter Graph G(V, E) besteht aus einer


z.B. Züge
Wien Graz Menge V (vertex) von Knoten und einer Menge E
(edge) von Kanten, d.h.
Linz Klagenfurt V = {v1, v2, …, v|V|}
Salzburg E = {e1, e2, … e|E|}

Ablaufbeschreibungen
Eine Kante e ist eine ungeordnetes Paar von Knoten
z.B. Projektplanung Maschinenhalle
aus V, d.h. e = [vi, vj] mit vi,vj Î V
Kanten rep. Abhängigkeiten v1 e1 = [v1, v2] v2
Fundamente
Zufahrt Rohbau G(V, E)
V = {v1, v2, v3}
e2 = [v1, v3] e3 = [v2, v3]
Außenanlage Lieferung Maschinen Dach E = {e1, e2, e3}
Innenausbau
Montage Maschinen v3

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

407 408

Kantenfolge, -zug, Weg Kreis

Eine Kantenfolge von v1 nach vn in einem Graphen G ist eine Ein Kreis ist ein Kantenzug, bei dem die Knoten v 1, v2,
endliche Folge von Kanten [v1,v2], [v2,v3], …, [vn-1,vn], wobei
je 2 aufeinanderfolgende Kanten einen gemeinsamen …, vn-1 alle verschieden sind und v n = v1 gilt
v1 v3
Endpunkt haben v2

KF1 = [v1,v2], [v2,v3] oder KF 2 = [v1,v2], [v2,v3], [v3,v1], [v1,v2] v4


v6
v1 v2 v1 v2 Kreise:
v2, v3, v5, v7, v2
v3 v3, v4, v5, v3 v5
v3
v2, v3, v4, v5, v7, v2
Eine Kantenzug ist eine Kantenfolge, in der alle Kanten v7
verschieden sind, (im Beispiel ist KF1 ein Kantenzug, KF2 nicht.)
Ein Graph heißt verbunden oder zusammenhängend, wenn für alle möglichen
Ein Weg oder Pfad ist eine Kantenfolge in der alle Knoten
Knotenpaare vj,vk ein Pfad existiert, der vj mit vk verbindet
verschieden sind (ein einzelner Knoten gilt auch als Weg)
Ein Baum ist daher ein verbundener kreisloser (azyklischer) Graph
VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta
409 410

Teilgraph Komponente

Ein Graph G’(V’, E’) heißt Teilgraph von G(V, E), wenn Alle Knoten, die durch einen Weg verbunden werden
V’ Í V und E’ Í E können, heißen Komponente eines Graphen
v1
G’(V’, E’)
V’ = {v1, v3}
E’ = {e2}
e2 = [v1, v3]
v1
v3 v3
v2
Ein Teilgraph G’’(V’’,E’’) ist spannender Teilgraph von v4
G(V,E), wenn V’’ = V und G’’ einen Baum bildet v6
v1 e1 = [v1, v2] v2
G’’(V’’, E’’) Komponenten: v7
V’’ = {v1, v2, v3} v5
E’’ = {e1, e2} v1, v2, v5, v6
e2 = [v1, v3] v3, v4, v7 v8
v8
v3

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

411 412

6.2 Gerichteter Graph 6.3 Speicherung von Graphen

Ein gerichteter Graph G(V, E) besteht aus einer Wir unterscheiden 2 Methoden zur Speicherung von
Menge V von Knoten und einer Menge E von Graphen
Kanten, wobei die Kanten geordnete Paare <vi,vj> Adjazenzmatrix-Darstellung
von Knoten aus V sind Adjazenzlisten-Darstellung
v1

e2 = <v2, v1>
e1 = <v4, v1>
v4 G(V, E) Ein Knoten v heißt adjazent zu einem Knoten w, wenn
e6 = <v1, v4>
v2
V = {v1, v2, v3, v4, v5}
E = {e1, e2, e3, e4, e5, e6}
eine Kante von v nach w führt, z.B.
e5 = <v4, v5> ungerichtete Kante: gerichtetet Kante:
e4 = <v1, v3>
v adjazent zu w v adjazent zu w
e3 = <v2, v3> w adjazent zu v w aber NICHT adjazent zu v
v5 v
v

v3 w
w
Zwischen v1 und v4 existieren 2 Kanten, eine Hin- und Rückkante
(auch Doppelkante).

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


413 414

6.3.1 Adjazenzmatrix Adjazenzmatrix-Beispiele

Bei der Adjazenzmatrix-Darstellung repräsentieren die Ungerichteter Graph


Knoten Indexwerte einer 2-dimensionalen Matrix A v1 v2
v1 v2 v3
Wenn der Knoten v adjazent zum Knoten w ist, wird das Feld v1 1 1
A[v,w] in der Matrix gesetzt (z.B. 1, ‘true’, Wert, etc.) v2 1 1
v3 1 1
... v ... w ...
v v3
...
v 1
... Bei un-
w
w 1 gerichteten
Gerichteter Graph v1 v2 v3 v4 v5 v6
... v1
Graphen ist
v1 1 1
die Matrix
v ... v ... w ... symmetrisch v2 v4 v2 1 1
... v3
w v 1
... v4 1 1
w v5 1
... v5
Feld bleibt leer, da v6
v3
w nicht adjazent zu v v6

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

415 416

Eigenschaften 6.3.2 Adjazenzliste

+ gut für kleine Graphen oder Graphen mit vielen Bei der Adjazenzlistendarstellung werden für jeden
Kanten Knoten alle adjazenten Knoten in einer linearen
+ Überprüfung von Adjazenzeigenschaft O(1) Liste gespeichert
+ manche Algorithmen einfacher Somit werden nur die auftretenden Kanten vermerkt

- dfs schlecht, Rechenaufwand O(|V|2) v v w

- quadratischer Speicheraufwand O(|V| 2) w


w v

v w
v
w
w

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


417 418

Adjazenzliste-Beispiele Code, Eigenschaften

Ungerichteter Graph C-Code


v1 v2 struct node {
v3 v2 int v;
v1
struct node *next;
v2 V1 v3 };
v3 struct node *adjliste[maxV];
v3 v1 v2

Gerichteter Graph Eigenschaften:


v1
v4 v4 v3
+ gut für Graphen mit wenigen Kanten
v1
v2 v2 + linearer Speicheraufwand O(n)
v3 v3 v1 + dfs gut, Rechenaufwand O(|V|+|E|)
v4
v1 v5
- Überprüfung Adjazenzeigenschaft O(|V|)
v5 v5 - manche Algorithmen komplexer
v3 v6 v6
v6

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

419 420

6.4 Topologisches Sortieren Interpretation durch gerichteten Graphen

Problem: Ausgehend von einer binären Beziehung Binäre Beziehung zwischen Elementen ist gerichtete
(z.B. „muß erledigt sein, bevor man weitermachen Kante zwischen entsprechenden Knoten
kann mit“) von Elementen ist zu klären, ob es eine Prof. Bumstead
Reihenfolge der Elemente gibt, ohne eine der
Beziehungen zu verletzen.
Unterhose
Beispiel: Socken
Professor Bumstead kleidet sich an Uhr
Hose Schuhe
Kleidungsstücke sind: Unterhose, Socken, Schuhe, Hosen,
Hemd
Gürtel, Hemd, Krawatte, Sakko, Uhr
Beziehung: Kleidungsstück A muss vor B angezogen Gürtel
werden Krawatte
Problem: Finde eine Ankleidereihenfolge damit sich Prof.
Bumstead anziehen kann. Sakko

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


421 422

Topologische Ordnung eines DAG Eine mögliche Vorgangsweise

Eine Topologische Ordnung eines gerichteten 1. Suche einen Knoten aus dem nur Kanten
azyklischen Graphs G (directed acyclic graph, DAG) hinausführen
ist eine lineare Anordnung aller Knoten, sodass 2. Ordne ihn in der topologischen Ordnung an
wenn G eine Kante <u, v> enthält, u vor v in der 3. Lösche ihn aus dem Graphen
Anordnung steht
4. Weiter bei 1.
Falls der Graph nicht azyklisch ist, gibt es keine
topologische Ordnung

Lösung Professor Bumstead

Socken Unterhose Hose Schuhe Uhr Hemd Gürtel Krawatte Sakko

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

423 424

Knotengrad induzierter Teilgraph

Eingangs- und Ausgangsgrad eines Knoten Ein Graph G’(V’, E’) heißt induzierter Teilgraph
indegree(v) mit v aus V: | { v' | <v', v> aus E} | (Untergraph) von G(V, E), wenn V’ Í V und
d.h. Anzahl der in v einmündenden Kanten E’=E∩{V’xV’}.
outdegree(v) mit v aus V: | { v' | <v, v'> aus E} |
V={v1, v2, v3, v4, v5, v6} V’ = V \ {v1} = {v2, v3, v4, v5, v6}
d.h. Anzahl der von v ausgehenden Kanten v1
v4 v4
v2 v2

Hose Hemd v5 v5
v3 v3
v6 v6
indegree: 1, outdegree: 2 indegree: 0, outdegree: 2

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


425 426

Algorithmus zum toplogischen Sortieren 6.5 Traversieren eines Graphen

lfdNr = 0; Unter dem Traversieren eines Graphen versteht man das


while (∃ v ∈ G: indegree(v) = 0) { systematische und vollständige Besuchen aller Knoten des
Graphen
lfdNr = lfdNr + 1;
Es lassen sich prinzipiell 2 Ansätze unterscheiden:
N[v] = lfdNr; Tiefensuche, dfs
G = induzierter Teilgraph von V\{v}; depth-first search - Traversierung
Breitensuche, bfs
} breadth-first search - Traversierung
if (V = {}) Über diese beiden Ansätzen lassen sich fast alle wichtigen
G ist azyklisch; // N enthält die topologische Ordnung für G Problemstellungen auf Graphen lösen, z.B.
Suche einen Weg vom Knoten v nach w?
else
Besitzt der Graph einen Zyklus?
G ist nicht azyklisch; // es existiert keine top. Ordnung Finde alle Komponenten?
...

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

427 428

Das „Königsberger Brücken“ Problem Abstraktion

Leonhard Euler, 1736 Frage: Gibt es einen Kreis im Graphen der alle Kanten genau
Die Stadt Königsberg (Kaliningrad) liegt an den Ufern und einmal enthält? A
auf 2 Inseln des Flusses Prigel und ist durch 7 Brücken
verbunden
A
C D

C D B

Euler löste das Problem, indem er bewies, dass so ein Kreis


B genau dann möglich ist, wenn der Graph zusammenhängend
Frage: Gibt es einen Weg auf dem ich die Stadt besuchen und der Knotengrad aller Knoten gerade ist Eulersche Graphen
kann, alle Brücken genau einmal überquere und an den Solche Graphen werden Eulersche Graphen genannt. werden als das erste
gelöste Problem der
Anfangspunkt zurückkehre? Für Kaliningrad gilt dies offensichtlich nicht. Graphentheorie angesehen

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


429 430

Beweisskizze Beweisskizze (2)

Satz: Damit so ein Kreis existieren kann, müssen alle Knoten geraden Graph erfüllt Bedingung, d.h. Kreis muss existieren
Knotengrad haben Laut Beweis entferne einen Kreis nach dem anderen, bis alle Kanten
Knoten muss einmal betreten und einmal verlassen werden entfernt sind, Kombination der Kreise liefert Lösung
Bedingung suffizient? Existiert immer ein Kreis?
Beweis durch Induktion A
A 1
A 2
Hypothese: verbundener Graph G mit < m Kanten, wobei alle Knoten geraden A A
Knotengrad besitzen, enthält einen Kreis, dessen Kanten genau einmal besucht C 5
werden C D C 4 D
C D D 7
Ansatz: Entferne einen Kreis P (gerader Knotengrad, gerade Anzahl von Kanten) aus
dem Graph, es bleibt ein Graph G‘ mit geraden Knotengrad zurück (weiteren Kreis C 6
entfernen usw.) B B B B 3
Problem: Graph könnte durch das Entfernen eines Kreises in Komponenten G‘ 1, G‘2, B
... G‘k zerfallen, jede Komponente erfüllt aber wieder Bedingung gerader
Knotengrad, d.h. Hypothese auf Komponenten ebenfalls anwendbar, ergibt k Aus der Regel für die Kombination der Kreise lässt sich ein
Kreise P1, P2, ... Pk entsprechender Algorithmus zum Finden eines Eulerschen Kreises
Kombination dieser Kreise zu Gesamtkreis, indem man bei beliebigem Knoten im ableiten
Kreis P beginnt und Kreis solange bis zu einem Knoten v j, verfolgt, der zu führt zur Problemstellung des Traversieren eines Graphen
Komponente G‘ j gehört. Von dort Verfolgung von entsprechenden Kreis P j

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

431 432

6.5.1 Depth-first Search Ansatz

Idee Algorithmus
Wir interpretieren den Graphen als rekursiver Ansatz, zu besuchende Knoten werden am Stack (Rekursion)
Labyrinth, wobei die Kanten Wege und vermerkt.
die Knoten Kreuzungen darstellen. “Zuerst in die Tiefe , danach in die Breite gehen”
void besuche-dfs ( Knoten x ) {
Beim depth-first search Ansatz versuchen wir einen
markiere Knoten x mit ‘besucht’;
möglichst langen neuen Pfad zurückzulegen. Wenn wir
for ( alle zu x adjazente nicht besuchte Knoten v )
keinen neuen Weg mehr finden, gehen wir zurück und
besuche-dfs ( v );
versuchen den nächsten Pfad. Rekursiver Ansatz
}
Wenn wir zu einer Kreuzung kommen, markieren wir sie (im
Markierung: Ein Feld mit den Knotenbezeichnungen als Index, initialisiert
Labyrinth durch einen Stein). Wir merken uns mögliche
mit ‘unbesucht’ (keine Steine).
Pfadalternativen.
Kommen wir zu einer markierten Kreuzung über einen noch Analogie
nicht beschrittenen Weg, gehen wir diesen Weg wieder Buch lesen, Detailinformation suchen, Sukkzessiver Lernansatz,
zurück (wir waren schon mal da). Entscheidungsbaum, Auswahlkriterien, etc.

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


433 434

Beispiel, dfs Methode dfs

v1 v2 v3 v4 v5 v6 dfs-Traversierung eines Graphen


v1 v1
Ausgehend vom Knoten v1 1.
2.
v4 Markierung u u u u u u v4
wird der Graph mit dem
dfs-Ansatz traversiert. v2
Adjazenzliste 6.
Besuchte Knoten 5.
v2 3.
werden auf einem Stack v3
v5
v4 v3 v2 (Rekursion) vermerkt.
v3 v1
Reihenfolge der Knoten eigentlich
v2 v3 v1
v5
Verhalten beliebig, abh. von der physischen 4.

v3 Speicherung des Graphen v6


v2 v1 des Stacks v4
v4 v3
v1 v2 v4 v5 v6 v3 v2
v6 v5 v5 v1 Schritt v1 1. 2. v5 3. v6 4. 5. 6.

v6 v4 v5 v6
v6 v4
v3 v3 v3 v3
v1 v2 v2 v2 v2 v2
v5

Push Pop

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

435 436

Beispiel, dfs (2) C++ - Code


#define besucht 1
v1 v2 v3 v4 v5 v6 #define unbesucht 0
// maxV defined elsewhere
besuche-dfs(1) b u u u u u
besuche-dfs(4) class node { public: int v; node *next;}
b u u b u u node *adjliste[maxV]; // Adjazenzliste
check 1 besucht
besuche-dfs(5)
int mark[maxV]; // Knotenmarkierung
b u u b b u
check 4 besucht void traversiere() {
besuche-dfs(6) b u u b b b int k;
check 5 besucht for(k = 0; k <= maxV; ++k) mark[k] = unbesucht;
besuche-dfs(3) b u b b b b for(k = 0; k <= maxV; ++k) if(mark[k]==unbesucht)
besuche-dfs(2) b b b b b b besuche-dfs(k);
check 1, 3 besucht }
check 1 besucht void besuche-dfs(int k) {
check 2 besucht node *t;
mark[k] = besucht;
for(t = adjliste[k]; t != NULL; t = t->next)
if(mark[t->v] == unbesucht)
dfs(t->v);
}

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


437 438

6.5.2 Breadth-first Search Algorithmus

Idee Iterativer Ansatz


Man leert einen Topf mit Tinte auf den zu besuchende Knoten werden in einer Queue gemerkt
Achtung: Da kein
Startknoten. Die Tinte ergießt sich in alle “Zuerst in die Breite , danach in die Tiefe gehen” Stack „automatisch“
zur Verfügung steht,
Richtungen (über alle Kanten) auf einmal muss eine geeignete
void besuche-bfs(Knoten x) { Datenstruktur zum
Beim breadth-first search Ansatz werden alle möglichen stelle (Enqueue) Knoten x in Queue; „Merken“ der zu
Alternativen auf einmal erforscht, über die gesamte Breite besuchenden Knoten
markiere Knoten x ‘besucht’; vorgesehen werden:
der Möglichkeiten while(Queue nicht leer) { Queue

Dies bedeutet, dass zuerst alle möglichen, von einem Knoten hole (Dequeue) ersten Knoten y von der Queue;
weggehenden, Kanten untersucht werden, und danach erst for(alle zu y adjazente nicht besuchte Knoten v) {
zum nächsten Knoten weitergegangen wird stelle (Enqueue) v in die Queue;
markiere Knoten v ‘besucht’;
Analogie } // for
Iterativer
Überblick über Buch verschaffen, Generelle Information } // while Ansatz
suchen, Hierarchischer Lernansatz, Auswahlüberblick, etc. }
VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

439 440

Beispiel, bfs Methode bfs

v1 v2 v3 v4 v5 v6 bfs-Traversierung eines Graphen v1 2.


v1 1.
Ausgehend vom Knoten v1 wird v4
v4 Markierung u u u u u u
der Graph mit dem v2
bfs-Ansatz traversiert 4.
3.
Adjazenzliste 5.
v2
Besuchte Knoten werden in v3
v5
einer Queue vermerkt
v4 v3 v2
v1
Verhalten der Queue
v3 6.
v2 v3 v1
v6
v5
v3 Schritt 1. v2 2. 3. 4. 5. 6.
v2 v1
v1 v3 v5
v4 v6
v4
v6 v5 v5 v1 v2 v5
v3 v2 v5
v6 v1 v2 v5 v6
v6 v4 v4 v3

v5 v1 v4 v3 v2 v5 v6

Enqueue Dequeue

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


441 442

Beispiel, bfs (2) C++ - Code


#define besucht 1
#define unbesucht 0
besuche-bfs(1) // maxV defined elsewhere ,mark initialized „unbesucht“
v1 v2 v3 v4 v5 v6
Enqueue(1), Dequeue(1)
Enqueue(4,3,2) class node { public: int v; node *next;}
b u u u u u node *adjliste[maxV]; // Adjazenzliste
Dequeue(4) int mark[maxV]; // Knotenmarkierung
Enqueue(5) b u u b u u Queue queue(maxV);
check 1 besucht
Dequeue(3) b u b b u u void besuche-bfs(int k) {
check 2,1 besucht node *t;
Dequeue(2) b b b b u u queue.Enqueue(k);
check 3,1 besucht mark[k]= besucht;
Dequeue(5) b b b b b u while(!queue.IsQueueEmpty()) {
Enqueue(6)
k = queue.Dequeue();
b b b b b b
for(t = adjliste[k]; t != NULL; t = t->next)
check 4 besucht if(mark[t->v] == unbesucht) {
Dequeue(6) queue.Enqueue(t->v); mark[t->v] = besucht;
check 5 besucht }
}
}
}

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

443 444

Aufwand von dfs und bfs Schichtenkonzept zur Problemlösung

Aufwandsabschätzung abhängig von der


Anwendungsebene:
Speicherungsform des Graphen Beispiele
Bestimmend Aufwand für das Finden der adjazenten Knoten - günstigste Weg von a nach b
- gute Züge in einem Spiel
Adjazenzliste
dfs und bfs: O (|V| + |E|)
Werkzeugebene:
Jeder Knoten wird einmal besucht, Adjazenzlisten werden Beispiele
iterativ abgearbeitet - Graphdurchquerung von v1 nach v2
Bei vollständig verbundenen Graphen O ( |V2| ), da jeder Knoten - Topologische Anordnung
|V|-1 Kanten besitzt, d.h. |E| » |V2|
Adjazenzmatrix Implementationsebene:
dfs und bfs: O ( |V|2 ) Beispiele
- Rekursive Traversierung
Aufwand zum Finden der adj. Nachfolger eines Knoten - Iterative Traversierung
O( |V| )
VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta
445 446
6.5.3 Das “Bauer, Wolf, Ziege und Kohlkopf”-
Lösungsskizzen
Problem
Beispiele Klassisches Problem
Weg von Knoten x nach y finden Ein Bauer möchte mit einem Wolf, einer Ziege und einem
Von x ausgehend Graph traversieren bis man zu y kommt (d.h. y Kohlkopf einen Fluss überqueren. Es steht ihm hierzu ein
markiert wird).
kleines Boot zur Verfügung, in dem aber nur 2 Platz
Beliebigen Kreis im ungerichteten Graph finden
haben.
Von jedem Knoten Traversierung des Graphen starten. Kreis ist
gefunden, falls man zu einem markierten Knoten kommt (man war Weiters stellt sich das Problem, dass nur der Bauer rudern
schon einmal da). kann, und der Wolf mit der Ziege und die Ziege mit dem
Beliebigen Kreis im gerichteten Graph finden Kohlkopf nicht allein gelassen werden kann, da sonst der
Von jedem Knoten Traversierung des Graphen starten. Kreis ist eine den anderen frisst.
gefunden, falls man zu einem markierten Knoten kommt. Wichtig:
Gesetzte Markierungen müssen beim Zurücksteigen wieder Es soll eine Transportfolge gefunden
gelöscht werden. werden, dass alle ‘ungefressen’ das
… andere Ufer erreichen.

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

447 448

Kodierung des Problems (1) Kodierung des Problems (2)

Das Problem wird durch einen Graphen dargestellt, wobei Eine Bootsfahrt (Kante) gibt an, wer im Boot übersetzt, d.h. führt eine
die Knoten die Positionen der zu Transportierenden und Position in die nächste über, d.h
die Kanten die Bootsfahrten repräsentieren.
linkes Ufer rechtes Ufer
Eine Position (Knoten) definiert, wer auf welcher Seite des Flusses Position 1
ist, Wolf Fluss Bauer
linkes Ufer rechtes Ufer
R L L R Kohlkopf Ziege
Wolf Fluss Bauer
Kohlkopf Ziege
Wolf Bauer Ziege
Dieses ist eine ‘sichere’ Position, da niemand gefressen wird. Bootsfahrt Kohlkopf
Eine Position kann in einem 4 elementigen Vektor kodiert werden,
wobei jedem der 4 zu Transportierenden ein Vektorelement
zugeordnet ist und L das linke Ufer bzw. R das rechte bezeichnet, linkes Ufer rechtes Ufer
d.h. der obigen Position entspricht der folgende Vektor Position 2
Bauer Fluss Ziege
Bauer Wolf Kohlkopf Ziege L L L R Wolf
R L L R Kohlkopf

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


449 450

Problemrepräsentation Lösung

Der gesamte Problembereich lässt sich somit durch einen Lösungsweg


Graphen darstellen, wobei die Positionen durch die Knoten Kodierung:
(Bauer, Wolf, Kohlkopf, Ziege)
und die Bootsfahrten durch die Kanten repräsentiert werden, Startposition
z.B. (Ausschnitt) L L L L

L L L R L L L R
L L L L
R L L R

R L L R R R L R
R L R R
R L R R
R R L R
L R L L
L L R L
Die Lösung wird somit durch einen Weg bestimmt, der von der
Anfangsposition (alle 4 auf dem linken Ufer = LLLL ) zu der R R R L
Endposition (alle 4 auf dem rechten Ufer = RRRR ) führt. Endposition

Dies lässt sich durch eine simple Traversierung des R R R R


Graphen lösen. L R R L

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

451 452

C-Programm Hilfsfunktionen

Wir wählen einen bfs-Ansatz (iterativ, mit Hilfe einer Queue) int Bauer(int Ort) {return 0 != (Ort & 0x08);}
int Wolf(int Ort) {return 0 != (Ort & 0x04);}
Die Position wird in einer integer Variable binär (stellenwertig) kodiert int Ziege(int Ort) {return 0 != (Ort & 0x02);}
Bauer 3. Bit, Wolf 2. Bit, Kohlkopf 1. Bit, Ziege 0.Bit, wobei 0 linkes Ufer und int Kohl(int Ort) {return 0 != (Ort & 0x01);}
1 rechtes Ufer bedeutet int sicher(int Ort) {
Die Funktionen ‘Bauer’, ‘Wolf’, ‘Kohl’ und ‘Ziege’ liefern die aktuelle if((Ziege(Ort) == Kohl(Ort)) &&
Position zurück. (Ziege(Ort) != Bauer(Ort))) return 0;
if((Wolf(Ort) == Ziege(Ort)) &&
Die Funktion ‘sicher’ bestimmt, ob eine Position sinnvoll ist, d.h. niemand (Wolf(Ort) != Bauer(Ort))) return 0;
wird gefressen. return 1;
}
‘DruckeOrt’ dient zur verständlichen Ausgabe der Positionen.
In der Queue ‘Zug’ werden die zu besuchenden Knoten vermerkt. void DruckeOrt(int Ort) {
cout << ((Ort & 0x08) ? "R " : "L ");
Der beschrittene Weg (Traversierung) wird im Feld ‘Weg’ gespeichert cout << ((Ort & 0x04) ? "R " : "L ");
(max. 16 Positionen). cout << ((Ort & 0x02) ? "R " : "L ");
C-Spezialitäten 0x08 Hexadezimaldarstellung einer Zahl cout << ((Ort & 0x01) ? "R " : "L ");
cout << endl;
^ bitweise exklusives Oder, XOR }
<< Linksshift Operator

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


453 454

Traversierung 6.6 Minimaler Spannender Baum


void main() { Den Kanten des Graphen G(V, E) ist ein Wert zugeordnet
Queue<int> Zug;
int Weg[16]; Wie wird aus (Netzwerk). Ein Minimaler Spannender Baum MSB ist ist ein
for(int i = 0; i < 16; i++) Weg[i] = -1; diesem bfs spannender Teilgraph, dessen Summe der Kantenwerte
Zug.Enqueue(0x00);
while(!Zug.IsEmpty()) { Ansatz ein dfs minimal ist.
int Ort = Zug.Dequeue(); Ansatz?
Für jede Kante [u, v] Î E existiert ein Gewicht w(u, v), welches die Kosten
for (int Pers = 1; Pers <= 8; Pers <<= 1) {
int nOrt = Ort ^ (0x08 | Pers); der Verbindung angibt
if(sicher(nOrt) && (Weg[nOrt] == -1)) { Ziel: Finde eine azyklische Teilmenge T Í E, die alle Knoten verbindet
Weg[nOrt] = Ort; und für die gilt, w(T) = Σ(u,v) ÎT w(u, v) ist ein Minimum
Zug.Enqueue(nOrt);
} Beispiel:
} Verdrahtungsproblem in einem elektronischen Schaltplan
}
cout << "Weg:\n"; Alle Pins müssen untereinander verdrahtet werden, wobei die
for(int Ort = 15; Ort > 0; Ort = Weg[Ort]) DruckeOrt(Ort); Drahtlänge minimal sein soll
cout << '\n'; d.h. V ist die Menge der Pins, E die Menge der möglichen Verbindungen
}
zwischen Pin-Paaren, w(u,v) Drahtlänge zwischen Pin u und v

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

455 456

Beispiel: Minimaler Spannender Baum Generischer MSB Algorithmus

Ansatz durch Greedy Algorithmus


8 7 1. Algorithmus verwaltet eine Menge A von Kanten, die immer eine
B C D Teilmenge eines möglichen MSB sind
4 9 2. MSB wird schrittweise erzeugt, Kante für Kante, wobei für jede Kante
2 überprüft wird, ob sie zu A hinzugefügt werden kann, ohne Bedingung
1 zu verletzen
A 11 14 So eine Kante heißt „sichere Kante“ (safe edge)
I 4 E
7 6 Wie finde ich so
Generic-MSB(G, w) {
8 10 eine sichere
A = {};
Kante?
while (A bildet keinen MSB) {
H G F
finde eine Kante [u,v] die für A "sicher" ist
1 2
A = A È { [u,v] }
Gewicht des MSB: 37 }
MSB ist nicht eindeutig, Kante [B, C] könnte durch [A, H] ersetzt werden }

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


457 458

6.6.1 Kruskal Algorithmus Kruskal Algorithmus (2)

Grundidee: MSB-Kruskal(G(V, E), w) {


A = {};
1. Die Menge der Knoten repräsentiert einen Wald for (jeden Knoten v Î V)
bestehend aus |V| Komponenten make-set(v);
an Beginn keine Kante sortiere die Kanten aus E nach aufsteigendem Gewicht w
for(jede Kante [u,v]ÎE in der Reihenfolge der Gewichte)
2. Die sichere Kante, die hinzugefügt wird, ist immer if(find-set(u) != find-set(v)) {
die Kante mit dem niedrigsten Gewicht, die zwei A = A È { [u,v] }
unterschiedliche Komponenten verbindet union(u, v)
} w enthält die Gewichte zwischen den Knoten, z.B.
Greedy Ansatz Gewicht zwischen u und v = w(u,v)
return A; make-set(v) erzeugt eine Baum mit Knoten v
in jedem Schritt wird die Kante mit niedrigstem Gewicht zum } find-set(v) liefert ein repräsentatives Element für
Wald hinzugefügt die Menge die v enthält
union vereinigt 2 Bäume zu einem Baum

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

459 460

Beispiel: Kruskal Algorithmus Mengenoperationen für Kruskal


1 B
8
C
7
D 5 B
8
C
7
D
9 B
8
C
7
D
make-set(x) { union(x, y) {
4 2 9 4 9 4 9
2 2 p[x] = x; link(find-set(x), find-set(y));
A 11 I 4 14 E A 11 14 11
I 4 E A I 4 14 E
7 6 7 6 7 6
rank[x] = 0; }
8 10 8 10 8 10
H G F H G F F }
1 2 1 2 H
1
G
2 p[x] enthält den Elternknoten
2 7 6 10 link(x,y) {
B
8
C D B
8
C
7
D B
8
C
7
D von x (Vertreter der Teilmenge)
4 2 9 4 2 9 4 2 9 if (rank[x] > rank[y]) p[y] = x; rank[] ist eine obere Grenze
11
A I 4 14 E A 11 I 4 14 E A 11 I 4 14 E else { der Höhe von x (Anzahl der
7 6 7 6 7 6
8 10 8
H G F
10 8 10 p[x] = y; Kanten zwischen x und einem
H G F H G F
1 2 1 2
3
1 2
if (rank[x] = rank[y]) Nachfolger-Blatt a
B
8
C
7
D 7 B
8
C
7
D 11 8 7
find-set(v) sucht die Wurzel
4 2 9 4 9 4
B C D
9
rank[y] = rank[y] + 1;
2 2
A 11 I 4 14 E A 11 I 4 14 E A 11 14
} und trägt sie danach jedem
I 4 E
8
7 6
10 8
7 6
10 8
7 6 } Knoten als Elternknoten ein
10
H G F H G F F
1 2 1 2 H
1
G
2 find-set(x) {
4 B
8
C
7
D 8 B
8
C
7
D 12 B
8
C
7
D if(x != p[x]) p[x] = find-set(p[x]);
4 2 9 4 9 4 9
2 2
A 11 14 11
return p[x];
I 4 E A I 4 14 E A 11 I 14 E
4
8
7 6
10 8
7 6 7 6 }
10 8 10
H G F H G F F
1 2 H G
1 2 1 2

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


461 462

6.6.2 Prim Algorithmus Prim Algorithmus

MSB-Prim(G(V,E), w, r) {
Grundidee: Q ist eine Priority Queue die alle Knoten
Q = V;
1. Die Menge A bildet einen einzelnen Baum for(jeden Knoten u Î Q) entsprechend ihres key Wertes speichert
key[v] ist das minimale Gewicht der
key[u] = ¥;
2. Die sichere Kante, die hinzugefügt wird, ist immer key[r] = 0;
Kante die v mit einem Knoten im Baum
die Kante mit dem niedrigsten Gewicht, die den verbindet
pred[r] = NIL;
r ist die Wurzel (Startknoten) des MSB
Baum mit einem Knoten verbindet, der noch nicht while(Q != {}) { pred(v) speichert den Vorgänger von v
u = Extract-Min(Q)
im Baum ist
for(jeden Knoten v adjazent zu u)
Greedy Ansatz if(v Î Q && w(u,v) < key[v]) {
pred[v] = u;
key[v] = w(u,v);
}
}
}

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

463 464

Beispiel: Prim Algorithmus Aufwand

Aufwand der Algorithmen stark abhängig von der Implementation


1 B
8
C
7
D 4 B
8
C
7
D
7 B
8
C
7
D
der Mengenoperationen bzw. der Datenstrukturen für die
4 9 4 9

A 11 I
2

4 14 E A 11
2

14 A
4

11
2 9
Mengenverwaltung (Priority Queue, ...)
I 4 E I 4 14 E
7 6
8
H G F
10 8
7 6

F
10 8
7 6
10 Kruskal: Im günstigsten Fall O(E log E)
2 H G H G F
1 1 2 1 2
2 8 7 5 8 7 8 7
Initialisierung O(V)
B C D B C D 8
B C D
4 2 9 4 2 9 4 2 9 Kanten sortieren O(E log E)
A 11 I 4 14 E A 11 14 11
I E A
8
7 6 7 6
4
7
I
6
4 14 E
O(E) mal disjunkte Teilmengen finden O(E log E)
10 8 10 8 10 Lässt sich durch Fibonacci-
H
1
G
2
F H
1
G
2
F H
1
G
2
F
Prim: Im günstigsten Fall O(E log V) Heap verbessern auf
3 8 7 6 8 7 9 8 7 O(E + V log V)
4
B
2
C D
9 4
B C D
9 4
B C D
9
PQ als Heap, d.h. Aufbau O(V log V)
2 2
A 11 I 4 14 E A 11 I 4 14 E A 11 I 4 14 E while Schleife |V| mal, Extract-Min O(log V), d.h. O(V log V)
7 6 7 6 7 6
8
H G F
10 8
H G F
10 8
F
10 For Schleife O(E) mal, key verändern in PQ O(log V), d.h. O(E log V)
1 2 H G
1 2 1 2
Summe beider Schleifen O(E log V + V log V) = O(E log V)

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


465 466

6.7 Kürzeste Wege Beispiel: Streckennetz einer Fluglinie

Gewichte zwischen Knoten können als Weglängen Annahme: nur positive Kantenwerte
oder Kosten angesehen werden Manche Algorithmen funktionieren nur mit positiven Werten

Es ergibt sich oft die Fragestellung nach dem (der) 1


kürzesten Weg(e) zwischen 100
10
• Einem Knoten und allen anderen Knoten 30 5
2
• Zwei Knoten
• Zwischen allen Knoten 60
50 10
Annahme: alle Kosten sind gespeichert in der
Kostenmatrix C (C[u,v] enthält Kosten von u nach v) 3 4
20

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

467 468
6.7.1 Dijkstra Algorithmus
Dijkstra Algorithmus
Single Source Shortest Paths
Algorithmus zur Suche des kürzesten 1
10 S = { 1 };
Weges von einem Startknoten zu allen
2 for ( i = 2; i <= |V|; i++ )
anderen Knoten 30
MinC[i] = C[1, i];
Idee while ( | V \ S | ) > 1) {
Ausgehend vom Startknoten werden beginnend 4 Akt = Knoten aus V \ S, sodaß MinC[Akt] = Minimum;
mit dem kürzesten Weg zu einem Knoten, 20 S = S È { Akt };
die nächst-längeren Wege zu allen anderen 50 100 for (jeden Knoten v1 aus V \ S)
Knoten gesucht und die kürzesten Wege für 3
MinC[ v1 ] = MIN (MinC[ v1 ], MinC[Akt] + w[Akt, v1]);
die entsprechenden Knoten vermerkt. 10
}
Ähnlich Prim‘s Algorithmus auf der Basis eines 5
bfs mit Prioritätsfunktion der Weglänge S Menge der bereits bearbeiteten Knoten
60 Akt Knoten, der gerade bearbeitete wird
3
C Kostenmatrix
10
MinC bisher bekanntester kürzester Weg
5
5
5
VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta
469 470

Berechnung 6.7.2 All Pairs Shortest Paths

Bevor wir die Fragestellung der kürzesten Wege


1
10
100 zwischen allen Knoten klären, wollen wir zuerst die
30 5 (einfachere) Frage behandeln, zwischen welchen
2 Knoten existieren überhaupt Wege
Führt zu 2 Algorithmen
50 60
10 Warshall: welche Knoten sind durch Wege verbunden
S Akt MinC
{1} - [/, 10, ∞, 30, 100] Floyd: alle kürzesten Wege zwischen den Knoten
{1,2} 2 [/, 10, 60, 30, 100] 3 4
{1,2,4} 4 [/, 10, 50, 30, 90] 20
{1,2,3,4} 3 [/, 10, 50, 30, 60]

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

471 472

Transitive Hülle Warshall Algorithmus

Fragestellung welche Knoten durch Wege verbunden Idee


(erreichbar) sind führt zur Frage nach der Iteratives Hinzufügen von Kanten im Graphen für Pfade der
Transitiven Hülle Länge 2
1. i k j a
d.h. Pfad (i,k) und (k,j) wird durch
Ein gerichteter Graph G‘(V, E‘) wird transitive (und neue Kante (i,j) beschrieben
reflexive) Hülle eines Graphen G(V, E) genannt, 2. i k j a
in weiterer Folge wird dann natürlich
genau dann wenn: auch Pfad (i,j) und (j,a) als Pfad der
Länge 2 gefunden (in Wirklichkeit 3. i k j a
(v, w) Î E‘ Û es existiert ein Pfad von v nach w in G klarerweise Pfad der Länge 3), usw.
Führt dazu, dass die neuen Kanten immer längere Pfade
beschreiben, bis alle möglichen Pfade gefunden sind
Ausgangspunkt: Adjazenzmatrix von G Ansatz durch 3 verschachtelte Schleifen, ähnlich der
Matrizenmultiplikation

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


473 474

Warshall Algorithmus (2) Beispiel: Warshall (1)

warshall (Matrix a) {
n = a.numberofRows(); a Adjazenzmatrix
bei a als Bit-Matrix 0 4 2 3 1
for(int k = 0; k < n; k++) | binärer OR Operator
for(int i = 0; i < n; i++) & binärer AND Operator
for(int j = 0; j < n; j++)
a[i,j] = a[i,j] | a[i,k] & a[k,j]; 0 1 2 3 4 0 1 2 3 4
} 0 0 0 0 0 1 0 0 1 1 1 1
1 0 0 0 0 0 1 0 0 0 0 0
Fügt Pfad als neue True (1), falls Weg
Kante (falls sie noch zwischen i und j 2 0 0 0 1 0 2 0 1 0 1 0
nicht existiert) in über k existiert
den Graphen ein 3 0 1 0 0 0 3 0 1 0 0 0
4 0 0 1 0 0 4 0 1 1 1 0

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

475 476

Beispiel: Warshall (2) Floyd Algorithmus

Werte für K (Durchläufe äußere Schleife):


0: keine Kante, da a(?,0) nicht möglich
Berechnung der kürzesten Wege zwischen allen
1: keine Kante, da a(1,?) nicht möglich Knoten ist simpel aus dem Warshall Algorithmus
4: a(0,4), a(4,1) ⇒ a(0,1)
2: Kante a(4,2), a(2,3) 3: a(2,3), a(3,1) ⇒ a(2,1) a(0,4), a(4,2) ⇒ a(0,2)
ableitbar
⇒ a(4,3) a(4,3), a(3,1) ⇒ a(4,1) a(0,4), a(4,3) ⇒ a(0,3) Wird wie Treesort Floyd zugeschrieben
Unterschied
0 4 2 3 1 0 4 2 3 1 0 4 2 3 1
Adjazenzmatrix speichert die Weglängen zwischen den
Knoten (entspricht der Kostenmatrix)
0 1 2 3 4 0 1 2 3 4 0 1 2 3 4 Statt 0/1 Werte die Wegkosten
0 0 0 0 0 1 0 0 0 0 0 1 0 0 1 1 1 1
Beim Feststellen eines Pfades über 2 Kanten einfache
1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0
2 0 0 0 1 0 2 0 1 0 1 0 2 0 1 0 1 0
Berechnung der Weglänge dieser neuen Kante und
3 0 1 0 0 0 3 0 1 0 0 0 3 0 1 0 0 0 Vergleich mit aktueller Weglänge (falls schon vorhanden)
4 0 0 1 1 0 4 0 1 1 1 0 4 0 1 1 1 0 Statt logisches AND die Berechnung der Kostensumme

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


477 478

Floyd Algorithmus (2) Beispiel: Floyd

floyd (Matrix a) {
n = a.numberofRows(); 8 2
for(int k = 0; k < n; k++) 0 1 2
3
for(int i = 0; i < n; i++)
5
for(int j = 0; j < n; j++) {
int newPathLength = a[i,k] + a[k,j];
if(newPathLength < a[i,j])
a[i,j] = newPathLength;
Berechnung der 0 1 2 0 1 2
}
Weglänge über
} neuen Pfad 0 0 8 5 0 0 7 5
Eintrag in die Kostenmatrix,
falls neuer Weg kürzer als 1 3 0 ¥ 1 3 0 8
möglicherweise vorhandener
alter Weg 2 ¥ 2 0 2 5 2 0

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

479 480

Beispiel: Floyd (2) 6.8 Genereller iterativer Ansatz

Ausgangsposition k: 0 Genereller iterativer Ansatz zur Traversierung eines


Kanten: (1,0) (0,2) ⇒ (1,2), Kosten: 8
0 1 2
Graphen mit Hilfe 2 (simpler) Listen
8 2 8 0 1 2
2
0 1 2
0 0 8 5
0 1 2 OpenList
3 3 8 0 0 8 5
1 3 0 ¥
Speichert bekannte aber noch nicht besuchte Knoten
1 3 0 8
5
2 ¥ 2 0
5
2 ¥ 2 0
CloseList
Speichert alle schon besuchten Knoten
k: 1 k: 2 Expandieren eines Knoten
(0,1) (1,2) ⇒ (0,2): 16 (0,2) (2,0) ⇒ (0,0): 10
(2,1) (1,0) ⇒ (2,0): 5 (0,2) (2,1) ⇒ (0,1): 7 Generieren der Nachfolger eines Knoten
(2,1) (1,2) ⇒ (2,2):10 (1,2) (2,0) ⇒ (1,0): 13 d.h. OpenList enthält alle generierten (bekannten), aber
0 1 2
0
8
1
2
2 0
7
1
2
2
0 1 2 noch nicht expandierten Knoten, CloseList alle
3 8 0 0 8 5
3 8 0 0 7 5 expandierten Knoten
1 3 0 8
5
2 5 2 0
5
1 3 0 8
Ohne weitere Steuerung Traversierungsansatz
2 5 2 0
5 5 unsystematisch
VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta
481 482

Unsystematische Traversierung Beispiel (F)

Search(Knoten v) {
OpenList = [v]; 0
CloseList = []; 1 5 3
while (OpenList != []) {
Akt = beliebigerKnotenAusOpenList; // ??? 4 2
OpenList = OpenList \ [Akt];
Es werden alle Knoten
CloseList = CloseList + [Akt]; besucht, die vom
process(Akt); // whatever to do 8 Startknoten aus
for(alle zu Akt adjazente Knoten v1){ 7 6 erreichbar sind.
Unterschied gerichteter –
if (v1 ∉ OpenList && v1 ∉ CloseList) ungerichtetere Graph?
z.B.: Search(5)
OpenList = OpenList + [v1];
OpenList: 5|3,4|4,0|0,2,8|2,8|8|
} CloseList: 5,3,4,0,2,8
} Akt: 5|3|4|0|2|8
}

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

483 484
6.8.1 Zusammenhangskomponente im
Zusammenhangskomponente
ungerichteten Graphen
Erweiterung von Search SearchAndMark(Knoten v; int Knum) {
OpenList = [v];
Feld zum Vermerken der Komponenten K[ |V| ] CloseList = [];
int Vanz = |V|;
while (OpenList != []) {
int Knum = 0;
for (int i = 0; i < Vanz; i++) Akt = beliebigerKnotenAusOpenList;
if(K[i] == 0) { OpenList = OpenList \ [Akt];
Knum = Knum + 1; CloseList = CloseList + [Akt];
SearchAndMark(i, Knum); K[Akt] = Knum;
} for(alle zu Akt adjazente Knoten v1){
if (v1 ∉ OpenList && v1 ∉ CloseList)
SearchAndMark(Knoten v; int Knum) { OpenList = OpenList + [v1];
neue Version von Search wobei }
process(Akt); entspricht K[Akt] = Knum; }
} }

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


485 486

Beispiel (F) Systematisierung der Traversierung

Systematische Traversierung schon bekannt


0
1 5 3 Tiefensuche dfs
Breitensuche bfs
4 2 Unklarer Programmteil
Frage: beliebigerKnotenAusOpenList
Was wäre Systematisierung durch Organisation der Auswahl
8 bei einem
7 6 gerichteten Aufbau der Liste
Graphen? Position des einzufügenden Elements in der Liste
bfs: OpenList = OpenList + [v1]; am Ende
OpenList: 5|1,3,4|3,4|4,0|0,2,8|2,8|2|6|7
K dfs: OpenList = [v1] + OpenList; am Anfang
CloseList: 5,1,3,4,0,2,8|6,7
Akt: 5|1|3|4|0|2|8|6|7 0 1 2 3 4 5 6 7 8
Zugriff auf die OpenList
1 1 1 1 1 1 2 2 1
Zugriff: First(OpenList); Zugriff immer auf das erste Element

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

487 488

Systematische Traversierung Beispiel (F)

Search(Knoten v) {
OpenList = [v]; 0
CloseList = []; 1 5 3
while (OpenList != []) {
Akt = First(OpenList);
OpenList = OpenList \ [Akt]; 4 2
CloseList = CloseList + [Akt];
process(Akt);
for(alle zu Akt adjazente Knoten v1){ 8
7 6
if (v1 ∉ OpenList && v1 ∉ CloseList)
dfs: OpenList = [v1] + OpenList;
bfs: OpenList = OpenList + [v1]; z.B.: Search(5) mit dfs z.B.: Search(5) mit bfs
} OpenList: 5|3,4|0,4|4|2,8|8| OpenList: 5|3,4|4,0|0,2,8|2,8|8|
} CloseList: 5,3,0,4,2,8 CloseList: 5,3,4,0,2,8
Akt: 5|3|0|4|2|8 Akt: 5|3|4|0|2|8
}

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


489 490
6.8.2 Dijkstra Algorithmus mit OL/CL
Noch ein kleines Problem
Kürzester Weg von S nach Z
OpenList = [S]; CloseList = [];
Systematisierung noch nicht ganz vollständig while (true) {
Anweisung if ( OpenList == [] ) return –1 // war nix!
Akt = ElementAusOpenList, sodass Akt.c = min;
for(alle zu Akt adjazente nicht besuchte Knoten v1){
if (Akt = Z) return Akt.c;
führt zu undefinierter Reihenfolge aller adjazenter OpenList = OpenList \ [Akt];
CloseList = CloseList + [Akt];
Knoten bei der Weiterbearbeitung for (jeden Knoten v1 adjazent zu Akt) {
Reihenfolge definiert durch die interne Graphenspeicherung if ( v1 Ï OpenList && v1 Ï CloseList ) {
Adjazenzliste, Adjazenzmatrix v1.c = Akt.c + C[Akt, v1];
OpenList = OpenList + [v1];
Annahme: adjazente Knoten werden aufsteigend } else {
v.c Speichert die Länge
sortiert eingetragen if (v1 Î OpenList)
des aktuell kürzesten
if (Akt.c + C[Akt,v1] < v1.c) Weges vom Startknoten
v1.c = Akt.c + C[Akt,v1]; zum Knoten v
}
}

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta

491 492

Beispiel (F) Beweisskizze

Satz: Falls ein Knoten v bereits in der CloseList ist, kann es


Gesucht: kürzester Weg von 1 nach 5 keinen günstigeren Pfad vom Startknoten nach v geben als
jenen, der bereits berechnet wurde
OpenList: 1 d.h. nochmals besucht Knoten, die schon in der CloseList sind, können
1|2,4,5|5,3|5| 100 einen Pfad nicht verkürzen
10
CloseList: Annahme: K in CloseList und Akt.c + C(Akt, K) < K.c
1,2,4,3 30 5
Akt: 2 In dem Schritt, als K aus der OpenList in die Akt
1|2|4|3|5 CloseList gebracht wurde, galt offenbar C(Akt,K)
K.c £ Akt.c Ú K.c £ pred(Akt).c S
c:
50 60 pred(Akt) bezeichnet einen Vorgänger von Akt
1 2 3 4 5 10 K
0 10 60 30 100 Es gilt aber auch pred(Akt).c < Akt.c, somit also
50 90 3 4
K.c £ Akt.c Ú K.c £ pred(Akt).c < Akt.c ⇒ K.c £ Akt.c
60
20 Widerspruch: es gibt keine positiven Akt.c, C(Akt, K), K.c,
sodass diese Ungleichung gilt

VO Algorithmen und Datenstrukturen E. Schikuta VO Algorithmen und Datenstrukturen E. Schikuta


493

Was nehmen wir mit?

Graphen
Definitionen
Gerichtete und ungerichtete Graphen
Topologisches Sortieren
Traversierung
Bfs und dfs
„Bauer, Wolf, Ziege du Kohlkopf“ Problem
Spannende Bäume
Kürzeste Wege
Generell iterativer Ansatz

VO Algorithmen und Datenstrukturen E. Schikuta