31.10.2013 Aufrufe

ADS – Vorlesung Prof. Dr. Wolfram Conen

ADS – Vorlesung Prof. Dr. Wolfram Conen

ADS – Vorlesung Prof. Dr. Wolfram Conen

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>ADS</strong> <strong>–</strong> <strong>Vorlesung</strong><br />

<strong>Prof</strong>. <strong>Dr</strong>. <strong>Wolfram</strong> <strong>Conen</strong><br />

Inhalte:<br />

- Greedy-Algorithmen<br />

- Matroide<br />

- Greedy-Beispiel Huffman-Codierung<br />

11.06.2008 (c) W. <strong>Conen</strong>, FH GE, <strong>ADS</strong> 1


Greedy-Optimierung<br />

• Nehmen Sie an, sie brechen nachts in eine Villa ein und<br />

wollen<br />

soviel an Werten mitnehmen, wie sie tragen können<br />

so schnell wie möglich wieder raus<br />

• Es gelten folgende Nebenbedingungen<br />

Die Bewohner sind verreist, wir haben im Prinzip<br />

„reichlich Zeit“<br />

Wir kennen den Wert aller Wertgegenstände<br />

Wir können nicht alles mitnehmen, nur ein bestimmtes<br />

Gewicht (sonst wäre „Alles mitnehmen“ optimal)<br />

Die Gewichte kennen wir auch (Handwaage ist immer<br />

dabei!)<br />

11.06.2008 (c) W. <strong>Conen</strong>, FH GE, <strong>ADS</strong> 2


Greedy-Optimierung<br />

• Dieses Problem ist (in krimineller Verkleidung) das<br />

klassische Knapsack Problem (Rucksack-Problem), formal:<br />

Gegeben ist eine Menge M = {1,..,n} von Gegenständen<br />

mit den Werten v i und den Gewichten w i . Gesucht ist M‘<br />

⊆ M mit<br />

∑ i ∈ M‘ w i ≤ w max<br />

<br />

d.h. die Summe der Gewichte der Gegenstände in M‘<br />

überschreitet ein vorgegebenes Maximalgewicht nicht.<br />

Der Wert der Gegenstände soll so groß wie möglich sein:<br />

Max M‘ ⊆ M ← ∑ i ∈ M‘ v i<br />

11.06.2008 (c) W. <strong>Conen</strong>, FH GE, <strong>ADS</strong> 3


Greedy-Optimierung<br />

• Lösungsidee:<br />

<br />

<br />

Gegenstände nach dem Verhältnis von Wert zu Gewicht<br />

(„Wert pro Kilo“) absteigend sortieren (der mit dem<br />

größten Wert pro Gewichtseinheit steht also vorne), z.B.<br />

in einer PQueue<br />

Dann nehmen wir solange Gegenstände aus der PQueue,<br />

wie wir sie noch tragen können<br />

• Diese Strategie ist „gierig“! (English: Greedy) <strong>–</strong> man nimmt<br />

das „Vielversprechendste“ zuerst usw.<br />

• Ist das immer sinnvoll?<br />

11.06.2008 (c) W. <strong>Conen</strong>, FH GE, <strong>ADS</strong> 4


Greedy-Optimierung<br />

• Natürlich nicht (würde ich sonst so fragen...)<br />

• Wir können maximal 50kg tragen, es gibt die folgenden<br />

Gegenstände<br />

<br />

<br />

<br />

Lehrbuch über Algorithmen und Datenstrukturen,<br />

Gewicht w 1<br />

= 10kg, Wert v 1<br />

= 60 Euro, d.h. 6 Euro pro kg<br />

Taschenrechner mit eingebautem Dijkstra,<br />

Gewicht w 2<br />

= 20kg, Wert v 2<br />

= 100 Euro, d.h. 5 Euro pro kg<br />

Allegorische Statue, die die ewige Schönheit von (bottom-up)<br />

Heapsort symbolisiert,<br />

Gewicht w 3<br />

= 30kg, Wert v 3<br />

= 120 Euro, d.h. 4 Euro pro kg<br />

• Was liefert die Greedy-Strategie als Resultat?<br />

• Wie sieht das optimale Resultat aus?<br />

11.06.2008 (c) W. <strong>Conen</strong>, FH GE, <strong>ADS</strong> 5


Greedy-Optimierung<br />

• Aber manchmal geht es auch...sogar immer, wenn die<br />

Problemstellung entsprechend ist.<br />

• Andere Gegenstände:<br />

Ein Haufen Schnipsel mit Klausurlösungen,<br />

Gewicht 10kg, Wert 60 Euro, 6 Euro pro kg<br />

Ein Haufen Goldstaub,<br />

<br />

Gewicht 20kg, Wert 100 Euro, 5 Euro pro kg<br />

Ein Haufen Silberstaub,<br />

Gewicht 30kg, Wert 120 Euro, 4 Euro pro kg<br />

• Jetzt können wir die Gegenstände beliebig teilen:<br />

• Also nehmen wir die Klausurschnipsel, den Goldstaub, und füllen<br />

unseren Rucksack mit Silberstaub auf (zu einem Gesamtwert von<br />

60+100+80 = 240 Euro)<br />

• Besser geht es natürlich nicht!<br />

11.06.2008 (c) W. <strong>Conen</strong>, FH GE, <strong>ADS</strong> 6


Greedy-Optimierung<br />

<br />

Probleme des ersten Typs (mit unteilbaren Gegenständen)<br />

heißen<br />

0-1 Knapsack Probleme<br />

<br />

Probleme des zweiten Typs (mit beliebig teilbaren<br />

Gegenständen) heißen<br />

Fractional Knapsack<br />

<br />

<br />

Fractional Knapsack Probleme lassen sich immer „greedy“<br />

lösen!<br />

0-1 Knapsacks nur ab und an „zufällig“!<br />

11.06.2008 (c) W. <strong>Conen</strong>, FH GE, <strong>ADS</strong> 7


Greedy-Optimierung<br />

<br />

Unser „kürzeste-Wege-Problem“ lässt sich auch „Greedy“<br />

lösen <strong>–</strong> und genau das tut der Dijkstra auch!<br />

<br />

Das gleiche gilt für das „Minimum Spanning Tree“-<br />

Problem, und auch Kruskal bzw. Prim lösen das Problem<br />

„greedy“<br />

<br />

Ein guter Hinweis darauf ist oft die Verwendung einer<br />

PQueue...<br />

11.06.2008 (c) W. <strong>Conen</strong>, FH GE, <strong>ADS</strong> 8


Arbeitsweise von Greedy-Algorithmen<br />

<br />

Wir haben folgendes zur Verfügung<br />

• Eine Menge von Kandidaten C, aus denen wir die Lösung<br />

konstruieren wollen (z.B. Kanten beim MST)<br />

• Eine Teilmenge S ⊆ C, die bereits ausgewählt wurde<br />

• Boole‘sche Funktion solution, die sagt, ob eine Menge von<br />

Kandidaten eine legale Lösung des Problems darstellt<br />

(unabhängig davon, ob die Lösung optimal ist)<br />

• Eine Testfunktion feasible, die sagt, ob eine Teillösung unter<br />

Umständen zu einer kompletten legalen Lösung erweitert<br />

werden kann<br />

• Eine Auswahlfunktion select, die den nächsten<br />

„vielversprechendsten“ Kandidaten liefert<br />

• Eine Zielfunktion value, die uns den Wert einer Lösung<br />

angibt<br />

11.06.2008 (c) W. <strong>Conen</strong>, FH GE, <strong>ADS</strong> 9


Arbeitsweise von Greedy-Algorithmen<br />

Function greedy(c)<br />

S ← ∅<br />

while not solution(S) and C ≠ ∅ do<br />

x ← select(C)<br />

C ← C - {x}<br />

if feasible(S ∪ {x}) then<br />

S ← S ∪ {x}<br />

if solution(S) then<br />

return S<br />

else return „There_is_no_solution“<br />

Mit der Funktion value(S) kann man am Ende den Wert der<br />

gefundenen Lösung bestimmen (falls es eine gab...)<br />

11.06.2008 (c) W. <strong>Conen</strong>, FH GE, <strong>ADS</strong> 10


Welche Probleme sind „greedy“ lösbar?<br />

• Wenn das Problem sich als Matroid modellieren läßt, dann kann<br />

man es „Greedy“ lösen!<br />

• Aber was ist ein Matroid? [s. Literaturempfehlungen]<br />

• Es gilt sogar: ein Problem lässt sich genau dann „greedy“ lösen<br />

(allgemein für jede Gewichtungsfunktion der Elemente in die<br />

positiven reellen Zahlen), wenn es eine Matroid-Struktur aufweist<br />

(s. auch „Das Geheimnis des kürzesten Weges“, Literaturhinweis<br />

zu Gin1b)<br />

11.06.2008 (c) W. <strong>Conen</strong>, FH GE, <strong>ADS</strong> 11


Noch ein wichtiges Problem, das man „greedy“ angehen kann:<br />

Datenkompression<br />

• Ist ihre Festplatte ständig zu klein?<br />

• ...oder ihre Internet-Anbindung zu langsam?<br />

• Dann ist Datenkompression ein Thema für Sie!<br />

• Ziele:<br />

<br />

<br />

möglichst platzsparende Datenspeicherung bzw.<br />

Übertragung<br />

entpacken möglich, ohne Fehler in den Daten zu<br />

hinterlassen<br />

11.06.2008 (c) W. <strong>Conen</strong>, FH GE, <strong>ADS</strong> 12


Datenkompression<br />

• Zwei Teilprozesse:<br />

<br />

<br />

Kompression: Ein Prozess, der Daten in einer komprimierte,<br />

also „kleinere“, Form überführt<br />

Expansion: Ein Prozess, der aus der komprimierten Form die<br />

Ausgangsdaten rekonstruiert<br />

• Beispielfälle für „Original“-Daten:<br />

<br />

<br />

Ein Text aus 256.000 Zeichen, jedes der 256 möglichen<br />

(ASCII-)Zeichen tritt genau 1000-mal auf<br />

Der Text besteht aus 256.000-mal dem Zeichen ‚a‘<br />

• Beide Texte nehmen 256.000*8 = 2.048.000 Bit Plattenplatz ein.<br />

11.06.2008 (c) W. <strong>Conen</strong>, FH GE, <strong>ADS</strong> 13


Datenkompression<br />

<br />

Betrachten wir einmal die Wahrscheinlichkeit, dass an<br />

einer bestimmten Stelle der Files ein bestimmtes Zeichen<br />

auftaucht:<br />

• Im ersten File ist die Wahrscheinlichkeit für das<br />

Auftauchen jedes Zeichens an der ersten betrachteten<br />

Position gleich, nämlich 1/256, z.B. für ‚a‘<br />

An später betrachteten Positionen verschieben sich<br />

die Wahrscheinlichkeiten abhängig von den vorher<br />

bereits betrachteten Zeichen (wenn es z.B. gar kein<br />

a mehr gibt), aber „ungefähr“ bleibt es bei der<br />

Wahrscheinlichkeit 1/256 auch an den anderen<br />

Positionen<br />

• Im zweiten Fall ist die Wahrscheinlichkeit für das<br />

Auftauchen von ‚a‘ an jeder Position 1.<br />

11.06.2008 (c) W. <strong>Conen</strong>, FH GE, <strong>ADS</strong> 14


Datenkompression<br />

• Im ersten Fall besteht eine hohe Unsicherheit darüber,<br />

welches Zeichen an der betrachteten Position auftritt.<br />

• Um zwischen den verschiedenen möglichen „Ereignissen“<br />

(das Auftreten eines bestimmten der 256 Zeichen) zu<br />

unterscheiden, müssen wir den aufgetretenen Fall genau<br />

angeben<br />

• Um 256 Ereignisse zu unterscheiden, brauchen wir<br />

log 2 256 Bit, also 8 ;-)<br />

11.06.2008 (c) W. <strong>Conen</strong>, FH GE, <strong>ADS</strong> 15


Datenkompression<br />

• Im zweiten Fall wissen wir mit Sicherheit, welches<br />

Zeichen an der betrachteten Position auftritt (nämlich „a“)<br />

• Um zwischen den verschiedenen möglichen „Ereignissen“ zu<br />

unterscheiden, brauchen wir eigentlich gar keine<br />

Information<br />

• Wir müssen nur wissen, wieviele „a“ auftreten<br />

• Insgesamt können wir das File durch „Jetzt kommen<br />

256.000 ‚a‘“ vollständig beschreiben (also mit ungefähr 150<br />

Bit)<br />

• Intuitiv ist klar, dass man im ersten Fall nicht sehr viel<br />

komprimieren kann, im zweiten aber schon!<br />

11.06.2008 (c) W. <strong>Conen</strong>, FH GE, <strong>ADS</strong> 16


Datenkompression<br />

• Zum Komprimieren muss man den „Eingabetext“ sinnvoll<br />

kodieren.<br />

• Elementare Idee:<br />

Zeichen, die häufig vorkommen, erhalten<br />

vergleichsweise kurze Codes<br />

• Das nennt man „variable Kodierung“<br />

• Sie soll den folgenden Ausdruck minimieren<br />

∑ l(c i )*f(c i ), 1 ≤ i ≤ n<br />

<br />

<br />

<br />

n = Anzahl der Zeichen<br />

l(c i ) = Länge der Codierung des Zeichens c i<br />

f(c i ) = Häufigkeit von c i im Text<br />

11.06.2008 (c) W. <strong>Conen</strong>, FH GE, <strong>ADS</strong> 17


Datenkompression<br />

a b c d e f<br />

Häufigkeit 45 13 12 16 9 5<br />

ASCII 01100001 01100010 01100011 01100100 01100101 01100110<br />

Code 1 0 011 100 101 0011 1100<br />

Code 2 0 101 100 111 1101 1100<br />

Was ist schlecht am Code 1? Probieren Sie mal, 001100101 zu expandieren!<br />

Man könnte natürlich die Länge des nächsten Codes abspeichern, aber so<br />

recht macht das keinen Sinn...bei Code 2 geht das auch so!<br />

11.06.2008 (c) W. <strong>Conen</strong>, FH GE, <strong>ADS</strong> 18


Datenkompression<br />

a b c d e f<br />

Häufigkeit 45 13 12 16 9 5<br />

Code 1 0 011 100 101 0011 1100<br />

Code 2 0 101 100 111 1101 1100<br />

• Dekodieren des Wortes 001100101 mit Code 1:<br />

• Stellen sie sich vor, sie lesen die Eingabe Zeichen für Zeichen<br />

von links nach rechts und müssen Entscheidungen treffen...<br />

0<br />

0<br />

f f<br />

1 f<br />

a,b,c,d,e,f<br />

1<br />

0<br />

0<br />

c,d,f<br />

b,e<br />

a<br />

1<br />

0<br />

0<br />

c,d<br />

b<br />

e<br />

1<br />

1<br />

0<br />

b<br />

d<br />

c<br />

1 1 e e<br />

11.06.2008 (c) W. <strong>Conen</strong>, FH GE, <strong>ADS</strong> 19


Datenkompression<br />

• Dekodieren des Wortes 001100101 mit Code 1:<br />

• Stellen sie sich vor, sie lesen die Eingabe Zeichen für Zeichen<br />

von links nach rechts<br />

• Zu Beginn sind noch alle Codes möglich<br />

• Aber bereits beim ersten Knoten können sie nicht exakt<br />

entscheiden, ob die 0 für ein a oder für b oder e steht...<br />

1<br />

f<br />

0<br />

f<br />

0<br />

f<br />

a,b,c,d,e,f<br />

0?<br />

1<br />

0<br />

0<br />

c,d,f<br />

b,e<br />

a<br />

0<br />

1<br />

0<br />

c,d<br />

b<br />

e<br />

1<br />

1<br />

0<br />

b<br />

d<br />

c<br />

1 1 e e<br />

11.06.2008 (c) W. <strong>Conen</strong>, FH GE, <strong>ADS</strong> 20


Datenkompression<br />

a b c d e f<br />

Häufigkeit 45 13 12 16 9 5<br />

Code 2 0 101 100 111 1101 1100<br />

• Dekodieren des Wortes 001100101 mit Code 2:<br />

1<br />

d<br />

1<br />

a,b,c,d,e,f<br />

0<br />

d,e,f<br />

1 0<br />

e,f<br />

b,c,d,e,f<br />

0<br />

b,c<br />

1 b<br />

0 c<br />

a<br />

1 e<br />

0 f<br />

aafb<br />

11.06.2008 (c) W. <strong>Conen</strong>, FH GE, <strong>ADS</strong> 21


Datenkompression<br />

• Definition: Eine Codierung heißt präfix-frei, wenn kein<br />

Code Anfangsstück (=Präfix) eines anderen Codes ist<br />

• Einen solchen Code kann man offensichtlich mit Hilfe von<br />

binären Entscheidungsbäumen beschreiben:<br />

<br />

<br />

<br />

<br />

Die Blätter sind die zu kodierenden Zeichen<br />

Die Codes ergeben sich aus den Wegen im Baum, die<br />

von der Wurzel zu den Zeichen führen<br />

Eine Zweig nach links steht für ein 0, ein Zweig nach<br />

rechts für eine 1<br />

Eine solche Kodierung ist immer präfix-frei, weil zu jeder<br />

Zeit klar ist, wie es im Baum weitergeht (es gibt keine<br />

Wahlmöglichkeiten)<br />

11.06.2008 (c) W. <strong>Conen</strong>, FH GE, <strong>ADS</strong> 22


Präfix-freie Codes<br />

• Einige mögliche binäre Codebäume für die Zeichen a,b,c<br />

a,b,c<br />

a,b,c<br />

a,b,c<br />

•„unschlau“<br />

a<br />

b,c<br />

b<br />

a,c<br />

a<br />

b,c<br />

b<br />

c<br />

a<br />

c<br />

b<br />

c<br />

c<br />

a,b,c<br />

a,b<br />

a b<br />

•„normal“<br />

• Welcher Baum ist nun optimal?<br />

• Der rechte Baum auf keinen Fall!<br />

• Bei den anderen drei Bäumen hängt<br />

das von den Auftretenshäufigkeiten der<br />

Buchstaben ab<br />

c<br />

11.06.2008 (c) W. <strong>Conen</strong>, FH GE, <strong>ADS</strong> 23


Präfix-freie Codes<br />

• Einige mögliche binäre Codebäume für die Zeichen a,b,c<br />

(1) a,b,c (2) a,b,c (3)<br />

a,b,c<br />

a<br />

b,c<br />

b<br />

a,c<br />

c<br />

a,b<br />

b<br />

c<br />

a<br />

c<br />

a<br />

b<br />

• Welcher Baum ist nun optimal?<br />

a/1,b/1,<br />

c/1<br />

Baum 1 1+2+2=<br />

5<br />

Baum 2 2+1+2=<br />

5<br />

Baum 3 2+2+1=<br />

5<br />

a/2,b/1,<br />

c/1<br />

2*1+2+2=<br />

6<br />

2*2+1+2=<br />

7<br />

2*2+2+1=<br />

7<br />

a/3,b/1,<br />

c/1<br />

3*1+2+2<br />

=7<br />

3*2+1+2<br />

=9<br />

3*2+2+1<br />

=9<br />

a/3,b/2,<br />

c/1<br />

3*1+2*2+2<br />

=9<br />

3*2+2*1+2<br />

=10<br />

3*2+2*2+1<br />

=11<br />

a/1,b/2,c/2<br />

1*1+2*2+2*2<br />

=9<br />

1*2+2*1+2*2<br />

=8<br />

1*2+2*2+2*1<br />

=8<br />

11.06.2008 (c) W. <strong>Conen</strong>, FH GE, <strong>ADS</strong> 24


Präfix-freie Codes<br />

• Zwei mögliche binäre Codebäume für die Zeichen a,b,c,d,e,f<br />

„balanciert“<br />

a,b,c,d,e,f<br />

a,b,c,d,e,f<br />

„kettenförmig“<br />

a,b,c<br />

d,e,f<br />

a<br />

b,c,d,e,f<br />

a<br />

b,c<br />

d<br />

e,f<br />

b<br />

c,d,e,f<br />

b<br />

c<br />

e<br />

f<br />

c<br />

d,e,f<br />

• Welcher Baum ist nun optimal?<br />

• Alle Buchstaben gleichhäufig, z.B. einmal:<br />

2+3+3+2+3+3 = 16 (links),<br />

1+2+3+4+5+5 = 20 (rechts)<br />

• Häufigkeiten: a/6,b/5,c/4,d/3,e/2,f/1<br />

6*2+5*3+4*3+3*2+2*3+1*3=54 (links),<br />

6*1+5*2+4*3+3*4+2*5+1*5=55 (rechts)<br />

d<br />

e<br />

e,f<br />

f<br />

11.06.2008 (c) W. <strong>Conen</strong>, FH GE, <strong>ADS</strong> 25


Präfix-freie Codes<br />

• Zwei mögliche binäre Codebäume für die Zeichen a,b,c,d,e,f<br />

„balanciert“<br />

a,b,c,d,e,f<br />

a,b,c,d,e,f<br />

„kettenförmig“<br />

a,b,c<br />

d,e,f<br />

a<br />

b,c,d,e,f<br />

a<br />

b,c<br />

d<br />

e,f<br />

b<br />

c,d,e,f<br />

b<br />

c<br />

e<br />

f<br />

c<br />

d,e,f<br />

• Welcher Baum ist nun optimal?<br />

• Häufigkeiten: a/12,b/10,c/8,d/6,e/4,f/2<br />

12*2+10*3+8*3+6*2+4*3+2*3=108 (links),<br />

12*1+10*2+8*3+6*4+4*5+2*5=110 (rechts)<br />

• Häufigkeiten: a/50,b/30,c/12,d/6,e/4,f/2<br />

50*2+30*3+12*3+6*2+4*3+2*3=256 (links),<br />

50*1+30*2+12*3+6*4+4*5+2*5=200 (rechts)<br />

d<br />

e<br />

e,f<br />

f<br />

11.06.2008 (c) W. <strong>Conen</strong>, FH GE, <strong>ADS</strong> 26


Präfix-freie Codes<br />

• Zwei mögliche binäre Codebäume für die Zeichen a,b,c,d,e,f<br />

„balanciert“<br />

a,b,c,d,e,f<br />

104 104<br />

a,b,c,d,e,f<br />

„kettenförmig“<br />

a<br />

a,b,c<br />

b<br />

b,c<br />

c<br />

d,e,f<br />

• Warum ist der rechte Baum soviel besser bei der<br />

letzten Verteilung?<br />

• Eine gleichmäßige Aufteilung führt zu einer<br />

Minimierung der gewichteten Höhen<br />

(=Codelänge * Vorkommen) der Knoten!<br />

a<br />

b,c,d,e,f<br />

92 12<br />

54<br />

50<br />

42<br />

d<br />

6<br />

e<br />

e,f<br />

30 12 4 2<br />

f<br />

6<br />

50<br />

b<br />

30<br />

c<br />

12<br />

d<br />

6<br />

c,d,e,f<br />

d,e,f<br />

e<br />

e,f<br />

24<br />

f<br />

4 2<br />

12<br />

6<br />

11.06.2008 (c) W. <strong>Conen</strong>, FH GE, <strong>ADS</strong> 27


Präfix-freie Codes<br />

• Geht das noch besser? Hm... probieren wir mal...<br />

104<br />

a,b,c,d,e,f<br />

104<br />

a,b,c,d,e,f<br />

a,f<br />

b,c,d,e<br />

a f b c,d,e<br />

50 2 30<br />

30<br />

c d,e<br />

12<br />

12<br />

6 4 6<br />

• Links von oben „lokal optimal“ aufgeteilt<br />

• Chiffrelänge links: 244, rechts: 200! Aua!<br />

a<br />

50<br />

b<br />

b,c,d,e,f<br />

52 52 54<br />

d e<br />

d<br />

c<br />

c,d,e,f<br />

22 24<br />

d,e,f<br />

10 12<br />

e,f<br />

e f<br />

4 2<br />

6<br />

11.06.2008 (c) W. <strong>Conen</strong>, FH GE, <strong>ADS</strong> 28


Datenkompression<br />

• Unsere „neue“ Aufgabe ist also:<br />

<br />

<br />

Gegeben ist eine Datei mit zu komprimierenden Daten<br />

Man konstruiere einen binären Entscheidungsbaum, der<br />

zu einer optimalen präfix-freien Codierung des<br />

Dateiinhalts führt.<br />

• Das Problem ist das Finden der besten Struktur des<br />

Baumes!<br />

• <strong>Dr</strong>ei Ideen folgen...<br />

11.06.2008 (c) W. <strong>Conen</strong>, FH GE, <strong>ADS</strong> 29


Datenkompression<br />

• Idee 1 („Brute-Force“, „vollständige Enumeration“):<br />

Wir bauen alle möglichen Binärbaumstrukturen ohne überflüssige<br />

Knoten (also keine Bäume vom Typ „unschlau“)<br />

Wir bestimmen die Chiffrelängen all dieser Bäume<br />

..und wählen dann den besten Baum aus (also den bzw, einen<br />

derjenigen mit der kürzesten Chiffrelänge)<br />

• Problem hier:<br />

Es gibt „fürchterlich viele“ mögliche Baumstrukturen!<br />

Wieviele können sie für 3 Knoten bauen?<br />

Wieviele für 4 Knoten, wieviele für n Knoten?<br />

• Diese Lösungsidee ist VIEL ZU TEUER!<br />

• Aber: sie ist optimal, d.h. sie wählt sicher den besten Baum aus!<br />

11.06.2008 (c) W. <strong>Conen</strong>, FH GE, <strong>ADS</strong> 30


Datenkompression<br />

• Idee 2 (Shannon-Fano):<br />

Wir ordnen die Buchstaben nach Häufigkeit absteigend in einer Liste an,<br />

z.B. [13, 9,4,3,2,2,1]<br />

Jetzt suchen wir einen sogenannten Splitpunkt, an dem wir die Liste in<br />

zwei Teile spalten. Diese Suche wird rekursiv für jede Teilliste wiederholt.<br />

Dieser Splitpunkt soll unter allen möglichen Splitpunkten so gewählt sein,<br />

dass die Summen der Häufigkeiten in den beiden Listenteilen möglichst<br />

nah beieinander liegen - mit anderen Worten: die Differenz zwischen den<br />

beiden Häufigkeitsummen soll minimiert werden<br />

Mögliche Aufteilungen:<br />

• [] (Gewicht 0), [13,9,4,3,2,2,1] (Gewicht 34), Differenz: 34<br />

• [13] (Gewicht 13), [9,4,3,2,2,1] (Gewicht 21), Differenz: 8<br />

• [13,9] (22) [4,3,2,2,1] (12), Differenz: 10<br />

• [13,9,4] (18) [3,2,2,1] (8) ...<br />

• Wenn man von links die Differenzen betrachtet, dann hat man einen<br />

Splitpunkt gefunden, sobald die Differenz wieder anwächst (die wird<br />

erst kleiner und steigt dann unweigerlich wieder)<br />

• Es kann Gleichstände zwischen max. zwei Splitpunkten geben, dann<br />

wählt man den linken/oberen oder rechten/unteren, je nach Vorgabe<br />

11.06.2008 (c) W. <strong>Conen</strong>, FH GE, <strong>ADS</strong> 31


Datenkompression<br />

• Idee 2 (Shannon-Fano):<br />

Vorteile:<br />

• Das Verfahren ist sehr günstig zu rechnen <strong>–</strong> die Knoten<br />

werden sortiert (n log n) und dann werden n-1 Splitpunkte<br />

bestimmt (schlimmstenfalls wird immer bis zur „Mitte“+1<br />

jeder Liste aufsummiert, O(log n * (n/2 + 1)), insgesamt<br />

also O(n log n).<br />

<br />

Nachteile:<br />

• Das Verfahren ist NICHT optimal!<br />

• Beispiel s. Übung<br />

11.06.2008 (c) W. <strong>Conen</strong>, FH GE, <strong>ADS</strong> 32


Datenkompression<br />

• Idee 3 (Huffman):<br />

Wir ordnen Knoten, die die einzelnen Buchstaben repräsentieren, nach Häufigkeit<br />

AUFSTEIGEND in einer Liste an, z.B. [a/1,b/2,c/2,d/3,e/4,f/9,g/13], Ablage am<br />

besten in einer PQueue<br />

Jetzt entnehmen wir die beiden vorderen Knoten und erzeugen daraus einen neuen<br />

Vaterknoten für die beiden entnommenen Knoten.<br />

Der neue Knoten erhält als Gewicht die Summen der Gewichte seiner beiden Kinder.<br />

Er wird in die PQueue eingefügt!<br />

Das wiederholen wir solange, bis nur noch ein Knoten in der PQueue ist.<br />

• Machen wir das einmal „abstrakt“ für die Liste oben:<br />

Initial: [a/1,b/2,c/2,d/3,e/4,f/9,g/13], a und b entnehmen, (a,b) mit Gewicht<br />

1+2=3 einstellen (kann vor oder auch hinter d/3 landen <strong>–</strong> das ist nicht festgelegt!)<br />

[c/2,d/3,(a,b)/3,e/4,f/9,g/13], c und d entnehmen, (c,d) mit Gewicht 5 einstellen<br />

[(a,b)/3,e/4,(c,d)/5,f/9,g/13], (a,b) und e entnehmen, (a,b,e) mit Gewicht 7<br />

einstellen<br />

[(c,d)/5,(a,b,e)/7,f/9,g/13], (c,d) und (a,b,e) entnehmen, (a,b,c,d,e) mit Gewicht<br />

12 einstellen<br />

[f/9,(a,b,c,d,e)/12,g/13], f und (a,b,c,d,e) entnehmen, (a,b,c,d,e,f) mit Gewicht 21<br />

einstellen<br />

[(a,b,c,d,e,f)/21,g/13], (a,b,c,d,e,f) und g entnehmen, (a,b,c,d,e,f,g) mit Gewicht<br />

34 einstellen<br />

Fertig!<br />

11.06.2008 (c) W. <strong>Conen</strong>, FH GE, <strong>ADS</strong> 33


Datenkompression<br />

• Idee 3 (Huffman):<br />

• Zur Erinnerung hier nochmal die Operationen auf der PQueue:<br />

a,b raus -> (a,b) rein; c,d -> (c,d); (a,b), e -> (a,b,e);<br />

(c,d), (a,b,e) -> (a,b,c,d,e); f , (a,b,c,d,e) -> (a,b,c,d,e,f);<br />

(a,b,c,d,e,f),g -> (a,b,c,d,e,f,g)<br />

• Der Algorithmus baut also folgenden Codebaum „auf dem Kopf“:<br />

a<br />

b<br />

e<br />

a,b c d<br />

a,b,e<br />

c,d<br />

f<br />

a,b,c,d,e<br />

a,b,c,d,e,f<br />

g<br />

a,b,c,d,e,f,g<br />

11.06.2008 (c) W. <strong>Conen</strong>, FH GE, <strong>ADS</strong> 34


Datenkompression<br />

• Idee 3 (Huffman):<br />

Vorteile:<br />

• Das Verfahren ist sehr günstig zu rechnen <strong>–</strong> die Knoten<br />

werden (teil-)sortiert (O(n log n)) und dann werden O(n-1)<br />

innere Knoten gebildet (und dabei wird die Pqueue aufrecht<br />

erhalten zu Kosten von jeweils O(log n) pro Operation bei<br />

einer Heapimplementierung mit n-1 Inserts und 2(n-1)<br />

DeleteMins im Worstcase), also Kosten von O(n log n)<br />

insgesamt<br />

• Das Verfahren ist <strong>–</strong> unglaublich, aber wahr <strong>–</strong> optimal!<br />

<br />

Nachteile:<br />

• Keine<br />

11.06.2008 (c) W. <strong>Conen</strong>, FH GE, <strong>ADS</strong> 35


Huffman-Codierung<br />

• Baum zur Kodierung auf Basis der Zeichenhäufigkeit<br />

optimal aufbauen<br />

• Infos über die gewählte Codierung in der erzeugten Datei<br />

mit der Komprimierung speichern<br />

• Führt je nach Daten zu Komprimierungen ca. zwischen<br />

20%-70% (im worst-case spart man nix...im Gegenteil, die<br />

Codetabelle kostet ja auch etwas)<br />

11.06.2008 (c) W. <strong>Conen</strong>, FH GE, <strong>ADS</strong> 36


Huffman-Codierung: Ablauf<br />

1. Ein Durchlauf zur Bestimmung der vorkommenden<br />

Zeichen und zur Ermittlung ihrer Vorkommenshäufigkeit<br />

2. Aufbau des optimalen Codebaums<br />

3. Ableiten der Codes und Codelängen aus dem Baum<br />

4. Abspeichern der Codeinformationen in der Ausgabedatei<br />

5. Zweiter Durchlauf, um die Zeichen zu codieren, nebst<br />

Ablage in der Ausgabedatei<br />

11.06.2008 (c) W. <strong>Conen</strong>, FH GE, <strong>ADS</strong> 37


Huffman-Codierung: Ablauf<br />

• Häufigkeitsermittlung ist klar<br />

• Aufbau des Codebaums:<br />

<br />

„Gierige“ Suche nach einem optimalen Baum (Gierig,<br />

weil die Zeichen in der Reihenfolge „absteigende<br />

Häufigkeit“ genau einmal angepackt werden)<br />

• Aus dem Baum kann die Codetabelle abgeleitet werden<br />

• Vollständiges Beispiel s. Übungsaufgabe bzw. Mitschrieb<br />

11.06.2008 (c) W. <strong>Conen</strong>, FH GE, <strong>ADS</strong> 38


Huffman-Codierung: Expansion<br />

<br />

<br />

<br />

Die Codetabelle wird in der Ausgabedatei abgespeichert<br />

Aus der Codetabelle kann man direkt den Baum<br />

rekonstruieren<br />

• 0 = links, 1 = rechts, die Tiefe eines Zeichens entspricht<br />

der Länge des Codes für ein Zeichen<br />

Die Expansion läßt dann den binären „Codestring“ durch den<br />

Baum rieseln:<br />

1. Beginn mit dem ersten Zeichen des Codestrings<br />

2. Wegwahl entsprechend der binären Ziffern entlang des<br />

Baumes, beginnend mit der Wurzel, bis ein Blatt erreicht<br />

wird<br />

3. Zum Blatt gehöriges Zeichen ausgeben und auf die Wurzel<br />

zurückgehen, wenn noch nicht alles expandiert ist, zum<br />

Schritt 2 zurückkehren<br />

11.06.2008 (c) W. <strong>Conen</strong>, FH GE, <strong>ADS</strong> 39


Literatur<br />

• Zum generellen Greedy-Ablauf und zur Huffman-Codierung:<br />

B. Owsnicki-Klewe: Algorithmen und Datenstrukturen, 4.<br />

Auflage, Wißner-Verlag, Augsburg, 2002 (gut lesbares<br />

Buch, launig-nett geschrieben, kann beim Verstehen<br />

sicher helfen, kaum/keine Beweise, wenig Aufgaben,<br />

keine Lösungen, aber dafür nicht sehr teuer, ca. 15 Euro,<br />

und berührt viele unserer Themen)<br />

Ansonsten finden sie praktisch in allen genannten<br />

Büchern Informationen zu Greedy-Algorithmen und<br />

Codierungen<br />

• Zu Matroiden: In allen guten Büchern zu Optimierung (z.B.<br />

dem von Korte und Nguyen) oder auch in Cormen, Rivest,<br />

Leierson, Stein oder bei Schöning (s. frühere<br />

Literaturangaben).<br />

11.06.2008 (c) W. <strong>Conen</strong>, FH GE, <strong>ADS</strong> 40

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

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!