Алгоритм сжатия Хаффмана

Я реализовал сжатие файлов с использованием алгоритма Хаффмана, но проблема в том, что для включения распаковки сжатого файла используемое дерево кодирования или сами коды также должны быть записаны в файл. Вопрос в том, как мне это сделать? Как лучше всего написать дерево кодирования в начале сжатого файла?


person agnieszka    schedule 24.05.2009    source источник
comment
Дубликат stackoverflow.com/questions/759707/   -  person Lasse V. Karlsen    schedule 24.05.2009
comment
это фактически дубликат. Извините   -  person agnieszka    schedule 24.05.2009


Ответы (9)


В базовой библиотеке сжатия (BCL) есть довольно стандартная реализация кодирования Хаффмана, включая рекурсивную функцию, которая записывает дерево в файл. Посмотрите на Хаффмана. Он просто записывает листья по порядку, чтобы декодер мог восстановить то же дерево.

BCL хорош еще и тем, что там есть несколько других довольно простых алгоритмов сжатия. Это очень удобно, если вам нужно накатить собственный алгоритм.

person Todd Gamblin    schedule 24.05.2009

Во-первых, рассматривали ли вы использование стандартного потока сжатия (например, GZipStream в .net)?

О том, как / где записывать данные, вы можете управлять позицией Streams с помощью Seek (даже зарезервировать таким образом место). Если вы заранее знаете размер Дерева, вы можете начать писать после этой позиции. Но вы можете разместить дерево кодирования после фактических данных и просто убедиться, что вы знаете, с чего оно начинается. Т.е. зарезервируйте немного места впереди, запишите сжатые данные, запишите позицию, запишите дерево, перейдите на передний план и запишите позицию.

person Henk Holterman    schedule 24.05.2009

Предполагая, что вы сжимаете 8-битные символы (т.е. байты), а алгоритм не адаптивен, самым простым способом было бы сохранить не дерево, а распределение значений. Например, запомнив, как часто вы находили байт 0, как часто байт 1, ..., как часто байт 255. Затем при обратном чтении файла вы можете повторно собрать дерево. Это простейшее решение, но для него требуется больше всего места для хранения (например, для покрытия больших файлов вам потребуется 4 байта на значение, то есть 1 КБ).

Вы можете оптимизировать это, не сохраняя точно, как часто каждый байт был найден в файле, а вместо этого нормализуя значения до 0..255 (0 = найдено меньше всего, ...), и в этом случае вам нужно будет только сохранить 256 байт. Повторная сборка дерева на основе этих значений приведет к тому же дереву. (Это не сработает, как указал Эдмунд и рассматриваемый 759707 - дополнительные ссылки и ответы на ваш вопрос см. Там)

P.S .: И, как сказал Хенк, использование seek () позволяет вам сохранить место в начале файла для сохранения значений позже.

person dseifert    schedule 24.05.2009
comment
ISTR с Хаффманом, частоты действительно влияют на получаемое дерево - рейтингов недостаточно. Например. при вводе, где A встречается намного чаще, чем любые другие буквы, вы можете ожидать, что 0 = A, но если A и B встречаются довольно часто, вы получите 00 = A и 01 = B. - person Edmund; 24.05.2009

В большинстве реализаций используется каноническая кодировка Хаффмана. Вам нужно только компактно сохранить длину символа. Вот реализация: shcodec. Другой способ - использовать полустатическое кодирование Хаффмана (периодическое изменение масштаба), тогда вам не нужно хранить какое-либо дерево.

person bill    schedule 14.06.2009
comment
+1 канонический код Хаффмана: хранить только длины кода каждого символ. - person David Cary; 22.07.2011

Вместо того, чтобы записывать дерево кода в файл, напишите, как часто был найден каждый символ, чтобы программа распаковки могла сгенерировать такое же дерево.

person Erich Kitzmueller    schedule 24.05.2009

Самым наивным решением было бы предварительно проанализировать дерево сжатия и записать 256 значений в заголовок вашего файла.

person Blindy    schedule 24.05.2009

Поскольку каждый узел в дереве Хаффмана является либо ветвью с двумя дочерними элементами, либо листом, вы можете использовать один бит для однозначного представления каждого узла. Для листа сразу же следуйте 8 битам для этого узла.

например для этого дерева:

    /\
   /\ A
  B /\
   C  D

Вы можете сохранить 001 [B] 01 [C] 1 [D] 1 [A]

(Оказывается, именно это и происходит в опубликованном ранее примере huffman.c, но не так, как было описано выше).

person JimG    schedule 24.05.2009

лучше посылать частоты символов и строить дерево на принимающей стороне. Эти данные будут постоянного размера для фиксированного алфавита. Я предполагаю, что это должно быть сериализовано и помещено в файл. Отправка дерева зависит от его реализации, для того, что я пробовал, подход на основе массивов приводит к большему количеству неиспользуемой памяти для дерева, поскольку большую часть времени дерево может не быть сбалансированным деревом. Если бы дерево было сбалансированным, то наилучшим вариантом было бы представление массива.

Харисанкар Кришна болван

person quiet_penguin    schedule 07.12.2011

Вы пробовали адаптивное кодирование Хаффмана? На первый взгляд кажется, что дерево вообще не нужно отправлять, но нужно еще поработать, чтобы оптимизировать и синхронизировать локон.

person quiet_penguin    schedule 07.12.2011