Die zentrale Idee bei Verfahren der verlustfreien Datenkompression besteht darin, häufig vorkommende Zeichen (allgemeiner: Sequenzen) durch kurze Bitfolgen zu repräsentieren, und seltene durch lange. Sind die Zeichen in der Ursprungsdatei tatsächlich sehr ungleich verteilt, ergibt sich so in der Summe eine Reduktion des Speicheraufwandes.
Wir möchten ein Verfahren implementieren, das
Unser (einfacher) Ansatz soll jedes Zeichen aus der Eingabedatei in drei Schritten verarbeiten:
Der erste Schritt ist auch als Move-To-Front-Codierung (MTF) bekannt und Teil des sehr leistungsfähigen bzip2. Wir initialisieren ein Array a der Größe 256 so, dass a[i] = i. Müssen wir nun ein bestimmtes Zeichen x codieren, geben wir aus, an welcher Stelle es in diesem Array steht (mit anderen Worten: den Index i, so dass a[i] = x). Gleichzeitig holen wir es an die Position 0 des Arrays und verschieben alle Zeichen zwischen Position 0 und i um eins nach hinten.
Zu Illustrationszwecken verwenden wir hier nur ein Array der Größe zwölf, das mit den Zeichen A (an Index 0) bis L (Index 11) gefüllt ist.
A | B | C | D | E | F | G | H | I | J | K | L |
L | A | B | C | D | E | F | G | H | I | J | K |
E | L | A | B | C | D | F | G | H | I | J | K |
Im zweiten Schritt müssen wir nun die Zahlencodes in Bitsequenzen umwandeln, so dass kleine Codes kurze Sequenzen erhalten. Gleichzeitig muss gewährleistet sein, den Bitstrom beim Decodieren wieder in die einzelnen Bitsequenzen zerlegen zu können. Dies gelingt mit folgendem präfixfreien Code:
Zahlencode | Bitsequenz |
0 | 0 000 |
1 | 0 001 |
7 | 0 111 |
8 | 10 00000 |
11 | 10 00011 |
32 | 10 11000 |
38 | 10 11110 |
39 | 10 11111 |
40 | 11 00000000 |
41 | 11 00000001 |
255 | 11 11010111 |
Der dritte Schritt besteht nur mehr darin, diese Bitsequenz byteweise in die Ausgabe zu schreiben. Wir füllen dazu die Bytes von links nach rechts. Sofern das letzte Byte nicht komplett mit gültigen Bits belegt ist, wird es mit Einsen aufgefüllt, was auf keinen Fall mehr als gültige Bitsequenz interpretiert werden kann. Unsere obige Bitsequenz ergibt also die drei folgenden Bytes, wobei fünf Einsen angefügt werden mussten:
Dieses Verfahren ist umkehrbar. Sehen wir im Bitstrom zunächst eine 0, wissen wir, dass die nächsten drei Bits als Zahlencode zwischen 0 und 7 interpretiert werden müssen. Sehen wir eine 10 bzw. eine 11, so gehören die nächsten fünf bzw. acht Bits zusammen. Und initialisieren und modifizieren wir unser Array wie beim Komprimieren, lässt sich aus der Zahlenfolge 0, 11, 0, 5 auch wieder der ursprüngliche Text ,,ALLE`` gewinnen.
Die Aufgabe: Schreiben Sie zwei Programme - mtf-encode und mtf-decode - die von der Standardeingabe lesen, auf die Standardausgabe schreiben und dabei nach oben beschriebenem Verfahren komprimieren bzw. wieder dekomprimieren. Wenn Ihre Programme funktionieren, brauchen Sie Ihrem Tutor die nachfolgend beschriebenen Zwischenstufen nicht vorzuführen, sie dienen lediglich als Anleitung.
int getIndex(int character)welche das gegebene Zeichen character in dem Array sucht und seinen Index zurückgibt, nachdem sie es im Array nach vorn geholt hat.
void writeBits(int code)welche für den gegebenen Zahlencode die zugehörige Bitsequenz erzeugt (siehe obige Tabelle) und in Bytes verpackt. Dazu können Sie beispielsweise eine globale Puffervariable vom Typ int verwenden, in die Sie die Bitsequenzen hineinschieben; und sobald mindestens acht Bits enthalten sind, schreiben Sie diese als Zeichen in die Standardausgabe. Sehen Sie ferner eine Funktion
void flushBuffer()vor, die zum Schluss aufzurufen ist und, falls noch Bits im Puffer verblieben sind, ihn mit Einsen auffüllt und als letztes Zeichen ausgibt.
Sie können diese Funktionen testen, indem Sie mit ihnen die Codes 0 bis 255 in Bitsequenzen abbilden und das Ergebnis mit der Datei 0-255.mtf aus dem ftp-Verzeichnis vergleichen.
int getBits(int howMany)die (ebenfalls mittels einer Puffervariable) die nächsten howMany Bits aus der Standardeingabe holt.
Bemerkung: Dass unsere Implementierung keine sonderlich beeindruckenden Kompressionsraten erreicht, hat zwei Gründe:
Viel Erfolg!