2011-12-18 15:04:21 +01:00

306 lines
8.3 KiB
Plaintext

let
! Array, in dem der aktuelle Eingabeblock gespeichert wird
var input : array 245 of Char;
! Gibt den Füllstand des Eingabeblocks an. Besonders wichtig für den letzten Block, der das Array nicht vollständig ausfüllt.
var iSize : Integer;
! Eine Zeigervariable, die auf die aktuelle Position in input zeigt.
var iP : Integer;
! Diverse temporäre Variablen
var tmpchar : Char;
var tmpint : Integer;
var i : Integer;
var j : Integer;
! Code wird benutzt um die Anzahl der Codewörter zu zählen.
! Mittels Vertauschung in sortiert wird die Abbildung von Huffmann-Code auf Code-Wort erzeugt
! und schließlich wird mittels sortiert ein Code-Wort auf den Huffmann-Code abgebildet.
var code : array 16 of Integer;
var sortiert : array 16 of Integer;
! Liefert die unteren 4 Bits einer Integerzahl als Integer-Wert
! z.B. 37 wird binär zu 0010.0101 unc low liefert dann integer(0101) = 5
proc low(c : Integer, var l : Integer) ~
l := c // 16;
! Analog zu low, nur dass die oberen 4 Bit als Integer-Wert zurück gegeben werden
proc high(c : Integer, var h : Integer) ~
begin
h := c;
i := 0;
while i < 4
do begin
if (h // 2) = 1 then
h := h - 1
else ;
h := h / 2;
i := i + 1;
end;
end;
! Um die Häufigkeiten der Code-Wörter zu sortieren benutze ich Bubble-Sort.
! Dies ist die Tauschefunktion, die in dem Array die Werte der Position x und x + 1 vertauscht.
proc tausche(var a : array 16 of Integer, x : Integer) ~
let
var t : Integer
in begin
t := a[x];
a[x] := a[x + 1];
a[x + 1] := t;
end;
! Es ist ein Bitweises schreiben nötig. Um dies zu realisieren müssen solange Bits
! zwischengespeichert werden, bis 8 Bits geschrieben wurden. Diese können dann
! mit put auf die Ausgabe gelegt werde.
! Speichert die bisher geschriebenen Bits
var bitBuffer : Integer;
! Gibt an, wie viel Bits schon geschrieben wurden
var bitBufP : Integer;
! Sammelt die zu schreibenden Bits in bitBuffer (mittels Shift-Operationen)
! und schreibt schließlich das char (wenn 8 Bits gesammelt)
proc putBit(b : Boolean) ~
begin
! Um eine Stelle nach links shiften
bitBuffer := bitBuffer * 2;
! Mit einer 1 rechts auffüllen, falls true geschrieben werden soll
if b = true then
bitBuffer := bitBuffer + 1
else ;
! Füllstand im BitBuffer anpassen
bitBufP := bitBufP + 1;
! Wenn der BitBuffer voll ist, mittels put Zeichen schreiben und Buffer zurücksetzen
if bitBufP = 8 then
begin
put(chr(bitBuffer));
bitBufP := 0;
bitBuffer := 0;
end else;
end;
! BitBuffer flushen, also char schreiben, auch wenn noch nicht 8 Bits gesammelt sind.
proc flushbitBuffer() ~
begin
while bitBufP < 8 do
bitBuffer := bitBuffer * 2;
put(chr(bitBuffer));
bitBufP := 0;
bitBuffer := 0;
end;
! hcode ist die Darstellung eines einzelnen Huffmann-Code-Worts
type hcode ~ record
! Gibt von links nach rechts die Bits an
bits : array 7 of Boolean,
! Gibt an, wie viele Bits das H-Code-Wort hat.
valid : Integer
end;
! Alle 16 möglichen H-Code-Wörter werden in diesem Array gespeichert.
var huffmann : array 16 of hcode;
! HuffmannCode mit dem Index hc in Ausgabe (mittels BitBuffer) schreiben
proc writeBits(hc : Integer) ~
let
var k : Integer
in begin
k := 0;
! So lange Bit schreiben, bis alle gültigen Bits eines HF-Code-Worts geschrieben wurden
while k < huffmann[hc].valid
do begin
putBit(huffmann[hc].bits[k]);
k := k + 1;
end;
end;
! Gibt an, ob es sich um den ersten gelesenen Block handelt oder nicht. Wird nach dem ersten Durchlauf auf true gesetzt.
var firstRun : Boolean;
! Die Ermittlte Zuordnung Code-Wort -> Huffmann-Code wird in die Ausgabe geschrieben.
proc writeCodierung() ~
begin
i := 0;
while i < 16
do begin
put(chr(code[i]));
i := i + 1;
end
end;
var testeof : Boolean
in begin
! Initalisierungen
iSize := 0;
iP := 0;
bitBuffer := 0;
bitBufP := 0;
firstRun := false;
! Array sortiert vorbereiten, um Permutation zu erreichen
i := 0;
while i < 16
do begin
sortiert[i] := i;
i := i + 1;
end;
! Darstellung des verwendetetn statischen Huffmann-Code
! Aus Beispieldokumenten habe ich folgende Häufigkeiten erhalten:
! 0: 128, 1: 62, 2: 236, 3: 153, 4: 214, 5: 144, 6: 372, 7: 195, 8: 27, 9: 54, 10: 33, 11: 19, 12: 95, 13: 63, 14: 77, 15: 88
! Aus diesen Werte habe ich diese Codierung erzeugt (nach Huffmann)
! In diesem Array steht die Codierung nach Häufigkeit der Code-Wörter aufsteigend sortiert.
huffmann := [
{ bits ~ [true,true,true,true,true,true,true], valid ~ 7}, ! CodeWort für 11
{ bits ~ [true,true,true,true,true,true,false], valid ~ 7}, ! CodeWort für 8
{ bits ~ [true,true,true,true,true,false,false], valid ~ 6}, ! CodeWort für 10
{ bits ~ [false,true,true,true,true,false,false], valid ~ 5}, ! CodeWort für 9
{ bits ~ [false,true,true,true,false,false,false], valid ~ 5}, ! CodeWort für 1
{ bits ~ [true,false,true,true,true,false,false], valid ~ 5}, ! CodeWort für 13
{ bits ~ [true,false,true,true,false,false,false], valid ~ 5}, ! CodeWort für 14
{ bits ~ [true,true,true,true,false,false,false], valid ~ 5}, ! CodeWort für 15
{ bits ~ [false,true,true,false,false,false,false], valid ~ 4}, ! CodeWort für 12
{ bits ~ [true,false,true,false,false,false,false], valid ~ 4}, ! CodeWort für 0
{ bits ~ [true,true,false,true,false,false,false], valid ~ 4}, ! CodeWort für 5
{ bits ~ [true,true,false,false,false,false,false], valid ~ 4}, ! CodeWort für 3
{ bits ~ [true,true,true,false,false,false,false], valid ~ 4}, ! CodeWort für 7
{ bits ~ [false,true,false,false,false,false,false], valid ~ 3},! CodeWort für 4
{ bits ~ [true,false,false,false,false,false,false], valid ~ 3},! CodeWort für 2
{ bits ~ [false,false,true,false,false,false,false], valid ~ 2} ! CodeWort für 6
];
! Solange weitermachen, bis Dateiende erreicht wurde
eof(var testeof);
while \testeof
do begin
! Der Eingabeblock wird gelesen und in input gespeichert
iP := 0;
eof(var testeof);
while (iP < 245) /\ \testeof
do begin
get(var input[iP]);
iP := iP + 1;
eof(var testeof);
end;
! Füllmenge des Buffers setzen
iSize := iP;
! Dieser Teil wird nur beim ersten Block ausgeführt
! Es wird die Häufigkeit der einzelnen Code-Wörter gezählt und aufsteigend sortiert
! Es entsteht dadurch eine Zuordnung von aktuellem Code-Wort zu dem obigen Huffman-Code
! Ich versuche so einen optimalen Huffman-Code zu approximieren.
if \firstRun then
begin
! Codeanzahl zählen und in code speichern
iP := 0;
tmpint := 0;
while iP < iSize
do begin
low(ord(input[iP]),var tmpint);
code[tmpint] := code[tmpint] + 1;
high(ord(input[iP]),var tmpint);
code[tmpint] := code[tmpint] + 1;
iP := iP + 1;
end;
! Codeanzahlen ausgeben
! i := 0;
! while i < 16
! do begin
! puteol();
! putint(i);
! put(':');
! putint(code[i]);
! i := i + 1;
! end;
! puteol();
! Code-Array sortieren mit Bubblesort
i := 0;
while i < 16
do begin
j := 0;
while j < 15
do begin
if code[j] > code[j+1] then
begin
tausche(var code, j);
tausche(var sortiert, j);
end
else;
j := j + 1;
end;
i := i + 1;
end;
! Abbildung: Code Wort in Quelltext -> Huffman-Codewort erstellen (Abbildungsrichtung von sortiert wird umgedreht)
i := 0;
while i < 16
do begin
code[sortiert[i]] := i;
i := i + 1
end;
! Sortierten Code ausgeben (z.B. für Debugging)
! i := 0;
! while i < 16
! do begin
! puteol();
! put('c');
! putint(i);
! put(':');
! putint(code[i]);
! i := i + 1
! end;
writeCodierung();
! Den vorangegangenen Teil für die nächsten Blöcke nicht mehr ausführen
firstRun := true;
end else ;
! Ausgabe schreiben, indem für jedes Char im input-Array zunächst
! high ermittelt wird und mittels writeBits der zugehörige H-Code geschrieben wird
! und das gleiche für low getan wird.
iP := 0;
while iP < iSize
do begin
high(ord(input[iP]), var tmpint);
! Debugging-Ausgaben
!puteol();
!put('h');
!putint(ord(input[iP]));
!put(',');
!putint(tmpint);
!put(',');
!putint(code[tmpint]);
writeBits(code[tmpint]);
low(ord(input[iP]), var tmpint);
! Debugging-Ausgaben
!put(',');
!put('l');
!putint(ord(input[iP]));
!put(',');
!putint(tmpint);
!put(',');
!putint(code[tmpint]);
writeBits(code[tmpint]);
iP := iP + 1;
end;
eof(var testeof);
end;
end;