La codificación Huffman (también conocida como Codificación Huffman) es un algoritmo para realizar la compresión de datos y forma la idea básica detrás de la compresión de archivos. Esta publicación habla sobre la codificación de longitud fija y de longitud variable, los códigos decodificables únicos, las reglas de prefijo y la construcción del árbol de Huffman.

Visión general

Ya sabemos que todo personaje son secuencias de 0's y 1's y se almacena usando 8 bits. Esto se conoce como "codificación de longitud fija", ya que cada carácter usa la misma cantidad de almacenamiento de bits fijos.

Dado un texto, ¿cómo reducir la cantidad de espacio requerido para almacenar un carácter?

La idea es utilizar "codificación de longitud variable". Podemos aprovechar el hecho de que algunos caracteres aparecen con más frecuencia que otros en un texto (consulte este) para diseñar un algoritmo que pueda representar el mismo fragmento de texto utilizando un número menor de bits. En la codificación de longitud variable, asignamos un número variable de bits a los caracteres según su frecuencia en el texto dado. Entonces, algunos caracteres podrían terminar tomando un solo bit, y algunos podrían terminar tomando dos bits, algunos podrían codificarse usando tres bits, y así sucesivamente. El problema con la codificación de longitud variable radica en su decodificación.

Dada una secuencia de bits, ¿cómo decodificarla de forma única?

Consideremos la string aabacdab. Tiene 8 contiene caracteres y usa almacenamiento de 64 bits (usando codificación de longitud fija). Si anotamos, la frecuencia de caracteres a, b, c y d son 4, 2, 1, 1, respectivamente. Tratemos de representar aabacdab usando un número menor de bits usando el hecho de que a ocurre con más frecuencia que b, y b ocurre con más frecuencia que c y d. Comenzamos asignando aleatoriamente un código de un solo bit 0 a a, código de 2 bits 11 a by código de 3 bits 100 y 011 a personajes c y d, respectivamente.

a 0
b 11
c 100
d 011

Entonces, la string aabacdab será codificado para 00110100011011 (0|0|11|0|100|011|0|11) utilizando los códigos anteriores. Pero el verdadero problema radica en la decodificación. Si tratamos de decodificar la string 00110100011011, conducirá a la ambigüedad, ya que se puede decodificar,

0|011|0|100|011|0|11    adacdab
0|0|11|0|100|0|11|011   aabacabd
0|011|0|100|0|11|0|11   adacabab

and so on

Para evitar ambigüedades en la decodificación, nos aseguraremos de que nuestra codificación satisfaga la "regla del prefijo", lo que dará como resultado "códigos decodificables de forma única". La regla del prefijo establece que ningún código es un prefijo de otro código. Por código, nos referimos a los bits utilizados para un carácter en particular. En el ejemplo anterior, 0 es el prefijo de 011, lo que viola la regla del prefijo. Si nuestros códigos satisfacen la regla del prefijo, la decodificación no será ambigua (y viceversa).

Consideremos de nuevo el ejemplo anterior. Esta vez asignamos códigos que cumplen la regla del prefijo a los caracteres 'a', 'b', 'c', y 'd'.

a   0
b   10
c   110
d   111

Usando los códigos anteriores, la string aabacdab será codificado para 00100110111010 (0|0|10|0|110|111|0|10). Ahora podemos decodificar de forma única 00100110111010 volver a nuestra string original aabacdab.

Ahora que tenemos claro la codificación de longitud variable y la regla de prefijo, hablemos de la codificación Huffman.

Codificación de Huffman

La técnica funciona creando un árbol binario de nodos Un nodo puede ser un nodo hoja o un nodo interno. Inicialmente, todos los nodos son nodos hoja, que contienen el carácter en sí, el peso (frecuencia de aparición) del carácter. Los nodos internos contienen peso de carácter y enlaces a dos nodos secundarios. Como convención común, un poco 0 representa seguir al hijo izquierdo, y un poco 1 representa seguir al hijo correcto. Un árbol terminado tiene n nudos de hojas y n-1 nodos internos. Se recomienda que Huffman Tree descarte los caracteres no utilizados en el texto para producir las longitudes de código más óptimas.

 
Usaremos un cola de prioridad para construir Huffman Tree, donde el nodo con la frecuencia más baja tiene la prioridad más alta. Los siguientes son los pasos completos:

1. Cree un nodo de hoja para cada personaje y agréguelo a la cola de prioridad.

2. Mientras haya más de un nodo en la queue:

  • Quite los dos nodos de la prioridad más alta (la frecuencia más baja) de la queue.
  • Cree un nuevo nodo interno con estos dos nodos como hijos y una frecuencia igual a la suma de las frecuencias de ambos nodos.
  • Agregue el nuevo nodo a la cola de prioridad.

3. El nodo restante es el nodo raíz y el árbol está completo.

Considere un texto que consta de sólo 'A', 'B', 'C', 'D', y 'E' caracteres y sus frecuencias son 15, 7, 6, 6, 5, respectivamente. Las siguientes figuras ilustran los pasos seguidos por el algoritmo:
 

Huffman Coding: Step 1


Huffman Coding: Step 2


Huffman Coding: Step 3


Huffman Coding: Step 4


Huffman Coding: Step 5

 
La ruta desde la raíz hasta cualquier nodo hoja almacena el código de prefijo óptimo (también llamado código Huffman) correspondiente al carácter asociado con ese nodo hoja.

Huffman Tree

Implementación

A continuación se muestra la implementación en C++, Java y Python del algoritmo de compresión de codificación de Huffman:

C++


Descargar  Ejecutar código

Resultado:

Huffman Codes are:
 
c 11111
h 111100
f 11101
r 11100
t 11011
p 110101
i 1100
g 0011
l 00101
a 010
o 000
d 10011
H 00100
. 111101
s 0110
m 0111
e 110100
  101
n 1000
u 10010
 
The original string is:
Huffman coding is a data compression algorithm.
 
The encoded string is:
00100100101110111101011101010001011111100010011110010000011101110001101010101011001101011011010101111110000111110101111001101000110011011000001000101010001010011000111001100110111111000111111101
 
The decoded string is:
Huffman coding is a data compression algorithm.

Java


Descargar  Ejecutar código

Resultado:

Huffman Codes are: { =100, a=010, c=0011, d=11001, e=110000, f=0000, g=0001, H=110001, h=110100, i=1111, l=101010, m=0110, n=0111, .=10100, o=1110, p=110101, r=0010, s=1011, t=11011, u=101011}
 
The original string is: Huffman coding is a data compression algorithm.
 
The encoded string is: 11000110101100000000011001001111000011111011001111101110001100111110111000101001100101011011010100001111100110110101001011000010111011111111100111100010101010000111100010111111011110100011010100
 
The decoded string is: Huffman coding is a data compression algorithm.

Python


Descargar  Ejecutar código

Resultado:

Huffman Codes are: {‘l’: ‘00000’, ‘p’: ‘00001’, ‘t’: ‘0001’, ‘h’: ‘00100’, ‘e’: ‘00101’, ‘g’: ‘0011’, ‘a’: ‘010’, ‘m’: ‘0110’, ‘.’: ‘01110’, ‘r’: ‘01111’, ‘ ‘: ‘100’, ‘n’: ‘1010’, ‘s’: ‘1011’, ‘c’: ‘11000’, ‘f’: ‘11001’, ‘i’: ‘1101’, ‘o’: ‘1110’, ‘d’: ‘11110’, ‘u’: ‘111110’, ‘H’: ‘111111’}
 
The original string is: Huffman coding is a data compression algorithm.
 
The encoded string is: 11111111111011001110010110010101010011000111011110110110100011100110110111000101001111001000010101001100011100110000010111100101101110111101111010101000100000000111110011111101000100100011001110
 
The decoded string is: Huffman coding is a data compression algorithm.

Tenga en cuenta que el almacenamiento de la string de entrada es de 47×8 = 376 bits, pero nuestra string codificada solo ocupa 194 bits, es decir, alrededor de 48% de compresión de datos. Para que el programa sea legible, hemos utilizado la clase de string para almacenar la string codificada del programa anterior.

Dado que las estructuras de datos de cola de prioridad eficientes requieren O(log(n)) tiempo por inserción, y un árbol binario completo con n hojas tiene 2n-1 nodos, y el árbol de codificación de Huffman es un árbol binario completo, este algoritmo opera en O(n.log(n)) tiempo, donde n es el número total de caracteres.

 
Referencias:

https://en.wikipedia.org/wiki/Huffman_coding
https://en.wikipedia.org/wiki/Variable-length_code
Dr. Naveen Garg, IIT–D (Conferencia – 19 Compresión de datos)