Die Shannon-Fano-Kodierung und Huffman-Kodierung sind eine Art der Entropiekodierung.
Dieser Artikel beschreibt, wie zu einem gegebenen Satz von Zeichen-Wahrscheinlichkeits-Paaren die Kodierung erstellt werden kann, wie also die Anforderung der Entropie umgesetzt werden kann.
Da zu einem Entropiekodierer immer auch ein Modell gehört, sollten die zusätzlichen Informationen aus dem Artikel zur Entropiekodierung entnommen werden.
Von der Entropie-Kodierung her ist bekannt, dass Zeichen mit einer unterschiedlichen Anzahl von Bits kodiert werden müssen, wenn man eine speichersparende Darstellung erhalten möchte. Es ist aber nicht möglich, den Zeichen einfach Bitfolgen zuzuweisen und diese auszugeben.
Wird zum Beispiel das Zeichen A mit der Bitfolge „10“, das Zeichen B mit der Folge „01“ und C mit „0“ kodiert, dann wird die Zeichenkette ABC zu „10010“. Diese Folge wird aber auch von der Zeichenkette „ACA“ erzeugt. Es ist also nicht mehr eindeutig erkennbar, für welche Zeichenfolge die Bitfolge „10010“ steht.
Um diese Mehrdeutigkeit zu verhindern, müssen die den Zeichen zugewiesenen Bitfolgen die Eigenschaft besitzen, präfixfrei zu sein, d. h. keine Bitfolge, die für ein einzelnes Zeichen steht, darf am Anfang eines anderen Zeichens stehen. Diese Eigenschaft ist im oberen Beispiel nicht erfüllt, da die Bitfolge „0“, die für C steht, am Anfang der B zugewiesenen Folge steht.
Wie kann nun ein präfixfreier Code erzeugt werden?
PraefixCodeBaum.png Die Grundidee ist, einen binären Baum für die Darstellung des Codes zu verwenden. In dem Baum stehen die Blätter für die zu kodierenden Zeichen, während die Kanten für die zu schreibenden oder gelesenen Bits stehen.
Das Bild zeigt einen Baum, der von der gewünschten Form ist. Die inneren Knoten sind durchnummeriert, um sie benennen zu können.
Um nun die Bitfolge zu ermitteln, die für eines der Zeichen stehen soll, muss festgelegt werden, wie die Abzweige kodiert werden sollen. Eine Variante ist, zu sagen, dass linke Teilbäume mit einer 0 und rechte mit einer 1 kodiert werden. Daraus folgen für den Beispielbaum folgende Bitfolgen:
| A | B | C | D | E |
|---|---|---|---|---|
| 00 | 01 | 100 | 101 | 11 |
Genauso gut ist aber auch eine Menge von anderen Kodierungen möglich. Hier nur noch ein paar Beispiele:
| A | B | C | D | E |
|---|---|---|---|---|
| 10 | 11 | 000 | 001 | 01 |
| 11 | 10 | 010 | 011 | 00 |
| 11 | 10 | 001 | 000 | 01 |
Will man nun eine Zeichenfolge kodieren, so werden die den entsprechenden Zeichen zugewiesenen Bitfolgen hintereinander ausgegeben. Die Bitfolge „ACDC“ wird mit der ersten Kodierung zu der Bitfolge „00100101100“.
Um diese Bitfolge zu dekodieren, wird sie Bit für Bit abgearbeitet. Der Dekodierer muss sich dabei die aktuelle Position im Baum merken. Gestartet wird an der Wurzel, also im Knoten 1. Dann wird das erste Bit gelesen, eine 0. Das bedeutet bei dieser Kodierung nach links, der aktuelle Knoten wird also 2. Es folgt ein weiteres 0-Bit. Der aktuelle Knoten ist jetzt A. Es wird A ausgegeben und der aktuelle Knoten wieder auf 1 gesetzt. Das als nächstes gelesene 1-Bit führt dazu, dass der aktuelle Knoten die 3 ist usw.
Das nun noch zu lösende Problem ist, wie erstellt man einen solchen Baum, bei dem die durchschnittliche Anzahl der Fragen, bis ein Zeichen eindeutig ermittelt ist, im Mittel möglichst klein ist, also möglichst dicht an der Entropie liegt.
Shannon-Fano-Kodierung und Huffman-Kodierung sind zwei unterschiedliche Algorithmen zur Konstruktion dieser Bäume.
Der nach Claude Shannon und Robert Fano benannte Algorithmus arbeitet mit folgender Vorschrift:
Das wichtige Element an diesem Algorithmus ist der erste Schritt. Dieser sorgt dafür, dass Zeichen mit ähnlichen Wahrscheinlichkeiten oft im selben Teilbaum enden. Das ist wichtig, da Knoten im selben Baum Bitfolgen mit ähnlichen Codelängen erhalten (der maximale Unterschied kann nur die Anzahl der Knoten in diesem Baum betragen). Sind die Wahrscheinlichkeiten nun sehr unterschiedlich kann man keine Bitfolgen mit den notwendigen Längenunterschieden erzeugen. Das führt dazu, dass seltene Zeichen zu kurze Bitfolgen und häufige Zeichen zu lange Bitfolgen erhalten.
Das Beispiel zeigt die Konstruktion des Shannon-Codes für ein kleines Alphabet. Die gleichen Werte werden weiter unten auch für den Huffman-Code verwendet, damit die Ergebnisse vergleichbar sind. Die fünf zu kodierenden Zeichen haben folgende Häufigkeiten:
Sortiert sind die Werte schon, also direkt zu Schritt 2, dem Partitionieren. Am Anfang sind alle Zeichen in einer Partition (im Bild a).
Die exakte Mitte läge bei 19,5 Zeichen. 15 ist 4,5 unter dem Mittelwert, 15+7 hingegen nur 2.5 drüber - eine bessere Partitionierung gibt es nicht. Das Alphabet wird also so in 2 Teile unterteilt, dass der eine Teil die Zeichen A und B und der andere Teil den Rest (C, D und E) enthält (Bild b). Beide Partitionen enthalten noch mehr als 1 Zeichen, müssen also weiter zerteilt werden. Die Partition mit A und B kann nur in 2 Teile mit je einem Zeichen zerlegt werden. Die andere Gruppe hat 2 Möglichkeiten. 6+6 ist weiter von der Mitte entfernt, als 6 alleine. Also wird in die 2 Partitionen mit C und D+E unterteilt (Bild c). Schließlich wird noch D und E zerteilt. Der entstandene Entscheidungsbaum ist im Bild Abschnitt d dargestellt.
Die Bitlängen für die einzelnen Zeichen betragen also:
2 Bits für A, B und C und je 3 Bits für D und E. Das ergibt eine durchschnittliche Bitzahl von
Bits pro Zeichen.
Da die Zuweisung, wie oben besprochen, nicht eindeutig ist, hier nur ein Beispiel für eine mögliche Kodierung aufgrund dieses Baumes:
| A | B | C | D | E |
|---|---|---|---|---|
| 00 | 01 | 10 | 110 | 111 |
Der vom Shannon-Fano-Algorithmus erzeugte Baum ist nicht immer optimal, deshalb wurde ein anderer Algorithmus gesucht. David A. Huffman hat ihn 1952 gefunden. Dieser Algorithmus liefert beweisbar immer einen optimalen Baum für die gegebenen Wahrscheinlichkeiten.
Während der Shannon-Fano-Baum von der Wurzel zu den Blättern erstellt wird, arbeitet der Algorithmus zur Konstruktion des Huffman-Baums in entgegengesetzter Richtung.
Das gleiche Beispiel wie bei Shannon-Fano-Code führt zu folgenden Schritten.
Der Wald wird erstellt. Im Bild ist in Abschnitt a der Zustand zu sehen. Am oberen Ende sind immer die Häufigkeiten für die Bäume angezeigt, da diese vom Algorithmus benötigt werden.
Die beiden Bäume mit den geringsten Häufigkeiten sind E und C oder D. Diese werden entfernt (im Beispiel D und E), ein neuer Baum mit einer Häufigkeit von 5+6=11 wird erstellt und in den Wald eingefügt (Bild b).
Als nächstes werden B und C zusammengefasst. Der neue Baum hat die Häufigkeit 13 (Bild c).
Nun werden die 2 bereits zusammengefassten Bäume ein weiteres Mal verbunden (Bild d).
Schließlich wird A mit dem Rest zu einem Baum verbunden (Bild e). Der Algorithmus ist hiermit beendet, da nur noch ein Baum im Wald vorhanden ist.
Die Codelängen für die einzelnen Zeichen sind diesmal 1 Bit für A und 3 Bit für alle anderen Zeichen. Dies führt zu einer durchschnittlichen Bitzahl von
Bits pro Zeichen.
Im Vergleich zu 2,28 Bits pro Zeichen, wie bei Shannon Fano, ist das eine Verbesserung.
Dazu zuerst ein paar Definitionen:
ist das Alphabet, für das der Code erstellt werden soll. Es enthält Zeichen.
Da es nur endlich viele verschiedene Binärbäume mit
Für den Beweis werden 2 Hilfssätze benötigt:
Lemma 1: Jeder innere Knoten hat in einem Huffman-Baum zwei Kind-Knoten.
Beweis: Angenommen, es gibt einen Baum
Für diesen neuen Baum gilt:
Da die Wahrscheinlichkeiten größer 0 sind, gilt
Lemma 2: Wenn
Beweis: Angenommen es gibt einen Baum
Die Summe der Häufigkeiten aller Zeichen in
Tauscht man nun in
Der neue Baum hat also eine durchschnittliche Codelänge gleich oder kürzer der des originalen Baumes. Damit ist auch der Baum ein Huffman-Baum.
Lemma 3: In einem gegebenen Huffman-Baum
Dieser neue Baum ist ein Huffman-Baum für das modifizierte Alphabet
Beweis: In Baum
Der eigentliche Beweis läuft nun über vollständige Induktion.
Induktionsanfang: Der Algorithmus liefert offensichtlich einen optimalen Baum für 2 Zeichen.
Induktionsschritt: Wird durch Lemma 3 bewiesen. Angenommen, der Algorithmus liefert einen optimalen Baum für das vorhandene Problem mit den 2 seltensten Zeichen, dann liefert er auch einen für das gegebene Problem, da er genau diese Ersetzung durchführt.
Die zeiteffiziente Implementation scheitert oft an den vielen Bitoperationen, die notwendig sind, um Bytes aus den einzelnen Bits zu bilden, die einzelnen Bits beim Dekodieren auszuwerten und den Weg im Baum nachzuvollziehen.
Es gibt aber effiziente Algorithmen, um diese Prozesse zu beschleunigen (siehe zlib Bibliothek: *)
Soll ein Kodierer programmiert werden, der mit einem dynamischen Modell arbeitet, so muss der Baum regelmäßig für das neue Modell neu erstellt, oder aktualisiert werden. Auch dafür gibt es effiziente Algorithmen, die die häufigste Veränderung, die Erhöhung der Häufigkeit eines Zeichens um 1, effizient am Huffman-Baum ausführen können, ohne den gesamten Baum neu erstellen zu müssen. (Die Suche nach „dynamic Huffman“ liefert einige Ergebnisse)
Daneben gibt es auch noch andere Ansätze, die nicht mit Huffman-Bäumen arbeiten, sondern die Zeichen durch die von den AVL-Bäumen her bekannten Rotations-Operationen in ihrer Höhe den aktuellen Häufigkeiten anpassen (siehe splay-trees).
Muss so ein Kodierungsbaum in der kodierten Datei mit an den Decoder übergeben werden, wie es bei statistischen Verfahren (siehe Entropiekodierung) notwendig ist, braucht man eine möglichst kompakte Repräsentation.
Dazu werden ein paar Beobachtungen ausgenutzt.
Ein auf diese Art sortierter Baum kann ausgegeben werden, indem man nur ausgibt, welche Zeichen mit wie vielen Bits verschlüsselt werden. Die innere Struktur des Baumes wird dadurch vollständig beschrieben.
Im Beispielfall vom Huffman-Algorithmus müsste man also ausgeben, dass es 1 Zeichen mit Länge 1, nämlich A, und 4 Zeichen mit Länge 3 gibt. Das könnte man mit der Zeichenkette "\x01A\x00\x04BCDE" erledigen (C-Syntax: \xyy steht für das Zeichen mit dem hexadezimalen ASCII Code yy). Diese Zeichenkette wird folgendermaßen interpretiert: \x01 bedeutet, dass es ein Zeichen mit Kodelänge 1 gibt. Das Zeichen folgt: A. \x00 bedeutet, dass es kein Zeichen mit Kodelänge 2 gibt. \x04: es gibt 4 Zeichen mit Kodelänge 3, diese folgen.
Dieses Verfahren wird z. B. von JPEG bei der optimierten Ausgabe von Bildern benutzt. Hier wird anstatt einer der vorgegebenen festen Kodierungen ein optimaler Code (Huffman) erzeugt und auf diese Weise dem Dekodierer mitgegeben. In den Spezifikationen von ISO steht mehr zu diesem Thema.
Die vorgestellten Algorithmen verwenden immer eine ganzzahlige Anzahl von Bits, um ein Zeichen darzustellen. Das führt zwangsweise zu einer nicht optimalen Kodierung (im Sinne der Entropie), außer für den sehr seltenen Fall, dass die Wahrscheinlichkeiten aller Zeichen
Die verwendeten Verfahren weichen unter folgenden Bedingungen besonders vom Optimum ab:
Diese Probleme können mit einer „Umstrukturierung“ des Alphabets vermindert werden.
Oder man vermeidet diese Probleme und verwendet Arithmetisches Kodieren.
Huffmanovo kódování | Shannon-Fano coding | Huffman coding | Algoritmo de Huffman | Huffmanin koodaus | Codage de Huffman | קוד הופמן | Codifica di Huffman | ハフマン符号 | 허프만 코딩 | Huffmancodering | Kodowanie Huffmana | Codificação de Huffman | Huffmankodning | รหัสฮัฟแมน และ รหัสแชนนอน-ฟาโน | 哈夫曼树
This article is licensed under the GNU Free Documentation License.
It uses material from the
"Shannon-Fano-Kodierung".
Home Page • arts • business • computers • games • health • hospitals • home • kids & teens • news • physicians • recreation• reference • regional • science • shopping • society • sports • world