30.01.2015 Aufrufe

pdf, 387 KB

pdf, 387 KB

pdf, 387 KB

MEHR ANZEIGEN
WENIGER ANZEIGEN

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

Hurra! Ihre Datei wurde hochgeladen und ist bereit für die Veröffentlichung.

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!