27.11.2012 Aufrufe

Algorithmen und Datenstrukturen

Algorithmen und Datenstrukturen

Algorithmen und Datenstrukturen

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.

<strong>Algorithmen</strong> <strong>und</strong><br />

<strong>Datenstrukturen</strong><br />

Kapitel 7:<br />

<strong>Algorithmen</strong>konstruktion II<br />

Sommersemester 2007<br />

Prof. Dr. Stefan Fischer


Inhalt<br />

� Dynamische Programmierung<br />

� Verteilte Berechnungen<br />

� Zufallsgesteuerte <strong>Algorithmen</strong><br />

2/47


Dynamische Programmierung<br />

� Gr<strong>und</strong>prinzip<br />

� Beispiel: Fibonacci-Zahlen<br />

� Das Rucksack-Problem<br />

� Textsuche (Vorberechnung)<br />

3/47


Gr<strong>und</strong>prinzip<br />

� Rekursive Lösungsstruktur:<br />

1. Aufteilung in abhängige Teilprobleme (Ggs: Teile-<strong>und</strong>-Herrsche<br />

mit unabhängigen Teilproblemen)<br />

2. Berechnen <strong>und</strong> Zwischenspeichern wiederkehrender<br />

Teilergebnisse<br />

3. Bestimmung des Gesamtergebnisses unter Verwendung der<br />

Teilergebnisse<br />

� Häufig verwendet bei Optimierungsproblemen:<br />

� Interpretation der Teilergebnisse als optimale Lösung eines<br />

"kleineren" Teilproblems<br />

� Ggf. zusätzlicher Schritt 4: Konstruktion der optimalen Lösung auf<br />

Basis der berechneten Teillösungen.<br />

Dabei ggf. Hinzuziehung weiterer Informationen aus Schritt 3.<br />

4/47


Beispiel (1/2)<br />

Beispiel Fibonacci-Zahlen:<br />

fib:IN 0 →IN mit<br />

fib(0) = 0<br />

fib(1) = 1<br />

n > 1: fib(n) = fib(n-1) + fib(n-2)<br />

Analoge Rekursive Lösung<br />

in Java Pseudocode:<br />

public int fibRek(int n) {<br />

if (n = 0) return 0;<br />

if (n = 1) return 1;<br />

return fibRek(n-1)+fibRek(n-2);<br />

}<br />

Berechnung wiederholt<br />

bestimmte Schritte:<br />

fib(2) = fib(1) + fib(0)<br />

fib(3) = fib(2) + fib(1)<br />

fib(4) = fib(3) + fib(2) ...<br />

Aufwandsabschätzung:<br />

T(n) = Anzahl Additionen<br />

T(0) = 0<br />

T(1) = 0<br />

T(n) = 1+T(n-1)+T(n-2) für n≥2<br />

=> Rekursive Lösung ist teuer!<br />

Es geht billiger mit dynamischer Programmierung.<br />

5/47


Beispiel (2/2)<br />

Iterative dynamische Lösung in Java Pseudocode:<br />

public int fibDynPro(int n) {<br />

int result;<br />

if (n = 0) return 0;<br />

if (n = 1) return 1;<br />

int fibMinus1 = 1, fibMinus2 = 0;<br />

for(int i=2; i


Das Rucksack-Problem (1/8)<br />

� Die Story:<br />

� Schatzsucher findet Schatz bestehend aus Edelsteinen.<br />

� Jeder Edelstein hat<br />

- ein bestimmtes Gewicht <strong>und</strong><br />

- einen bestimmten Wert.<br />

� Er hat nur einen Rucksack, dessen Kapazität durch ein maximales<br />

Gewicht gegeben ist.<br />

� Die Aufgabe: befülle den Rucksack mit Edelsteinen<br />

� ohne die Gewichtsbeschränkung zu verletzen<br />

� bei Maximierung des Wertes der Edelsteine.<br />

7/47<br />

x kg y €<br />

≤ z kg


Das Rucksack-Problem (2/8)<br />

� Formale Fassung des Rucksack-Problems (engl. Knapsack-P.):<br />

� Gegeben<br />

� Kapazität c ∈ IN<br />

� Menge O mit n∈ IN Objekten o 1 , o 2 ,..., o n<br />

� Gewichtsfunktion g:O→IN<br />

� Bewertungsfunktion w: O→IN<br />

� Gesucht ist O’⊆ O mit<br />

Dabei gelte ∑<br />

j∈<br />

O<br />

g ( j)<br />

><br />

c<br />

∑<br />

j∈O'<br />

g( j)<br />

≤ c <strong>und</strong> w(<br />

j)<br />

maximal<br />

∑<br />

j∈O'<br />

Anmerkung: Eigtl. 0-1 Knapsack Problem, da nur ganze Objekte<br />

betrachtet werden dürfen (ansonsten Fractional Knapsack Problem).<br />

8/47


Das Rucksack-Problem (3/8)<br />

� Erste Lösungsidee: Greedy<br />

� Aber: Greedy funktioniert nicht!<br />

� Beispiel: O = { o 1, o 2, o 3 }, Kapazität c = 5<br />

� Gewichte: g(o 1 ) = 1, g(o 2 ) = 2, g(o 3 ) = 3<br />

� Werte: w(o 1 ) = 6, w(o 2 ) = 10, w(o 3 ) = 12<br />

� Greedy: Nimm Objekt mit größtem relativen Wert bis Rucksack voll!<br />

� Relative Werte ( r(o)=w(o)/g(o) ): r(o 1) = 6, r(o 2) = 5, r(o 3) = 4<br />

� Ergebnis: O’={o 1, o 2}, mit<br />

∑<br />

j∈O'<br />

sicher nicht maximal!<br />

Besser ist O’’={o3 , o2 } m.∑<br />

j∈<br />

g( j)<br />

= 3 < c = 5 <strong>und</strong><br />

O''<br />

∑ ∈O<br />

j<br />

'<br />

w(<br />

j)<br />

= 16<br />

∑<br />

j∈O''<br />

g( j)<br />

= 5 ≤ c = 5 u. w(<br />

j)<br />

= 22<br />

9/47


Das Rucksack-Problem (4/8)<br />

� Zweite Lösungsidee: Backtracking<br />

� Funktioniert, ist aber aufwändig!<br />

� Beispiel: O = { o 1, o 2, o 3 , o 4 }, c = 10<br />

� Gewichte: g(o 1 ) = 2, g(o 2 ) = 2, g(o 3 ) = 6, g(o 4 ) = 5<br />

� Werte: w(o 1 ) = 6, w(o 2 ) = 3, w(o 3 ) = 5, w(o 4 ) = 4<br />

� Lösungsraum<br />

(Konfigurations-<br />

baum):<br />

10 8<br />

8<br />

6<br />

(0,0) (5,4) (6,5) (2,3) (7,7) (8,8) (2,6) (7,10) (8,11) (4,9) (9,13) (10,14)<br />

10/47<br />

Zur Disposition:<br />

o :(g,w)<br />

10 4 8 2 8 2 6 0<br />

10 5 4 8 3 2 8 3 2 6 1 0<br />

*Restkapazität<br />

10*<br />

nein<br />

ja<br />

10 8<br />

Teilbäume gleich<br />

> Optimierungspotenzial<br />

> Dyn. Prog<br />

o 1 :(2,6)<br />

o 2 :(2,3)<br />

o 3 :(6,5)<br />

o 4 :(5,4)


Das Rucksack-Problem (5/8)<br />

Rekursive Backtracking-Lösung in Java Pseudocode:<br />

public int btKnapsack(int i, int restkapazität ) { // Aufruf: btKnapsack(1,c)<br />

// Rückgabewert: Wert d. optimalen Füllung bei O={oi,...,on} <strong>und</strong><br />

c=restkapazität<br />

Objekt o=objekte[i]; // objekte[] ist globale Variable mit Indexmenge {1,2,....,n}<br />

if ( i==objekte.length ) // Ende der Rekursion: o ist das letzte Objekt<br />

if (o.gewicht() > restkapazität) // wenn o nicht mehr hinein passt, dann<br />

return 0; // bleibt es draußen<br />

else return o.wert(); // andernfalls kommt es hinein <strong>und</strong> steigert den Wert<br />

else if (o.gewicht() > restkapazität) // analog bei den anderen Objekten<br />

return btKnapsack(i+1, restkapazität)<br />

else return max( btKnapsack(i+1,restkapazität),<br />

btKnapsack(i+1,restkapazität–o.gewicht())+o.wert() ); //<br />

Wenn es noch hinein passt, werden dennoch<br />

} // beide Möglichkeiten betrachtet<br />

Anmerkung: Optimierungspotenzial (Ausnutzen wiederkehrender Berechnungen)<br />

wird hier nicht genutzt!<br />

11/47


Das Rucksack-Problem (6/8)<br />

� Lösung durch dynamische Programmierung<br />

� Beispiel: O = { o 1 , o 2 , o 3 , o 4 , o 5 }, c = 10<br />

� Gewichte: g(o 1 ) = 2, g(o 2 ) = 2, g(o 3 ) = 6, g(o 4 ) = 5, g(o 5 ) = 4<br />

� Werte: w(o 1 ) = 6, w(o 2 ) = 3, w(o 3 ) = 5, w(o 4 ) = 4 , w(o 5 ) = 6<br />

� Idee: In Iteration rückwärts die Resultate der Aufrufe btKnapsack(i,r)<br />

berechnen > Verwendung eines zweidimensionalen Feldes f:<br />

i<br />

r<br />

0 1 2 3 4 5 6 7 8 9 10<br />

5 0 0 0 0 6 6 6 6 6 6<br />

4 0 0 0 0 6 6 6 6 6 10 10<br />

3 0 0 0 0 6 6 6 6 6 10 11<br />

2 0 0 3 3 6 6 9 9 9 10 11<br />

Beispiel*: f[4,9]=btKnapsack(4,9)=10 (d.h. o 4 <strong>und</strong> o 5 haben bei<br />

Restkapazität 9 noch Platz: Wert der Füllung = 10)<br />

*Anstelle der Java-üblichen Schreibweise f[4][9] wird im Foglenden f[4,9] verwendet.<br />

6<br />

12/47


Das Rucksack-Problem (7/8)<br />

� Beachte zentrale Anweisungen in btKnapsack(i,r):<br />

� ... else return max( btKnapsack(i+1,restkapazität),<br />

�<br />

Bsp.:<br />

btKnapsack(i+1,restkapazität–o.gewicht())+o.wert() ) ...<br />

0 1 2 3 4 5 6 7 8 9 10<br />

5 0 0 0 0 6 6 6 6 6 6<br />

4 0 0 0 0 6 6 6 6 6 10 10<br />

3 0 0 0 0 6 6 6 6 6 10 11<br />

2 0 0 3 3 6 6 9 9 9 10 11<br />

f[3,8] = max(f[4,8], f[4,2]+5) = max(6,0+5) = 6<br />

Idee für dynamische Programmierung verfeinert:<br />

1. Berechnung der Werte für i=n <strong>und</strong> alle Restkapazitäten von 0 bis c.<br />

2. Dann von i=n-1 bis 2 Berechnung der Feldeinträge für jeweils alle Kapazitäten<br />

unter Rückgriff auf die bereits berechneten Werte der Zeile i+1.<br />

3. Gesamtergebnis f[1,c] dann durch Einzelberechnung<br />

(f[1,10] = max(f[2,10], f[2,8]+6) = max(11,9+6) = 15).<br />

6<br />

13/47


Das Rucksack-Problem (8/8)<br />

Dynamische Programmierung in Java Pseudocode:<br />

public int dpKnapsack(int n, int c ) {// Aufruf: dpKnapsack(objekte.length,c)<br />

int[][] f = new int[2,n][0,c]; // Deklaration des Feldes (CAVE: Java-unüblich)<br />

// Initialisierung des Feldes für i = n<br />

for (int r = 0; r r ) f[n,r] = 0;<br />

else f[n,r] = objekte[n].wert();<br />

// Berechnung des Feldes für i = n-1,...,2<br />

for (int i = n-1; i >=2; i = i-1)<br />

for (int r = 0; r r ) f[i,r] = f[i+1,r];<br />

else f[i,r] = max( f[i+1,r], f[i+1, r- objekte[i].gewicht()]<br />

+objekte[i].wert() );<br />

// Berechne f[1,c] (den maximal erreichbaren Wert)<br />

if ( objekte[1].gewicht() > c ) return f[2,c];<br />

else return max( f[2,c], f[2, c-objekte[1].gewicht()] + objekte[1].wert() );<br />

}<br />

14/47


Textsuche<br />

� Problem: Finden eines Wortes in einem (längeren) Text.<br />

� Konkret:<br />

� Gegeben:<br />

- Array a von Zeichen der Länge n<br />

(Bsp.: a="Eine Rose ist eine Rose ist eine Rose")<br />

- Array s von Zeichen der Länge m (i.d.R. m


Textsuche – Brute-Force-Lösung<br />

� Brute-Force-Lösung:<br />

� Suche ersten übereinstimmenden Buchstaben (Laufindex i).<br />

� Falls gef<strong>und</strong>en an Position i=j: vergleiche nachfolgende Buchstaben<br />

� Falls erfolgreich: Ende <strong>und</strong> Rückgabe von i<br />

� Falls nicht erfolgreich: erhöhe i um 1 <strong>und</strong> mache weiter mit Schritt 1<br />

Konkret (Java-Pseudocode):<br />

public int bruteForceSearch( char[] a, char[] s ) {<br />

int k; // Laufvariable<br />

for (int i = 0; i


Textsuche - Beispiel<br />

a<br />

s<br />

0 1 2 3 4 5 6 7<br />

8 9 10 11 12 13 14 15 ...<br />

E i n e R o s e i s t e i<br />

R o s e<br />

i=0 (k=0) R o s e<br />

i=1 (k=0) R o s e<br />

i=2..3 (k=0) ...<br />

i=4 (k=0) R o s e<br />

i=5 (k=0) R o s e<br />

i=5 (k=1) R o s e<br />

i=5 (k=2) R o s e<br />

s.length=4 // ...relevanter Teil:<br />

for (int i = 0; i


Textsuche – Laufzeit bei Brute-Force<br />

� Maßstab für Laufzeit:<br />

Anzahl Vergleiche<br />

� Worst-Case:<br />

� Auftreten Worst-Case:<br />

Wenn ab jeder Position in a die Zeichenkette s bis auf das letzte<br />

Zeichen auftritt.<br />

Beispiel: a="aaaaaaaaaaaaaaaaaab" s="aaab"<br />

=> (3) wird bei jedem Zeichen aus a betreten (d.h. n-m Mal)<br />

<strong>und</strong> vollständig (d.h. m Mal) durchlaufen<br />

� Anzahl Vergleiche: (n-m)*m<br />

� Laufzeit: O((n-m)*m) = O(nm)<br />

� Gewünscht: Verbesserung der Laufzeit insbesondere für große Muster<br />

bzw. für große s.<br />

(1)<br />

(2)<br />

(3)<br />

(4)<br />

// Relevanter Teil:<br />

... for (int i = 0; i


Textsuche – Verbesserung<br />

Verschieben des Suchmusters bei Misserfolg des Vergleichs nicht um 1<br />

sondern um Entfernung e<br />

Problem: e hängt vom Muster s ab<br />

Beispiel 1:<br />

a="123123x123" <strong>und</strong> s="123x" (alle Zeichen verschieden)<br />

=> Bei Misserfolg kann bis zur Stelle des Mismatch verschoben<br />

werden.<br />

Beispiel 2:<br />

a=„345345345x123" <strong>und</strong> s=„345345x" (Teilmuster wiederholt sich)<br />

=> bei Misserfolg im 7‘ten Vergleich (k=6) muss a mit s ab Position<br />

4 von s verglichen werden (i=3 <strong>und</strong> k=3).<br />

Ablauf: i=0 > Übereinstimmung 0.-5. Zeichen > Fehler bei<br />

k=6 > i=i+3 ...<br />

19/47


Algorithmus von Knuth-Morris-Pratt(1/5):<br />

� Idee: Für jedes Zeichen s[k] im Muster merken, um wie viele<br />

Positionen bei Misserfolg des Vergleiches a[i+k]==s[k] in a<br />

vorangeschritten werden kann.<br />

� Hilfsstruktur hierfür: int[] dis = new int[s.length]<br />

� Achtung: Index i wird mit k inkrementiert. Mittels dis[] wird k<br />

korrigiert!<br />

Beispiel:<br />

a<br />

0 1 2 3 4 5 6 7<br />

dis -1 0 0 0 1 1<br />

i=0..4, k=0..4 s A B C A A B<br />

i=4..5, k=1..2<br />

i=5..7, k=0..2<br />

8 9 10 11 12 13 14<br />

A B C A B A B A B C A A B A B<br />

A B C A A B<br />

Korrektur: k=1<br />

A B C A A B<br />

Korrektur: k=0<br />

Korrektur: k=0<br />

i=7..12, k=0..5 A B C A A B Rückgabe: i-k=7<br />

20/47


Algorithmus von Knuth-Morris-Pratt(2/5):<br />

� Problem: Bestimmen des Distanzfeldes dis.<br />

� Notwendig: Überprüfung des Musters auf sich wiederholende<br />

Teilmuster s[0]...s[j]. Findet sich eine Wiederholung des Umfanges j≥0<br />

links vom kritischen Vergleichsindex k, d.h. ist s[k-1-j] ...s[k-1] gleich<br />

s[0]...s[j], so kann der Vergleich s[0]...s[j] ausgelassen werden. D.h. k<br />

kann gleich j+1 gesetzt werden.<br />

Beispiel:<br />

a<br />

0 1 2 3 4 5 6 7<br />

i=0..4, k=0..4 s A B C A A B<br />

8 9 10 11 12 13 14<br />

A B C A B A B A B C A A B A B<br />

s[0]...s[0] ist gleich s[k-1-0]...s[k-1]=s[3]<br />

=> Verschieben auf k = j+1 = 0+1 = 1<br />

s A B C A A B<br />

k =1 ist zugleich der Index für<br />

den nächsten Vergleich!<br />

21/47


Algorithmus von Knuth-Morris-Pratt (3/5):<br />

� Lösungsidee zur Bestimmung des Distanzfeldes dis (grob):<br />

Eine Kopie des Musters wird am Muster selbst vorbei<br />

geschoben, wobei die überlappenden Zeichen verglichen<br />

werden. In dis werden die jeweils übereinstimmenden<br />

Zeichen gespeichert.<br />

Beispiel:<br />

s<br />

0 1 2 3 4 5<br />

A B C A A B<br />

dis[i]<br />

i=1 s A B C A A B 0<br />

i=2 s A B C A A B 0<br />

i=3 s<br />

A B C A A B 0<br />

i=4 s<br />

A B C A A B 1<br />

i=5 s<br />

A B C A A B 1<br />

dis[i]= "0 oder x+1, falls ∃x:<br />

s[i-1-x]...s[i-1]=s[0]...s[x]"<br />

Bei Ungleichheit nach rechts<br />

verschieben um ein Feld<br />

Verschieben stoppt bei<br />

Gleichheit!<br />

Bei erster Ungleichheit Verschieben<br />

wieder aufnehmen!<br />

22/47


Algorithmus von Knuth-Morris-Pratt (4/5):<br />

Bestimmung des Distanzfeldes in Java Pseudocode:<br />

public int[] initDis(char[] s ) {<br />

int[] dis = new int[s.length]; // Deklaration des Feldes<br />

int i = 0, j = -1; // Deklaration/Initialisierung temporärer Laufvariablen<br />

dis[0] = -1; // Init. dis[0]<br />

// i „durchwandert“ das Muster von links (0) nach rechts bis s.length-2<br />

while (i < s.length-1) {<br />

// j „zählt“ die gleichen Anfangszeichen<br />

while (j >= 0 && s[i] != s[j]) j=dis[j]; // Schleifenrumpf nur bei s[i]≠s[j] relevant<br />

// hiernach ist s[i]=s[j];<br />

//nur solange werden j <strong>und</strong> i inkrementiert u. dis[i] gesetzt<br />

i=i+1; j=j+1;<br />

dis[i] = j;<br />

}<br />

return dis;<br />

}<br />

23/47


Algorithmus von Knuth-Morris-Pratt (5/5):<br />

Nun zur eigentlichen Suchfunktion in Java Pseudocode:<br />

public int kmpSearch(char[] a, char[] s ) {<br />

int[] dis = initDis(s); // Berechnung des Distanzfeldes<br />

int i = 0, j = 0; // Deklaration/Initialisierung temporärer Laufvariablen<br />

// i „durchwandert“ den Text von links (0) nach rechts bis a.length-1<br />

while (i < a.length) {<br />

// j „zählt“ die gleichen Anfangszeichen<br />

while (j >= 0 && s[j] != a[i]) j=dis[j]; // Schleifenrumpf nur bei a[i]≠s[j] relevant<br />

// hiernach ist a[i]=s[j]; nur solange werden j <strong>und</strong> i inkrementiert<br />

i=i+1; j=j+1;<br />

if (j==s.length) return i-s.length;<br />

}<br />

return -1;<br />

}<br />

24/47


Anmerkungen<br />

� Laufzeit von kmpSearch() :<br />

� Laufzeit initDis(): Maximal 2m Durchläufe => O(m)<br />

� Laufzeit kmpSearch(): O(m)+“Maximal 2n Durchläufe“<br />

� O(n+m)<br />

� Vorteil von kmpSearch() entfaltet sich erst bei sich<br />

wiederholenden Textmustern im Suchstring.<br />

� Weiterer Vorteil: In der zu durchsuchenden Zeichenkette<br />

muss nie zurückgegangen werden (gut bei externen<br />

Speichermedien).<br />

� Was hat all dies mit dynamischer Programmierung zu tun:<br />

das hier eingesetzte Prinzip der Vorberechnung ist eine<br />

Spezialisierung der dynamischen Programmierung.<br />

� „Variante“ von kmpSearch(): Boyer-Moore<br />

25/47


Inhalt<br />

� Dynamische Programmierung<br />

� Verteilte Berechnungen<br />

� Zufallsgesteuerte <strong>Algorithmen</strong><br />

26/47


Verteilte Berechnungen<br />

� Analogon Hausbau:<br />

� Schritte:<br />

� Baugrube ausheben<br />

� Bodenplatte gießen<br />

� Mauern & Dach decken<br />

� Fenster einbauen<br />

� Türen einbauen<br />

� Tapezieren<br />

� ...<br />

� Abhängigkeiten sind<br />

einzuhalten!<br />

=> Paralleles Arbeiten<br />

erfordert Koordination<br />

Prinzipiell durch<br />

eine Person möglich<br />

=> Dauert<br />

(sehr) lange<br />

Besser:<br />

Teamwork<br />

=> Schnell, da<br />

parallel gearbeitet<br />

werden kann<br />

27/47


Parallelisierung/Sequenzialiserung<br />

� Lässt sich ein Problem in unabhängige Teilprobleme<br />

zerlegen, so bietet sich zwecks Steigerung der Effizienz die<br />

unabhängige Berechnung der Teilprobleme durch<br />

getrennte Prozessoren an (Parallelisierung):<br />

Nach Bearbeitung der Teilprobleme: Zusammenführen<br />

der Ergebnisse (Sequenzialisierung).<br />

...<br />

28/47


Prozesse<br />

� Zentraler Begriff: der Prozess (=Vorgang einer<br />

algorithmisch arbeitenden Informationsbearbeitung)<br />

� Konzept: Pro Zeiteinheit wird auf jedem Prozessor genau<br />

ein Prozess ausgeführt.<br />

� Prozesse haben Lebenszyklus (vereinfacht):<br />

� sie werden gestartet <strong>und</strong> laufen ab,<br />

� sie werden blockiert <strong>und</strong> warten (z.B. auf Eingabe),<br />

� sie werden wiederbelebt <strong>und</strong> laufen ab <strong>und</strong><br />

� sie werden beendet <strong>und</strong> bleiben terminiert.<br />

� Ein Prozess kann sog. Kind-Prozesse anstoßen.<br />

Notwendig: Kommunikation von Prozessen<br />

(über Status des (Kind-)Prozesses, bzgl. Daten (z.B.<br />

Rechenergebnisse) etc.)<br />

suspend<br />

initiated<br />

running<br />

waiting<br />

start<br />

terminated<br />

29/47<br />

resume<br />

kill


Realisierung<br />

� Varianten (grob):<br />

� Mehrere Prozessoren befinden sich auf einer Platine<br />

(Mehrprozessorsystem)<br />

� In einem Netzwerk von Rechnern steht pro Rechner<br />

ein Prozessor zur Verfügung (Cluster)<br />

Kombinationen sind möglich!<br />

Prinzip: Ein Prozess gibt lediglich an, ob <strong>und</strong> welche<br />

Kind-Prozesse erzeugt <strong>und</strong> gestartet werden<br />

sollen. Die Verteilung <strong>und</strong> Durchführungskontrolle<br />

(inkl. Nachrichtenvermittlung) übernimmt das<br />

(Netzwerk-) Betriebssystem (abgek. BS).<br />

Multiprocessingsysteme ermöglichen virtuelle<br />

Parallelität auf nur einem Prozessor: Hier verteilt<br />

das BS Rechenzeit(scheiben) auf Prozesse.<br />

Windows 2000<br />

UNIX ...<br />

30/47


Modellierung verteilter Berechnung (1/3)<br />

� Petri-Netze (C.A. Petri 1962) dienen der Modellierung<br />

sogenannter nebenläufiger <strong>und</strong> nichtdeterministischer Abläufe.<br />

� Gr<strong>und</strong>elemente dieser gerichteten Graphen:<br />

1. Transitionen: stellen elementaren Arbeitsschritt dar<br />

2. Stellen: Zwischenlager für "Datenobjekte„<br />

zerlegen<br />

3. Marken: Datenobjekt/Kontrollfluss<br />

Teilproblem 1<br />

Bedingung: Nur zwischen Stellen <strong>und</strong> Transitionen (<strong>und</strong> umgekehrt)<br />

bestehen Verbindungen.<br />

Idee: Transitionen verarbeiten die Marken der Stellen ihres<br />

Vorbereichs <strong>und</strong> geben die Resultate an Stellen im Nachbereich ab<br />

Unsortierte Liste<br />

Sortieren<br />

t→t+1<br />

Sortierte Liste<br />

Unsortierte Liste<br />

Sortieren<br />

Sortierte Liste<br />

31/47


Modellierung verteilter Berechnung (2/3)<br />

� Petri-Netze formal (Definition):<br />

� Ein Petrinetz ist ein 4-Tupel (S,T,F,M) mit:<br />

� S≠∅ (Menge von Stellen)<br />

� T≠∅ ∧ S∩T=∅ (von S unterschiedliche Menge von Transitionen)<br />

� F⊆S×T ∪ T×S (Flussrelation zw. Stellen <strong>und</strong> Transitionen u.u.)<br />

� M: S→IN 0 (Startmarkierung der Stellen)<br />

� Weitere Definitionen:<br />

� •t = {s∈S|(s,t) ∈F} für t∈T<br />

(Vorbereich einer Transition)<br />

Beispiel:<br />

� t• = {s∈S|(t,s) ∈F} für t∈T<br />

(Nachbereich einer Transition) •t1={s1,s2}<br />

t1• ={s2,s3}<br />

s1<br />

s3<br />

s2<br />

t1<br />

32/47


Modellierung verteilter<br />

Berechnung (3/3)<br />

� Ausführbarkeit einer Transition t: Gilt für eine Markierung<br />

M': S→IN 0, dass ∀s ∈ •t : M'(s)≥1, so ist t ausführbar.<br />

� Semantik: Folge von Markierungen > Schaltregel<br />

� Schaltregel: Eine Markierung M': S→IN 0 kann aus einer Markierung M<br />

wie folgt hervorgehen:<br />

Beispiel:<br />

•t1={s1,s2}<br />

t1• ={s2,s3}<br />

M(s1)=3, M(s2)=1,<br />

M(s3)=1<br />

(=> t1 ausführbar)<br />

M'(s)=<br />

s1<br />

s3<br />

s2<br />

t1<br />

M(s)+1 falls t ausführbar, s∈t• aber s∉•t<br />

M(s)-1 falls t ausführbar, s∈•t aber s∉t•<br />

M(s) sonst<br />

M»M'<br />

s1<br />

s3<br />

s2<br />

t1<br />

M'(s1)=2,<br />

M'(s2)=1,<br />

M'(s3)=2<br />

33/47


Petri-Netze – Gr<strong>und</strong>legende Strukturen (1/2)<br />

• Sequentieller Ablauf Transition 1 Transition 2<br />

• Parallelisierung<br />

• Synchronisation<br />

(Sequenzialisierung)<br />

Transition 1<br />

Transition 1<br />

Transition 2<br />

Transition 2<br />

Transition 3<br />

Transition 3<br />

34/47


Petri-Netze – Gr<strong>und</strong>legende Strukturen (2/2)<br />

• Alternative<br />

Achtung !<br />

Transition 1<br />

Markenfluß ist nicht deterministisch!<br />

• Schleife<br />

Transition 2<br />

Transition 3<br />

Transition 3<br />

Transition 1 Transition 2<br />

35/47


Beispiel: Hausbau 2<br />

Baugrube ausheben<br />

Grube<br />

ausgehoben<br />

Bau genehmigt<br />

F<strong>und</strong>ament giessen<br />

Keller mauern<br />

Bodenplatte giessen<br />

F<strong>und</strong>ament gegossen<br />

Türen sind<br />

einzubauen<br />

Türen<br />

eingebaut<br />

Mauern möglich<br />

Türen einbauen<br />

Mauern & Dach decken<br />

Haus fertig<br />

Fenster eingebaut<br />

Tapezieren<br />

Eigentlich Spezialfall von Petri-Netz: Bedingungs-/Ereignisnetz (> Kontrollfluss)<br />

Fenster<br />

sind<br />

einzubauen<br />

36/47<br />

Fenster einbauen


Weitere Aspekte<br />

� Erweiterungen von Petri-Netzen:<br />

� Stellen erhalten Kapazität (maximale Markenanzahl)<br />

� Beziehungen erhalten Gewicht (wird bei der Berechnung der<br />

Folgemarkierung anstelle "1" verwendet)<br />

� Marken werden gefärbt<br />

� u.s.w. (> Theoretische Informatik)<br />

� Petri-Netze (oder verwandte Beschreibugen) werden<br />

häufig für Prozessmodellierung eingesetzt; oft auch nur zur<br />

Veranschaulichung.<br />

� Potentielle Probleme nebenläufiger Prozesse:<br />

Deadlocks/Livelocks<br />

� Wichtiges Hilfsmittel für Koordination von Prozessen:<br />

Semaphoren (Dijkstra) > Regelung des Zugriffs auf<br />

gemeinsame Ressource<br />

37/47


Inhalt<br />

� Dynamische Programmierung<br />

� Verteilte Berechnungen<br />

� Zufallsgesteuerte <strong>Algorithmen</strong><br />

38/47


Zufallsgesteuerte <strong>Algorithmen</strong><br />

� Gr<strong>und</strong>prinzip<br />

� Gr<strong>und</strong>muster<br />

� Monte Carlo <strong>Algorithmen</strong><br />

� Las Vegas <strong>Algorithmen</strong><br />

� Allgemeiner Las Vegas Algorithmus<br />

� Macao Algorithmus<br />

39/47


Gr<strong>und</strong>prinzip<br />

� Idee: Verwendung zufällig gewählter Daten, um die<br />

Laufzeit eines Algorithmus zu senken.<br />

� Einige Aufgaben sind heute überhaupt nur<br />

auf diese Weise effizient zu lösen.<br />

� Beispiel: Primzahleigenschaft großer Zahlen<br />

� Zentrale Eigenschaft zufallsgesteuerter <strong>Algorithmen</strong>: sie<br />

sind nicht deterministisch.<br />

� Zentrales Werkzeug zufallsgesteuerter <strong>Algorithmen</strong>:<br />

� Zufallszahlengeneratoren<br />

� Beispiel (Java): public static double random() der Klasse Math<br />

realisiert eine im Intervall [0,1[ gleichverteilte Zufallsvariable<br />

� S.a. Klasse Random<br />

40/47


Gr<strong>und</strong>muster für den Entwurf<br />

� Auswahl: aus einer Menge deterministischer <strong>Algorithmen</strong><br />

zur Lösung eines Teilproblems wird zufällig einer<br />

ausgewählt<br />

� Stichprobe: aus einer zufällig gewählten Stichprobe von<br />

Daten wird auf Eigenschaft aller Daten geschlossen<br />

� Zeuge (Betrifft Ja/Nein-Entscheidungen): Auf hinreichend<br />

viele Daten (die Zeugen) angewendet bestätigen<br />

deterministische Alg. ein Ereignis mit Wahrscheinlichkeit<br />

p>0,5 (>Monte Carlo)<br />

� Umordnung: Eingabemenge wird zufällig umgeordnet<br />

(>etwaige für Laufzeit negative Trends zerstören)<br />

41/47


Monte Carlo <strong>Algorithmen</strong><br />

� Prinzip: Monte Carlo <strong>Algorithmen</strong> (MCA) liefern nur mit einer<br />

Wahrscheinlichkeit p Bei Entscheidungsproblemen: p≠0,5<br />

� Gr<strong>und</strong>muster:<br />

� Ein MCA y:=mc(x) liefert ein korrektes Ergebnis nur mit<br />

Wahrscheinlichkeit p


MCA: Beispiel<br />

� Berechnung der Zahl π.<br />

� Formel für Kreisfläche: A= πr²<br />

� Betrachte Einheitskreis im 1. Quadranten<br />

Seien x <strong>und</strong> y Zufallszahlen aus [0,1[.<br />

⇒ p:=P( (x, y)∈A' )=A'/1= π/4<br />

1<br />

A'<br />

⇒A'= πr²/4= π/4<br />

Fläche Quadrat=1<br />

Wird dieses Experiment n Mal wiederholt <strong>und</strong> "landen" c Punkte (x,y)<br />

in A', so gilt π(n)=4c/n<br />

Beispiel: In einem Zufallsexperiment mit 10000 gleichverteilten<br />

Punkten (x,y) ∈ [0,1[×[0,1[ erfüllen 7874 Punkte die Bedingung x²+y² π(10000)=4*7874/10000=3.1496 (für den Fehler gilt: εMC-Integration)<br />

1<br />

43/47


Las Vegas <strong>Algorithmen</strong><br />

� Prinzip: Im Ggs. zu MCA liefert ein Las Vegas Algorithmus (LVA) immer das<br />

richtige Ergebnis, wenn er terminiert.<br />

� Unterscheidung:<br />

� Er terminiert mit Wahrscheinlichkeit presult) <strong>und</strong> dabei Zufallszahlen verwendet. Sie testet zudem,<br />

// ob das Ergebnis richtig ist <strong>und</strong> gibt das Resultat zurück (>erfolg)<br />

return result;<br />

}<br />

44/47


Allg. LVA: Eigenschaften/Beispiel<br />

� Es gibt keine obere Schranke für die Laufzeit des allgemeinen LVA.<br />

� Gr<strong>und</strong>: Im Extremfall werden unendlich viele schlechte Ergebnisse<br />

geraten <strong>und</strong> immer wieder verworfen.<br />

� Daher Forderung: der ungünstigste erwartete Fall ist immer endlich.<br />

� Beispiel: Zufälliges Färben von Elementen<br />

� Gegeben: Menge S mit n Elementen, paarweise verschiedene<br />

Untermengen S0,...,Sk-1⊆S mit |Si| = r > 0. Es gelte k≤2r-2.<br />

� Gesucht: Färbung der Elemente von S derart, dass jedes Si wenigstens ein<br />

rotes <strong>und</strong> ein schwarzes Element enthält.<br />

� Algorithmus: suggestResultSimple() ordnet jedem Element zufällig<br />

irgendeine Farbe zu <strong>und</strong> gibt zurück, ob erfolgreich.<br />

� Offensichtlich: Nicht immer korrekte Lösung.<br />

� Frage: Wahrscheinlichkeit für falsche Lösung?<br />

45/47


Allg. LVA: Beispiel Fortsetzung<br />

Frage: Wahrscheinlichkeit für falsche Lösung?<br />

P(ein Element wird rot gefärbt)<br />

= P(ein Element wird schwarz gefärbt) = 1/2<br />

P(alle Elemente von Si sind rot) = 1/ 2r = 2-r<br />

P(irgend ein Si ist vollständig rot gefärbt) ≤ k*2-r<br />

Voraussetzung: k≤2r-2<br />

Damit: P(irgend ein Si ist vollständig rot gefärbt) ≤ k*2-r ≤ 2r-2*2-r = 1/4<br />

=> P(irgend ein Si ist einheitlich (rot oder schwarz) gefärbt) ≤ 1/2<br />

=> suggestResultSimple() liefert<br />

mit einer Wahrscheinlichkeit ≤ 1/2 eine falsche Lösung <strong>und</strong><br />

mit einer Wahrscheinlichkeit ≥ 1-1/2=1/2 eine korrekte Lösung<br />

(Voraussetzung für allg. LVA erfüllt)<br />

46/47


Macao <strong>Algorithmen</strong><br />

� Macao <strong>Algorithmen</strong> entstehen meist aus gewöhnlichen<br />

deterministischen <strong>Algorithmen</strong>, indem<br />

� die Elemente der Eingabemenge in zufälliger Folge bearbeitet<br />

werden, oder<br />

� ein Zufallsgenerator genutzt wird, um ein Element zufällig zu<br />

wählen.<br />

� Beispiel für 1.: randomizedInputArrayQuickSort()<br />

� Beispiel für 2.: quickSort() mit determinePivotElement()-<br />

Dienst, der auf zufälliger Auswahl des Pivot-Elements<br />

beruht<br />

47/47

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

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!