BALFRE VAZQUEZ CASTREJON
Ivana Yhoalibeth Vazquez Magallon
Te quedo increíble, muchas gracias por tu aportación
Sergio Eyzhan Del Castillo
Muchas gracias, está genial!
La compresión de archivos es un proceso fascinante que utilizamos a diario sin entender realmente cómo funciona. Detrás de cada archivo ZIP hay una serie de algoritmos matemáticos que permiten reducir significativamente el tamaño de nuestros datos sin perder información. Comprender estos mecanismos no solo satisface nuestra curiosidad, sino que nos ayuda a entender mejor cómo funcionan nuestras computadoras a nivel fundamental.
¿Cómo funciona la compresión de archivos?
La compresión de archivos es un proceso matemático que busca representar la misma información utilizando menos bits. Para entender este concepto, analizaremos un ejemplo práctico comprimiendo la frase "MANZANAS AMARILLAS DE ANA".
Esta frase contiene 25 caracteres (incluyendo espacios), lo que normalmente ocuparía 25 bytes o 200 bits en una computadora (cada byte son 8 bits). Sin embargo, mediante técnicas de compresión, podemos reducir significativamente este tamaño.
El primer paso es analizar la frecuencia de cada letra en nuestra frase:
La clave de la compresión está en asignar códigos más cortos a los caracteres que aparecen con mayor frecuencia, y códigos más largos a los que aparecen menos veces.
Creación del árbol binario para la compresión
Para implementar esta idea, utilizamos una estructura llamada árbol binario. En este árbol:
Siguiendo el orden de frecuencia, construimos nuestro árbol:
Proceso de codificación
Una vez construido el árbol, podemos codificar nuestra frase. Por ejemplo, la palabra "MANZANAS" se codificaría así:
Al codificar toda la frase "MANZANAS AMARILLAS DE ANA", obtenemos una secuencia de 98 bits, en lugar de los 200 bits originales. Esto representa una compresión de más del 50%, lo cual es bastante significativo.
¿Por qué los archivos ZIP contienen caracteres extraños?
Cuando abrimos un archivo ZIP con un editor de texto, vemos caracteres sin sentido. Esto ocurre porque:
Por ejemplo, nuestros 98 bits comprimidos se agruparían en aproximadamente 13 bytes. Estos bytes, interpretados como caracteres ASCII, producirían una secuencia aparentemente aleatoria y sin sentido para el ojo humano.
Además de los datos comprimidos, un archivo ZIP también contiene información sobre la estructura del árbol utilizado para la compresión. Esta información es esencial para poder descomprimir correctamente el archivo y recuperar los datos originales.
Aplicaciones y algoritmos de compresión
El ejemplo que hemos analizado es una versión simplificada de la codificación Huffman, uno de los algoritmos de compresión más conocidos. Sin embargo, existen muchos otros algoritmos con diferentes características:
La elección del algoritmo depende del tipo de datos y de las necesidades específicas:
La compresión de datos es fundamental en la era digital, permitiendo almacenar y transmitir grandes cantidades de información de manera eficiente. Desde las imágenes que compartimos en redes sociales hasta los archivos que enviamos por correo electrónico, la compresión está presente en casi todas nuestras interacciones digitales.
La próxima vez que comprimas un archivo, recuerda que detrás de ese simple clic hay un fascinante proceso matemático trabajando para optimizar tus datos. ¿Te animas a implementar este algoritmo en tu lenguaje de programación favorito? Comparte tu código en los comentarios y exploremos juntos el mundo de la compresión de datos.
BALFRE VAZQUEZ CASTREJON
Ivana Yhoalibeth Vazquez Magallon
Te quedo increíble, muchas gracias por tu aportación
Sergio Eyzhan Del Castillo
Muchas gracias, está genial!
gemma clavero del moral
Ana Fernanda Gutierrez Villanueva
Profesor🔧 Funcionalidad principal:
Nodo y heapq para crear un árbol binario según las frecuencias de cada carácter en el texto original.manzanas_amarillas_de_ana) en una cadena binaria comprimida.graphviz para dibujar el árbol de Huffman, permitiendo entender cómo se ramifican los caracteres según su frecuencia.El binario resultante se imprime, junto con los códigos de cada letra.
Se comprueba que el texto descomprimido es idéntico al original: manzanas_amarillas_de_ana.
Jose Ricardo Dueñas Suarez
gracias
Heberth López
Qué bien organizado y explicado, excelente aporte!
Jorge del Campo Andrade
Rodrigo Martinez
Los arboles (binarios) tienen una complejidad de busqueda nlog(n) por lo general, te recomiendo buscar que hacer con heaps, son mucho mejores para hacer busquedas (decompresiones)
Gabriel Obregón
¿Cómo funcionan los archivos comprimidos ".zip"?
Los archivos ".zip" son conocidos como archivos comprimidos. La compresión se basa en una interesante ecuación matemática que permite reducir el tamaño del archivo utilizando menos bits para representar la información.
Vamos a entender este proceso paso a paso utilizando una palabra como ejemplo.
Ejemplo: Comprimir la palabra "MANZANAS_AMARILLAS_DE_ANA"
1. Análisis de frecuencia de letras
Primero, contamos cuántas veces aparece cada letra o símbolo:
2. Almacenamiento en la computadora
¿Cómo reducir el tamaño?
Usamos compresión con un árbol binario
Organizamos las letras según su frecuencia: las más comunes se representan con menos bits.
Por ejemplo:
Ejemplo codificado: "MANZANAS"
M = 0001
A = 1
N = 01
Z = 0000001
A = 1
N = 01
A = 1
S = 00001
Codificación completa de "MANZANAS_AMARILLAS_DE_ANA"
M = 0001
A = 1
N = 01
Z = 0000001
A = 1
N = 01
A = 1
S = 00001
_ = 001
A = 1
M = 0001
A = 1
R = 00000001
I = 00000001
L = 000001
L = 00001
A = 1
S = 00001
_ = 001
D = 0000000001
E = 0000000001
_ = 001
A = 1
N = 01
A = 1
Al final, el número total de bits usados fue 98 bits.
Comparación: antes y después
Sin comprimir: 25 letras × 8 bits = 200 bits
Con compresión: 98 bits
Ahorro: más del 50%
¿Qué pasa con los caracteres “extraños” en los archivos .zip?
Al convertir todos esos ceros y unos en bytes (grupos de 8 bits), se obtienen 13 bytes. Muchos de esos bytes representan caracteres que parecen "basura", pero en realidad son parte del archivo comprimido.
¿Cómo se descomprime?
La clave está en guardar el árbol binario en el encabezado del archivo. Así, cuando el sistema lo abre, puede usar el árbol para volver a convertir los bits en letras originales.
Conclusión
Este es un ejemplo básico de compresión, una técnica que permite representar información de forma más eficiente. Aunque existen muchos algoritmos distintos, este demuestra cómo la frecuencia de los caracteres puede ayudarnos a reducir el tamaño de un archivo.
Alfredo Olmedo
Los algoritmos de compresión son procedimientos de codificación diseñados para representar una cantidad de información utilizando un menor volumen de datos. El objetivo principal es reducir el espacio de almacenamiento necesario y acelerar la transmisión de datos.
Se pueden clasificar principalmente en dos categorías:
La elección del algoritmo de compresión depende de varios factores, incluyendo el tipo de datos, la necesidad de preservar la información original, la tasa de compresión deseada y los recursos computacionales disponibles para la compresión y descompresión.
Ejemplo de Algoritmo Brotli para la compresión de recursos web
import brotli
import time
# Datos de ejemplo (un texto largo)
texto_original = """
Este es un texto de ejemplo bastante largo que vamos a comprimir usando el algoritmo Brotli.
El objetivo es demostrar cómo se puede reducir el tamaño de los datos utilizando esta técnica de compresión sin pérdida.
Brotli es conocido por ofrecer una buena relación de compresión, especialmente para archivos de texto y HTML.
Se utiliza ampliamente en la compresión de recursos web para mejorar la velocidad de carga de las páginas.
Podemos observar la diferencia de tamaño entre el texto original y los datos comprimidos.
Luego, descomprimiremos los datos para verificar que la información original se recupera correctamente.
Este proceso ilustra el principio fundamental de la compresión sin pérdida.
"""
# Codificar el texto a bytes
datos_originales = texto_original.encode('utf-8')
tamaño_original = len(datos_originales)
print(f"Tamaño original de los datos: {tamaño_original} bytes")
# Comprimir los datos usando Brotli
inicio_compresion = time.time()
datos_comprimidos = brotli.compress(datos_originales)
fin_compresion = time.time()
tamaño_comprimido = len(datos_comprimidos)
tiempo_compresion = fin_compresion - inicio_compresion
print(f"Tamaño de los datos comprimidos: {tamaño_comprimido} bytes")
print(f"Tiempo de compresión: {tiempo_compresion:.4f} segundos")
print(f"Relación de compresión: {tamaño_original / tamaño_comprimido:.2f}")
# Descomprimir los datos usando Brotli
inicio_descompresion = time.time()
datos_descomprimidos = brotli.decompress(datos_comprimidos)
fin_descompresion = time.time()
tiempo_descompresion = fin_descompresion - inicio_descompresion
print(f"Tiempo de descompresión: {tiempo_descompresion:.4f} segundos")
# Decodificar los bytes a texto nuevamente
texto_descomprimido = datos_descomprimidos.decode('utf-8')
# Verificar si el texto original y el descomprimido son iguales
if texto_original == texto_descomprimido:
print("La descompresión fue exitosa. Los datos originales y descomprimidos son idénticos.")
else:
print("Error: Los datos originales y descomprimidos no coinciden.")
Juan Jose Suaza
me encanto este video,hoy lo vimos en clase con mis compañeros y a todos nos ayudo,en este momento vamos a graduarnos y estoy muy feliz.
acabo de pasar el examen con 41 segundos VAMOSS
EN EL PROXIMO VIDEO NOS VEMOS :)
Daniel F Lopez
Sebastian Luque
Hola daniel una pregunta. Estoy estudiando pyton y este curso a la vez. ¿Cuanto tiempo te tomo dominar las bases de pyton?(estructuras de datos, bucles y funciones)
Daniel F Lopez
Hola Sebastian, apoyo lo que dijo Freddy clases atrás en que aprender las bases de los lenguajes de programación es trivial, puede que te tome semanas o meses pero lo importante es aprender a cómo resolver problemas con ello, lo importante es aprender y aplicar. Y también dependerá del área o campo de conocimiento a lo que lo quieras aplicar.
Camila Fernanda Torres Parra
Eduardo Guerrero
Que buen código. Me ha ayudadoa estudiar. Gracias.
Fernando Antonio Flores Velez
¿Este lo hiciste en JS?
Me pareció interesante el cómo lo hiciste.
luciano andres muñoz gomez
este video me parece muy importante para nuestro aprendizaje de platzy
Juan Jose Suaza
muy buen video
Valeria Arredondo
me encanto el video
Neil Ruiz
simon jaramillo
muy bueno el video,hoy mis compañeros y yo aprendimos muchas cosas nuevas, espero que siga asi la plicacion
luciano andres muñoz gomez
🥱
Daniel F Lopez
¡Hola! Te comparto mis notas y apuntes de esta clase de compresión:
Heiller Stiven Tamayo Amorteguí
Cómo hiciste para tomar este tipo de notas?
Daniel F Lopez
¡Hola Heiller! Son notas tipo Cornell y las trabajo en Google Docs, puedes encontrar la plantilla original en: Notas Cornell | Pat Ugarte
Lizette Rosalía Dazza Hernández
📦 Clase 21: ¿Cómo funciona un ZIP?
• Un archivo .ZIP es un formato de compresión que reduce el tamaño de uno o varios archivos para ahorrar espacio o facilitar su envío. • Fue creado por Phil Katz en 1989 con su herramienta PKZIP. • No modifica el contenido de los archivos, solo cambia cómo se almacenan los datos dentro.
⚙️ Cómo funciona la compresión ZIP
💡 Ventajas del formato ZIP • Reduce el espacio de almacenamiento. • Puede contener múltiples archivos o carpetas. • Facilita la transferencia por correo o nube. • Compatible con casi todos los sistemas operativos (Windows, macOS, Linux, Android, iOS).
🧐 Aunque ZIP es el más popular, existen otros formatos como RAR, 7Z o TAR.GZ, que ofrecen mayor compresión o mejor manejo de archivos grandes. Sin embargo, ZIP sigue siendo el estándar universal por su equilibrio entre velocidad, compatibilidad y simplicidad.
Jesus Percy Nazario Portilla
Lo que Freddy explica es un árbol binario de Huffman es utilizado en la codificación de Huffman, que es un algoritmo de compresión de datos sin pérdida, esto también se enseña en la carrera de investigación operativa o investigación de operaciones, computación científica.
Alfonso Neil Jiménez Casallas
el algoritmo que mencionó Freddy en este video es nada más y nada menos que "Huffman Coding" para compresión de archivos y la estructura de datos corresponde a un árbol de Huffman, comparto esta referencia Huffman Coding | Greedy Algo-3 | GeeksforGeeks
import heapq from collections import Counter, namedtuple class Node(namedtuple("Node", ["char", "freq", "left", "right"])): def __lt__(self, other): return self.freq < other.freq def build_huffman_tree(text): frequency = Counter(text) heap = [Node(char, freq, None, None) for char, freq in frequency.items()] heapq.heapify(heap) while len(heap) > 1: node1 = heapq.heappop(heap) node2 = heapq.heappop(heap) merged = Node(None, node1.freq + node2.freq, node1, node2) heapq.heappush(heap, merged) return heap[0] if heap else None def build_codes(node, prefix="", codebook={}): if node is not None: if node.char is not None: codebook[node.char] = prefix build_codes(node.left, prefix + "0", codebook) build_codes(node.right, prefix + "1", codebook) return codebook def huffman_compress(text): root = build_huffman_tree(text) codebook = build_codes(root) compressed = ''.join(codebook[char] for char in text) return compressed, codebook, root def huffman_decompress(compressed, root): result = [] node = root for bit in compressed: node = node.left if bit == '0' else node.right if node.char: result.append(node.char) node = root return ''.join(result) def text_to_binary(text): return ''.join(f'{ord(c):08b}' for c in text) # Ejemplo de uso if __name__ == "__main__": texto_original = "MANZANAS AMARILLAS DE ANA" comprimido, codigos, arbol = huffman_compress(texto_original) print("Texto original:", texto_original) print("Texto original en binario (ASCII):", text_to_binary(texto_original)) print("Texto comprimido (en bits):", comprimido) print("Tabla de códigos:", codigos) texto_recuperado = huffman_decompress(comprimido, arbol) print("Texto descomprimido:", texto_recuperado)
Este código representa la simplificación de la clase: (ojo: no se programar en Python, apenas iniciando y por lo tanto todo es bastante básico)
frase original: MANZANAS AMARILLAS DE ANA
largo de la frase original en bits: 200
frase comprimida: →♠Âc☺♀$☺&À
largo de la frase comprimida en bits: 98
porcentaje de compresión: 51.0 %
diccionario de frecuencias: { 'M': 2, 'A': 8, 'N': 3, 'Z': 1, 'S': 2, ' ': 3, 'R': 1, 'I': 1, 'L': 2, 'D': 1, 'E': 1 }
diccionario de bits: { 'A': '1', 'N': '01', ' ': '001', 'M': '0001', 'S': '00001', 'L': '000001', 'Z': '0000001', 'R': '00000001', 'I': '000000001', 'D': '0000000001', 'E': '00000000001'}
# --- Paso 1: Calcular las frecuencias de cada letra def calcular_frecuencias(phrase): frequencies = {} for char in phrase: if char in frequencies: frequencies[char] = frequencies[char] + 1 else: frequencies[char] = 1 return frequencies # --- Paso 2: Convertir el diccionario a una lista de tuplas (caracter, frecuencia) # ---------- ya quel diccionario es rapido para ubicar las letras y crear las frecuencias pero la lista es mas facil de ordenar def convertir_a_lista(diccionario): return [(char, freq) for char, freq in diccionario.items()] # --- Paso 3: Ordenar la lista de tuplas por frecuencia def ordenar_lista(lista): return sorted(lista, key=lambda x: x[1], reverse=True) # --- Paso 4: Imprimir la lista de tuplas ordenada def imprimir_lista_ordenada(lista): for char, freq in lista: print(f"{char}: {freq}") # --- Paso 5: Creo un diccionario de tuplas que sean caracter, expresion en bits teniendo en cuenta que tiene tantos 0 a la izquierda como su posicion en la lista y un 1 al final # ---------- Si A es la letra con mas apariciones entonces A = 1, la segunda es la n entonces se representa como 01 y la tercera como 001 y asi sucesivamente def convertir_a_diccionario_de_bits(lista): diccionario_de_bits = {} expresion_binaria = "" for i in range(len(lista)): for j in range(i): expresion_binaria = "0" + expresion_binaria expresion_binaria = expresion_binaria + "1" diccionario_de_bits[(lista[i][0])] = expresion_binaria expresion_binaria = "" return diccionario_de_bits # --- Paso 6: Ahora se crea la frase en binario con la expresion binaria de cada letra def crear_frase_binaria(frase, diccionario_de_bits): frase_binaria = "" for char in frase: frase_binaria = frase_binaria + diccionario_de_bits[char] return frase_binaria # --- Paso 7: Se divide la frase en bytes y se arregla el ultimo byte con relleno de 0's en caso de tener menos de 8 bits def dividir_en_bytes(frase_binaria): bytes = [] padding_necesario = 8 - (len(frase_binaria) % 8) frase_binaria = frase_binaria + '0' * padding_necesario for i in range(0, len(frase_binaria), 8): bytes.append(frase_binaria[i:i+8]) return bytes # --- Paso 8: convertir cada byte a su representacion alfanumerica y ir montando la nueva frase comprimida def convertir_a_frase_comprimida(bytes): frase_comprimida = "" for byte in bytes: frase_comprimida = frase_comprimida + chr(int(byte, 2)) return frase_comprimida input_phrase = "MANZANAS AMARILLAS DE ANA" #input_phrase = input("Ingrese una frase: ") dic_frecuencies = calcular_frecuencias(input_phrase) lista = convertir_a_lista(dic_frecuencies) lista_ordenada = ordenar_lista(lista) diccionario_en_bits = convertir_a_diccionario_de_bits(lista_ordenada) frase_binaria = crear_frase_binaria(input_phrase, diccionario_en_bits) bytes = dividir_en_bytes(frase_binaria) frase_comprimida = convertir_a_frase_comprimida(bytes) print('frase original: ',input_phrase) print( 'largo de la frase original en bits: ',len(input_phrase*8)) print('frase comprimida:',frase_comprimida) print('largo de la frase comprimida en bits: ',len(frase_binaria)) print('porcentaje de compresion: ',(1-(len(input_phrase*8)/len(input_en_binario)))*100) print("diccionario de frencuencias: ",dic_frecuencies) print("diccionario de bits: ",diccionario_en_bits) print('division por bytes: ',bytes)
Mi humilde compresor en JS:
let string = "TRES TRISTES TIGRES"; function compress_string(string) { let all_letters = []; // array unidimensional que contendrá todas las letras una única vez, para efectos de búsqueda y conteo let count_letters = []; // array bidimensional que contendrá cada letra y el número de veces que aparece, para construir el árbol binario let binary_tree = []; // array bidimensional que contendrá el árbol binario asociado a cada letra del string let compressed_string = ""; // string de salida codificado // Iteramos sobre cada letra de string for (let i = 0; i < string.length; i++) { if (!all_letters.includes(string[i])) { all_letters.push(string[i]); // [letter] // Si la letra actual no existe en all_letters, la añadimos a unique_letters count_letters.push([string[i], 1]); // [letter, count] } else { // Si la letra actual ya existe en all_letters, aumentamos +1 el count de esa letra en count_letters let index = all_letters.indexOf(string[i]); let count = count_letters[index][1]; count_letters[index][1] = count + 1; } } count_letters.sort((a, b) => { // Reordenamos count_letters de mayor a menor, según el número de apariciones (count) return b[1] - a[1]; }); // Nuestro count_letters // console.log(count_letters); // Creamos la función que comprimirá el string, en base a count_letters count_letters.forEach((e, index) => { let bit_code = "1"; // índice de codificación for (let i = 0; i < index; i++) { // Para cada elemento de count_letters, codificamos su contenido en base al número de apariciones bit_code = "0" + bit_code; } // Agregamos el string codificado en binary_tree binary_tree.push([e[0], bit_code]); }); // Nuestro binary_tree // console.log(binary_tree); // Iteramos nuevamente sobre cada letra de string para asignar los bits del árbol binario for (let i = 0; i < string.length; i++) { // Tomamos cada letra de string y buscamos su valor binario en binary_tree for (let j = 0; j < binary_tree.length; j++) { if (binary_tree[j][0] === string[i]) { // Una vez encontrado el valor binario, lo añadimos a compressed_string compressed_string += binary_tree[j][1]; } } } // Nuestro compressed_string return compressed_string; } compress_string(string);
Mi propuesta de código en Python para la compresión sería:
def create_compression_dict(element): comp_dict = {} count_dict = {} for e in element: if e in count_dict: count_dict[e]+=1 else: count_dict[e]=1 counter = 0 for i in {k: v for k, v in sorted(count_dict.items(), key=lambda item: item[1], reverse=True)}: comp_dict[i] = "0"*counter + "1" counter += 1 return comp_dict def compressed_and_ascii(element, compression_dict): chain = "" for e in element: chain += str(compression_dict[e]) return chain def str_to_ascii_binary(element): chain = "" for e in element: chain += str(format(ord(e), '08b')) return chain def main(): element = "trees_are_the_backbone_of_efficient_algorithms" print(f"Element considered: {element}\n") uncompressed = str_to_ascii_binary(element) print(f'Uncompressed:\n\tBits: {len(uncompressed)}\n\tRaw: {uncompressed}') compression_dict = create_compression_dict(element) compressed = compressed_and_ascii(element, compression_dict) print(f'Compressed:\n\tBits: {len(compressed)}\n\tRaw: {compressed}') if __name__ == "__main__": main()
// 1. Analizar frecuencia de caracteres function calcularFrecuencias(texto) { const mapa = new Map(); for (const char of texto) { mapa.set(char, (mapa.get(char) || 0) + 1); } return mapa; } // Clase nodo del árbol class Nodo { constructor(char, freq, izq = null, der = null) { this.char = char; this.freq = freq; this.izq = izq; this.der = der; } } // 2. Construir árbol binario basado en frecuencia function construirArbol(frecuencias) { let nodos = []; for (const [char, freq] of frecuencias) { nodos.push(new Nodo(char, freq)); } while (nodos.length > 1) { nodos.sort((a, b) => a.freq - b.freq); const izq = nodos.shift(); const der = nodos.shift(); const nodoPadre = new Nodo(null, izq.freq + der.freq, izq, der); nodos.push(nodoPadre); } return nodos[0]; } // 3 y 4. Generar códigos y asignarlos function generarCodigos(nodo, codigo = "", tabla = {}) { if (!nodo) return; if (nodo.char !== null) { tabla[nodo.char] = codigo; } generarCodigos(nodo.izq, codigo + "0", tabla); generarCodigos(nodo.der, codigo + "1", tabla); return tabla; } // 5. Reemplazar caracteres por código binario function comprimirTexto(texto, tablaCodigos) { return texto.split("").map(char => tablaCodigos[char]).join(""); } // Ejemplo de uso const textoOriginal = "Hola Freddy, gracias a platzi le demostre a mi papa que no era necesario ir a la universidad"; const frecuencias = calcularFrecuencias(textoOriginal); const arbol = construirArbol(frecuencias); const tabla = generarCodigos(arbol); const comprimido = comprimirTexto(textoOriginal, tabla);
Les comparto la solución que construí en JavaScript para realizar la compresión real de la información, cuyo resultado emplea menos bits de los 98 utilizados en el vídeo de la clase. Esta mejora de más del 20% se obtiene a partir de un método diferente de construcción del árbol, el cual inicia con los caracteres de menor frecuencia de aparición dentro de la cadena procesada, y su representación gráfica luce así :
function frequencyTable(string) { const frequencies = new Map(); for (const character of string) { frequencies.set(character, (frequencies.get(character) || 0) + 1); } return frequencies; } function tree(freqMap) { const nodes = Array.from(freqMap.entries()).map(([char, freq]) => ({ char, freq, left: null, right: null })); while (nodes.length > 1) { nodes.sort((a, b) => a.freq - b.freq); const left = nodes.shift(); const right = nodes.shift(); nodes.push({ char: null, freq: left.freq + right.freq, left, right }); } return nodes[0]; } function branches(node, prefix = '', codeMap = {}) { if (node.char !== null) { codeMap[node.char] = prefix; } else { branches(node.left, prefix + '0', codeMap); branches(node.right, prefix + '1', codeMap); } return codeMap; } function zip(string) { const freqMap = frequencyTable(string); const root = tree(freqMap); const binCodes = branches(root); const strZip = Array.from(string).map(char => binCodes[char]).join(''); return { freqMap, strZip, root }; } function unzip(strZip, root) { const binCodes = branches(root); console.log("Los valores binarios de cada caracter son: ", binCodes); console.log("La información comprimida es: ", strZip); let result = ''; let node = root; for (const bit of strZip) { node = bit === '0' ? node.left : node.right; if (node.char !== null) { result += node.char; node = root; } } console.log("La información descomprimida es: ", result); return result; } zip("MANZANAS_AMARILLAS_DE_ANA"); const { freqMap, strZip, root } = zip("MANZANAS_AMARILLAS_DE_ANA"); console.log("La tabla de frecuencias es: ", freqMap); unzip(strZip, root);