Esta implementação modifica a codificação de Huffman clássica em C#, substituindo a sequência binária padrão (0 e 1) por um dicionário personalizado de caracteres. Isso permite o uso da codificação para criptografia simples. Ajustes são feitos automaticamente: se o dicionário tiver mais elementos do que os caracteres únicos no texto, o excesso é removido. Valores duplicados no dicionário também são eliminados. A estrutura da árvore binária é adaptada para usar arrays em vez de filhos esquerdo/direito, o que afeta operações tradicionais em árvores.
O código a seguir demonstra a classe CifraHuffman, que encapsula a lógica. Primeiro, definimos uma classe auxiliar para os nós da árvore:
using System;
using System.Collections.Generic;
using System.Linq;
public class CifraHuffman
{
public class No : IComparable
{
public No[] Filhos { get; set; }
public int Peso { get; set; }
public char Chave { get; set; }
public No() { }
public No(int peso, char chave)
{
this.Peso = peso;
this.Chave = chave;
}
public int CompareTo(object obj)
{
No outro = obj as No;
if (outro.Peso > this.Peso)
return 1;
else if (outro.Peso < this.Peso)
return -1;
return 0;
}
}
private char[] dicionarioOriginal;
private char[] dicionarioAtivo;
public CifraHuffman(char[] dicionario)
{
this.dicionarioOriginal = dicionario.Distinct().ToArray();
this.dicionarioAtivo = this.dicionarioOriginal;
}
public No[] CalcularFrequencias(string texto)
{
var lista = new List<No>();
char[] caracteres = texto.ToCharArray();
if (caracteres.Length < dicionarioOriginal.Length)
{
char[] temp = new char[caracteres.Length];
Array.Copy(dicionarioOriginal, temp, caracteres.Length);
dicionarioAtivo = temp;
}
while (caracteres.Length > 0)
{
char atual = caracteres[0];
int contagem = caracteres.Count(c => c == atual);
lista.Add(new No(contagem, atual));
caracteres = caracteres.Where(c => c != atual).ToArray();
}
return lista.ToArray();
}
public No ConstruirArvore(No[] nos)
{
No raiz = null;
var fila = nos;
while (true)
{
if (fila.Length <= dicionarioAtivo.Length)
{
raiz = new No();
raiz.Filhos = fila;
break;
}
Array.Sort(fila);
var novoNo = new No();
novoNo.Filhos = new No[dicionarioAtivo.Length];
int indice = fila.Length - 1;
for (int i = 0; i < dicionarioAtivo.Length && indice >= 0; i++, indice--)
{
novoNo.Peso += fila[indice].Peso;
novoNo.Filhos[i] = fila[indice];
}
var sobra = fila.Take(fila.Length - dicionarioAtivo.Length + 1).ToArray();
sobra[sobra.Length - 1] = novoNo;
fila = sobra;
}
return raiz;
}
public Dictionary<char, string> GerarTabelaCodigos(No raiz)
{
var tabela = new Dictionary<char, string>();
PercorrerArvore(raiz, "", tabela);
return tabela;
}
private void PercorrerArvore(No no, string codigoAtual, Dictionary<char, string> tabela)
{
if (no.Filhos == null)
{
tabela[no.Chave] = codigoAtual;
return;
}
for (int i = 0; i < no.Filhos.Length; i++)
{
PercorrerArvore(no.Filhos[i], codigoAtual + dicionarioAtivo[i], tabela);
}
}
public string Codificar(string textoOriginal, Dictionary<char, string> tabela)
{
string resultado = "";
foreach (char c in textoOriginal)
{
resultado += tabela[c];
}
return resultado;
}
public string Decodificar(string codigo, Dictionary<char, string> tabela)
{
string resultado = "";
int posicao = 0;
while (posicao < codigo.Length)
{
foreach (var par in tabela)
{
if (codigo[posicao] == par.Value[0] && posicao + par.Value.Length <= codigo.Length)
{
string trecho = codigo.Substring(posicao, par.Value.Length);
if (trecho == par.Value)
{
resultado += par.Key;
posicao += par.Value.Length;
break;
}
}
}
}
return resultado;
}
public string ProcessarTexto(string texto, out Dictionary<char, string> tabelaSaida)
{
var frequencias = CalcularFrequencias(texto);
var arvore = ConstruirArvore(frequencias);
var tabela = GerarTabelaCodigos(arvore);
string codigo = Codificar(texto, tabela);
tabelaSaida = tabela;
return codigo;
}
}
No programa principal, a classse é utilizada para codificar e decodifiacr uma string:
class Programa
{
static void Main(string[] args)
{
string textoOriginal = "exemplo Huffman";
CifraHuffman cifra = new CifraHuffman("xyz123".ToCharArray());
Dictionary<char, string> mapeamento;
string codigo = cifra.ProcessarTexto(textoOriginal, out mapeamento);
Console.WriteLine("Codificação:");
Console.WriteLine(codigo);
string textoDecodificado = cifra.Decodificar(codigo, mapeamento);
Console.WriteLine("Decodificação:");
Console.WriteLine(textoDecodificado);
Console.ReadLine();
}
}