Skip to content
IRC-CodingIRC-Coding
Huffman-Codeadaptiver HuffmanDatenkompressionAlgorithmenEntropiekodierungPython

Adaptiver Huffman-Code: Dynamische Datenkompression für Azubis

Lerne den Huffman-Code und den adaptiven Huffman-Code verständlich. Wir erklären Dir als Azubi mit Python-Code, wie Daten verlustfrei komprimiert werden.

S

schutzgeist

6 min read
Baumdiagramm des Huffman-Codes mit Häufigkeiten und Binärcodes

Adaptiver Huffman-Code: Dynamische Datenkompression für Azubis

Einleitung

In der Ausbildung zum Fachinformatiker begegnest Du immer wieder dem Huffman-Code. Er ist ein Klassiker der Informatik und ein gutes Beispiel für verlustfreie Datenkompression. Doch was ist der Unterschied zum adaptiven Huffman-Code? Und wo nutzt man das heute noch?

In diesem Artikel erkläre ich Dir beide Verfahren Schritt für Schritt. Am Ende verstehst Du, wie Huffman-Codes entstehen, warum der adaptive Huffman-Code auf einen Durchgang verzichtet und wie Du das Konzept mit wenig Python-Code selbst ausprobieren kannst.

Huffman-Code: In a Nutshell

Der klassische Huffman-Code wurde 1952 von David A. Huffman entwickelt. Seine Idee ist simpel: Zeichen, die sehr häufig vorkommen, bekommen kurze Bit-Codes. Zeichen, die selten vorkommen, bekommen längere Codes.

Stell Dir ein Wort vor, das aus den Buchstaben A, B, C und D besteht. A kommt sehr oft vor, D nur einmal. Ein normaler Code würde jedem Buchstaben die gleiche Anzahl Bits geben, zum Beispiel zwei Bit. Der Huffman-Code sagt: A bekommt 0, B bekommt 10, C bekommt 110 und D bekommt 1110. Dadurch sparst Du insgesamt Platz, weil die meisten Buchstaben kurz sind.

Wichtig ist, dass kein Code das Präfix eines anderen Codes ist. Wenn A 0 ist, darf kein anderer Code mit 0 beginnen. Nur so kannst Du den Bitstrom später wieder eindeutig auflösen.

Kernkomponenten des Huffman-Algorithmus

  • Häufigkeitszähler: Zuerst zählst Du, wie oft jedes Zeichen in den Daten vorkommt.
  • Prioritätswarteschlange: Die Zeichen werden in eine Min-Heap eingefügt, sortiert nach Häufigkeit.
  • Binärer Baum: In jedem Schritt werden die beiden seltensten Knoten zu einem neuen Knoten zusammengefasst. Das wiederholst Du, bis nur noch ein Baum übrig bleibt.
  • Code-Tabelle: Durchläufe vom Wurzelknoten zu den Blättern. Links wird 0, rechts wird 1.

Wie wichtig ist das in der Praxis

Als Anwendungsentwickler wirst Du den Huffman-Code selten selbst implementieren. Er ist jedoch in vielen Formaten versteckt: ZIP, PNG, GZIP und PDF nutzen Huffman-Codierung als Teil ihrer Kompression.

Wenn Du später mit Bibliotheken für Dateiformate oder Streaming arbeitest, hilft Dir das Verständnis, warum manche Daten besser komprimierbar sind als andere.

Wie der adaptive Huffman-Code funktioniert

Der klassische Huffman-Code hat einen Nachteil: Er braucht zwei Durchgänge. Zuerst zählt man alle Häufigkeiten, dann baut man den Baum. Bei einem Video-Stream oder einer Netzwerkverbindung hast Du aber die Daten nicht alle auf einmal.

Der adaptive Huffman-Code arbeitet mit einem Durchgang. Er startet mit einer Annahme, wie oft jedes Zeichen vorkommt. Dann liest er die Daten Stück für Stück. Nach jedem gelesenen Zeichen aktualisiert er die Häufigkeiten und passt den Baum an. Dadurch entsteht ein dynamischer Code, der sich dem Datenstrom anpasst.

Ein bekanntes Verfahren ist der Algorithmus von Faller, Gallager und Knuth, kurz FGK. Ein weiterer ist der Algorithmus von Vitter. Beide garantieren, dass der Baum immer die sogenannte Geschwister-Eigenschaft erfüllt. Das bedeutet, dass Knoten mit gleicher Häufigkeit in einer bestimmten Reihenfolge bleiben.

Hier ist ein vereinfachtes Python-Beispiel, das die Idee zeigt. Es baut nach jedem Zeichen den Baum neu auf. In der Praxis würde man den Baum nur gezielt aktualisieren.

import heapq
from collections import defaultdict

class Knoten:
    def __init__(self, zeichen, hauefigkeit, links=None, rechts=None):
        self.zeichen = zeichen
        self.haeufigkeit = hauefigkeit
        self.links = links
        self.rechts = rechts

    # Wichtig für den Heap: Knoten werden nach Häufigkeit sortiert
    def __lt__(self, andere):
        return self.haeufigkeit < andere.haeufigkeit

def baue_tabelle(wurzel, prefix="", tabelle=None):
    if tabelle is None:
        tabelle = {}
    if wurzel.zeichen is not None:
        tabelle[wurzel.zeichen] = prefix or "0"
    else:
        baue_tabelle(wurzel.links, prefix + "0", tabelle)
        baue_tabelle(wurzel.rechts, prefix + "1", tabelle)
    return tabelle

class EinfacherAdaptiverHuffman:
    def __init__(self):
        # Zähler startet bei 1, damit noch unbekannte Zeichen einen Wert haben
        self.haeufigkeit = defaultdict(lambda: 1)

    def update(self, zeichen):
        # Nach jedem Zeichen wird die Häufigkeit erhöht
        self.haeufigkeit[zeichen] += 1

    def tabelle(self):
        # Baue aus den aktuellen Häufigkeiten einen Huffman-Baum
        heap = [Knoten(z, h) for z, h in self.haeufigkeit.items()]
        heapq.heapify(heap)
        while len(heap) > 1:
            a = heapq.heappop(heap)
            b = heapq.heappop(heap)
            heapq.heappush(heap, Knoten(None, a.haeufigkeit + b.haeufigkeit, a, b))
        return baue_tabelle(heap[0])

# Beispiel: Verarbeite einen Text Buchstabe für Buchstabe
text = "abrakadabra"
huff = EinfacherAdaptiverHuffman()

for buchstabe in text:
    huff.update(buchstabe)
    tabelle = huff.tabelle()
    code = tabelle[buchstabe]
    print(f"{buchstabe} -> {code}")

Das Programm zeigt, wie sich die Codes während des Lesens ändern. Am Anfang sind alle Buchstaben gleich wichtig, daher sind die Codes ungefähr gleich lang. Mit der Zeit bekommen häufige Buchstaben wie a immer kürzere Codes.

Vorteile und Nachteile

VerfahrenVorteilNachteil
Klassischer HuffmanOptimal für bekannte HäufigkeitenBenötigt zwei Durchgänge
Adaptiver HuffmanEin Durchgang, kein Häufigkeits-Scan nötigAufwendigeres Update des Baums
Moderne Verfahren wie ANS oder BrotliBessere Kompression und GeschwindigkeitKomplexer und weniger didaktisch

Buchempfehlungen zum Thema

Algorithmen & Datenstrukturen

Bücher über Algorithmen, Komplexitätsanalyse, Datenstrukturen und algorithmische Sicherheit

Algorithmen: Eine Einführung von Thomas H. Cormen u.a.

Algorithmen: Eine Einführung von Thomas H. Cormen u.a.

Bei Amazon ansehen

Affiliate-Link: Bei einem Kauf erhalten wir möglicherweise eine Provision.

Das Wichtigste in Kürze

  • Der Huffman-Code teilt kurze Codes an häufige Zeichen und lange Codes an seltene Zeichen.
  • Der adaptive Huffman-Code aktualisiert den Baum während des Lesens und braucht keinen zweiten Durchgang.
  • In der Praxis findest Du Huffman-Codierung in ZIP, PNG und GZIP wieder.
  • Moderne Verfahren wie Brotli oder ANS haben Huffman in vielen Bereichen abgelöst, aber das Grundprinzip bleibt wichtig.

FAQ: Adaptiver Huffman-Code

1. Was ist der Huffman-Code?

Der Huffman-Code ist ein verlustfreies Verfahren zur Datenkompression. Es ordnet häufigen Zeichen kurze Bitfolgen und seltenen Zeichen längere Bitfolgen zu.

2. Was ist der adaptive Huffman-Code?

Der adaptive Huffman-Code baut und aktualisiert den Huffman-Baum während des Datenstroms. Er braucht keinen zweiten Durchgang, um Häufigkeiten im Voraus zu zählen.

3. Was bedeutet verlustfreie Datenkompression?

Verlustfreie Kompression reduziert die Datenmenge, ohne Informationen zu entfernen. Nach dem Dekodieren liegen die Originaldaten vollständig vor.

4. Wie entsteht ein Huffman-Code?

Zuerst zählt man die Häufigkeiten. Dann fasst man immer die beiden seltensten Zeichen oder Teilbäume zu einem neuen Baum zusammen, bis nur noch ein Baum übrig bleibt.

5. Was ist das Präfixfreiheitsprinzip?

Kein Code darf der Anfang eines anderen Codes sein. Dadurch kann der empfangene Bitstrom eindeutig dekodiert werden, ohne zusätzliche Trennzeichen.

6. Was ist der Vorteil des adaptiven Huffman-Codes?

Er arbeitet mit einem einzigen Durchgang und passt sich laufend an veränderte Häufigkeiten an. Das ist ideal für Streaming oder Netzwerkdaten.

7. Was ist der Nachteil des adaptiven Huffman-Codes?

Das ständige Aktualisieren des Baums ist aufwendiger als ein einmaliger Aufbau. Moderne Verfahren sind oft schneller und komprimieren besser.

8. Wo wird Huffman-Codierung heute verwendet?

Huffman-Codierung steckt in ZIP, PNG, GZIP, PDF und vielen weiteren Formaten. Meist ist sie Teil eines größeren Kompressionsverfahrens wie DEFLATE.

9. Was sind moderne Alternativen zum Huffman-Code?

Arithmetic Coding, Range Coding, ANS und kontextbasierte Verfahren wie Brotli oder Zstandard erreichen oft eine bessere Kompression und Geschwindigkeit.

10. Was ist ein Knoten im Huffman-Baum?

Ein Blattknoten repräsentiert ein Zeichen. Innere Knoten entstehen durch das Vereinigen von zwei Teilbäumen und speichern die Summe der Häufigkeiten.

11. Was ist ein Min-Heap in diesem Zusammenhang?

Ein Min-Heap ist eine Datenstruktur, die das Zeichen mit der niedrigsten Häufigkeit schnell zurückgibt. Das beschleunigt den Bau des Huffman-Baums.

12. Was bedeutet Entropiekodierung?

Entropiekodierung nutzt die unterschiedliche Häufigkeit von Zeichen aus, um die durchschnittliche Codelänge zu minimieren. Huffman ist ein klassisches Beispiel dafür.

13. Brauche ich Huffman in der Ausbildung?

Ja, der Huffman-Code ist ein Standardthema in der Informatik-Ausbildung. Er veranschaulicht wichtige Konzepte wie Bäume, Heaps und Datenkompression.

14. Kann ich Huffman mit Python implementieren?

Ja, mit der heapq-Bibliothek und einem einfachen Baum lässt sich der Huffman-Code in wenigen Zeilen Python umsetzen. Unser Beispiel oben zeigt Dir einen Einstieg.

15. Ist der adaptive Huffman-Code für Streaming geeignet?

Ja, er wurde genau für solche Szenarien entwickelt. Er komprimiert Daten während des Lesens und muss nicht erst die gesamte Datei kennen.

Quellen

  • Huffman, David A. (1952): A Method for the Construction of Minimum-Redundancy Codes. Proceedings of the IRE.
  • Vitter, Jeffrey Scott (1987): Design and Analysis of Dynamic Huffman Codes. Journal of the ACM.
  • Salomon, David: Data Compression. The Complete Reference. Springer.
Zurück zum Blog
Share:

Ähnliche Beiträge