Listing 20
unit Huffmann;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, HuffmannList;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Memo1: TMemo;
Memo2: TMemo;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private-Deklarationen }
public
{ Public-Deklarationen }
end;
const
Bits: array[0..7] of Byte = (1, 2, 4, 8, 16, 32, 64, 128);
var
Form1: TForm1;
BitcoBuffer: DWord;
StringBuffer: string;
HBaumBuffer: THuffmannList;
implementation
{$R *.DFM}
procedure SetBits(var b: string; bitco: DWord; isset: Boolean);
var byt, bit: Byte;
begin
if Length(b)<(bitco div 8)+1 then b:=b+chr(0);
byt:=ord(b[(bitco div 8)+1]);
bit:=bitco-(bitco div 8)*8;
if isset then
begin
if (byt and Bits[bit])=0 then byt:=byt+Bits[bit];
end
else
begin
if (byt and Bits[bit])<>0 then byt:=byt-Bits[bit];
end;
b[(bitco div 8)+1]:=chr(byt);
end;
function GetBits(b: string; bitco: DWord): Boolean;
var byt, bit: Byte;
begin
byt:=ord(b[(bitco div 8)+1]);
bit:=bitco-(bitco div 8)*8;
result:=((byt and Bits[bit])<>0);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
HBaumBuffer:=THuffmannList.Create;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
HBaumBuffer.Free;
end;
function HuffmannCompress(source: string; HBaum: THuffmannList; var bitco: DWord): string;
var cv, vv, vc, id: DWord;
s: string;
SList: TStringList;
HList: THuffmannList;
Temp: THuffmann;
begin
SList:=TStringList.Create;
SList.sorted:=False;
HList:=THuffmannList.Create;
//1. Häufigkeiten ermitteln und in HList speichern
Temp.HCount:=0; Temp.HType:=False; //Blatt
for cv:=0 to 255 do HList.Add(Temp);
for cv:=1 to Length(source) do
begin
Temp:=HList[ord(source[cv])];
vv:=Temp.HCount; inc(vv); Temp.HCount:=vv;
Temp.HToken:=source[cv];
HList[ord(source[cv])]:=Temp;
end;
cv:=0;
while cv<HList.Count do
if HList[cv].HCount=0 then HList.Delete(cv) else inc(cv);
HList.Sort;
//2. HBaum aufbauen
HBaum.Clear;
while HList.Count>=2 do
begin
//HCount addieren und letzten beiden in Baum aufnehmen
Temp.HRight:=HBaum.Add(HList[HList.Count-1]);
Temp.HLeft:=HBaum.Add(HList[HList.Count-2]);
Temp.HCount:=HList[HList.Count-2].HCount+HList[HList.Count-1].HCount;
Temp.HType:=True; //Knoten
HList.Delete(HList.Count-1); //zwei letzten El. löschen
HList.Delete(HList.Count-1);
HList.Add(Temp); //Knoten aufnehmen
HList.Sort; //Knoten einsortieren
end;
HBaum.Add(HList[HList.Count-1]); //letztes El.(Wurzel) in HBaum
HList.Free;
//3. Code ermitteln und Daten komprimieren
for cv:=0 to 255 do
begin
SList.Add('');
for vc:=0 to HBaum.Count-1 do
if (HBaum[vc].HToken=chr(cv)) and not HBaum[vc].HType then
begin
vv:=vc+1; id:=vc;
while vv<HBaum.Count do
begin
if HBaum[vv].HType and ((HBaum[vv].HLeft=id) or (HBaum[vv].HRight=id)) then
begin
s:=SList[cv];
if HBaum[vv].HRight=id then s:='1'+s else s:='0'+s;
SList[cv]:=s;
id:=vv;
end;
inc(vv);
end;
Break;
end;
end;
result:=''; bitco:=0;
for cv:=1 to Length(source) do
begin
s:=SList[ord(source[cv])];
for vv:=1 to Length(s) do begin SetBits(result, bitco, (s[vv]='1')); inc(bitco); end;
end;
SList.Free;
end;
function HuffmannDeCompress(dest: string; HBaum: THuffmannList; bitco: DWord): string;
var cv, vv, id: DWord;
begin
id:=HBaum.Count-1; vv:=0; cv:=0; result:='';
for cv:=0 to bitco-1 do
begin
if GetBits(dest, cv) then
id:=HBaum[id].HRight //gehe nach rechts
else
id:=HBaum[id].HLeft; //nach links
if not HBaum[id].HType then begin result:=result+HBaum[id].HToken; id:=HBaum.Count-1; end; //Blatt
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
caption:='Kompression ...';
StringBuffer:=HuffmannCompress(Memo1.Text, HBaumBuffer, BitcoBuffer);
caption:='OK';
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
caption:='DeKompression ...';
Memo2.Text:=HuffmannDeCompress(StringBuffer, HBaumBuffer, BitcoBuffer);
if Memo1.Text=Memo2.Text then caption:='OK: gleich' else caption:='OK: ungleich';
end;
end.
//Unit HuffmannList: bildet die Klasse THuffmannList
//diese Liste nimmt beim Kompressionsvorgang den Huffmannbaum auf
unit HuffmannList;
interface
uses
Windows, Messages, SysUtils, Classes;
type
THuffmann = record
HCount: DWord;
HToken: Char;
HLeft,
HRight: DWord;
HType: Boolean; //Knoten=True; Blatt=False;
end;
THuffmannArray = array[0..0] of THuffmann;
THuffmannList = class(TObject)
private
FCount: LongInt;
FHuffmann: ^THuffmannArray;
function GetValue(Index: LongInt): THuffmann;
procedure SetValue(Index: LongInt; Value: THuffmann);
procedure QuickSort(L, R: Integer);
public
constructor Create;
destructor Destroy; override;
function Add(const Value: THuffmann): LongInt; //normal Add
procedure Insert(Index: LongInt; const Value: THuffmann);
procedure Delete(Index: LongInt);
procedure Clear;
procedure Sort;
procedure LoadFromFile(fn: string);
procedure SaveToFile(fn: string);
property Count: LongInt read FCount;
property Value[Index: LongInt]: THuffmann read GetValue write SetValue; default;
end;
function Huffmann(HCount: Word; HToken: Char; HLeft, HRight: Word; HType: Boolean): THuffmann;
implementation
constructor THuffmannList.Create;
begin
inherited Create;
FCount := 0;
ReAllocMem(FHuffmann, (FCount + 1) * SizeOf(THuffmann));
end;
destructor THuffmannList.Destroy;
begin
ReAllocMem(FHuffmann, 0);
inherited Destroy;
end;
function THuffmannList.GetValue(Index: LongInt): THuffmann;
begin
if (not Assigned(Self)) or (Index < 0) or (Index >= FCount) then
begin MessageBox(0, PChar('Index außerhalb des zulässigen Bereichs.'), PChar('Information'), MB_OK+MB_ICONINFORMATION); Exit; end;
Result := FHuffmann^[Index];
end;
procedure THuffmannList.SetValue(Index: LongInt; Value: THuffmann);
begin
if (not Assigned(Self)) or (Index < 0) or (Index >= FCount) then
begin MessageBox(0, PChar('Index außerhalb des zulässigen Bereichs.'), PChar('Information'), MB_OK+MB_ICONINFORMATION); Exit; end;
FHuffmann^[Index] := Value;
end;
function THuffmannList.Add(const Value: THuffmann): LongInt;
begin
FHuffmann^[FCount]:=Value;
Result:=FCount;
inc(FCount);
ReAllocMem(FHuffmann, (FCount + 1) * SizeOf(THuffmann));
end;
procedure THuffmannList.Insert(Index: LongInt; const Value: THuffmann);
begin
if (Index < 0) or (Index >= FCount) then
begin MessageBox(0, PChar('Index außerhalb des zulässigen Bereichs.'), PChar('Information'), MB_OK+MB_ICONINFORMATION); Exit; end;
inc(FCount);
ReAllocMem(FHuffmann, (FCount + 1) * SizeOf(THuffmann));
System.Move(FHuffmann^[Index], FHuffmann^[Index+1], (FCount-Index)*sizeof(THuffmann));
FHuffmann^[Index]:=Value;
end;
procedure THuffmannList.Delete(Index: LongInt);
begin
if (Index < 0) or (Index >= FCount) then
begin MessageBox(0, PChar('Index außerhalb des zulässigen Bereichs.'), PChar('Information'), MB_OK+MB_ICONINFORMATION); Exit; end;
System.Move(FHuffmann^[Index+1], FHuffmann^[Index], (FCount-Index-1)*sizeof(THuffmann));
dec(FCount);
ReAllocMem(FHuffmann, (FCount + 1) * SizeOf(THuffmann));
end;
procedure THuffmannList.Clear;
begin
FCount := 0;
ReAllocMem(FHuffmann, (FCount + 1) * SizeOf(THuffmann));
end;
procedure THuffmannList.Sort;
begin
if (FHuffmann <> nil) and (FCount > 0) then QuickSort(0, FCount - 1);
end;
procedure THuffmannList.LoadFromFile(fn: string);
var fs: file;
buffer: Integer;
cv: Integer;
begin
AssignFile(fs, fn);
{$I-}
Reset(fs, 1);
{$I+}
if IOResult = 0 then
begin
BlockRead(fs, FCount, sizeof(LongInt));
ReAllocMem(FHuffmann, (FCount + 1) * SizeOf(THuffmann));
for cv:=0 to FCount-1 do
BlockRead(fs, FHuffmann^[cv], sizeof(THuffmann));
end;
CloseFile(fs);
end;
procedure THuffmannList.SaveToFile(fn: string);
var fs: file;
cv: Integer;
begin
AssignFile(fs, fn);
{$I-}
Rewrite(fs, 1);
{$I+}
if IOResult = 0 then
begin
BlockWrite(fs, FCount, sizeof(LongInt));
for cv:=0 to FCount-1 do
BlockWrite(fs, FHuffmann^[cv], sizeof(THuffmann));
end;
CloseFile(fs);
end;
//Routinen
procedure THuffmannList.QuickSort(L, R: Integer);
var I, J: Integer;
P: Word;
Temp: THuffmann;
begin
repeat
I := L;
J := R;
P := FHuffmann^[(L + R) shr 1].HCount;
repeat
while FHuffmann^[I].HCount>P do Inc(I);
while FHuffmann^[J].HCount<P do Dec(J);
if I <= J then
begin
Temp:=FHuffmann^[I]; FHuffmann^[I]:=FHuffmann^[J]; FHuffmann^[J]:=Temp; //Items tauschen
Inc(I);
Dec(J);
end;
until I > J;
if L < J then QuickSort(L, J);
L := I;
until I >= R;
end;
//Funktion Huffmann gibt einen THuffmann-Datensatz zurück (außerhalb der Klasse THuffmannList)
function Huffmann(HCount: Word; HToken: Char; HLeft, HRight: Word; HType: Boolean): THuffmann;
begin
result.HCount:=HCount;
result.HToken:=HToken;
result.HLeft:=HLeft;
result.HRight:=HRight;
result.HType:=HType;
end;
end.
Zurück zur Hauptseite