pdf, 387 KB
pdf, 387 KB
pdf, 387 KB
Sie wollen auch ein ePaper? Erhöhen Sie die Reichweite Ihrer Titel.
YUMPU macht aus Druck-PDFs automatisch weboptimierte ePaper, die Google liebt.
Algorithmen und Datenstrukturen<br />
4. Semester Wirtschaftsinformatik<br />
SS 2010<br />
Prof. Dr. Heinrich Paessens<br />
0. Begriffe<br />
1. Einführung<br />
1.1 Beispiele für Algorithmen<br />
- Verschiedene Algorithmen für dasselbe Problem<br />
- Entwurfstechniken für Algorithmen<br />
1.2 Typen von Lösungsverfahren (Optimierungsprobleme)<br />
1.3 Algorithmenkomplexität<br />
1.4 Problemkomplexität<br />
2. Lineare Datenstrukturen<br />
2.1 Eindimensionale Felder<br />
2.2 Speicherung linearer Felder<br />
2.3 Stapel, Rekursionen und Schlangen<br />
2.4 Mehrdimensionale Felder<br />
3. Komplexe Datenstrukturen<br />
3.1 Graphen - Definitionen<br />
3.2 Darstellung von Problemen durch Graphen<br />
3.3 Speicherung von Graphen<br />
4. Graphenalgorithmen<br />
4.1 Kürzeste Wege Algorithmen<br />
4.1.1 Dijkstra-Algorithmus<br />
4.1.2 Ford-Algorithmus<br />
4.1.3 Tripel-Algorithmus<br />
4.1.4 Bellman-Algorithmus (Typ A)<br />
4.1.5 Topologisches Sortieren - Bellman-Algorithmus (Typ B)<br />
4.2 Bestimmung von Minimalgerüsten<br />
5. Bäume<br />
5.1 Binärbäume - Speicherung, Durchsuchen von Binärbäumen<br />
5.2 Binäre Suchbäume<br />
5.3 Heapsort<br />
6. Spezielle Algorithmen und praktische Anwendungsbeispiele<br />
Literatur:<br />
CORMEN,T.H.; LEISERSON,C.E.; RIVEST,R.; STEIN,C.: Algorithmen - Eine Einführung.<br />
Oldenbourg Verlag<br />
DOMSCHKE, W.: Logistik I. Transport. Oldenbourg Verlag<br />
DOMSCHKE, W.: Logistik II: Rundreisen und Touren. Oldenbourg Verlag<br />
HERRMANN, D.: Algorithmen Arbeitsbuch. Addison Wesley Verlag<br />
OTTMANN, T.; WIDMAYER, P.: Algorithmen und Datenstrukturen. Informatik Bd. 70,<br />
BI Wissenschaftsverlag<br />
SEDGEWICK, R.: Algorithmen. Addison Wesley Verlag<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 1 von 75
0. BEGRIFFE<br />
INFORMATION:<br />
Zweckgerichtetes, neues Wissen<br />
Darstellung von Informationen:<br />
- a, b, c... -> Text<br />
- 1, 2, 3... -> Zahlen<br />
- Bilder, Symbole, Farben, Worte, Ton<br />
DATEN:<br />
NACHRICHT:<br />
Informationen in einer Darstellung, die zur weiteren<br />
Verarbeitung geeignet ist<br />
Information zum Zwecke der Weitergabe<br />
früher:<br />
DV (Datenverarbeitung): Verarbeitung von Daten mit Hilfe von<br />
Algorithmen, Methoden etc. zu neuen Daten<br />
EDV:<br />
IV:<br />
heute:<br />
IT:<br />
Elektronische DV<br />
Informationsverarbeitung<br />
Informationstechnologie<br />
INFORMATIK (informatique, computer science):<br />
Wissenschaft, die sich mit der systematischen und automatischen Verarbeitung,<br />
Speicherung und Übertragung von Informationen befasst<br />
Vereinigungen:<br />
Deutschland: Gesellschaft für Informatik (GI)<br />
http://www.gi-ev.de<br />
USA: Association for Computing Machinery (ACM)<br />
http://www.acm.org (-> digitale Bibliothek)<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 2 von 75
Gegenstände der Informatik<br />
Informatik<br />
Informationstechnik<br />
Informatik-<br />
Anwendungen<br />
Informatik-<br />
Auswirkungen<br />
Computer-<br />
Hardware<br />
Methoden der<br />
Software-<br />
Entwicklung<br />
Verfahren der<br />
Nachrichtentechnik<br />
Anwender Benutzer Betroffene<br />
Geoinformatik<br />
Ingenieurinformatik<br />
Wirtschaftsinformatik<br />
Rechts- Verwaltungs- Medizinische<br />
informatik informatik Informatik<br />
Bioinformatik<br />
Quelle: Gesellschaft für Informatik (1985)<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 3 von 75
Die WIRTSCHAFTSINFORMATIK (WI) befasst sich mit der<br />
- Konzeption<br />
- Entwicklung<br />
- Einführung<br />
- Nutzung<br />
- Wartung<br />
von Anwendungssystemen der computergestützten Informationsverarbeitung<br />
im Unternehmen.<br />
Fendt FH FL:<br />
Erkenntnis- und Gestaltungsobjekt der WIRTSCHAFTSINFORMATIK<br />
sind Informations- und Kommunikationssysteme (IuK) in Wirtschaft<br />
und Verwaltung.<br />
PROBLEM: Gegeben ist ...<br />
Gesucht ist ...<br />
- Optimierungsprobleme<br />
- Min, Max Bestimmung<br />
Bsp.<br />
Kürzesten Weg bestimmen,<br />
Lineare Optimierung<br />
Maximum Subarray Problem<br />
- Nichtoptimierungsprobleme<br />
- Bestimmung einer zulässigen Lösung<br />
Bsp. Primzahlen berechnen,<br />
Sortieren von Zahlen,<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 4 von 75
ALGORITHMUS:<br />
vollständige, endliche Beschreibung eines Verfahrens zur Lösung eines<br />
Problems<br />
- Verbalbeschreibung<br />
- Pseudocode (programmiernahe, detailliert, formalisiert)<br />
- Implementierung (Darstellung des Algorithmus in einer<br />
Programmiersprache)<br />
Strukturelemente eines Algorithmus:<br />
- Wertzuweisung(Aktion, Befehl),<br />
- Bedingte Anweisung (Auswahl, Selektion)<br />
- Laufanweisung (Wiederholung, Iteration, Schleife)<br />
- Folge (Sequenz)<br />
PSEUDO-CODE:<br />
Ein mit Hilfe eines Pseudo-Codes beschriebenes Verfahren besteht aus<br />
einer Folge von Anweisungen, die jeweils einzeln in einer Zeile<br />
geschrieben werden. Enthält eine Anweisung wiederum eine Folge von<br />
Anweisungen (Sequenz), so wird diese Anweisungsfolge nach rechts<br />
eingerückt. Die Abarbeitung der Anweisungen erfolgt von oben nach<br />
unten.<br />
In dieser Veranstaltung wird folgende Darstellung benutzt<br />
(Schlüsselworte sind fett, Platzhalter sind in spitzen Klammern<br />
angegeben):<br />
Wertzuweisung (Aktion, Befehl):<br />
← <br />
z.B. x ← x + 1<br />
Bedingte Anweisung (Auswahl, Selektion):<br />
falls dann <br />
andernfalls <br />
z.B. falls x > 5 dann y←0<br />
andernfalls y←1<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 5 von 75
Laufanweisung (Wiederholung, Iteration, Schleife):<br />
für ← ,… , führe aus<br />
<br />
<br />
…<br />
Anmerkung: die Laufvariable erhält sukzessive (Inkrement jeweils<br />
+1) alle ganzzahligen Werte aus dem Intervall zwischen Startund<br />
Endwert zugewiesen. Falls der Startwert größer ist als der<br />
Endwert, wird Anweisung 1 , … nicht durchgeführt<br />
oder<br />
für ← ,… , (-1) führe aus<br />
<br />
<br />
…<br />
Anmerkung: die Laufvariable erhält sukzessive (Inkrement jeweils<br />
-1) alle ganzzahligen Werte aus dem Intervall zwischen Startund<br />
Endwert zugewiesen. Falls der Startwert kleiner ist als der<br />
Endwert, wird Anweisung 1 , … nicht durchgeführt<br />
oder<br />
solange führe aus<br />
<br />
<br />
…<br />
Anmerkung: die Anweisung(en) werden solange wiederholt<br />
ausgeführt, bis der boolesche Ausdruck den Wahrheitswert<br />
‚falsch’ liefert.<br />
oder<br />
wiederhole<br />
<br />
<br />
…<br />
bis <br />
Anmerkung: die Anweisung(en) werden solange wiederholt<br />
ausgeführt, bis der boolesche Ausdruck den Wahrheitswert<br />
‚wahr’ aufweist.<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 6 von 75
Beispiel für einen Algorithmus:<br />
(1) Koche Wasser<br />
(2) Nehme Kaffeedose aus dem Schrank<br />
(3) Gib Kaffeepulver in die Tasse<br />
(4) Fülle Wasser in die Tasse<br />
oder detaillierter:<br />
(1) Koche Wasser<br />
(1.1) Fülle Wasserkessel mit Wasser<br />
(1.2) Stelle Wasserkessel auf Herdplatte<br />
(1.3) Schalte Herdplatte an<br />
(1.4) Warte, bis das Wasser kocht<br />
(1.5) Schalte Herdplatte aus<br />
(2) Nehme Kaffeedose aus dem Schrank<br />
(2.1) Falls Kaffeedose leer<br />
dann hole neue Dose<br />
(3) Gib Kaffeepulver in die Tasse<br />
(3.1) Öffne Kaffeedose<br />
(3.2) Entnehme einen Löffel Kaffee<br />
(3.3) Kippe Löffel über der Tasse<br />
(3.4) Schließe Kaffeedose<br />
(4) Fülle Wasser in die Tasse<br />
(4.1) Gieße Wasser aus dem Kessel in die<br />
Tasse, bis diese gefüllt ist<br />
DATENSTRUKTUR:<br />
Organisations- und Speicherform der im Algorithmus benötigten Daten<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 7 von 75
1. EINFÜHRUNG<br />
1.1 BEISPIELE FÜR ALGORITHMEN<br />
Problem GGT Bestimmung des größten gemeinsamen Teilers<br />
Gegeben: 2 positive, ganze Zahlen x, y<br />
Gesucht: größte Integerzahl, durch die x und y<br />
ohne Rest dividiert werden können<br />
Algorithmus GGT-1: ,brute force‘-Methode (naive Methode)<br />
Verbalbeschreibung:<br />
S1: bestimme t: die kleinere Zahl von x und y<br />
falls x=y: x=y ist GGT -> ENDE<br />
S2: dividiere x und y durch t<br />
S3: falls Division x/t und y/t ohne Rest möglich:<br />
t = GGT von x, y -> ENDE<br />
falls Division x/t und y/t ohne Rest nicht möglich:<br />
setze t ← t-1<br />
gehe zu S2<br />
Pseudocode: falls x < y dann t ← x andernfalls t ← y<br />
solange (x MOD t < > 0) oder (y MOD t < > 0)<br />
führe aus<br />
t ← t-1<br />
GGT = t<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 8 von 75
Algorithmus GGT-2: Euklidscher Algorithmus<br />
Verbalbeschreibung:<br />
S1: Vermindere die größere Zahl um die kleinere Zahl, bis die<br />
‚größere Zahl‘ kleiner ist als die ‚kleinere Zahl‘;<br />
falls die ‚kleinere Zahl‘ gleich der ‚Größeren‘ ist,<br />
setze Kleinere = Größere = GGT -> ENDE<br />
S2: Vertausche die ‚kleinere‘ mit der ‚größeren Zahl‘,<br />
gehe zu S1<br />
Problem MSP Maximum Subarray Problem<br />
Gegeben: Folge X von n ganzen Zahlen<br />
Gesucht: zusammenhängende Teilfolge von X mit<br />
maximaler, nichtnegativer Summe<br />
Algorithmus MSP-1: ,brute force‘-Methode (naive Methode)<br />
Verbalbeschreibung:<br />
S1: bestimme alle möglichen zusammenhängenden Teilfolgen<br />
von X<br />
S2: berechne ihre Summen<br />
S3: die Teilfolge mit der größten Summe ist die gesuchte<br />
Teilfolge -> ENDE<br />
Pseudocode: max_bis_jetzt ← 0<br />
für i ← 1, ..., n führe aus<br />
für j ← i, ..., n führe aus<br />
summe ← 0<br />
für k ← i, ..., j führe aus<br />
summe ← summe + X[k]<br />
max_bis_jetzt ← max(max_bis_jetzt, summe)<br />
{ max_bis_jetzt enthält den Wert der maximalen<br />
Summe}<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 9 von 75
Algorithmus MSP-2: Divide and Conquer - Verfahren<br />
(teile und herrsche (bearbeite))<br />
msp_2(X)<br />
Falls X nur 1 Element a enthält:<br />
falls a > 0 setze msp_2 ← a<br />
andernfalls setze msp_2 ← 0<br />
andernfalls<br />
S1: teile X in eine linke Teilfolge A und eine rechte Teilfolge<br />
B annähernd gleicher Größe<br />
S2: Bestimme die maximale Summe der Elemente einer<br />
zusammenhängenden Teilfolge, die beide Randelemente der<br />
Trennstelle enthält:<br />
a) Bestimme das rechte 'Randmaximum' maxRandA der<br />
linken Teilfolge A<br />
b) Bestimme das linke 'Randmaximum' maxRandB der<br />
rechten Teilfolge B<br />
c) Bestimme die Summe von a) und b) maxRandA/B<br />
S3: a) Bestimme die maximale Summe einer zusammenhängenden<br />
Teilfolge in A :<br />
max_in_A ← msp_2(A)<br />
b) Bestimme die maximale Summe einer zusammenhängenden<br />
Teilfolge in B :<br />
max_in_B ← msp_2(B)<br />
S4: msp_2 ← max (max_in_A, max_in_B, maxRandA/B)<br />
Algorithmus MSP-3: Inspektionsverfahren<br />
max_bis_jetzt ← 0 und maxRand ← 0<br />
für i ← 1, ..., n führe aus<br />
maxRand ← maxRand + X[i]<br />
falls maxRand < 0 dann maxRand ← 0<br />
falls max_bis_jetzt < maxRand<br />
dann max_bis_jetzt ← maxRand<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 10 von 75
1.2 TYPEN VON LÖSUNGSVERFAHREN (Optimierungsprobleme)<br />
EXAKTE VERFAHREN: die optimale Lösung wird nach endlich<br />
vielen Schritten erreicht<br />
HEURISTISCHE VERFAHREN: eine Lösung wird durch Anwendung<br />
eines plausiblen Lösungsansatzes nach strategischen<br />
Gesichtspunkten oder ‘Durchprobieren’ verschiedener<br />
Lösungsansätze erreicht. Die gefundene Lösung ist nicht<br />
notwendigerweise optimal. Die Güte eines heuristischen<br />
Verfahrens ist insbesondere danach zu beurteilen, wie weit<br />
die gefundene Lösung vom Optimum entfernt liegt.<br />
1.3 ALGORITHMENKOMPLEXITÄT<br />
Kriterien zur Beurteilung von Algorithmen:<br />
- Einfachheit<br />
- Verständlichkeit<br />
- Länge<br />
- Speicherplatzbedarf<br />
- Daten<br />
- Quellcode<br />
- intern<br />
- extern<br />
- Rechenzeitbedarf<br />
abhängig von<br />
- Rechnertyp<br />
- Betriebssystem<br />
- Programmiersprache<br />
- Compiler<br />
- Compileroptionen (on/off)<br />
- Implementierung<br />
- Problemgröße<br />
- Problemtyp<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 11 von 75
angegeben in -<br />
- absolute Rechenzeit (z.B. in Sekunden)<br />
- Anzahl der Schlüsseloperationen<br />
- worst case<br />
- average case (Erwartungswert)<br />
- ‚big-O‘–Notation : Obergrenze der Größenordnung<br />
des Wachstums des Rechenzeitbedarfs<br />
Größenordnungen des Wachstums des Rechenzeitbedarfs (n: Problemgröße):<br />
O(...) n=10 n=100 n=1000 Bezeichnung<br />
des Wachstums<br />
O(1) z.B. 1 1 1 konstant<br />
O(log 2 n) z.B. 3.32 6.64 9.97 logarithmisch<br />
O(n) z.B. 10 100 1.000 linear<br />
O(n*log 2 n) z.B. 33.2 664.4 9965 überlogarithmisch<br />
O(n 2 ) z.B. 100 10.000 1.000.000 quadratisch<br />
O(n 3 ) z.B. 1.000 1.000.000 1.000.000.000 kubisch<br />
O(2 n ) z.B. 1024 10 30 10 301 exponentiell<br />
O(n!) z.B.<br />
3.628.800<br />
9*10 157 10 2567 faktoriell<br />
1.4 PROBLEMKOMPLEXITÄT<br />
P-PROBLEM:<br />
Problem, zu dem mindestens ein exaktes Verfahren<br />
existiert, dessen Rechenzeitverhalten in<br />
Abhängigkeit von der Größe des Problems<br />
durch ein Polynom darstellbar ist.<br />
NP-PROBLEM: Problem, zu dem kein exaktes Verfahren<br />
existiert, dessen Rechenzeitverhalten in Abhängigkeit<br />
von der Größe des Problems durch ein<br />
Polynom darstellbar ist<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 12 von 75
VERGLEICH MAXIMUM SUBARRAY PROBLEM - ALGORITHMEN<br />
(Rechenzeiten in std:min:sek)<br />
O(...)<br />
n =<br />
1000 3.000 10.000 100.000 1.000.000 10.000.00<br />
0<br />
100.000.000<br />
MSP- 1a O(n 3 ) 00:05:08 02:15:72<br />
MSP- 1b O(n 2 ) 00:00:00 00:00:34 00:04:01 06:44:27<br />
MSP - 2 O(n log n) 00:00:00 00:00:00 00:00:02 00:00:23 00:02:47 00:27:54 05:04:77<br />
MSP- 3a O(n) 00:00:00 00:00:00 00:00:00 00:00:01 00:00:13 00:01:23 00:12:29<br />
MSP- 3b O(n) 00:00:00 00:00:00 00:00:00 00:00:01 00:00:04 00:00:43 00:04:29<br />
Dell, Latitude D410<br />
C# 2003<br />
Windows XP<br />
n : Anzahl Elemente<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 13 von 75
2. LINEARE DATENSTRUKTUREN<br />
2.1 EINDIMENSIONALE FELDER / LINEARE FELDER<br />
Ein LINEARES FELD (lineare Liste, array) A ist eine Datenstruktur, die<br />
aus nmax KNOTEN (Elementen) desselben Datentyps besteht. Ein<br />
lineares Feld wird auch als 'strukturierter Datentyp' bezeichnet.<br />
Jeder Knoten mit Ausnahme des letzten Knotens hat genau einen<br />
Nachfolger. Jed48<br />
er Knoten mit Ausnahme des ersten Knotens hat genau einen Vorgänger.<br />
nmax ist die maximale Anzahl der Knoten von A und wird als GRÖßE<br />
oder LÄNGE des Feldes A bezeichnet.<br />
0 ≤ n ≤ nmax Knoten besitzen einen Informationsgehalt und werden als<br />
DATENKNOTEN, nmax - n Knoten besitzen keinen Informationsgehalt<br />
und werden als FREIE KNOTEN bezeichnet.<br />
A:<br />
10 15 8 25<br />
n<br />
nmax<br />
A:<br />
Index:<br />
10 15 8 25<br />
1 2 3 4 5 6<br />
Datenknoten<br />
Freie Knoten<br />
Standardmäßig sind die Knoten mit 1, ..., nmax, die Datenknoten mit 1,<br />
..., n und die freien Knoten mit n+1, ..., nmax durchnumeriert. Die Länge<br />
des Feldes A kann aus der Ober- und Untergrenze ermittelt werden:<br />
nmax = Obergrenze – Untergrenze + 1<br />
Der i-te Knoten wird mit Ai , A(i) bzw. A[i] oder als Knoten mit INDEX<br />
oder ADRESSE i bezeichnet.<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 14 von 75
Problem PRIM Primzahlenbestimmung<br />
Gesucht: aufsteigend sortierte Speicherung und Ausgabe aller<br />
Primzahlen im Bereich 2,...,n sowie die Anzahl der<br />
Primzahlen im genannten Bereich.<br />
Primzahlen: alle Zahlen, die nur durch 1 oder sich selbst<br />
ohne Rest teilbar sind. 1 wird nicht als Primzahl bezeichnet.<br />
Alle Primzahlen außer 2 sind ungerade. (2,3,5,7,11,13,17,19,...)<br />
Algorithmus PRIM-1: Test aller ungeraden Zahlen p≥3 auf Division<br />
ohne Rest<br />
S1: 2 ist eine Primzahl. Markiere 2 als Primzahl.<br />
S2: Setze p ← 3.<br />
S3: Prüfe, ob p durch keine bisher gefundene Primzahl<br />
ohne Rest dividiert werden kann. Ist dies der Fall, ist p<br />
eine Primzahl und markiere sie als Primzahl.<br />
S4: Setze p ← p+2.<br />
S5: Fall p ≤ n gehe zu S3.<br />
S6: Gebe die markierten Primzahlen aus. ->ENDE.<br />
Algorithmus PRIM-2: Sieb des Eratosthenes<br />
S1: Markiere alle Werte 2 ,..., n als Primzahlen<br />
S2: Führe alle möglichen Multiplikationen i * j (i,j: ganze<br />
Zahlen; i,j ≥ 2) mit dem Ergebnis ≤ n durch und<br />
entferne bei den sich ergebenden Werten die<br />
Markierung.<br />
(alle sich bei der Multiplikation ergebenden Werte sind<br />
keine Primzahlen !)<br />
S3: Gebe alle noch markierten Werte aus dem Bereich 2,..,n<br />
aus. -> ENDE.<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 15 von 75
2.2 SPEICHERUNG LINEARER FELDER<br />
Operationen in linearen Feldern:<br />
a) Durchsuchen und gegebenenfalls 'Bearbeitung' aller Datenknoten<br />
z.B. Ausgabe aller Datenknoten mit Wert > 7<br />
b) Suchen eines bestimmten Datenknotens<br />
b1) des i-ten Datenknotens<br />
b2) des Datenknotens mit Inhalt WERT<br />
c) Einfügen eines neuen Datenknotens mit Wert NEU vor/nach dem i-<br />
ten Datenknoten<br />
d) Entfernen des i-ten Datenknotens<br />
e) Umordnung eines Feldes nach bestimmten Kriterien<br />
z.B. aufsteigende Sortierung<br />
f) Vereinigung von Feldern<br />
2.2.1 Sequentielle Speicherung linearer Felder<br />
Die Datenknoten A[1], A[2], ..., A[n] eines linearen Feldes sind so<br />
angeordnet, dass der<br />
logische Nachfolger von A[i] in A[i+1]<br />
logische Vorgänger von A[i] in A[i-1]<br />
gespeichert ist, d.h.<br />
logische Reihenfolge ≅ physikalische Speicherreihenfolge<br />
Adresse, Index des i-ten Datenknotens in der logischen Reihenfolge:<br />
Untergrenze (Basisadresse) + i - 1<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 16 von 75
Pseudocode der Operationen (Basisadresse: 1):<br />
a) für i ← 1, ..., n führe aus<br />
falls A[i] > 7 dann 'Ausgabe i und A[i]'<br />
b) b1) 'bearbeite' A[i]<br />
b2) index ← 0<br />
für i ← 1, ..., n führe aus<br />
falls A[i] = WERT dann<br />
falls index=0 dann 'kein entsprechender<br />
Datenknoten gefunden'<br />
index←i<br />
'i ist der gesuchte Index'<br />
c) Einfügen nach dem i-ten Datenknoten in der logischen Reihenfolge:<br />
für j ← n, ..., i+1 (-1) führe aus<br />
A[j+1] ← A[j]<br />
A[i+1] ← NEU<br />
n ← n+1<br />
1 2 3 4 5 6 7 ... n<br />
i<br />
v e rsc h ie b e n<br />
e in fü g e n<br />
d) Entfernen des i-ten Datenknotens in der logischen Reihenfolge:<br />
für j ← i, ..., n-1 führe aus<br />
A[j] ← A[j+1]<br />
n ← n - 1<br />
1 2 3 4 5 6 7 . .. n<br />
i<br />
v e r s c h i e b e n<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 17 von 75
e) z.B. folgende Umordnungsvorschrift:<br />
Anordnung der Datenknoten A[1], ..., A[n] derart, dass eine Folge<br />
A'[1], A'[2], ..., A'[s], A[1], A''[1], A''[2], ..., A''[t]<br />
(n=s+1+t)<br />
entsteht mit A'[i] < A[1] ≤ A''[j]<br />
(keine Benutzung eines zusätzlichen Feldes !)<br />
Beispiel:<br />
A:<br />
1 2 3 4 5 6 1 2 3 4 5 6<br />
7 8 5 9 10 1 5 1 17<br />
8 9 10<br />
1. Möglichkeit ('verschieben'):<br />
A: 7 8 5 9 10 1 A: 5 7 8 9 10 1<br />
A:<br />
5 1 7 8 9 10<br />
t ← 1<br />
für i ← 2, ..., n führe aus<br />
falls A[i] < A[t], dann<br />
merke ← A[i]<br />
für j ← i, ... , t+1 (-1) führe aus<br />
A[j] ← A[j-1]<br />
A[t] ← merke<br />
t ← t + 1<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 18 von 75
2. Möglichkeit ('tauschen'):<br />
A: 7 8 5 9 10 1 A: 5 7 8 9 10 1<br />
A:<br />
5 1 7 9 10 8<br />
t ← 1, merke ← A[1]<br />
für i ← 2, ..., n führe aus<br />
falls A[i] < merke, dann<br />
A[t] ← A[i]<br />
A[i] ← A[t+1]<br />
A[t+1] ← merke<br />
t ← t + 1<br />
2.2.2 Verkettete Speicherung linearer Felder<br />
Lineares Feld:<br />
1 2 3 4 5 6 7 8 9 10<br />
A: 7 8 5 10 4 1<br />
nmax<br />
Sequentielle Speicherung:<br />
Knoten: a b<br />
a: Adresse, Index b: Dateninhalt (falls Datenknoten)<br />
A: 1 7 2 8 3 5 4 10 5 4 6 1 ...<br />
9 10<br />
nmax<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 19 von 75
Verkettete Speicherung:<br />
Knoten: a b c<br />
a: Adresse, Index b: Dateninhalt (falls Datenknoten)<br />
c: Zeiger auf die Adresse des nächsten Knotens in der logischen<br />
Reihenfolge (c=nill: kein weiterer Knoten vorhanden)<br />
ANFANG: Zeiger auf die Adresse des 1. Datenknotens in der logischen<br />
Reihenfolge.<br />
ANFANG=nill: kein Datenknoten vorhanden, n=0<br />
FREI:<br />
Zeiger auf die Adresse des 1. freien Knotens.<br />
FREI=nill: kein freier Knoten vorhanden (n=nmax)<br />
Zeigerinhalt des letzten Datenknotens in der logischen Reihenfolge<br />
sowie Zeigerinhalt des letzten freien Knotens: nill<br />
ANFANG=1 FREI=7<br />
A: 1 7 2 2 8 3 3 5 4<br />
4 10 5 5 4 6 6 1 nill<br />
7 8 8 9 9 10<br />
10 nill<br />
oder z.B.<br />
ANFANG=2<br />
FREI=3<br />
A: 1 8 10 2 7 1 3 5<br />
4 4 6 5 7 6 1 nill<br />
7 9 8 10 4 9 nill<br />
10 5 8<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 20 von 75
d.h. logische Reihenfolge muss nicht der physikalischen Speicherreihenfolge<br />
entsprechen<br />
Pseudocode der Operationen (Basisadresse: 1)<br />
a) pos ← anfang<br />
solange pos ≠ nill führe aus<br />
falls A[pos] > 7 dann 'Ausgabe A[pos]'<br />
pos ← zeiger[pos]<br />
b) b1) pos ← anfang<br />
für j ← 1,...,i-1 führe aus<br />
pos ← zeiger[pos]<br />
'bearbeite' A[pos]<br />
b2) log_position ← 0<br />
index ← 0<br />
pos ← anfang<br />
solange pos ≠ nill führe aus<br />
log_position ← log_position + 1<br />
falls A[pos] = WERT<br />
dann<br />
index ← pos<br />
pos ← nill<br />
andernfalls pos ← zeiger[pos]<br />
falls index=0 dann 'kein entsprechender Datenknoten<br />
gefunden'<br />
andernfalls 'der Datenknoten mit Inhalt<br />
WERT hat die Adresse index und<br />
steht an Stelle log_position in der<br />
logischen Reihenfolge'<br />
c) Einfügen nach dem Datenknoten mit Adresse i in der logischen<br />
Reihenfolge:<br />
falls frei=nill dann 'Meldung', ENDE<br />
A[frei] ← NEU<br />
Merke ← zeiger[frei]<br />
zeiger[frei] ← zeiger[i]<br />
zeiger[i] ← frei<br />
frei ← merke<br />
n ← n+1<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 21 von 75
d) Entfernen des Datenknotens, der dem Datenknoten mit Adresse i in<br />
der logischen Reihenfolge folgt:<br />
merke ← zeiger[i]<br />
zeiger[i] ← zeiger[zeiger[i]]<br />
zeiger[merke] ← frei<br />
frei ← merke<br />
n ← n-1<br />
e) pos ← anfang<br />
w ← A[pos]<br />
solange zeiger[pos] ≠ nill führe aus<br />
falls A[zeiger[pos]] < w dann<br />
merke ← zeiger[pos]<br />
zeiger[pos] ←<br />
zeiger[zeiger[pos]]<br />
zeiger[merke] ← anfang<br />
anfang ← merke<br />
andernfalls pos ← zeiger[pos]<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 22 von 75
Beispiel Patientenliste<br />
Bettnr. Patient Zeiger<br />
1 Kunze 7 anfang = 5 frei = 10<br />
2 6<br />
3 Dreher 11<br />
4 Müller 12 logische Reihenfolge<br />
5 Ahrens 3 = alphabetische Reihenfolge<br />
6 nill<br />
7 Meier 4 physikalische Speicherreihenfolge<br />
8 Grünlich 1 = Bettnummernreihenfolge<br />
9 Schmidt nill<br />
10 2<br />
11 Fischer 8<br />
12 Nelke 9<br />
Beispiel Vertriebsfirma<br />
Vertreter Anfang Kunde Zeiger<br />
1 Bauer 12 1 Vater 4<br />
2 Keller 3 2 5<br />
3 Haller nill 3 Jäger 14<br />
4 Neumann 9 4 Zaus nill<br />
5 7<br />
Frei = 2 6 Zedelmann nill<br />
7 11<br />
8 Ritter 15<br />
9 Abraham 10<br />
10 Eisen 19<br />
11 13<br />
12 Groß 17<br />
13 16<br />
14 Wung 6<br />
15 Wrege nill<br />
16 18<br />
17 Schmidt 1<br />
18 20<br />
19 Eismann 8<br />
20 nill<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 23 von 75
FORMEN DER VERKETTUNG:<br />
a) einfach verkettet: jeder Knoten enthält die Adresse des<br />
nächsten Datenknotens (Nachfolger) in der logischen Reihenfolge<br />
b) doppelt verkettet: jeder Knoten besitzt 2 Zeiger<br />
Vorwärtszeiger : enthält die Adresse des nächsten<br />
Datenknotens (Nachfolger) in der logischen<br />
Reihenfolge<br />
Rückwärtszeiger : enthält die Adresse des vorangehenden<br />
Datenknotens (Vorgänger) in der logischen<br />
Reihenfolge<br />
ANFANG:<br />
enthält die Adresse des 1. Datenknotens in<br />
der logischen Reihenfolge.<br />
ENDE:<br />
enthält die Adresse des letzten Datenknotens<br />
in der logischen Reihenfolge<br />
a b c d a: Adresse, Index b: Dateninhalt<br />
c: Rückwärtszeiger d: Vorwärtszeiger<br />
z.B. ANFANG = 2 ENDE = 4 FREI = 3<br />
1 2 4 2 nill 1 3 nill nill 4 1 nill<br />
c) kreisförmig verkettet: der Zeiger des letzten Datenknotens<br />
in der logischen Reihenfolge zeigt auf den 1. Datenknoten in der<br />
logischen Reihenfolge, d.h. er enthält die Adressse ANFANG<br />
z.B. ANFANG = 2 FREI = 3<br />
1 4 2 1 3 nill 4 2<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 24 von 75
2.3 STAPEL, REKURSION UND SCHLANGEN<br />
2.3.1 Stapel und Rekursion<br />
Stapel (Keller, Stack): Lineares Feld, bei dem die „Bearbeitung“<br />
(Einfügen und Entfernen) nur am Anfang des<br />
Feldes vorgenommen werden kann<br />
(LIFO-Prinzip: last in, first out)<br />
z.B. Bücherstapel<br />
Sequentielle Speicherung:<br />
n<br />
nmax<br />
1 2 3 4 5 6 7 8 9 10<br />
A: xx yy zz<br />
↑<br />
anfang=3<br />
Einfügen: anfang ← anfang + 1<br />
A[anfang] ← NEU<br />
n ← n + 1<br />
Entfernen: anfang ← anfang – 1<br />
n ← n - 1<br />
Verkettete Speicherung: anfang = 3 frei = 4<br />
1 yy 2 2 xx nill 3 zz 1 4 nill<br />
anfang ⇒ 3 zz<br />
2 yy<br />
1 xx<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 25 von 75
Einfügen:<br />
Entfernen:<br />
falls frei = NILL dann 'Meldung', ENDE<br />
A[frei] ← NEU<br />
merke ← zeiger[frei]<br />
zeiger[frei] ← anfang<br />
anfang ← frei<br />
frei ← merke<br />
n ← n +1<br />
merke ← zeiger[anfang]<br />
zeiger[anfang] ← frei<br />
frei ← anfang<br />
anfang ← merke<br />
n ← n - 1<br />
Stapelanwendungen:<br />
1) Beispiel für eine rekursive Funktion<br />
Problem Ackermann Die Ackermann-Funktion A(n,x,y) ist für<br />
nichtnegative ganze Zahlen n, x, y durch<br />
⎧ x+1, falls n=0<br />
⎪ x, falls n=1 und y=0<br />
⎪ 0, falls n=2 und y=0<br />
A(n,x,y) = ⎨ 1, falls n=3 und y=0<br />
⎪ 2, falls n≥4 und y=0<br />
⎩ A(n-1, A(n,x,y-1), x), falls n≠0 und y≠0<br />
definiert.<br />
Beispiel: A(2, 3, 1) = A(1, A(2, 3, 0), 3)<br />
= A(1, 0, 3)<br />
= A(0, A(1, 0, 2), 0)<br />
= A(0, A(0, A(1, 0, 1), 0), 0)<br />
= A(0, A(0, A(0, A(1, 0, 0), 0), 0), 0)<br />
= A(0, A(0, A(0, 0, 0), 0), 0)<br />
= A(0, A(0, 1,0), 0)<br />
= A(0, 2, 0)<br />
= x + 1<br />
= 3<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 26 von 75
2) Notationen von arithmetischen Ausdrücken<br />
INFIX-Notation:<br />
PRÄFIX-Notation:<br />
POSTFIX-Notation:<br />
Operator steht zwischen den Operanden<br />
(gegebenenfalls Klammerung notwendig !)<br />
Operator steht vor den Operanden<br />
Operator steht nach den Operanden<br />
INFIX PRÄFIX POSTFIX<br />
A + B +AB AB+<br />
A + B * C A+[*BC]<br />
+A*BC<br />
A+[BC*]<br />
ABC*+<br />
(A + B) * C [+AB]*C<br />
*+ABC<br />
[AB+]*C<br />
AB+C*<br />
(A + B) / (C – D) [+AB] / [-CD]<br />
/+AB-CD<br />
[AB+] / [CD-]<br />
AB+CD-/<br />
Problem InfToPost<br />
Umwandlung eines INFIX-Ausdruckes Q in einen<br />
POSTFIX-Ausdruck P<br />
Algorithmus InfToPost:<br />
S1: ‘(‘ --> Stapel und ‘)’ an das Ende von Q anfügen<br />
S2: durchsuche Q von links nach rechts, bis der Stapel leer ist:<br />
a) falls OPERAND gefunden wird: --> P<br />
b) falls ÖFFNENDE KLAMMER gefunden wird:<br />
--> Stapel<br />
c) falls OPERATOR a gefunden wird:<br />
1) solange Operatoren vom Stapel entfernen und<br />
--> P, wie diese eine höhere oder dieselbe Priorität<br />
besitzen<br />
2) a --> Stapel<br />
d) falls SCHLIEßENDE KLAMMER gefunden wird:<br />
1) solange Operatoren vom Stapel entfernen und<br />
--> P, bis öffnende Klammer auftritt<br />
2) entferne öffnende Klammer aus dem Stapel, füge<br />
sie nicht zu P hinzu<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 27 von 75
Beispiel: Q: A + (B * C - D / E * F * G) * H<br />
S1: Q: A + (B * C - D / E * F * G) * H)<br />
S2:<br />
/ * *<br />
* - - -<br />
( ( ( ( *<br />
+ + + + +<br />
( ( ( ( (<br />
P: ABC*DE/F*G*-H*+<br />
Problem WertPostfix<br />
Ermittlung des Wertes eines POSTFIX-<br />
Ausdrucks P<br />
Algorithmus WertPostfix:<br />
S1: markiere das Ende des Ausdrucks P mit einer Marke z.B. ‘)’<br />
S2: durchsuche P von links nach rechts und wiederhole für jede<br />
Angabe von P bis die Markierung auftritt:<br />
a) falls OPERAND gefunden wird: --> Stapel<br />
b) falls OPERATOR a gefunden wird:<br />
1) entnehme dem Stapel den obersten Knoten<br />
X und den zweitobersten Knoten Y<br />
2) berechne Y a X<br />
3) Ergebnis von 2) --> Stapel<br />
S3: der Wert des Knotens im Stapel ist der Wert des Ausdrucks P<br />
Beispiel: P: 5, 6, 2, +, *, 12, 4, /, -<br />
2 ->X 4 ->X<br />
6 ->Y Y+X 8 ->X 12 ->Y Y/X 3 ->X<br />
5 5 ->Y Y*X 40 40 ->Y Y-X 37<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 28 von 75
2.3.2 Schlange<br />
Schlange:<br />
Lineares Feld, bei dem nur am Anfang Knoten entfernt<br />
und nur am Ende Knoten eingefügt werden können.<br />
(FIFO-Prinzip: first in, first out)<br />
z.B. Warteschlange am Schalter<br />
Schalter<br />
1 2 3 4 5 6<br />
anfang<br />
ende<br />
Sequentielle Speicherung (Methoden A, B, C)<br />
Einfügen:<br />
A<br />
'verschieben'<br />
B<br />
'von vorne'<br />
mit Abfrage<br />
siehe A<br />
C<br />
'mit mod-<br />
Operator'<br />
siehe A<br />
(1) falls n=nmax, dann<br />
'Meldung' ENDE<br />
(2) falls n=0, dann siehe A siehe A<br />
anfang←1,<br />
ende←0<br />
(3) falls ende=nmax,dann falls<br />
ende←nmax+1 ende=nmax,<br />
- anfang dann<br />
für i←1 ..ende ende←0<br />
setze<br />
A[i]<br />
←A[i+anfang-1]<br />
anfang←1<br />
(4) ende←ende+1 siehe A ende←<br />
(ende mod nmax)<br />
+ 1<br />
(5) A[ende] ← NEU siehe A siehe A<br />
(6) n←n+1 siehe A siehe A<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 29 von 75
Entfernen:<br />
(1) falls n=0, dann<br />
'Meldung', ENDE<br />
siehe A<br />
(2) anfang←anfang+1 falls<br />
anfang=nmax,<br />
dann<br />
anfang←1<br />
sonst<br />
anfang←<br />
anfang+1<br />
siehe A<br />
(3) n←n-1 siehe A siehe A<br />
anfang←<br />
(anfang mod<br />
nmax) +1<br />
2.4 MEHRDIMENSIONALE FELDER<br />
2.4.1 Zweidimensionale Felder / Matrizen<br />
a) nichtquadratische Matrizen (n m)<br />
n: Anzahl Zeilen<br />
m: Anzahl Spalten<br />
z.B. A (n = 3, m = 4) a 11 a 12 a 13 a 14<br />
mit a ij a 21 a 22 a 23 a 24<br />
i: Zeilenindex a 31 a 32 a 33 a 34<br />
j: Spaltenindex<br />
Speicherplatzbedarf: n*m Elemente<br />
Möglichkeiten bei eindimensionaler Speicherung:<br />
1) zeilenorientiert:<br />
a 11 , a 12 , a 13 , a 14 , a 21 , a 22 , a 23 , a 24 , a 31 , a 32 , a 33 , a 34<br />
2) spaltenorientiert:<br />
a 11 , a 21 , a 31 , a 12 , a 22 , a 32 , a 13 , a 23 , a 33 , a 14 , a 24 , a 34<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 30 von 75
Problem: Welche Adresse IJ besitzt dann z.B. a 32 (a 11 -> Adresse 1)<br />
zeilenorientiert: IJ = Basisadresse + (i - 1) * m + j –1<br />
a 32 -> IJ = 10<br />
spaltenorientiert: IJ = Basisadresse + (j - 1) * n + i – 1<br />
a 32 -> IJ = 6<br />
b) quadratische Matrizen (n = m)<br />
z.B. n = m = 4 a 11 a 12 a 13 a 14<br />
a 21 a 22 a 23 a 24<br />
a 31 a 32 a 33 a 34<br />
a 41 a 42 a 43 a 44<br />
Speicherplatzbedarf: n x n Elemente<br />
bei symmetrischen Matrizen mit a ij = a ji (z.B. bei Entfernungsmatrizen)<br />
sind folgende Speicherungsformen möglich:<br />
1. Untere Dreiecksmatrix inklusive Hauptdiagonale (i >= j)<br />
a) zeilenweise<br />
( i −1) * i<br />
IJ = Basisadresse + + j −1<br />
2<br />
b) spaltenweise IJ= <br />
Speicherplatzbedarf:<br />
n * ( n + 1)<br />
2<br />
Elemente<br />
2. Untere Dreiecksmatrix ohne Hauptdiagonale (i > j)<br />
a) zeilenweise<br />
( i − 2) * ( i −1)<br />
IJ = Basisadresse +<br />
+ j −1<br />
2<br />
b) spaltenweise<br />
j * ( j + 1)<br />
IJ = Basisadresse + ( j −1) * n + i − −1<br />
2<br />
Speicherplatzbedarf:<br />
n * ( n + 1)<br />
- n Elemente<br />
2<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 31 von 75
3. Obere Dreiecksmatrix ohne Hauptdiagonale (i < j)<br />
a) zeilenweise<br />
i * ( i + 1)<br />
IJ = Basisadresse + ( i −1) * n + j − −1<br />
2<br />
b) spaltenweise<br />
( j − 2) *( j −1)<br />
IJ = Basisadresse +<br />
+ i −1<br />
2<br />
Speicherplatzbedarf:<br />
n * ( n + 1)<br />
- n Elemente<br />
2<br />
2.4.2 Beliebige, mehrdimensionale Felder<br />
z.B. dreidimensional<br />
a ijk<br />
a 113 a 123 a 133 a 143<br />
a 213 a 223 a 233 a 243<br />
a 112 a 122 a 132 a 142<br />
a 212 a 222 a 232 a 242<br />
a 111 a 121 a 131 a 141<br />
a 211 a 221 a 231 a 241<br />
Möglichkeiten der eindimensionalen Speicherung:<br />
1) spaltenorientiert<br />
a 111 , a 211 , a 121 , a 221 , a 131 , a 231 , a 141 , a 241 , a 112 , a 212 , a 122 , ..., a 233 , a 143 , a 243<br />
1. Index wächst am schnellsten, 2. Index am zweitschnellsten, ...<br />
IJ = Basisadresse + (( ... ((E n *L n-1 +E n-1 ) L n-2 +E n-2 )...+E 3 ) L 2 + E 2 ) L 1 + E 1<br />
mit<br />
n: Anzahl Dimensionen<br />
L i : Obergrenze Dimension i - Untergrenze Dimension i + 1<br />
(Länge des Feldes in Dimension i; Anzahl der Feldelemente<br />
in Dimension i)<br />
E i : K i - Untergrenze Dimension i (K i : gegebener Index in<br />
Dimension i; Anzahl der Indizes, die vor Index K i in der<br />
Dimension i 'liegen')<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 32 von 75
2) zeilenorientiert<br />
a 111 ,a 112 , a 113 , a 121 , a 122 , a 123 , ..., a 241 , a 242 , a 243<br />
letzter Index wächst am schnellsten, zweitletzter Index am<br />
zweitschnellsten, ...<br />
IJ = Basisadresse + ( ... ((E 1 * L 2 + E 2 ) L 3 + E 3 ) L 4 + ... + E n-1 ) L n + E n<br />
Beispiel: A [2 ... 8, -4 ... 1, 6 ... 10]<br />
L 1 = 8 - 2 + 1 = 7<br />
L 2 = 1 - (-4) + 1 = 6<br />
L 3 = 10 - 6 + 1 = 5<br />
Adresse von A[5, -1, 8]<br />
E 1 = 5 - 2 = 3<br />
E 2 = -1 - (-4) = 3<br />
E 3 = 8 - 6 = 2<br />
Basisadresse = 1<br />
IJ = 1 + ((E 1 * L 2 + E 2 ) * L 3 + E 3 )<br />
= 1 + ((3 * 6 + 3) * 5 + 2)<br />
= 1 + 21 * 5 + 2 = 1 + 105 + 2 = 108<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 33 von 75
3. KOMPLEXE DATENSTRUKTUREN<br />
3.1 GRAPHEN - DEFINITIONEN<br />
Definition1:<br />
Ein ungerichteter Graph G = (V,E) besteht aus einer Menge von Knoten<br />
V={1,2,...,n} und Kanten E={e 1 ,e 2 ,...,e m }. Die Anzahl der Knoten wird mit<br />
n, die Anzahl der Kanten mit m bezeichnet.<br />
Die einer Kante e zugeordneten Knoten i, j werden Endknoten von e<br />
genannt. Man schreibt e = (i, j) oder e = (j, i) und sagt, dass die Kante e<br />
die Knoten i, j "verbindet". Knoten i heißt Nachbar des Knotens j und<br />
umgekehrt, falls e = (i, j) eine Kante in G ist.<br />
Ein gerichteter Graph G = [V,E] besteht aus einer Menge von Knoten<br />
V={1,2,...,n} und Pfeilen E={e 1 ,e 2 ,...,e m }. Die Anzahl der Knoten wird<br />
wiederum mit n, die Anzahl der Pfeile mit m bezeichnet. Ein gerichteter<br />
Graph G = [V,E] wird auch Digraph D = [V,E] genannt.<br />
Ein Graph G = (V,E), der sowohl Pfeile wie auch Kanten enthält, heißt<br />
gemischter Graph.<br />
Für einen Pfeil e wird e = [i, j] geschrieben; i heißt Anfangsknoten und j<br />
Endknoten des Pfeiles e. Man sagt auch, dass der Pfeil e "vom Knoten i<br />
ausgeht" und "in den Knoten j einmündet". Knoten j wird (unmittelbarer)<br />
Nachfolger von Knoten i, Knoten i (unmittelbarer) Vorgänger von<br />
Knoten j genannt. Die Menge aller Nachfolger eines Knotens i wird mit<br />
S i und die Menge aller Vorgänger eines Knotens i mit P i bezeichnet.<br />
weitere Definitionen siehe Veranstaltung Operations Research SS 2010<br />
3.2 DARSTELLUNG VON PROBLEMEN DURCH GRAPHEN<br />
siehe Veranstaltung Operations Research SS 2010<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 34 von 75
3.3 SPEICHERUNG VON GRAPHEN<br />
Bewerteter Digraph D1:<br />
2<br />
2<br />
e 1<br />
e 4<br />
e 5<br />
3<br />
e<br />
2 3 3<br />
1<br />
5<br />
e 1 1<br />
2<br />
e 7<br />
e 8<br />
e 6<br />
6<br />
2<br />
4<br />
3<br />
a) Adjazenzmatrix: A(D1)<br />
1 2 3 4 5<br />
1 0 1 1 0 0<br />
2 0 0 0 1 1<br />
3 0 0 0 1 1<br />
4 0 0 0 0 0<br />
5 0 1 1 0 0<br />
b) Bewertungsmatrix: C(D1)<br />
1 2 3 4 5<br />
1 0 3 2 ∞ ∞<br />
2 ∞ 0 ∞ 6 2<br />
3 ∞ oo 0 2 1<br />
4 ∞ oo ∞ 0 ∞<br />
5 ∞ 3 1 ∞ 0<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 35 von 75
c) Vektorform d) Vektorform - pfeilsortiert<br />
anfk endk c alt neu anfk endk c<br />
e 1 1 2 3 e 1 e 1 1 2 3<br />
e 2 1 3 2 e 2 e 2 1 3 2<br />
e 3 5 2 3 e 4 e 3 2 5 2<br />
e 4 2 5 2 e 7 e 4 2 4 6<br />
e 5 5 3 1 e 6 e 5 3 5 1<br />
e 6 3 5 1 e 8 e 6 3 4 2<br />
e 7 2 4 6 e 3 e 7 5 2 3<br />
e 8 3 4 2 e 5 e 8 5 3 1<br />
Pfeilnummernvektor:<br />
1 1<br />
2 3<br />
3 5<br />
4 7<br />
5 7<br />
6 9<br />
PN<br />
Bestimmung der Nachfolger eines Knotens i bei vektororientierter<br />
Speicherung eines pfeilsortierten Digraphen D<br />
Algorithmus NACHFOLGER - PN_GEN<br />
Aufbau des Pfeilnummernvektors PN:<br />
S1: für k ← 1 .. n führe aus: setze PN[k] ← 0<br />
setze PN[n+1] ← m+1<br />
S2: für alle Pfeile e p in der Reihenfolge p ← 1 .. m führe aus:<br />
falls ein neuer Anfangsknoten i auftritt, setze PN[i] ← p<br />
S3: Überprüfung auf Senken und isolierte Knoten (alle Knoten i mit<br />
PN[i]=0 sind Senken oder isolierte Knoten):<br />
für alle PN[k] in der Reihenfolge k ← n, …, 1 (-1) führe aus:<br />
falls PN[k]=0, setze PN[k] ← PN[k+1]<br />
Bestimmung der Nachfolger eines Knoten k:<br />
für p ← PN[k], ..., PN[k+1] - 1 führe aus :<br />
der Endknoten des Pfeiles mit Pfeilnummer p ist Nachfolger von k<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 36 von 75
Bestimmung der Vorgänger eines Knotens i bei vektororientierter<br />
Speicherung eines Digraphen D<br />
Algorithmus VORGÄNGER<br />
Benutzung folgender ganzzahliger linearer Felder:<br />
ANF_ZEIGER<br />
TEMP<br />
VORGÄNGER<br />
[1..n]<br />
[1..n]<br />
[1..m]<br />
Vorbereitungsschritt:<br />
S1: alle Datenknoten der Felder ANF_ZEIGER und VORGÄNGER<br />
auf Null setzen<br />
S2: Betrachtung der Endknoten aller Pfeile in der Reihenfolge e1,<br />
e2, ..., em :<br />
Fall 1:<br />
Fall 2:<br />
Endknoten k tritt zum ersten Male auf:<br />
sei p die Pfeilnummer des Pfeiles mit Endknoten k ;<br />
setze ANF_ZEIGER [k] ← TEMP [k] ← p<br />
Endknoten k tritt nicht erstmalig auf:<br />
die weiteren Pfeilnummern mit Endknoten k<br />
werden im Feld VORGÄNGER gespeichert;<br />
sei p die Pfeilnummer eines solchen Pfeiles,<br />
setze VORGÄNGER [TEMP [k] ] ← p<br />
TEMP [k] ← p<br />
Bestimmung der Vorgänger eines Knotens k:<br />
p ← ANF_ZEIGER [k]<br />
solange p 0 führe aus :<br />
der Anfangsknoten des Pfeiles mit Pfeilnummer p ist<br />
Vorgänger von k<br />
p ← VORGÄNGER [p]<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 37 von 75
Speicherform<br />
Anzahl<br />
Speicherelemente<br />
Speicherbedarf<br />
Beispiel<br />
vollständiger<br />
Digraph<br />
n=100<br />
m=n*(n-1)<br />
= 9900<br />
p=1.0<br />
Beispiel<br />
Straßennetz<br />
SL FL<br />
n=800<br />
m=2800<br />
Beispiel<br />
Straßennetz<br />
BW<br />
n=8500<br />
m=25000<br />
p=0.004 p=0.0004<br />
Bewertungsmatrix<br />
C(D) n*n 10.000 640.000 72.250.000<br />
pfeilorientiert:<br />
Anfangsknotenvekt.<br />
Endknotenvektor<br />
Bewertungsvektor<br />
pfeilorientiert und<br />
pfeilsortiert:<br />
Endknotenvektor<br />
Bewertungsvektor<br />
Pfeilnummernvektor<br />
m<br />
m<br />
m<br />
∑=3*m<br />
m<br />
m<br />
n+1<br />
∑=2*m<br />
+n+1<br />
29.700 8.400 75.000<br />
19.901 6.401 58.501<br />
n: Anzahl Knoten SL FL: Landkreis<br />
m: Anzahl Pfeile Schleswig-Flensburg<br />
p: Pfeildichte: m/(n*(n-1)) BW: Baden-Württemberg<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 38 von 75
4. GRAPHENALGORITHMEN<br />
4.1 KÜRZESTE WEGE ALGORITHMEN<br />
3 Problemstellungen:<br />
a) Kürzester Weg von Startknoten a nach Zielknoten b<br />
b) Kürzester Weg von Startknoten a zu allen anderen Knoten<br />
c) Kürzester Weg von jedem Knoten zu allen anderen<br />
(Entfernungsmatrix)<br />
Algorithmen: a) Nicholson<br />
b) Dijkstra, Ford, Desopo, Bellmann<br />
c) Tripel, Dantzig<br />
4.1.1 Dijkstra-Algorithmus<br />
2 1 4<br />
2<br />
4<br />
2<br />
7<br />
1 7 3 3 5<br />
1<br />
2<br />
1<br />
1<br />
6 3 7<br />
Startknoten a=1<br />
Schritt 0: R = {1} DIST(1) = 0 PRE(1) = 0<br />
DIST(i) = oo PRE(i) = 0 (i=2,3,4,5,6,7)<br />
Schritt 1: i = 1 j = 2, 3<br />
Schritt 2: DIST (2) > DIST (1) + C (1,2) ==> DIST (2) = DIST (1) + C (1,2)<br />
∞ > 0 + 2 = 2<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 39 von 75
R = {1, 2, 3} DIST (2) < DIST (3) ==> i = 2, j = 3, 4<br />
R = {2, 3, 4} etc. ...<br />
......<br />
......<br />
Folgende Werte ergeben sich:<br />
Knoten KW_DIST PRE<br />
1 0 0<br />
2 2 1<br />
3 5 4<br />
4 3 2<br />
5 8 3<br />
6 7 3<br />
7 9 5<br />
==> Kürzester Weg von 1 nach 7: 1 --> 2 --> 4 --> 3 --> 5 --> 7<br />
Wurzelbaum mit Wurzel Knoten 1 (jeder Knoten mit Ausnahme der<br />
Wurzel hat nur einen Vorgänger):<br />
Verlauf des kürzesten Weges von Knoten 1 zu allen anderen Knoten<br />
2 1 4<br />
2<br />
2<br />
1 3 3 5<br />
2<br />
1<br />
6 7<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 40 von 75
Bestimmung eines kürzesten Weges (Länge und Verlauf) von einem<br />
Startknoten a zu allen anderen Knoten in einem bewerteten<br />
Digraphen D = [V,E,c] mit dem<br />
Algorithmus von DIJKSTRA<br />
Eingabe:<br />
a: Startknoten<br />
c[i,j]:<br />
Bewertung (Länge) des Pfeiles von i nach j<br />
Ausgabe:<br />
kw_dist[i]:<br />
pre[i]:<br />
Voraussetzung:<br />
kürzeste Wegelänge von Startknoten a nach i<br />
Vorgänger von i auf dem kürzesten Weg von Startknoten<br />
a nach i<br />
D darf keine negativen Bewertungen enthalten<br />
S1: Initialisierung:<br />
Markiere Startknoten a:<br />
Setze für Knoten a:<br />
kw_dist[a] ← 0,<br />
pre[a] ← 0.<br />
Setze für alle anderen Knoten i (∀i ≠a):<br />
kw_dist[i] ← ∞,<br />
pre[i] ← 0.<br />
sei R die Menge der markierten<br />
Knoten, dann gilt a ∈ R (R={a}).<br />
S2: Falls ein oder mehrere Knoten markiert sind (R ≠ ∅):<br />
wähle einen Knoten aus mit MIN kw_dist[j],<br />
j ∈ R<br />
dieser Knoten sei i;<br />
sonst (R = ∅): ENDE Dijkstra-Algorithmus.<br />
S3: Für alle Nachfolger j ∈ S i , die noch nicht aus der Markierung<br />
entfernt worden sind, führe aus:<br />
falls kw_dist[i] + c[i,j] < kw_dist[j]:<br />
(1) setze kw_dist[j] ← kw_dist[i] + c[i,j],<br />
(2) setze pre[j] ← i,<br />
(3) markiere j (j ∈ R).<br />
Entferne die Markierung bei i (i ∉ R).<br />
Gehe zu S2.<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 41 von 75
4.1.2 Ford-Algorithmus<br />
R = {1 2 3 4 5 6 3 7 5 6 7} Auswahlkriterium in S2:<br />
der Knoten, der am längsten in R ist<br />
Knoten KW_DIST PRE<br />
1 0 0<br />
2 oo 2 0 1<br />
3 oo 7 6 5 0 1 2 4<br />
4 oo 3 0 2<br />
5 oo 9 8 0 3<br />
6 oo 8 7 0 3<br />
7 oo 10 9 0 5<br />
Beispiel mit negativer Bewertung:<br />
1<br />
10<br />
2<br />
2<br />
2<br />
4<br />
3<br />
-2<br />
4<br />
3<br />
Dijkstra a=1<br />
Knoten 1 2 3 4<br />
PRE 0 0 1 0 2 0 1 2<br />
KW_DIST 0 oo 2 oo 5 oo 10 4<br />
R = {1, 2, 4} i = 1<br />
R = {2, 4, 3} i = 2<br />
R = {4, 3} i = 4<br />
R = {3} i = 3<br />
R = 0<br />
Ford a=1<br />
Knoten 1 2 3 4<br />
PRE 0 0 1 0 2 0 1 2 3<br />
KW_DIST 0 oo 2 oo 5 oo 10 4 3<br />
R = {1, 2, 4, 3, 4, 4} i = 1, i = 2, i = 4, i = 3, i = 4, i = 4<br />
R = 0<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 42 von 75
Bestimmung eines kürzesten Weges (Länge und Verlauf) von einem<br />
Startknoten a zu allen anderen Knoten in einem bewerteten<br />
Digraphen D = [V,E,c] mit dem<br />
Algorithmus von FORD<br />
Eingabe:<br />
a: Startknoten<br />
c[i,j]:<br />
Bewertung (Länge) des Pfeiles von i nach j<br />
Ausgabe:<br />
kw_dist[i]:<br />
pre[i]:<br />
Voraussetzung:<br />
kürzeste Wegelänge von Startknoten a nach i<br />
Vorgänger von i auf dem kürzesten Weg von Startknoten<br />
a nach i<br />
D darf keine negativen Zyklen enthalten<br />
S1: Initialisierung:<br />
Markiere Startknoten a:<br />
Setze für Knoten a:<br />
kw_dist[a] ← 0,<br />
pre[a] ← 0.<br />
Setze für alle anderen Knoten i (∀i ≠a):<br />
kw_dist[i] ← ∞,<br />
pre[i] ← 0.<br />
sei R die Menge der markierten<br />
Knoten, dann gilt a ∈ R (R={a}).<br />
S2: Falls ein oder mehrere Knoten markiert sind (R ≠ ∅):<br />
wähle den Knoten aus, der am längsten (kürzesten) in R<br />
enthalten ist.<br />
dieser Knoten sei i;<br />
sonst (R = ∅): ENDE Ford-Algorithmus.<br />
S3: Für alle Nachfolger j ∈ S i führe aus:<br />
falls kw_dist[i] + c[i,j] < kw_dist[j]:<br />
(1) setze kw_dist[j] ← kw_dist[i] + c[i,j],<br />
(2) setze pre[j] ← i,<br />
(3) markiere j (j ∈ R).<br />
Entferne die Markierung bei i (i ∉ R).<br />
Gehe zu S2.<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 43 von 75
4.1.3 Tripel-Algorithmus<br />
P(D) = Vorgängermatrix<br />
C(D) = Bewertungsmatrix<br />
D =<br />
1<br />
1 2<br />
0<br />
3<br />
3<br />
1<br />
C(D)<br />
2 1 4<br />
5<br />
P(D)<br />
1 2 3 4 1 2 3 4<br />
1 0 1 0 oo 1 1 1 1 0<br />
2 2 0 oo 5 2 2 2 0 2<br />
3 oo 3 0 1 3 0 3 3 3<br />
4 oo 1 oo 0 4 0 4 0 4<br />
Z = 1:<br />
Die Hauptdiagonale sowie Spalte 1 und Zeile 1 lassen sich nicht<br />
verbessern. Eine Verbesserungsmöglichkeit besteht nur bei den anderen<br />
Elementen. Tatsächlich trifft dies nur in (Zeile 2, Spalte 3) zu<br />
(Verbesserungen sind 'dunkel' gekennzeichnet).<br />
C(D)<br />
P(D)<br />
1 2 3 4 1 2 3 4<br />
1 0 1 0 oo 1 1 1 1 0<br />
2 2 0 2 5 2 2 2 1 2<br />
3 oo 3 0 1 3 0 3 3 3<br />
4 oo 1 oo 0 4 0 4 0 4<br />
Z = 2: C(D) P(D)<br />
1 2 3 4 1 2 3 4<br />
1 0 1 0 6 1 1 1 1 2<br />
2 2 0 2 5 2 2 2 1 2<br />
3 5 3 0 1 3 2 3 3 3<br />
4 3 1 3 0 4 2 4 1 4<br />
Z = 3: C(D) P(D)<br />
1 2 3 4 1 2 3 4<br />
1 0 1 0 1 1 1 1 1 3<br />
2 2 0 2 3 2 2 2 1 3<br />
3 5 3 0 1 3 2 3 3 3<br />
4 3 1 3 0 4 2 4 1 4<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 44 von 75
Z = 4: C(D) P(D)<br />
1 2 3 4 1 2 3 4<br />
1 0 1 0 1 1 1 1 1 3<br />
2 2 0 2 3 2 2 2 1 3<br />
3 4 2 0 1 3 2 4 3 3<br />
4 3 1 3 0 4 2 4 1 4<br />
aus C(D) -->Entfernungsmatrix<br />
K(D)<br />
Bestimmung eines kürzesten Weges von jedem Knoten zu allen<br />
anderen Knoten eines bewerteten Digraphen D = [V,E,c], d,h.<br />
Erstellung der Entfernungsmatrix K(D) mit dem<br />
TRIPEL-Algorithmus<br />
Eingabe: C(D): Bewertungsmatrix<br />
P(D): Vorgängermatrix<br />
Ausgabe: K(D): Entfernungsmatrix (entstanden aus C(D))<br />
P(D): pij: Vorgänger des Knotens j auf dem<br />
kürzesten Weg von i nach j<br />
Voraussetzung:<br />
D darf keine negativen Zyklen enthalten<br />
Schritte 1,...,n:<br />
Berechne im z-ten (z←1,..,n) Schritt für alle<br />
Elemente cij, die nicht Element der z-ten Zeile,<br />
der z-ten Spalte oder der Hauptdiagonalen sind:<br />
neu alt alt alt<br />
cij ← MIN (cij , ciz + czj )<br />
sowie<br />
⎧ alt neu alt<br />
neu ⎪ pzj , falls cij < cij<br />
pij ← ⎨<br />
⎪ alt<br />
⎩ pij , sonst<br />
nach n Schritten: ENDE Tripel-Algorithmus<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 45 von 75
4.1.4 Bellmann Algorithmus – Typ A<br />
2<br />
6<br />
1<br />
4<br />
4<br />
1<br />
1<br />
6<br />
3<br />
5<br />
1 1 6 1 5<br />
a = 2<br />
Knoten 1 2 3 4 5 6<br />
PRE 0 2 4 3 0 0 4 0 2 0 3 6 0 1 1 1<br />
KW_DIST oo 6 5 3 0 oo 2 oo 1 oo 7 5 oo 7 6 4<br />
4.1.5 Topologisches Sortieren – Bellmann Algorithmus – Typ B<br />
1<br />
2<br />
6<br />
1<br />
4<br />
2<br />
4<br />
1<br />
1<br />
6<br />
3<br />
5<br />
3<br />
4<br />
5<br />
1 1 6 1 5<br />
6<br />
i δ - i<br />
L R = {1, 2 ,3 ,4 ,5 ,6}<br />
1 3 2 1 0 4 k = 1, 2, 3, 4, 5, 6 i = 2, 4, 3, 1, 6, 5<br />
2 0 1<br />
3 1 0 3<br />
4 1 0 2<br />
5 2 1 0 6<br />
6 2 1 0 5<br />
1<br />
6<br />
1<br />
4<br />
2<br />
1<br />
1<br />
6<br />
3<br />
5<br />
4 1 5 1 6<br />
a = 1<br />
Knoten 1 2 3 4 5 6<br />
PRE 0 0 1 0 2 0 3 0 4 0 5<br />
KW_DIST 0 oo 1 oo 2 oo 3 oo 4 oo 5<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 46 von 75
Bestimmung eines kürzesten Weges von einem Startknoten a zu allen<br />
anderen Knoten eines bewerteten Digraphen D = [V,E,c] mit dem<br />
Algorithmus von BELLMANN<br />
Eingabe: a : Startknoten<br />
c[i,j] : Bewertung des Pfeiles [i,j]<br />
Ausgabe: kw_dist[i] : Länge des kürzesten Weges von<br />
Startknoten a nach i<br />
pre[i] : Vorgänger des Knotens i auf dem<br />
kürzesten Weg von<br />
Startknoten a nach i<br />
VERSION a :<br />
D darf keine negativen Zyklen enthalten.<br />
Schritt 0: kw_dist[a] ← 0.<br />
kw_dist[i] ← ∞, ∀ i ≠ a.<br />
pre[i] ← 0 , ∀ i.<br />
Schritt 1: Durchführung für ∀ i ε V\{a} :<br />
falls kw_dist[i] > kw_dist[j]+c[j,i], (j ε P(i))<br />
setze kw_dist[i] ← kw_dist[j] + c[j,i],<br />
setze pre[i] ← j<br />
Schritt 2:<br />
Wiederholung von Schritt 1, bis kein kw_dist-<br />
Wert mehr verbessert werden kann.<br />
VERSION b :<br />
Schritt 0 :<br />
Schritt 1 :<br />
D ist topologisch sortiert.<br />
siehe Version a<br />
für i ← a+1,...,n führe aus:<br />
falls kw_dist[i] > kw_dist[j]+c[j,i], (j ε P(i))<br />
setze kw_dist[i] ← kw_dist[j] + c[j,i],<br />
setze pre[i] ← j<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 47 von 75
Topologische Sortierung<br />
eines zyklenfreien Digraphen D = [V,E] .<br />
Algorithmus TOPSORT<br />
Eingabe:<br />
Ausgabe:<br />
D = [V,E]<br />
L(i): 'neue' Knotennummer des Knotens i<br />
Schritt 0:<br />
R ← {1,...,n} = V<br />
k ← 1<br />
(zu vergebende aktuelle Knotennummer)<br />
Bestimme δ- j ∀ j ∈ R<br />
Schritt 1: Suche ein i ∈ R mit δ- i = 0<br />
Schritt 2: k ← k + 1<br />
R ← R \ { i }<br />
Existiert kein solches i -> ENDE des Algorithmus:<br />
D ist nicht zyklenfrei<br />
L(i) ← k<br />
Falls k = n-> ENDE des Algorithmus:<br />
D ist topologisch sortiert<br />
Bestimme für ∀ j ∈ Si: δ- j ← δ- j - 1<br />
Gehe zu Schritt 1<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 48 von 75
4.2 MINIMALGERÜSTE<br />
Problemstellung:<br />
Gegeben ist der zusammenhängende Graph G = (V,E,c). Gesucht ist ein<br />
Minimalgerüst G' = (V,E',c') zu G.<br />
Bestimmung eines Minimalgerüstes G' zu einem<br />
zusammenhängenden, bewerteten Graphen G = (V, E, c)<br />
Algorithmus MINGERÜST<br />
S1: Der Graph G' besteht aus der Knotenmenge V und der<br />
Kantenmenge E' = ∅<br />
S2: Wähle die Kante in G mit der geringsten Bewertung aus und füge<br />
sie zu G' hinzu, wenn dadurch kein Zyklus in G' entsteht.<br />
Existiert keine Kante in G mehr -> ENDE<br />
S3: Entferne die ausgewählte Kante aus G.<br />
S4: Gehe zu S2.<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 49 von 75
5. BÄUME<br />
Baum: - zyklenfreier Digraph<br />
- jeder Knoten (Ausnahme Wurzel) hat genau einen Vorgänger<br />
3<br />
1 2 4<br />
Wurzel<br />
innerer<br />
Knoten<br />
5<br />
Blatt (Endknoten)<br />
5.1 BINÄRBÄUME<br />
Zusatzbedingung: jeder Knoten hat maximal 2 Nachfolger<br />
A<br />
B<br />
E<br />
C D F<br />
linker Teilbaum<br />
Endknoten<br />
G<br />
H<br />
Darstellung von arithmetischen Ausdrücken:<br />
Operatoren = innere Knoten<br />
Operanden = Teilbäume oder Endknoten<br />
z.B. (a - b) / ((c * d) + e) f - (g - h) f - g - h<br />
/<br />
-<br />
-<br />
-<br />
+<br />
f -<br />
-<br />
h<br />
a<br />
b<br />
*<br />
e<br />
g<br />
h<br />
f<br />
g<br />
c<br />
d<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 50 von 75
Speicherung von binären Bäumen:<br />
Verkettet<br />
Zeiger LT<br />
INFO<br />
A<br />
Zeiger RT<br />
B<br />
NIL<br />
C<br />
NIL<br />
D<br />
E<br />
NIL NIL NIL NIL NIL<br />
F<br />
Sequentiell<br />
45<br />
22<br />
77<br />
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16<br />
11<br />
30<br />
90<br />
A<br />
45 22 77 11 30 90 15 25 99<br />
15 25<br />
99<br />
Wurzel --> 1. Element -> A[ 1 ] z.B. 90 -> RN von 77<br />
Linker Nachfolger von A[ I ] -> A[ 2 * I ] ==> 2 * 3 + 1 = 7<br />
Rechter Nachfolger von A[ I ] -> A[ 2 * I + 1 ]<br />
Vorgänger von A[ I ] -> A[ I / 2 ]<br />
max. Anzahl Speicherelemente: 2 t - 1<br />
(t: 'Tiefe' des Baumes)<br />
Durchsuchen von binären Bäumen<br />
A<br />
B<br />
C<br />
HR:<br />
A B D E F C G H I L K<br />
D<br />
E<br />
G<br />
H<br />
SR:<br />
D B F E A G C L I H K<br />
NR:<br />
D F E B G L I K H C A<br />
F<br />
I<br />
K<br />
LT / RT = Linker / Rechter Teilbaum<br />
L<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 51 von 75
1. Hauptreihenfolge / HR (Präordnung) S1: Bearbeite Wurzel<br />
S2: Bearbeite LT in HR<br />
(Rekursion)<br />
S3: Bearbeite RT in HR<br />
2. Symmetrische Reihenfolge / SR (Inordnung):<br />
S1: Bearbeite LT in SR<br />
S2: Bearbeite Wurzel<br />
S3: Bearbeite RT in SR<br />
3. Nebenreihenfolge / NR (Postordnung):<br />
S1: Bearbeite LT in NR<br />
S2: Bearbeite RT in NR<br />
S3: Bearbeite Wurzel<br />
5.2 BINÄRE SUCHBÄUME<br />
Ein binärer Suchbaum liegt dann vor, wenn gilt:<br />
A) alle Werte der Knoten der linken Nachfolgermenge (linker Teilbaum)<br />
eines Knotens i sind ≤ dem Wert des Knotens i und<br />
B) alle Werte der Knoten der rechten Nachfolgermenge (rechter Teilbaum)<br />
eines Knotens i sind ≥ dem Wert des Knotens i<br />
30<br />
20 60<br />
10 40 70<br />
50<br />
55<br />
51<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 52 von 75
Änderungen in binären Suchbäumen<br />
a) Knoten i einfügen: i als Endknoten (Blatt) unter Berücksichtigung<br />
der Bedingungen A) und B) ‘anhängen’<br />
b) Knoten i entfernen:<br />
b1) i hat keinen Nachfolger: i ‘abhängen’<br />
b2) i hat genau 1 Nachfolger: i ‘überbrücken’, d.h.<br />
entsprechenden Zeigerinhalt des Vorgängers von i durch<br />
die Adresse des Nachfolgers von i ersetzen<br />
b3) i hat 2 Nachfolger:<br />
i ersetzen durch den Knoten mit dem größten Wert im<br />
linken Teilbaum von i oder durch den Knoten mit dem<br />
kleinsten Wert im rechten Teilbaum von i. Das Entfernen<br />
des Ersatzknotens geschieht nach b1) bzw. b2)<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 53 von 75
5.3 HEAPSORT<br />
HEAP: Binärer Baum mit der Eigenschaft:<br />
Wert des Knotens i >= Wert jedes Nachfolgerknotens von i<br />
(-> der größte Wert steht in der Wurzel)<br />
SORTIERPROBLEM:<br />
GEGEBEN: lineares Feld A mit n Knoten, sequentiell gespeichert<br />
GESUCHT: absteigend sortierte Reihenfolge der Werte von A<br />
absteigende Sortierung eines linearen, sequentiell gespeicherten<br />
Feldes A<br />
Algorithmus HEAPSORT<br />
S1: der Heap besteht aus A[1]<br />
S2: für i← 2,...,n führe aus<br />
füge Knoten A[i] so in den bisherigen Heap ein, dass die<br />
Heapeigenschaft erhalten bleibt<br />
(-> Feld A besitzt jetzt die Heapeigenschaft)<br />
S3: a) in der Wurzel A[1] steht das größte Element. Gebe den<br />
Wert aus.<br />
b) entferne die Wurzel A[1] aus dem Feld A<br />
c) füge als Ersatzknoten den letzten Knoten von A in die Wurzel<br />
ein;<br />
falls kein Knoten von A mehr vorhanden ist -> ENDE:<br />
die ausgegeben Werte stellen die sortierte Reihenfolge dar.<br />
d) lasse diesen Knoten so absinken, dass die Heapeigenschaft<br />
wiederhergestellt ist:<br />
Vergleich mit den Nachfolgern; gegebenenfalls Tausch mit<br />
dem größten Nachfolger<br />
e) wiederhole S3<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 54 von 75
Beispiel Heapsort:<br />
1 2 3 4 5 6 7 8<br />
A: 44 30 50 22 60 55 77 55<br />
1 2 3 4 5 6 7 8<br />
S1: 44<br />
S2:<br />
1 2 3 4 5 6 7 8<br />
i=2: 44 30<br />
1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8<br />
i=3: 44 30 50 50 30 44<br />
1 2 3 4 5 6 7 8<br />
i=4: 50 30 44 22<br />
1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8<br />
i=5: 50 30 44 22 60 50 60 44 22 30<br />
1 2 3 4 5 6 7 8<br />
60 50 44 22 30<br />
1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8<br />
i=6: 60 50 44 22 30 55 60 50 55 22 30 44<br />
1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8<br />
i=7: 60 50 55 22 30 44 77 60 50 77 22 30 44 55<br />
1 2 3 4 5 6 7 8<br />
77 50 60 22 30 44 55<br />
1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8<br />
i=8: 77 50 60 22 30 44 55 55 77 50 60 55 30 44 55 22<br />
1 2 3 4 5 6 7 8<br />
77 55 60 50 30 44 55 22<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 55 von 75
S3:<br />
1 2 3 4 5 6 7 8<br />
77 55 60 50 30 44 55 22<br />
1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8<br />
77
6. SPEZIELLE ALGORITHMEN<br />
UND<br />
PRAKTISCHE ANWENDUNGSBEISPIELE<br />
6.1 Kalender-Algorithmen<br />
6.1.1 Bestimmung des Wochentages eines Datums<br />
Algorithmus BASISTAG<br />
S1: der 01.01.1900 war ein Montag. Zu jedem beliebigen späteren<br />
Datum kann dann der Wochentag berechnet werden.<br />
S2: für jedes folgende, volle Jahr nach dem 01.01.1900 verschiebt sich<br />
der Wochentag um 1 Tag, in Schaltjahren um 2 Tage.<br />
S3: für das angebrochene Jahr sind die bereits vergangenen Tage zu<br />
berücksichtigen. Der Wochentag verschiebt sich entsprechend.<br />
Anmerkung: Schaltjahre sind die Jahre, die ohne Rest durch 4 teilbar<br />
sind, jedoch nicht die vollen Jahrhunderte, bei denen die<br />
Division durch 400 ohne Rest nicht möglich ist.<br />
Algorithmus ZELLER (1877)<br />
Die Wochentagsnumerierung w<br />
(w=0: Sa, w=1: So, w=2: Mo, ..., w=6: Fr) kann wie folgt berechnet<br />
werden:<br />
S1: es seien t, m und j das Tages-, Monats- bzw. Jahresdatum<br />
S2: falls m
6.1.2 Bestimmung des Ostersonntag:<br />
(und damit aller beweglichen Feiertage für ein bestimmtes<br />
Jahr)<br />
Wann ist Ostersonntag <br />
Das Datum des Ostersonntag für jedes Jahr des 21. Jahrhunderts (2000-<br />
2099) kann wie folgt mit der Gauss'schen Regel zur Berechnung des<br />
Osterdatums ermittelt werden. Sie lautet:<br />
Algorithmus Ostersonntag<br />
Man dividiere die Jahreszahl<br />
durch 19 und nenne den Rest a,<br />
durch 4 und nenne den Rest b,<br />
durch 7 und nenne den Rest c.<br />
Die Division "(19a + 24) durch 30" ergebe den Rest d,<br />
die Division "(2b+4c+6d+5) durch 7" ergebe den Rest e.<br />
Der Ostersonntag liegt dann (d+e) Tage nach dem 22. März. Zu beachten<br />
sind die beiden Sonderfälle (Beschluss des Konzils von Nicäa (325)) :<br />
statt des 26. Aprils wird immer der 19. April gewählt; statt des 25. Aprils<br />
wird immer der 18. April gewählt, falls d=28 und a>10 gilt.<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 58 von 75
6.2 Erzeugung aller Permutationen (ohne Wiederholung)<br />
Gegeben sind n Elemente. Jede Anordnung der n Elemente heißt<br />
Permutation dieser Elemente. Sind alle Elemente verschiedenartig, so<br />
handelt es sich um Permutationen ohne Wiederholung. Sind nicht alle<br />
Elemente verschiedenartig, so spricht man von Permutationen mit<br />
Wiederholung.<br />
Anzahl der Permutationen ohne Wiederholung von n Elementen:<br />
n<br />
Π i = 1 * 2 * .... * (n-1) * n = n!<br />
i=1<br />
n! wird 'n-Fakultät' genannt. Es gilt 0! = 1.<br />
Beispiel:<br />
alle möglichen Permutationen (alle möglichen Anordnungen) der Zahlen<br />
1 2 3 (n=3): 1 2 3, 1 3 2, 2 1 3, 2 3 1, 3 1 2, 3 2 1<br />
Anzahl der Permutationen: n! = 3! = 1*2*3 = 6<br />
Bestimmung aller möglichen Permutationen (ohne Wiederholung)<br />
der Zahlen 1, ... , n<br />
Algorithmus PERMUTAT (rekursiv)<br />
Anfangswerte: info[1], ..., info[n] ← 0<br />
Aufruf: permutat (nr) mit nr ← 1<br />
Ausgabe: alle Permutationen werden im array info<br />
nacheinander generiert und ausgegeben (Zeile 6)<br />
permutat (nr)<br />
für i ← 1, …, n führe aus<br />
falls info[i] = 0 dann<br />
info[i] ← nr<br />
falls nr = n<br />
info[i] ← 0<br />
dann<br />
gebe info[1], …, info[n] aus<br />
// Ausgabe 1 Permutation<br />
andernfalls permutat (nr+1)<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 59 von 75
Aufgabe 1:<br />
Erstellen Sie ein C#-Programm (Konsolenanwendung), das<br />
a) eine n*n Matrix A (3
c) eine Methode GGT_2b wie b) jedoch rekursiv<br />
d) eine Methode GGT_2c unter Benutzung des Algorithmus GGT 2<br />
(Euklidische Methode mit MOD-Operator)<br />
e) eine Methode GGT_2d wie d) jedoch rekursiv<br />
Benutzen Sie als Testdaten z.B. GGT(31, 2.134.556) = 1, GGT(4.565.467,<br />
467.456.655) = 1, GGT(461.952, 116.298) = 18, GGT(31,103.333.323) = 31.<br />
Aufgabe 4:<br />
Erstellen Sie ein C#-Programm zum Problem MSP (Maximum Subarray<br />
Problem):<br />
a) Generierung eines Arrays X mit 1
Übung 2:<br />
In der folgenden Tabelle sind Rechenzeiten in Sekunden für verschiedene<br />
Algorithmen in Abhängigkeit von der Problemgröße n eingetragen.<br />
Vervollständigen Sie diese Tabelle.<br />
Algorithmus O( ) n = 100 n = 200 n = 1000<br />
Alg. A O(1) 13,5<br />
Alg. B O(n) 5<br />
Alg. C O(n 2 ) 8<br />
Alg. D O(n 3 ) 1000<br />
Aufgabe 5:<br />
Erstellen Sie ein C#-Programm zum Problem PRIM. Es sollen alle<br />
Primzahlen aus dem Zahlenbereich [1, ... ,n] und ihre Anzahl bestimmt<br />
werden. Die Primzahlen sollen in aufsteigender Reihenfolge gespeichert<br />
und ausgegeben werden. n ist einzulesen (1
Aufgabe 7:<br />
Erstellen Sie ein C#-Programm zu Operationen in sequentiell<br />
gespeicherten linearen Feldern. Zur Durchführung der Operationen soll<br />
kein weiteres Array benutzt werden. Besondere Beachtung sollen die<br />
'Sonderfälle' finden :<br />
- es existieren keine Datenknoten, d.h. n=0<br />
- es existiert genau ein Datenknoten, d.h. n=1<br />
- es gilt n=nmax<br />
a) als Testdaten sollen n (1
Aufgabe 8:<br />
Wie Aufgabe 7, jedoch bei verkettet gespeicherten linearen Feldern.<br />
a) als Testdaten sollen n (1
Aufgabe 10 (Josephusproblem):<br />
Das Josephusproblem kann wie folgt beschrieben werden:<br />
n Personen P 1 ,...,P n stehen im Kreise. Es wird 'durchgezählt', bei der<br />
Startperson beginnend. Die m-te Person soll jeweils aus dem Kreis<br />
ausscheiden. Es wird solange 'durchgezählt', bis keine Person mehr im<br />
Kreise vorhanden ist.<br />
Beispiel:<br />
n=14, m=2, Startperson=1<br />
P3<br />
P4<br />
P5<br />
P6<br />
P2<br />
P1<br />
P14<br />
P7<br />
P9<br />
P8<br />
P13<br />
P12<br />
P11<br />
P10<br />
Die Reihenfolge, in der die Personen aus dem Kreise ausscheiden, lautet:<br />
2, 4, 6, 8, 10, 12, 14, 3, 7, 11, 1, 9, 5 und schließlich 13.<br />
Erstellen Sie ein C#-Programm, das das Josephusproblem simuliert. n, m<br />
und die Nummer der Startperson sind einzulesen. Die jeweils<br />
ausscheidende Person, insbesondere die zuletzt ausscheidende, ist auf<br />
dem Bildschirm auszugeben. Zur Simulation soll ein kreisförmig<br />
verkettetes Feld ohne freie Knoten generiert werden. Die Personen P 1 , ...,<br />
P n können durch die Zahlen 1, ..., n in den Datenknoten dargestellt<br />
werden. Die logische Reihenfolge soll dabei der physikalischen<br />
Speicherreihenfolge entsprechen:<br />
z.B. n = 4 ANFANG = 1<br />
1 P 1 2 2 P 2 3 3 P 3 4 4 P 4 1<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 65 von 75
Aufgabe 11 (Ackermannfunktion):<br />
a) Erstellen Sie eine rekursive C#-Methode, die den Wert der<br />
Ackermann-Funktion für (n,x,y) berechnet.<br />
b) Erstellen Sie eine nichtrekursive, d.h. iterative C#-Methode, die den<br />
Wert der Ackermann-Funktion für (n,x,y) berechnet. Die<br />
Berechnung rekursiver Funktionen kann mit Hilfe eines Stapels geschehen.<br />
Bei der Berechnung der Ackermann-Funktion kann dabei<br />
wie folgt vorgegangen werden:<br />
S1: der Stapel besteht aus dem Knoten mit den Werten (n,x,y),<br />
S2: falls n=0 oder y=0<br />
dann setze t ← A(n,x,y),<br />
entferne den obersten Knoten vom Stapel,<br />
falls Stapel leer<br />
dann: ENDE: t ist der gesuchte Wert,<br />
andernfalls: ersetze den Wert des obersten<br />
Knotens (n,x,y) durch (n-1,t,x) ,<br />
andernfalls (falls n≠0 und y≠0) führe aus:<br />
füge neuen Knoten mit dem Wert (n,x,y-1) zum Stapel<br />
hinzu,<br />
S3: wiederhole S2.<br />
Beispiel A(2,3,1):<br />
(1,0,0) t←0<br />
(1,0,1) (0,0,0) t←1<br />
(2,3,0) t←0 (1,0,2) (1,0,2) (0,1,0) t←2<br />
(2,3,1) (1,0,3) (1,0,3) (1,0,3) (0,2,0) t←3<br />
Anmerkung zur Ergebniskontrolle:<br />
es gilt für die Ackermannfunktion :<br />
A(0, x, y) = x + 1<br />
A(1, x, y) = x + y<br />
A(2, x, y) = x * y<br />
A(3, x, y) = x y<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 66 von 75
Aufgabe 12 (Infix to Postfix):<br />
Erstellen Sie ein C#-Programm, das einen INFIX-Ausdruck Q mit<br />
einstelligen Operanden und den Operatoren +, -, *, / in einen POSTFIX-<br />
Ausdruck P mit Hilfe des Algorithmus INFTOPOST umwandelt.<br />
Hinweis: vereinbaren Sie Q,P vom Typ string, den Stapel als ein array<br />
vom Typ char []. Erstellen Sie dabei Methoden für das Einfügen in den<br />
bzw. Entfernen aus dem Stapel.<br />
Aufgabe 13 (Wert Postfix-Ausdruck):<br />
Erstellen Sie ein C#-Programm, das den Wert eines POSTFIX-Ausdrucks<br />
P mit Hilfe des Algorithmus WERTPOSTFIX berechnet. Der Stapel ist als<br />
ein array vom Typ double [], P vom Typ string, zu vereinbaren. P enthält<br />
nur einstellige Operanden und die Operatoren +, -, *, / .<br />
Aufgabe 14:<br />
Erstellen Sie ein C#-Programm zu folgendem Problem:<br />
zu simulieren ist das Verhalten einer Kundenwarteschlange an einem<br />
Bedienungsschalter. n ist die Anzahl der Kunden in der Warteschlange<br />
bei der Ausgangssituation. n ist einzulesen. Die Kunden sind durch ihre<br />
Kundennummer gekennzeichnet. Die Kundennummern A[i]<br />
(1
Aufgabe 15:<br />
Gegeben ist folgende symmetrische Entfernungstabelle (Angaben in km):<br />
Berlin Hamburg Frankfurt München<br />
Berlin 0 294 555 589<br />
Hamburg 0 495 782<br />
Frankfurt 0 460<br />
München 0<br />
Erstellen Sie ein C#-Programm, das<br />
a) die Informationen der Entfernungstabelle einliest und mit<br />
minimalem Speicheraufwand speichert,<br />
b) eine Erweiterung der Tabelle um:<br />
Flensburg --> Berlin 450<br />
Flensburg --> Hamburg 161<br />
Flensburg --> Frankfurt 656<br />
Flensburg --> München 943 ermöglicht,<br />
c) die Entfernungstabelle ausgibt,<br />
d) eine Abfrage der Entfernung von ... nach ... ermöglicht.<br />
Aufgabe 16:<br />
Gegeben sind die beiden mehrdimensionalen Felder<br />
A [-2..2, 2..22]<br />
B [1990..2010, -5..5, -10..5]<br />
Erstellen Sie ein C#-Programm, das<br />
a) die Anzahl der Feldelemente von A und B berechnet und ausgibt.<br />
(die Anzahl der Dimensionen n sowie die Unter- und Obergrenzen<br />
der einzelnen Dimensionen sind einzulesen)<br />
b) die Speicheradressen bei spalten- und zeilenweiser eindimensionaler<br />
Speicherung für ein Element a[i,j] bzw. b[i,j,k] berechnet<br />
und ausgibt. i,j bzw. i,j,k und die Basisadresse sind einzulesen.<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 68 von 75
Aufgabe 17:<br />
Gegeben ist ein bewerteter Digraph D2 = [V,E,c] mit V = {1,2,...,7} und E<br />
= e1,e2,...,e12} (siehe Datei a17_d2.net ):<br />
2<br />
e6<br />
1<br />
4<br />
1<br />
e1<br />
2<br />
e2<br />
7<br />
4<br />
e4<br />
3<br />
e10<br />
2<br />
e7<br />
3<br />
7<br />
5<br />
e11<br />
e3<br />
1<br />
2<br />
e5<br />
e8<br />
1<br />
1<br />
e12<br />
6<br />
3<br />
e9<br />
7<br />
Erstellen Sie ein C#-Programm:<br />
a) Speichern Sie den Digraphen D2 in einer Bewertungsmatrix C(D)<br />
und geben Sie die Bewertungsmatrix C(D) aus.<br />
b) Speichern Sie den Digraphen D2 in Vektorform (pfeilsortiert) und<br />
geben Sie die einzelnen Vektoren aus.<br />
c) Bestimmen Sie die Nachfolger z.B. der Knoten 1,6,7 in beiden Speicherungsformen.<br />
d) Bestimmen Sie die Vorgänger z.B. der Knoten 1,3,5 in beiden Speicherungsformen.<br />
e) Führen Sie die Aufgaben a) - d) ebenfalls für den folgenden Digraphen<br />
D3 durch (siehe Datei a17_d3.net )<br />
1 4<br />
2 e2<br />
3<br />
e3<br />
3<br />
1<br />
4<br />
2<br />
e1 e4<br />
5<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 69 von 75
Anmerkungen:<br />
1) Verwenden Sie auch zukünftig folgende Direktiven, Konstanten,<br />
Datentypen und Variablen :<br />
using AD_Bibliothek<br />
// Zeitmessung, Sortierung, Einlesen …<br />
const int nmax = 8600; // maximale Anzahl der Konten n<br />
const int nmax_plus_1 = nmax + 1;<br />
const int mmax = 25000; // maximale Anzahl der Pfeile m<br />
const int unendlich = 999999;<br />
int n; // Anzahl Knoten aktueller Digraph<br />
int m; // Anzahl Pfeile aktueller Digraph<br />
int[,] c = new int [nmax+1,nmax+1]; // Bewertungsmatrix<br />
int[] anfknoten = new int [mmax+1]; //Anfangsknotennumernvektor<br />
int[] endknoten = new int [mmax+1];// Endknotennummernvektor<br />
int[] cbewertung = new int [mmax+1];// Bewertungsvektor<br />
int[] pn = new int [nmax_plus_1+1]; // Pfeilnummernvektor<br />
int[] anf_zeiger = new int [nmax+1]; // siehe Alg. VORGAENGER<br />
int[] temp = new int [nmax+1]; // siehe Alg. VORGAENGER<br />
int[] vorgaenger = new int [mmax+1];// siehe Alg. VORGAENGER<br />
string datei_name;<br />
// z.B. a17_d2.net<br />
2) Verwenden Sie zum Einlesen der Digraphen (*.net-Dateien) die<br />
Einlesemethode LesenDatei.lesenNetDatei (datei_name, anfknoten,<br />
endknoten, cbewertung, ref n, ref m) (siehe AD_Bibliothek).<br />
3) Verwenden Sie zur Pfeilsortierung der Digraphen die Sortiermethode<br />
Quickersort.sort (anfknoten, endknoten, cbewertung, l, m)<br />
(siehe AD_Bibliothek) . Der Sortierschlüssel ist der 1. Parameter<br />
(hier: anfknoten). Sortiert wird von l, …, m. Die Elemente der<br />
Arrays endknoten und cbewertung werden entsprechend umsortiert.<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 70 von 75
Aufgabe 18:<br />
Implementieren Sie den DIJKSTRA-Algorithmus in C#<br />
a) in Matrixform mit der Methode<br />
public static void dmat<br />
(int[] pre, // pre[i]: Vorgänger von Knoten i<br />
int[] kw_dist, // kw_dist[i]: Länge KW von a<br />
nach i<br />
int[,] c, // Bewertungsmatrix C(D)<br />
int n,<br />
// Anzahl Knoten n von D<br />
int a<br />
// Startknoten<br />
)<br />
b) in Pfeilform mit der Methode<br />
public static void dpfeil<br />
(int[] pre, int[] kw_dist, int[] endknoten,<br />
int[] cbewertung, int[] pn, int n, int a)<br />
Verwenden Sie als Testdaten A17_d2.net (n=7, m=12). Ferner können<br />
als Daten die Straßennetze<br />
- angeln.net (n= 46, m= 168)<br />
- dh.net (n= 70, m= 226)<br />
- segeberg.net (n= 172, m= 572)<br />
- brd.net (n= 584, m= 2.218)<br />
- bw.net (n= 8.494, m= 24.844)<br />
- usa_hn.net (n= 128.111, m= 324.834)<br />
verwendet werden.<br />
Das Programm soll Länge und Verlauf des kürzesten Weges von<br />
Startknoten a zu einem einzugebenden Knoten k ausgeben. Falls Sie die<br />
Ortsnamen der Knoten (*.kdn-Dateien; bw.kdn und usa_hn.kdn nicht<br />
vorhanden) auch ausgeben möchten, so verwenden Sie zum Einlesen der<br />
Ortsnamen die Einlesemethode LesenDatei.lesenKdnDatei (datei_name,<br />
ort) (ort mit der Deklaration: string[] ort = new<br />
string[nmax+1]; (siehe AD_Bibliothek).<br />
Aufgabe 19:<br />
Implementieren Sie analog zu Aufgabe 18 den FORD-Algorithmus in<br />
C# jeweils als Methode in Pfeilform, wobei<br />
a) R als Stapel<br />
b) R als Schlange<br />
organisiert ist.<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 71 von 75
Aufgabe 20:<br />
Implementieren Sie den TRIPEL-Algorithmus in C# mit folgendem<br />
Methodenkopf:<br />
public static void tripel<br />
(int [,] c, // Bewertungsmatrix C(D)<br />
int [,] p, // Vorgängermatrix P(D) (nxn-Matrix)<br />
int n // Anzahl der Knoten n von D<br />
)<br />
Aufgabe 21:<br />
Implementieren Sie den BELLMANN-Algorithmus in den Versionen a<br />
und b jeweils als Methode in Pfeilform mit folgendem Methodenkopf:<br />
public static void bellmannPfeilA bzw.<br />
public static void bellmannPfeilB<br />
(int [] pre, int [] kw_dist, int [] anfknoten, int []<br />
cbewertung,<br />
int []vorgaenger, int [] anf_zeiger,<br />
int n, int a)<br />
Da der Bellmann-Algorithmus in der Version b topologisch sortierte<br />
Digraphen voraussetzt, benötigen wir zum Erzeugen derartiger<br />
Digraphen einen Graphengenerator. Erstellen Sie dazu eine Methode<br />
public static void<br />
generiereTopologischSortiertenDigraph<br />
(int [] pn ,int [] endknoten, int [] cbewertung,<br />
int n, ref int m)<br />
die einen topologisch sortierten Digraphen (also auch zyklenfreien) ohne<br />
parallele Pfeile mit genau einer Quelle (Knoten 1) und genau einer Senke<br />
(Knoten n) generiert. Dabei kann wie folgt vorgegangen werden:<br />
Für alle Knoten i in der Reihenfolge 1,...,n-1 werden Pfeile zu Knoten mit<br />
höheren Knotennummern (mit der Methode Random.Next) generiert,<br />
wodurch der generierte Digraph zyklenfrei und topologisch sortiert ist.<br />
Die Anzahl der Pfeile, die von einem Knoten ausgehen, soll maximal 5<br />
betragen.<br />
Zur topologischen Sortierung und zur Überprüfung, ob der Digraph<br />
topologisch sortiert werden kann (zyklenfrei ist), erstellen Sie die<br />
Methode<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 72 von 75
public static bool sortiereDigraphTopologisch<br />
(int []pn, int [] endknoten,<br />
int [] l<br />
//l[i] = neue Knoten-Nr.<br />
int n)<br />
die nur dann den Wert ‚true‘ liefert, wenn D topologisch sortiert werden<br />
konnte (also zyklenfrei ist).<br />
Aufgabe 22:<br />
Modifizieren Sie die Algorithmen von FORD und BELLMANN zur<br />
Bestimmung von kürzesten Wegen derart, dass sie zur Bestimmung von<br />
längsten Wegen benutzt werden können. Generieren Sie als Testdaten<br />
Digraphen mit der Methode generiereTopologischSortiertenDigraph (......)<br />
(siehe Aufgabe 21) oder benutzen Sie zum Testen die bekannten<br />
Straßennetze (Achtung: Bewertungen mit –1 multiplizieren !).<br />
Aufgabe 23:<br />
Implementieren Sie den Algorithmus MINGERUEST für ungerichtete<br />
Graphen G als Methode<br />
public static void mingeruest<br />
(int [] endknoten1,<br />
int [] endknoten2,<br />
int [] cbewertung,<br />
bool [] minimalgeruest,<br />
int<br />
int n, m,<br />
)<br />
kosten_minimalgeruest,<br />
mit minmalgeruest[i] = true(false): Kante i ist (nicht) im Gerüst<br />
kosten_minimalgeruest : Kosten des Minimalgerüstes<br />
Benutzen Sie die Methoden LesenDatei.lesenNetDatei (datei_name,<br />
endknoten1, endknoten2, cbewertung, ref n, ref m) zum Einlesen z.B. der<br />
Beispielgraphen a23a.net, a23b.net oder der Straßennetze und die<br />
Methode Quickersort.sort (cbewertung, endknoten1, endknoten2, 1, m) zur<br />
aufsteigenden Sortierung der Bewertungen. (siehe AD_Bibliothek).<br />
Sortierschlüssel ist dabei der 1. Parameter cbewertung.<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 73 von 75
Übung 3:<br />
Stellen Sie folgenden arithmetischen Ausdruck als binären Baum dar:<br />
(a+b-c)/(d*(e-(f-g))*(h-i-j))+k<br />
Übung 4:<br />
Gegeben sind die Haupt- (HR) und die Symmetrische (SR) Reihenfolge:<br />
HR: A B D E F C G H I L K SR: D B F E A G C L I H K<br />
Geben Sie den binären Baum an, der beiden Reihenfolgen entspricht.<br />
Übung 5:<br />
Gegeben ist folgender binäre Suchbaum:<br />
30<br />
20 60<br />
10 40 70<br />
50<br />
55<br />
51<br />
a) Geben Sie die symmetrische Reihenfolge an.<br />
b) Fügen Sie die Knoten mit den Werten 25 und 35 in den Baum ein.<br />
c) Entfernen Sie die Knoten mit den Werten 10, 55 und 30.<br />
Aufgabe 24:<br />
Implementieren Sie den Algorithmus HEAPSORT zur aufsteigenden<br />
Sortierung eines sequentiell gespeicherten linearen Feldes A. Es soll<br />
dabei 'in situ' ('vor Ort' im Array A), d.h. ohne Benutzung eines<br />
zusätzlichen Arrays, eine Methode<br />
public static void heapsort (int [] a, int n)<br />
erstellt werden. Generieren Sie das zu sortierende Array A mit n<br />
Elementen mit der Methode Random.Next(). Die Dateninhalte der<br />
Datenknoten von A sollen dabei Werte aus dem Wertebereich [0,...,99]<br />
annehmen. n ist einzulesen.<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 74 von 75
Aufgabe 25:<br />
Erstellen Sie ein C#-Programm, das für ein einzulesendes Datum in der<br />
Form tt mm jjjj den Wochentag nach der Basistag-Methode und der<br />
Methode von ZELLER bestimmt. Das Datum soll aus dem 20. oder den<br />
folgenden Jahrhunderten sein.<br />
Aufgabe 26:<br />
Erstellen Sie ein C#-Programm, das das Osterdatum für alle Jahre des 21.<br />
Jahrhunderts nach der Gauss'schen Regel berechnet und wie folgt auf<br />
dem Bildschirm ausgibt:<br />
Ostersonntag 2000 ist am 23. April Ostersonntag 2001 ist am 15. April<br />
...<br />
Ostersonntag 2008 ist am 23. März Ostersonntag 2009 ist am 12. April<br />
...<br />
Ostersonntag 2038 ist am 25. April ...<br />
... ...<br />
... Ostersonntag 2049 ist am 18. April<br />
... ...<br />
Ostersonntag 2076 ist am 19. April ...<br />
... ...<br />
Ostersonntag 2098 ist am 20. April Ostersonntag 2099 ist am 12. April<br />
Aufgabe 27:<br />
Bestimmen Sie eine minimale Rundreise, die jeden Knoten des Graphen<br />
mindestens einmal enthält<br />
a) mit dem heuristischen Verfahren des ‚Besten Nachfolgers‘. Erstellen<br />
Sie dazu eine Methode<br />
static void rundreise_bn<br />
(int[,] entfernung,<br />
//Entfernungsmatrix<br />
int n,<br />
//Anzahl Knoten<br />
int a,<br />
//Ausgangsknoten<br />
ref int[] min_route,<br />
//Routenverlauf<br />
ref int min_routenlaenge) //Routenlaenge<br />
b) mit einem exakten Verfahren mit Hilfe des Algorithmus<br />
PERMUTAT (siehe S. 59 Skript AD). Erstellen Sie dazu eine<br />
Methode<br />
static void rundreise_exakt<br />
(int[,] entfernung,<br />
//Entfernungsmatrix<br />
int n,<br />
//Anzahl Knoten<br />
ref int[] min_route,<br />
//Routenverlauf<br />
ref int min_routenlaenge, //Routenlaenge<br />
ref long anzahl_permutationen) //Anzahl Permutat.<br />
Algorithmen + Datenstrukturen SS 2010 23.03.10 75 von 75