{$MODE DELPHI} // Режим совместимости для работы с классами
program HuffmanFPC;
uses
SysUtils, Classes; // Classes содержит классический TList
type
// Узел дерева
PHuffmanNode = ^THuffmanNode; // Определяем тип-указатель
THuffmanNode = record
Ch: Char;
Freq: Integer;
Left, Right: PHuffmanNode;
end;
// Функция создания нового узла
function NewNode(ACh: Char; AFreq: Integer; ALeft: PHuffmanNode = nil; ARight: PHuffmanNode = nil): PHuffmanNode;
var
Node: PHuffmanNode;
begin
New(Node); // Выделяем память вручную
Node^.Ch := ACh;
Node^.Freq := AFreq;
Node^.Left := ALeft;
Node^.Right := ARight;
Result := Node;
end;
// Сравнение узлов для сортировки (по возрастанию частоты)
function CompareNodes(Item1, Item2: Pointer): Integer;
begin
Result := PHuffmanNode(Item1)^.Freq - PHuffmanNode(Item2)^.Freq;
end;
// Рекурсивный обход для вывода кодов
procedure PrintCodes(Node: PHuffmanNode; CurrentCode: string);
begin
if Node = nil then Exit;
// Если это лист (символ)
if (Node^.Left = nil) and (Node^.Right = nil) then
Writeln('"', Node^.Ch, '": ', CurrentCode);
PrintCodes(Node^.Left, CurrentCode + '0');
PrintCodes(Node^.Right, CurrentCode + '1');
end;
var
TextStr: string;
Freq: array[0..255] of Integer; // Массив для частот (проще словаря)
NodeList: TList; // Классический список указателей
i: Integer;
Left, Right, Parent: PHuffmanNode;
begin
TextStr := 'huffman linux fpc';
Writeln('Input: ', TextStr);
// 1. Считаем частоты через массив ASCII
FillChar(Freq, SizeOf(Freq), 0);
for i := 1 to Length(TextStr) do
Inc(Freq[Ord(TextStr[i])]);
// 2. Создаем список начальных узлов
NodeList := TList.Create;
for i := 0 to 255 do
if Freq[i] > 0 then
NodeList.Add(NewNode(Char(i), Freq[i]));
// 3. Строим дерево
while NodeList.Count > 1 do
begin
// Сортируем список по частоте
NodeList.Sort(@CompareNodes);
// Берем два самых маленьких (первые два после сортировки)
Left := PHuffmanNode(NodeList[0]);
Right := PHuffmanNode(NodeList[1]);
// Создаем родителя
Parent := NewNode(#0, Left^.Freq + Right^.Freq, Left, Right);
// Удаляем детей из списка и добавляем родителя
NodeList.Delete(0);
NodeList.Delete(0);
NodeList.Add(Parent);
end;
// 4. Выводим коды
Writeln('Codes:');
if NodeList.Count > 0 then
PrintCodes(PHuffmanNode(NodeList[0]), '');
// Очистка (в идеале нужно рекурсивно удалить всё дерево, но для теста хватит и этого)
NodeList.Free;
Writeln('Done. Press Enter.');
Readln;
end.