Escolar Documentos
Profissional Documentos
Cultura Documentos
1
Numa árvore, a codificação é feita partindo-se de folhas selecionadas (códigos válidos) e seguindo pelos ramos
até a raíz, sendo o código dado pelo caminho percorrido.
Já a decodificação é feita de forma inversa, partindo-se da raíz, lendo-se o código ao longo do percurso até uma
dada folha.
Como os caminhos são únicos, o código é unívoco.
E, como, ao chegar no destino (raíz ou folha), imediatamente tem-se o resultado, de certo, o código é instantâneo.
Na literatura, bons códigos de árvore binária são chamados de códigos de prefixo, sendo assim chamados pois
nenhuma palavra de código é prefixo de outra.
E como construir um código de prefixo que seja ótimo para uma dada DMS com probabilidades conhecidas?
Para responder, consideramos o caso de codificação de três mensagens do exemplo anterior.
Exemplo 2
Seja uma fonte ternária com probabilidades conhecidas.
Figura 2 - Obtenção do código de Huffman
A árvore completa da Figura 2a conta com várias podas de ramos possíveis com 3 folhas mas, de início, não
sabemos quais escolher ou, tão pouco, quais seriam ótimas para a fonte dada.
Huffman partiu das folhas, inicialmente desconhecidas (Figura 2b), e mostrou como chegar num código ótimo.
Como nada sabemos sobre a codificação dessa fonte, ordenamos as probabilidades e agrupamos as duas
mensagens menos frequentes. Com isto acabamos reduzindo o problema a uma fonte binária (Figura 2c).
Em seguida, desagrupamos os códigos com prefixo 1 e chegamos na árvore da Figura 2d cujo código é [0 10 11]
e que tem a palavra 0 atribuída à mensagem mais frequente.
O algoritmo de Huffman garante que o código obtido é de prefixo e que, ainda, alcança máxima eficiência.
De fato, na Figura 2, em (c) temos um código sabidamente ótimo com comprimento médio
L2 = 1p + 1q
que é igual a 1.
Antes disso, em (b), o comprimento médio era
L3 = 1p + 2r + 2s = 1p + 2(r + s) = 1p + 2q = L2 + 1q
Bem, se L2 é mínimo, então L3 também deve ser mínimo porque o termo 1q é constante.
Na apostila do curso, encontra-se detalhado o algoritmo para além de fontes ternárias.
E, por indução, demonstra-se que o código de Huffman é ótimo em todos os casos.
A seguir, apresentamos uma implementação computacional do algoritmo.
Exemplo 3
Seja uma fonte quaternária com probabilidades dadas.
O código a seguir mostra os passos do algoritmo de Huffman para 4 mensagens.
# Dados de entrada:
M={ '1' '2' '3' '4' }; # mensagens
P=[ .4 .3 .2 .1 ]; # probabilidades
sumP=sum(P) # verifica validade
2
# ESaída:
sumP = 1.00000
# a) Início:
P4=P # probabilidades
M4=M
# ESaída:
P4 =
0.40000 0.30000 0.20000 0.10000
M4 =
1 2 3 4
# b) Ordenação: (4 mensagens)
[P,ind]=sort(P)
# mensagem ordenada:
M4o=M4(ind)
# ESaída:
P =
0.10000 0.20000 0.30000 0.40000
ind =
4 3 2 1
M4o =
4 3 2 1
# c) Redução: (4 -> 3)
M3=M4o(2:end); # Copia
M3(1)={[M4o{1} M4o{2}]}
# ESaída:
P=[ P(1)+P(2) P(3:end) ] # Soma prob. 1 e 2
M3 =
43 2 1
P =
0.30000 0.30000 0.40000
# d) Ordenação: (3)
[P,ind]=sort(P)
M3o=M3(ind)
# ESaída:
P =
0.30000 0.30000 0.40000
ind =
2 1 3
M3o =
2 43 1
# e) Redução: (3 -> 2)
M2=M3o(2:end); # Copia
M2(1)={[M3o{1} M3o{2}]}
P=[ P(1)+P(2) P(3:end) ] # Soma prob. 1 e 2
# ESaída:
M2 =
243 1
P =
0.60000 0.40000
3
# f) Ordenação: (2)
[P,ind]=sort(P)
M2o=M2(ind)
# ESaída:
P =
0.40000 0.60000
ind =
2 1
M3o =
1 243
# g) Codificação: (2)
C2={}; # início da codificação
C2{1}='0'; # prefixo '0' para agrupamento 1
C2{2}='1'; # prefixo '1' para agrupamento 2
# Exibe M e C
disp('b
# ESaída:
M2 =
243 1
C2 =
0 1
# h) Codificação: (3)
C3={}; im=1; suf='0'
for m=M3 # mensagem
ig=1;
for g=M2 # grupo
if ! isempty(strfind(g{1},m{1})) # se grupo contém mensagem
if ! isempty(strfind(M2{1},m{1})) # se veio de desagrupamento
C3{im}=[C2{ig} suf]; # acrescenta prefixo e sufixo
suf='1';
else
C3{im}=[C2{ig}]; # senão, só acrescenta prefixo
endif
endif
ig=ig+1; # indice de grupo
endfor
im=im+1; # indice de mensagem
endfor
# Exibe M e C
disp('b
# ESaída:
suf = 0
M3 =
43 2 1
C3 =
00 01 1
# i) Codificação: (4)
C4={}; im=1; suf='0';
for m=M4 # mensagem
ig=1;
for g=M3 # grupo
if ! isempty(strfind(g{1},m{1})) # se grupo contém mensagem
if ! isempty(strfind(M3{1},m{1})) # se veio de desagrupamento
4
C4{im}=[C3{ig} suf]; # acrescenta prefixo e sufixo
suf='1';
else
C4{im}=[C3{ig}]; # senão, só acrescenta prefixo
endif
endif
ig=ig+1; # indice de grupo
endfor
im=im+1; # indice de mensagem
endfor
# Exibe M e C
disp('b
# ESaída:
M4 =
1 2 3 4
C4 =
1 01 000 001
# j) Fim
v Exercícios
1. Seja uma fonte ternária, DMS, com probabilidades 0.5, 0.25 e 0.25. Pede-se:
a) A entropia da fonte.
b) O comprimento médio do código de vírgula visto no Exemplo 1.
c) O código pré-vírgula {100,10,1} conta com mesma eficiência?
d) O código pré-virgula seria melhor? Teria alguma desvantagem na prática? É de prefixo? É de árvore
binária?
e) (opcional) G Faça os cálculos e análises para responder os itens anteriores usando ferramenta computa-
cional (Octave, Python etc.)
2. Seja o algoritmo de Huffman para 4 mensagens do Exemplo 3. Usando ferramenta computacional (Octave,
Python etc.) de sua preferência, pede-se:
a) Execute o algoritmo para uma DMS com probabilidades 0.4, 0.3, 0.2 e 0.1.
b) Verifique o resultado anterior manualmente.
c) O comprimento médio do código obtido nos itens anteriores. Compare-os.
d) Modifique o algoritmo para aceitar entrada com maior número de mensagens.
e) Repita a, b e c para uma DMS com probabilidades 0.45, 0.31, 0.14, 0.08 e 0.02. Use o seu algoritmo
modificado.
f) (opcional) G Aperfeiçoe o seu algoritmo para que sempre atribua sufixo 0 ao maior desagrupamento em
caso de empate de probabilidades. O algoritmo do Exemplo 3 garante isto?