Кодирование источников информации — фундаментальная часть теории информации и сжатия данных. В основе лежит задача представления символов исходного источника в виде битовых последовательностей так, чтобы средняя длина кода была минимальной при условии однозначного декодирования. Важнейшие понятия, которые нужно усвоить в самом начале: энтропия источника как мера неопределённости, средняя длина кода, префиксный код и редундантность (или избыточность). Понимание этих понятий позволяет оценивать, насколько эффективно мы сжимаем данные и какие алгоритмы при этом оптимальны.
Энтропия H(S) для дискретного источника S с известными вероятностями p_i символов s_i определяется формулой H = −∑ p_i log2 p_i и выражается в битах на символ. Энтропия даёт фундаментальный нижний предел для средней длины любого кода при условии кодирования независимых символов одинаковой статистики: средняя длина не может быть меньше H. Эта утверждение формулируется в виде теоремы Шеннона: при кодировании блоками длины n можно достичь средней длины, сколь угодно близкой к H, когда n→∞. На практике это означает, что для получения высокого уровня сжатия нужно учитывать статистику символов и, при необходимости, увеличивать размер блока, но это ведёт к росту задержки и вычислительных затрат.
Для практических конечномерных кодов важен критерий префиксности: префиксный код — это код, в котором ни один кодовыйword не является префиксом другого. Префиксные коды удобны тем, что они однозначно декодируемы при последовательном чтении битового потока без разделителей. Связанный с этим инструмент — неравенство Крафта–Макмиллана: для набора двоичных кодовых длин l_i необходимо и достаточно, чтобы выполнялось ∑ 2^(−l_i) ≤ 1. Это условие позволяет проверять существование префиксных кодов для заданного набора длин и служит теоретической основой для построения оптимальных кодов при целочисленных длинах.
Одним из наиболее известных алгоритмов для получения оптимального префиксного кода является код Хаффмана. Он даёт минимальную среднюю длину среди всех префиксных кодов для источника без памяти (пары символов независимы, и вероятности известны) при целочисленных длинах кодовых слов. Алгоритм прост и состоит из повторного объединения двух наименее вероятных символов. Последовательность шагов при построении кода Хаффмана:
Рассмотрим числовой пример. Пусть источник даёт символы A,B,C,D с вероятностями 0.4, 0.3, 0.2, 0.1. Энтропия H = −(0.4 log2 0.4 + 0.3 log2 0.3 + 0.2 log2 0.2 + 0.1 log2 0.1) ≈ 1.8465 бита/символ. Построим код Хаффмана: объединяем 0.1 и 0.2 → 0.3, получаем набор 0.4, 0.3, 0.3; далее объединяем 0.3 и 0.3 → 0.6; затем 0.4 и 0.6 → 1.0. Присваивая биты, получаем, например, A:0 (1 бит), B:10 (2 бита), C:110 (3 бита), D:111 (3 бита). Средняя длина L = 0.4·1 + 0.3·2 + 0.2·3 + 0.1·3 = 1.9 бита. Редундантность = L − H ≈ 0.0535 бита/символ. Проверим неравенство Крафта: 2^(−1)+2^(−2)+2^(−3)+2^(−3)=0.5+0.25+0.125+0.125=1.0 — условие выполнено.
Однако код Хаффмана ограничен целочисленными длинами. Для достижения средней длины, близкой к энтропии даже при небольших блоках, применяется арифметическое кодирование. Идея арифметического кодирования: представить всю последовательность как подинтервал [L,U) на отрезке [0,1), постепенно сужая интервал в соответствии с частотами символов; итоговый код — любое число из последнего интервала, представленный в двоичной форме. Арифметическое кодирование даёт возможность использовать дробные средние длины и достигает средней длины близкой к энтропии даже при коротких блоках. На практике арифметическое кодирование требует аккуратной работы с точностью и предотвращением ошибок округления; альтернативой является ассимптотически эквивалентное по эффективности контекстно-адаптивное бинарное арифметическое кодирование, а также range coding, упрощающий реализацию.
Кроме кодов с фиксированными статистиками, важна категория универсальных кодов и адаптивных методов, которые не требуют заранее известных вероятностей. Сюда входят алгоритмы семейства Lempel–Ziv (LZ77, LZ78, LZW) — они динамически строят словарь повторяющихся фрагментов и эффективны для источников с повторяющейся информацией. Другие примеры: кольцевые коды для целых чисел (Elias γ, δ, ω-коды), коды Голо́мба для геометрического распределения и адаптивные вариации Хаффмана. Для источников с памятью применяются методы моделирования контекстов (n-граммы, марковские модели) и последующее кодирование по частотам модели (контекстно-адаптивное кодирование).
На уровне оценки и практики полезно знать ключевые метрики и ограничения. Эффективность кода часто определяют как η = H / L (0 < η ≤ 1). Чем ближе η к 1, тем эффективнее код. При реализации важно учитывать компромиссы: увеличение размера блока снижает редундантность, но увеличивает задержку и требуемую память; арифметическое кодирование даёт лучшее сжатие, но усложняет потоковую обработку и повышает требования к точности; адаптивные алгоритмы удобны при неизвестных распределениях, но могут требовать дополнительного кода для передачи начальных условий. Также учитывают устойчивость к ошибкам — префиксные коды легко синхронизировать, тогда как арифметическое кодирование чувствительнее к потерям битов.
В завершение перечислим практические советы и последовательность действий при решении задач по кодированию источников информации — как учитель, дающий план при подготовке к задачам и проектам:
Понимание теории кодирования источников и навыки применения алгоритмов (Хаффман, арифметическое кодирование, LZ, универсальные коды) дают мощный инструментарий для разработки эффективных систем сжатия данных. При подготовке практических решений следует сочетать теоретическую оценку (энтропию, неравенство Крафта, теорему Шеннона) с практическими соображениями: адаптивность, вычислительная сложность и требования к точности. Такой системный подход позволит выбирать оптимальные методы кодирования в зависимости от типа источника и ограничений задачи.