Dando continuidade ao nosso Curso de Programação com a Linguagem C, nesta aula vamos iniciar o desenvolvimento do código de Huffman (Algoritmo de Huffman).
Nesta aula vamos desenvolver a Tabela de Frequência, a primeira etapa do Algoritmo de Huffman.
Como vimos na aula anterior, esta tabela pode ser um vetor de inteiros de tamanho 256, com índices no intervalo entre 0 e 255 abrangendo todos os índices da tabela ASCII. Como precisaremos percorrer esta tabela diversas vezes, vamos iniciar criando uma constante global para armazenar o tamanho da tabela.
/*
Tamanho da tabela de frequência
*/
#define TAM 256
Agora podemos criar na função main nossa tabela. Lembre-se que iremos trabalhar com caracteres e queremos a acentuação correta, então sempre utilizaremos o modificador unsigned para interpretar qualquer conjunto de bits como um valor sem sinal.
/*
Criação da tabela de frequência na função main
*/
int main() {
// texto de exemplo para testar o código
unsigned char texto[] = "Vamos aprender programação";
unsigned int tabela_frequencia[TAM];
setlocale(LC_ALL, "Portuguese");
return 0;
}
Agora que temos a tabela precisamos limpá-la, ou seja, iniciar cada posição com zero. Como iremos contar a frequência de cada caracter em cada posição da tabela precisamos ter certeza que não há lixo de memória para interferir no resultado final. A seguir é apresentado um procedimento para inicializar toda a tabela com zero.
/*
Procedimento para inicializar a tabela de frequência com zero
*/
void inicializa_tabela_com_zero(unsigned int tab[]){
int i;
for(i = 0; i < TAM; i++)
tab[i] = 0;
}
Agora que a tabela está completamente limpa, precisamos percorrer o texto a ser codificado e contar as ocorrências de cada caracter. Percorrer o texto contando a frequência de cada caracter para depois atualizar a tabela até pode ser feito, mas isso tornará o código mais lento e será necessário percorrer toda a tabela diversas vezes, até obtermos a frequência de todos os caracteres.
Como nossa tabela possui todos os índices da tabela ASCII, podemos contar a frequência de todos os caracteres ao mesmo tempo. Para um caracter X, acessamos a tabela na posição X e incrementamos o valor ali armazenado. Isso pode ser feito com a instrução a seguir:
/* Incremento do valor da posição texto[i] da tabela. */ tab[texto[i]]++;
Observe que a string texto possui o texto a ser codificado. Assim, cada posição i desse vetor possui algum caracter. A parte “texto[i]” retorna o caracter da posição i. Como este trecho está dentro do par de colchetes de acesso a um vetor, então será retornado não o caracter, mas o código da tabela ASCII que representa aquele caracter, um número entre 0 e 255. Feito isso, basta incrementar o valor daquela posição.
/*
Procedimento para contar a frequência dos caracteres
*/
void preenche_tab_frequencia(unsigned char texto[], unsigned int tab[]){
int i = 0;
while(texto[i] != '\0'){
tab[texto[i]]++;
i++;
}
}
Para ter certeza que tudo está funcionando como o esperado é interessante imprimir na tela nossa tabela de frequência. Isso será feito com a trecho de código a seguir.
/*
Procedimento para imprimir a tabela de frequência
*/
void imprime_tab_frequencia(unsigned int tab[]){
int i;
printf("\tTABELA DE FREQUENCIA\n");
for(i = 0; i < TAM; i++)
printf("\t%d = %u = %c\n", i, tab[i], i);
}
Ao executar o trecho de código acima para um texto pequeno, como a frase do nosso exemplo, você vai perceber que muitas posições da tabela estão vazias, com o valor 0 ( zero ). Para melhorar esta impressão, podemos fazer um teste e imprimir apenas as posições maiores que zero, indicando que existe ao menos uma ocorrência daquela caracter.
/*
Procedimento para imprimir a tabela de frequência
*/
void imprime_tab_frequencia(unsigned int tab[]){
int i;
printf("\tTABELA DE FREQUENCIA\n");
for(i = 0; i < TAM; i++){
if(tab[i] > 0)
printf("\t%d = %u = %c\n", i, tab[i], i);
}
}
Código parcial para o Algoritmo de Huffman – Parte I: Tabela de Frequência
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <locale.h>
/*
Código escrito por Wagner Gaspar
Outubro de 2021
*/
// Tamanho da tabela de frequência
#define TAM 256
//----------- parte 1: tabela de frequência ----------------------
void inicializa_tabela_com_zero(unsigned int tab[]){
int i;
for(i = 0; i < TAM; i++)
tab[i] = 0;
}
void preenche_tab_frequencia(unsigned char texto[], unsigned int tab[]){
int i = 0;
while(texto[i] != '\0'){
tab[texto[i]]++;
i++;
}
}
void imprime_tab_frequencia(unsigned int tab[]){
int i;
printf("\tTABELA DE FREQUENCIA\n");
for(i = 0; i < TAM; i++){
if(tab[i] > 0)
printf("\t%d = %u = %c\n", i, tab[i], i);
}
}
int main() {
unsigned char texto[] = "Vamos aprender programação";
unsigned int tabela_frequencia[TAM];
setlocale(LC_ALL, "Portuguese");
//----------- parte 1: tabela de frequência ---------------
inicializa_tabela_com_zero(tabela_frequencia);
preenche_tab_frequencia(texto, tabela_frequencia);
imprime_tab_frequencia(tabela_frequencia);
return 0;
}
