static void Main(string[] args) { string text = "This is short sample text to encode."; var tree = new HuffTree(); string encoded = tree.Encode(text); tree.Reset(); string decoded = tree.Decode(encoded); Console.WriteLine(decoded); }
public byte[] Compression(char[] textToEncrypt, string originalName) { //Calculamos la tabla: List <NodeTable> table = GenerateTable(textToEncrypt); //Incicializamos una cola e insertamos los valores: HuffQueue <NodeTable> queue = new HuffQueue <NodeTable>(); AddToQueue(table, queue); //Agregamos al árbol de Huffman: HuffTree tree = new HuffTree(); tree.Insert(queue, tree); //Agregar al árbol, las codificaciones: tree.AddBinary(tree.rootOriginal, 0, ""); //Añadimos a la tabla las codificaciones de cada caracter en su lugar correspondiente: //Para eso debemos llenar una lista con los caracteres y codificaciones del árbol: List <NodeTable> auxiliar = new List <NodeTable>(); tree.BinarysIncludes(tree.rootOriginal, auxiliar); //Ya con la lista, se lo agregamos a la "table": for (int i = 0; i < auxiliar.Count; i++) { for (int j = 0; j < table.Count; j++) { if (auxiliar[i].character == table[j].character) { table[j].binary = auxiliar[i].binary; } } } //Escribimos la codificación en lugar del texto original: string result = ""; StringBuilder concatenar = new StringBuilder(); for (int i = 0; i < textToEncrypt.Length; i++) { for (int j = 0; j < table.Count; j++) { if (textToEncrypt[i].ToString() == table[j].character) { //result += table[j].binary; concatenar.Append(table[j].binary); } } } result = concatenar.ToString(); //Separaramos por 8 bits y si no completa, agregar ceros: List <string> bytes = SeparateBytes(result); //Convertimos los bytes a decimales y los agregamos a otra lista: List <int> decimals = new List <int>(); for (int i = 0; i < bytes.Count; i++) { decimals.Add(ConvertBinaryToDecimal(bytes[i])); } // // // List <byte> oName = BytesToOriginalName(originalName); // // // //Mandamos a escribir todo el texto (incluyendo su metadata): byte[] response = ReturnBytesToWrite(table, decimals, oName); return(response); }
public List <char> Decompression(List <byte> bytes) { int startOfCompressedText = 0; //La primera posición del arreglo nos dirá cuántos carateres diferentes tiene: int diferentsCharacters = bytes[0]; //La segunda posición del arreglo nos dirá cuántos bytes ocupan las frecuencias: int bytesOfFrequencies = bytes[1]; //Se valida cuántos son: List <NodeTable> table = new List <NodeTable>(); //Si solo ocupan 1 byte, entonces... if (bytesOfFrequencies == 1) { int numberToReadMetadata = (diferentsCharacters * 2) + 1; startOfCompressedText = numberToReadMetadata; for (int i = 2; i <= numberToReadMetadata; i++) { //Leemos primero los caracteres: char character = (char)bytes[i]; i++; int frequency = bytes[i]; //Agregamos a la "table": NodeTable aux = new NodeTable { character = character.ToString(), frequency = frequency }; table.Add(aux); } } //Si ocupan 2 bytes, entonces... else if (bytesOfFrequencies == 2) { int numberToReadMetadata = (diferentsCharacters * 3) + 1; startOfCompressedText = numberToReadMetadata; for (int i = 2; i < numberToReadMetadata; i++) { //Leemos primero los caracteres: char character = (char)bytes[i]; i++; //Ya que las frecuencias ocupan dos bytes, debemos: //Primero: Convertir la 2da. y 3ra. posición a bytes int frequency1 = bytes[i]; i++; int frequency2 = bytes[i]; //Segundo: Ya convertidos a bytes, ambos se deben convertir a binarios string binary1 = ConvertDecimalToBinary(frequency1); if (binary1 == "") { binary1 = "0"; } string binary2 = ConvertDecimalToBinary(frequency2); if (binary2.Length < 8) { string copy = binary2; binary2 = ""; int restant = 8 - copy.Length; for (int j = 0; j < restant; j++) { binary2 += "0"; } binary2 += copy; } //Tercero: Concatenamos los dos binarios, para formar uno solo string resultantBinary = binary1 + binary2; //Cuarto: Convertimos el binario en decimal para obtener la frecuencia total int frequencyTotal = ConvertBinaryToDecimal(resultantBinary); //Agregamos a la "table": NodeTable aux = new NodeTable { character = character.ToString(), frequency = frequencyTotal }; table.Add(aux); } } //Se llena la tablita con sus probabilidades y se vuelve a hacer todo el proceso de la cola y el árbol, etc... //Se calcula la probabilidad de cada caracter: double totalFrequency = 0; for (int i = 0; i < table.Count; i++) { totalFrequency += table[i].frequency; } for (int i = 0; i < table.Count; i++) { table[i].probability = table[i].frequency / totalFrequency; } //Incicializamos una cola e insertamos los valores: HuffQueue <NodeTable> queue = new HuffQueue <NodeTable>(); AddToQueue(table, queue); //Agregamos al árbol de Huffman: HuffTree tree = new HuffTree(); tree.Insert(queue, tree); //Agregar al árbol, las codificaciones: tree.AddBinary(tree.rootOriginal, 0, ""); //Añadimos a la tabla las codificaciones de cada caracter en su lugar correspondiente: //Para eso debemos llenar una lista con los caracteres y codificaciones del árbol: List <NodeTable> auxiliar = new List <NodeTable>(); tree.BinarysIncludes(tree.rootOriginal, auxiliar); //Ya con la lista, se lo agregamos a la "table": for (int i = 0; i < auxiliar.Count; i++) { for (int j = 0; j < table.Count; j++) { if (auxiliar[i].character == table[j].character) { table[j].binary = auxiliar[i].binary; } } } //Ya con toda la table hecha, procedemos a leer el texto compreso para su descompresión: string largeBinary = ""; StringBuilder aux2 = new StringBuilder(); for (int i = startOfCompressedText + 1; i < bytes.Count; i++) { //Se convierte cada decimal a binario y se agrega a un solo string con el binario largo original: string binaryIndividual = ConvertDecimalToBinary(bytes[i]); //Si el tamaño, es menor a 8, entonces se agregan 0´s al inicio: if (binaryIndividual.Length < 8) { int restants = 8 - binaryIndividual.Length; string others = ""; for (int j = 0; j < restants; j++) { others += "0"; } string ok = others + binaryIndividual; aux2.Append(ok); } else { aux2.Append(binaryIndividual); } } largeBinary = aux2.ToString(); StringBuilder aux4 = new StringBuilder(); aux4.Append(largeBinary); //Ya con la cadena larga de binario... se van haciendo comparaciones en la "table" para obtener el texto original: bool empty = false; List <char> respuesta = new List <char>(); while (!empty) { bool match = false; int counter = 0; int posMatch = 0; while (!match) { counter++; for (int i = 0; i < table.Count; i++) { if (aux4.ToString(0, counter) == table[i].binary) { char[] aux = table[i].character.ToCharArray(); respuesta.Add(aux[0]); posMatch = counter; match = true; } } } //Se elimina lo que ya se encontró: if (match) { aux4.Remove(0, posMatch); } //Se comprueba si ya se debe dejar de leer: if (respuesta.Count == totalFrequency) { empty = true; } } return(respuesta); }
public void Insert(HuffQueue <NodeTable> valuesToInsert, HuffTree _root) { List <NodeHuffTree> listAux = new List <NodeHuffTree>(); //Validar si aún hay parejar para sacar en la cola: while (valuesToInsert.Nodes >= 2) { //Si está vacío el árbol se realiza el primer proceso de inserción: if (rootOriginal == null) { //Se sacan los dos nodos de la cola y se guardan: object first = valuesToInsert.ReturnRoot(); valuesToInsert.DeleteRoot(valuesToInsert); NodeTable firstSon = (NodeTable)first; object second = valuesToInsert.ReturnRoot(); valuesToInsert.DeleteRoot(valuesToInsert); NodeTable secondSon = (NodeTable)second; //Se crean los primeros dos nodos hermanos del HuffTree NodeHuffTree firstNewSon = new NodeHuffTree { character = firstSon.character, probability = firstSon.probability, }; NodeHuffTree secondNewSon = new NodeHuffTree { character = secondSon.character, probability = secondSon.probability, }; //Se crea la raíz por primera vez: NodeHuffTree root = new NodeHuffTree { character = "N" + proxNode.ToString(), probability = firstNewSon.probability + secondNewSon.probability, }; //Se valida quién será el hijo izquierdo y quién el hijo derecho if (secondNewSon.probability > firstNewSon.probability) { root.nodeRight = secondNewSon; root.nodeLeft = firstNewSon; } else { root.nodeRight = firstNewSon; root.nodeLeft = secondNewSon; } //Se agrega el padre a los dos hermanos: firstNewSon.nodeFather = root; secondNewSon.nodeFather = root; //Se asigna la raíz: rootOriginal = root; //Se agrega el padre creado a la cola: NodeTable toInsertAgainOnQueue = new NodeTable { character = "N" + proxNode.ToString(), probability = root.probability }; proxNode++; valuesToInsert.Insert(toInsertAgainOnQueue, root.probability); } //Si el árbol ya tiene algo, se realiza el siguiente proceso: else { //Se sacan los dos nodos de la cola y se guardan: object first = valuesToInsert.ReturnRoot(); valuesToInsert.DeleteRoot(valuesToInsert); NodeTable firstSon = (NodeTable)first; object second = valuesToInsert.ReturnRoot(); valuesToInsert.DeleteRoot(valuesToInsert); NodeTable secondSon = (NodeTable)second; //Se crean los dos nodos hermanos del HuffTree: NodeHuffTree firstNewSon = new NodeHuffTree { character = firstSon.character, probability = firstSon.probability, }; NodeHuffTree secondNewSon = new NodeHuffTree { character = secondSon.character, probability = secondSon.probability, }; //Se crea la nueva raíz que será padre de los dos nodos hermanos sin importar cuál sea el caso: NodeHuffTree root = new NodeHuffTree { character = "N" + proxNode.ToString(), probability = firstNewSon.probability + secondNewSon.probability, }; //Ya que tenemos los hermanos, se valida si alguno de los dos ya está en la Raiz del HuffTree: //Si hay alguno, entonces se busca en la listAux si el otro que no era igual a la raíz está: if ((rootOriginal.character == firstNewSon.character) || (rootOriginal.character == secondNewSon.character)) { bool matchOnList = false; int posMatch = 0; //Se busca en la listAux: for (int i = 0; i < listAux.Count; i++) { if ((listAux[i].character == firstNewSon.character) || (listAux[i].character == secondNewSon.character)) { matchOnList = true; posMatch = i; } } //Si se encontró, entonces se saca... se hace hermano con el que ya está en la raíz del HuffTree: if (matchOnList) { //Se obtiene el nodo de la lista y se elimina: NodeHuffTree valueMatchOnList = listAux[posMatch]; listAux.RemoveAt(posMatch); //Se hace una copia de la rootOriginal; HuffTree auxilarClone = (HuffTree)_root.Clone(); //Ya que tenemos los dos valores, solo insertamos de la manera correcta: if (valueMatchOnList.probability > auxilarClone.rootOriginal.probability) { root.nodeLeft = auxilarClone.rootOriginal; root.nodeRight = valueMatchOnList; } else { root.nodeLeft = valueMatchOnList; root.nodeRight = auxilarClone.rootOriginal; } //Se agrega el padre a los dos hermanos: valueMatchOnList.nodeFather = root; auxilarClone.rootOriginal.nodeFather = root; //Se cambia la raíz rootOriginal = root; //Se agrega el padre creado a la cola: NodeTable toInsertAgainOnQueue = new NodeTable { character = "N" + proxNode.ToString(), probability = root.probability }; proxNode++; valuesToInsert.Insert(toInsertAgainOnQueue, root.probability); } //Si no se encontró el otro en la lista... entonces solo se hace hermano con la raíz (el que no es igual): else { //Se hace una copia de la rootOriginal; HuffTree auxilarClone = (HuffTree)_root.Clone(); //Si es igual al firstNewSon, entonces la raíz se volverá hermano con el secondNewSon if (auxilarClone.rootOriginal.character == firstNewSon.character) { if (secondNewSon.probability > auxilarClone.rootOriginal.probability) { root.nodeLeft = auxilarClone.rootOriginal; root.nodeRight = secondNewSon; } else { root.nodeLeft = secondNewSon; root.nodeRight = auxilarClone.rootOriginal; } auxilarClone.rootOriginal.nodeFather = root; secondNewSon.nodeFather = root; } //Si es igual al secondNewSon, entonces la raíz se volverá hermano con el firstNewSon else if (auxilarClone.rootOriginal.character == secondNewSon.character) { if (firstNewSon.probability > auxilarClone.rootOriginal.probability) { root.nodeLeft = auxilarClone.rootOriginal; root.nodeRight = firstNewSon; } else { root.nodeLeft = firstNewSon; root.nodeRight = auxilarClone.rootOriginal; } auxilarClone.rootOriginal.nodeFather = root; firstNewSon.nodeFather = root; } //Se cambia la raíz rootOriginal = root; //Se agrega el padre creado a la cola: NodeTable toInsertAgainOnQueue = new NodeTable { character = "N" + proxNode.ToString(), probability = root.probability }; proxNode++; valuesToInsert.Insert(toInsertAgainOnQueue, root.probability); } } //Si no hay alguno, entonces: else { //Se busca en la listAux para encontrar alguno de los 2: bool matchOnList = false; for (int i = 0; i < listAux.Count; i++) { if ((listAux[i].character == firstNewSon.character) || (listAux[i].character == secondNewSon.character)) { matchOnList = true; } } //Si no se encuentra, entonces solo se inserta el root en la lista: if (!matchOnList) { if (secondNewSon.probability > firstNewSon.probability) { root.nodeLeft = firstNewSon; root.nodeRight = secondNewSon; } else { root.nodeLeft = secondNewSon; root.nodeRight = firstNewSon; } //Se agrega el padre a los dos hermanos: firstNewSon.nodeFather = root; secondNewSon.nodeFather = root; //Se agrega el padre creado a la cola: NodeTable toInsertAgainOnQueue = new NodeTable { character = "N" + proxNode.ToString(), probability = root.probability }; proxNode++; valuesToInsert.Insert(toInsertAgainOnQueue, root.probability); //Se inserta en la listAux listAux.Add(root); } //Si se encuentra, entonces se busca si los 2 están en la lista o si solo 1 está: else { //Se busca denuevo en la lista, pero esta vez, ambos por separado: bool matchFirstNewSon = false; int posMatchFirstNewSon = 0; for (int i = 0; i < listAux.Count; i++) { if (listAux[i].character == firstNewSon.character) { matchFirstNewSon = true; posMatchFirstNewSon = i; } } bool matchSecondNewSon = false; int posMatchSecondNewSon = 0; for (int i = 0; i < listAux.Count; i++) { if (listAux[i].character == secondNewSon.character) { matchSecondNewSon = true; posMatchSecondNewSon = i; } } //Si encuentra a los dos en la lista: if (matchFirstNewSon && matchSecondNewSon) { //Se guardan y se remueven de la lista: NodeHuffTree valueMatchOnList1 = listAux[posMatchFirstNewSon]; NodeHuffTree valueMatchOnList2 = listAux[posMatchSecondNewSon]; listAux.RemoveAt(posMatchFirstNewSon); //Se valida si no es mayor la posición, ya que se habrá eliminado: if (posMatchSecondNewSon > posMatchFirstNewSon) { posMatchSecondNewSon -= 1; } listAux.RemoveAt(posMatchSecondNewSon); //Se valida en qué posición van (izquierda, derecha): if (valueMatchOnList2.probability > valueMatchOnList1.probability) { root.nodeLeft = valueMatchOnList1; root.nodeRight = valueMatchOnList2; } else { root.nodeLeft = valueMatchOnList2; root.nodeRight = valueMatchOnList1; } //Se agrega el padre a los dos hermanos: valueMatchOnList1.nodeFather = root; valueMatchOnList2.nodeFather = root; //Se agrega el padre creado a la cola: NodeTable toInsertAgainOnQueue = new NodeTable { character = "N" + proxNode.ToString(), probability = root.probability }; proxNode++; valuesToInsert.Insert(toInsertAgainOnQueue, root.probability); //Se inserta en la listAux listAux.Add(root); } //Si solo se encuentra uno en la lista: else if (matchFirstNewSon || matchSecondNewSon) { //Si solo se encuentra el matchFirstNewSon if (matchFirstNewSon) { //Se guardan y se remueven de la lista: NodeHuffTree valueMatchOnList1 = listAux[posMatchFirstNewSon]; listAux.RemoveAt(posMatchFirstNewSon); //Se valida en qué posición van (izquierda, derecha): if (secondNewSon.probability > valueMatchOnList1.probability) { root.nodeLeft = valueMatchOnList1; root.nodeRight = secondNewSon; } else { root.nodeLeft = secondNewSon; root.nodeRight = valueMatchOnList1; } //Se agrega el padre a los dos hermanos: valueMatchOnList1.nodeFather = root; secondNewSon.nodeFather = root; //Se agrega el padre creado a la cola: NodeTable toInsertAgainOnQueue = new NodeTable { character = "N" + proxNode.ToString(), probability = root.probability }; proxNode++; valuesToInsert.Insert(toInsertAgainOnQueue, root.probability); //Se inserta en la listAux listAux.Add(root); } //Si solo se encuentra el matchSecondNewSon else if (matchSecondNewSon) { //Se guardan y se remueven de la lista: NodeHuffTree valueMatchOnList2 = listAux[posMatchSecondNewSon]; listAux.RemoveAt(posMatchSecondNewSon); //Se valida en qué posición van (izquierda, derecha): if (firstNewSon.probability > valueMatchOnList2.probability) { root.nodeLeft = valueMatchOnList2; root.nodeRight = firstNewSon; } else { root.nodeLeft = firstNewSon; root.nodeRight = valueMatchOnList2; } //Se agrega el padre a los dos hermanos: valueMatchOnList2.nodeFather = root; firstNewSon.nodeFather = root; //Se agrega el padre creado a la cola: NodeTable toInsertAgainOnQueue = new NodeTable { character = "N" + proxNode.ToString(), probability = root.probability }; proxNode++; valuesToInsert.Insert(toInsertAgainOnQueue, root.probability); //Se inserta en la listAux listAux.Add(root); } } } } } } }