Cómic: ¿Qué demonios es la "codificación de Huffman"?

Autor | 小 灰

Fuente | Programador Xiaohui (ID: chengxuyuanxiaohui)

En el último número, presentamos una estructura de datos especial "Árbol de Huffman", también conocido como el árbol binario óptimo. Los amigos que no lo hayan visto pueden hacer clic en el siguiente enlace:

Cómic: ¿Qué es el "árbol de Huffman"?

Entonces, ¿para qué sirve esta estructura de datos? Revelaremos la respuesta hoy.

¿Cómo almacenan la información los sistemas informáticos?

Una computadora no es una persona. No sabe chino ni inglés, y mucho menos imágenes y videos. Lo único que sabe es 0 (nivel bajo) y 1 (nivel alto).

Por lo tanto, todo el texto, imágenes, audio y video que vemos en la computadora se almacenan y transmiten en binario.

En un sentido estricto, la conversión de todo tipo de información que los humanos pueden comprender en una forma binaria que las computadoras pueden reconocer se denomina codificación.

Hay muchas formas de codificar, y el método de codificación con el que estamos más familiarizados es ASCII.

En el código ASCII, cada carácter se expresa como un número binario específico de 8 bits, como:

Obviamente, el código ASCII es una codificación de igual longitud, es decir, la longitud de codificación de cualquier carácter es igual.


¿Por qué dices eso? Veamos un ejemplo:

Si solo hay 6 caracteres A, B, C, D, E y F en una información, si usamos codificación de igual longitud, podemos diseñar cada carácter como una codificación binaria con una longitud de 3:

De esta manera, dada una información "ABEFCDAED", puede codificarse en binario "000 001 100 101 010 011 000 100 011", la longitud total del código es 27.

¿Pero es este método de codificación el diseño óptimo? ¿Qué sucede si hacemos que diferentes caracteres correspondan a diferentes códigos de longitud? Por ejemplo:

De esta manera, la información dada "ABEFCDAED" se puede codificar en binario "0 00 10 11 01 1 0 10 1", la longitud total de la codificación es solo 14.

Huffman Coding (Huffman Coding), también inventada por Huffman Coding del MIT, este método de codificación logra dos objetivos importantes:

1. Cualquier codificación de caracteres no es un prefijo de otras codificaciones de caracteres.

2. La longitud total de la codificación de la información es la más pequeña.


¿Cómo es el proceso de generación de código de Huffman? Veamos el siguiente ejemplo:

Si solo hay 6 caracteres A, B, C, D, E y F en una información, el número de ocurrencias es 2 veces, 3 veces, 7 veces, 9 veces, 18 veces, 25 veces, cómo diseñar el código correspondiente Que?

Podemos considerar estos 6 caracteres como 6 nodos de hoja y el número de ocurrencias de los caracteres como el peso del nodo para generar un árbol Huffman:

¿Cuál es el significado de esto?

Cada nodo del árbol Huffman incluye dos ramas, izquierda y derecha. Cada bit del binario tiene dos estados de 0 y 1. Podemos corresponder estos dos. La rama izquierda del nodo se considera 0, el nodo ¿Cuál es el resultado de la rama derecha como 1?

De esta manera, la ruta desde el nodo raíz del árbol Huffman a cada nodo hoja puede ser equivalente a un código binario:

El código binario generado por el árbol Huffman en el proceso anterior es el código Huffman.

Ahora, nos enfrentamos a dos problemas clave:

En primer lugar, ¿hay alguna ambigüedad causada por el problema de prefijo en el código generado? La respuesta no es ambigüedad.

Debido a que cada carácter corresponde a un nodo hoja del árbol Huffman, la ruta desde el nodo raíz a estos nodos hoja no tiene relación de inclusión, y el código binario resultante naturalmente no será un prefijo el uno del otro.

En segundo lugar, ¿puede el código generado de esta manera garantizar una longitud total mínima? La respuesta es si.

La característica importante del árbol Huffman es que la suma de todos los nodos de las hojas (peso X longitud del camino) es la más pequeña.

En el escenario de la codificación de información, el peso del nodo hoja corresponde a la frecuencia de aparición del carácter, y la longitud de la ruta del nodo corresponde a la longitud de codificación del carácter.

La suma de todos los caracteres (longitud del código de frecuencia X) es la más pequeña, lo que naturalmente significa que la longitud total del código es la más pequeña.


private Node root;

private Node[] nodes;



//构建哈夫曼树

public void createHuffmanTree(int[] weights) {

//优先队列,用于辅助构建哈夫曼树

Queue<Node> nodeQueue = new PriorityQueue<>();

    nodes = new Node[weights.length];



//构建森林,初始化nodes数组

for(int i=0; i<weights.length; i++){

        nodes[i] = new Node(weights[i]);

        nodeQueue.add(nodes[i]);

}



//主循环,当结点队列只剩一个结点时结束

while (nodeQueue.size() > 1) {

//从结点队列选择权值最小的两个结点

Node left = nodeQueue.poll();

Node right = nodeQueue.poll();

//创建新结点作为两结点的父节点

Node parent = new Node(left.weight + right.weight, left, right);

        nodeQueue.add(parent);

}

    root = nodeQueue.poll();

}



//输入字符下表,输出对应的哈夫曼编码

public String convertHuffmanCode(int index) {

return nodes[index].code;

}



//用递归的方式,填充各个结点的二进制编码

public void encode(Node node, String code){

if(node == null){

return;

}

    node.code = code;

    encode(node.lChild, node.code+"0");

    encode(node.rChild, node.code+"1");

}



public static class Node implements Comparable<Node>{

int weight;

//结点对应的二进制编码

String code;

Node lChild;

Node rChild;



public Node(int weight) {

this.weight = weight;

}



public Node(int weight, Node lChild, Node rChild) {

this.weight = weight;

this.lChild = lChild;

this.rChild = rChild;

}



@Override

public int compareTo(Node o) {

return new Integer(this.weight).compareTo(new Integer(o.weight));

}

}



public static void main(String[] args) {

char[] chars = {'A','B','C','D','E','F'};

int[] weights = {2,3,7,9,18,25};

HuffmanCode huffmanCode = new HuffmanCode();

    huffmanCode.createHuffmanTree(weights);

    huffmanCode.encode(huffmanCode.root, "");

for(int i=0; i<chars.length; i++){

System.out.println(chars[i] +":" + huffmanCode.convertHuffmanCode(i));

}

}

En este código, la clase Node agrega un nuevo código de campo para registrar el código binario correspondiente al nodo.

Después de construir el árbol Huffman, puede rellenar recursivamente el valor del código de cada nodo desde el nodo raíz hacia abajo.

【FIN】


Más recomendaciones interesantes

¿Qué pasa con Platón, que procesa mil millones de cálculos de gráficos de nodos cada minuto?

Detrás de cada lección en línea, se expone la tecnología hardcore negra

base de datos de agitar durante 40 años, un análisis en profundidad PostgreSQL, NewSQL Evolución

¿Los hackers usan el aprendizaje automático para entrar en pánico? ¡Ven y conoce estas 7 nuevas formas de robar datos!

☞Súper detallado! ¡Un artículo te dice cómo SparkStreaming integra Kafka! El código adjunto se puede practicar

En los idiomas Mover Libra, y 10 líneas de código para lograr su primer contrato inteligentes

Cada "observación" que pides, me lo tomo en serio

Artículos originales publicados en 1984 · Más de 40,000 elogios · 18.44 millones de visitas

Supongo que te gusta

Origin blog.csdn.net/csdnnews/article/details/105697466
Recomendado
Clasificación