Kodowanie Huffmana
Kodowanie Huffmana
Kodowanie Huffmana
You also want an ePaper? Increase the reach of your titles
YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.
Wstęp<br />
Statyczne kody <strong>Huffmana</strong><br />
Dynamiczne kody <strong>Huffmana</strong><br />
Praktyka<br />
<strong>Kodowanie</strong> <strong>Huffmana</strong><br />
Dawid Duda<br />
4 marca 2004<br />
Dawid Duda<br />
<strong>Kodowanie</strong> <strong>Huffmana</strong>
Wstęp<br />
Statyczne kody <strong>Huffmana</strong><br />
Dynamiczne kody <strong>Huffmana</strong><br />
Praktyka<br />
Wstęp<br />
Podstawowe oznaczenia i definicje<br />
Statyczne kody <strong>Huffmana</strong><br />
Wymagania wobec kodu<br />
Podstawowa idea<br />
Podsumowanie<br />
Dynamiczne kody <strong>Huffmana</strong><br />
Wstęp<br />
Algorytm FGK (Faller, Gallager i Knuth)<br />
Algorytm Vittera<br />
Praktyka<br />
Dawid Duda<br />
<strong>Kodowanie</strong> <strong>Huffmana</strong>
Wstęp<br />
Statyczne kody <strong>Huffmana</strong><br />
Dynamiczne kody <strong>Huffmana</strong><br />
Praktyka<br />
Podstawowe oznaczenia i definicje<br />
Podstawowe oznaczenia i definicje:<br />
◮ alfabet wejściowy: A = {a 1 , a 2 , . . . , a m }<br />
◮ informacja własna litery:<br />
i(A) = log<br />
◮ entropia (średnia informacja własna):<br />
1<br />
= − log P(A) (1)<br />
P(A)<br />
H = ∑ P(A i )i(A i ) = − ∑ P(A i ) log P(A i ) (2)<br />
◮ Tw. Shannona: średnia ilość bitów przypadająca na jeden<br />
zakodowany symbol nie jest mniejsza od entropii źródła<br />
◮ kod prefiksowy: kod, w którym żadne słowo kodowe nie jest<br />
prefiksem innego słowa kodowego<br />
Dawid Duda<br />
<strong>Kodowanie</strong> <strong>Huffmana</strong>
Wstęp<br />
Statyczne kody <strong>Huffmana</strong><br />
Dynamiczne kody <strong>Huffmana</strong><br />
Praktyka<br />
Wymagania wobec kodu<br />
Podstawowa idea<br />
Podsumowanie<br />
Co chcemy uzyskać:<br />
◮ każdemu symbolowi z alfabetu chcemy przypisać<br />
jednoznacznie słowo kodowe<br />
◮ symbolom rzadko występującym chcemy przypisać dłuższe<br />
słowa kodowe, a częściej występującym krótsze<br />
◮ chcemy móc jednoznacznie dekodować zakodowane dane<br />
◮ ale takich kodów jest wiele, który wybrać?<br />
◮ no i jak wybrać, aby taki kod móc szybko zbudować?<br />
Dawid Duda<br />
<strong>Kodowanie</strong> <strong>Huffmana</strong>
Wstęp<br />
Statyczne kody <strong>Huffmana</strong><br />
Dynamiczne kody <strong>Huffmana</strong><br />
Praktyka<br />
Wymagania wobec kodu<br />
Podstawowa idea<br />
Podsumowanie<br />
Cel: optymalny kod spełniający wymienione wymagania.<br />
Kluczowe obserwacje:<br />
◮ dla każdego jednoznacznie dekodowalnego kodu istnieje nie<br />
gorszy (w sensie średniej ilości bitów na symbol) kod<br />
prefiksowy<br />
◮ w kodzie optymalnym częściej występującym symbolom będą<br />
odpowiadały krótsze słowa kodowe a rzadziej występującym<br />
dłuższe<br />
◮ w kodzie optymalnym dwa symbole występujące najrzadziej<br />
będą miały słowa kodowe o tej samej długości<br />
Dawid Duda<br />
<strong>Kodowanie</strong> <strong>Huffmana</strong>
Wstęp<br />
Statyczne kody <strong>Huffmana</strong><br />
Dynamiczne kody <strong>Huffmana</strong><br />
Praktyka<br />
Wymagania wobec kodu<br />
Podstawowa idea<br />
Podsumowanie<br />
A P(A) c(A)<br />
a 2 0.4 c(a 2 )<br />
a 1 0.2 c(a 1 )<br />
a 3 0.2 c(a 3 )<br />
a 4 0.1 c(a 4 )<br />
a 5 0.1 c(a 5 )<br />
c(a 4 ) = α 1 · 0<br />
c(a 5 ) = α 1 · 1<br />
A P(A) c(A)<br />
a 2 0.4 c(a 2 )<br />
a 1 0.2 c(a 1 )<br />
a 3 0.2 c(a 3 )<br />
a 4 ′ 0.2 α 1<br />
c(a 3 ) = α 2 · 0<br />
c(a ′ 4 ) = α 2 · 1<br />
α 1 = α 2 · 1<br />
A P(A) c(A)<br />
a 2 0.4 c(a 2 )<br />
a 3 ′ 0.4 α 2<br />
a 1 0.2 c(a 1 )<br />
c(a ′ 3 ) = α 3 · 0<br />
c(a 1 ) = α 3 · 1<br />
α 2 = α 3 · 0<br />
A P(A) c(A)<br />
a 3 ′′ 0.6 α 3<br />
a 2 0.4 c(a 2 )<br />
c(a ′′<br />
3 ) = 0<br />
c(a 2 ) = 1<br />
α 3 = 0<br />
c(a 2 ) = 1<br />
c(a 1 ) = 01<br />
c(a 3 ) = 000<br />
c(a 4 ) = 0010<br />
c(a 5 ) = 0011<br />
Dawid Duda<br />
<strong>Kodowanie</strong> <strong>Huffmana</strong>
Wstęp<br />
Statyczne kody <strong>Huffmana</strong><br />
Dynamiczne kody <strong>Huffmana</strong><br />
Praktyka<br />
Wymagania wobec kodu<br />
Podstawowa idea<br />
Podsumowanie<br />
Algorytm konstrukcji drzewa <strong>Huffmana</strong>:<br />
1. umieść m liści na liście L<br />
2. dopóki lista L zawiera przynajmniej dwa elementy wykonuj<br />
2.1 usuń z listy L dwa elementy x oraz y o najmniejszej wadze<br />
2.2 stwórz nowy wierzchołek p, który będzie rodzicem x i y<br />
2.3 ustaw wagę wierzchołka p na sumę wag x i y<br />
2.4 umieść wierzchołek p na liście L<br />
Dawid Duda<br />
<strong>Kodowanie</strong> <strong>Huffmana</strong>
Wstęp<br />
Statyczne kody <strong>Huffmana</strong><br />
Dynamiczne kody <strong>Huffmana</strong><br />
Praktyka<br />
Wymagania wobec kodu<br />
Podstawowa idea<br />
Podsumowanie<br />
Algorytm <strong>Huffmana</strong> generuje optymalny kod, ale jaka jest jego<br />
średnia długość l? Twierdzenie:<br />
H(S) ≤ l ≤ H(S) + 1 (3)<br />
Dawid Duda<br />
<strong>Kodowanie</strong> <strong>Huffmana</strong>
Wstęp<br />
Statyczne kody <strong>Huffmana</strong><br />
Dynamiczne kody <strong>Huffmana</strong><br />
Praktyka<br />
Wymagania wobec kodu<br />
Podstawowa idea<br />
Podsumowanie<br />
Istnieje możliwość dokładniejszego oszacowania. Niech<br />
P max = max {P(a i )} m i=1<br />
wówczas<br />
◮ P max < 0.5 =⇒ l ≤ H(S) + P max<br />
◮ P max ≥ 0.5 =⇒ l ≤ H(S) + P max + 0.086<br />
Dawid Duda<br />
<strong>Kodowanie</strong> <strong>Huffmana</strong>
Wstęp<br />
Statyczne kody <strong>Huffmana</strong><br />
Dynamiczne kody <strong>Huffmana</strong><br />
Praktyka<br />
Wymagania wobec kodu<br />
Podstawowa idea<br />
Podsumowanie<br />
Zalety:<br />
◮ kod <strong>Huffmana</strong> minimalizuje sumę ważoną długości kodów, tj.<br />
jest optymalnym kodem prefiksowym<br />
◮ procedura budowy drzewa <strong>Huffmana</strong> jest szybka i prosta<br />
w implementacji<br />
◮ zarówno kodowanie jak i dekodowanie jest proste i efektywne<br />
Wady:<br />
◮ do budowy drzewa konieczne są statystyki kodowanej<br />
wiadomości<br />
◮ do przekazywanej/zapisywanej wiadomości trzeba dołączyć<br />
opis drzewa<br />
Dawid Duda<br />
<strong>Kodowanie</strong> <strong>Huffmana</strong>
Wstęp<br />
Statyczne kody <strong>Huffmana</strong><br />
Dynamiczne kody <strong>Huffmana</strong><br />
Praktyka<br />
Wstęp<br />
Algorytm FGK (Faller, Gallager i Knuth)<br />
Algorytm Vittera<br />
Cel: stworzenie jednoprzebiegowego algorytmu kodującego<br />
Metoda: utrzymywanie drzewa <strong>Huffmana</strong> obliczonego zgodnie<br />
z częstościami wystąpień symboli w dotychczas przetworzonym<br />
fragmencie<br />
Co zyskamy:<br />
◮ tylko jeden przebieg<br />
◮ nie trzeba przesyłać drzewa<br />
Problem: jak szybko uaktualniać drzewo <strong>Huffmana</strong>?<br />
Dawid Duda<br />
<strong>Kodowanie</strong> <strong>Huffmana</strong>
Wstęp<br />
Statyczne kody <strong>Huffmana</strong><br />
Dynamiczne kody <strong>Huffmana</strong><br />
Praktyka<br />
Wstęp<br />
Algorytm FGK (Faller, Gallager i Knuth)<br />
Algorytm Vittera<br />
Wierzchołkom w drzewie przypisujemy wagę, która dla liści jest<br />
równa ilości wystąpień kodowanego symbolu w dotychczasowym<br />
tekście, a dla wierzchołków wewnętrznych sumie wag dzieci. Niech<br />
M t = a i1 a i2 . . . a ik będzie dotychczas przetworzonym fragmentem.<br />
Następna litera a ik+1 będzie zakodowana oraz odkodowana przy<br />
użyciu drzewa <strong>Huffmana</strong> dla M t .<br />
Główna trudność: jak szybko zmodyfikować drzewo dla M t aby<br />
otrzymać drzewo dla M t+1 ? Proste zwiększenie o 1 wagi<br />
wierzchołka i jego rodziców nie zawsze da drzewo <strong>Huffmana</strong>.<br />
Rozwiązanie: wykorzystać własność sąsiedztwa<br />
Dawid Duda<br />
<strong>Kodowanie</strong> <strong>Huffmana</strong>
Wstęp<br />
Statyczne kody <strong>Huffmana</strong><br />
Dynamiczne kody <strong>Huffmana</strong><br />
Praktyka<br />
Wstęp<br />
Algorytm FGK (Faller, Gallager i Knuth)<br />
Algorytm Vittera<br />
Do wyprowadzenia algorytmu wykorzystamy pewną charakteryzację<br />
drzew <strong>Huffmana</strong>:<br />
Własność sąsiedztwa<br />
Drzewo binarne o p liściach oraz nieujemnych wagach<br />
wierzchołków w i jest drzewem <strong>Huffmana</strong> wtedy i tylko wtedy gdy:<br />
1. waga każdego wierzchołka jest sumą wag jego dzieci<br />
2. istnieje niemalejąca numeracja wierzchołków zgodna<br />
z niemalejącym uporządkowaniem według wagi taka, że dla<br />
1 ≤ j ≤ p − 1 wierzchołki 2j − 1 i 2j są sąsiadami i ich<br />
wspólny rodzic ma wyższy numer<br />
Dawid Duda<br />
<strong>Kodowanie</strong> <strong>Huffmana</strong>
Wstęp<br />
Statyczne kody <strong>Huffmana</strong><br />
Dynamiczne kody <strong>Huffmana</strong><br />
Praktyka<br />
Wstęp<br />
Algorytm FGK (Faller, Gallager i Knuth)<br />
Algorytm Vittera<br />
Rozwiązanie: aktualizacje drzewa wykonamy w dwóch fazach:<br />
1. przekształcenie drzewa do takiej postaci, w której proste<br />
zwiększenie wagi odpowiednich wierzchołków nie zaburzy<br />
własności sąsiedztwa<br />
2. zwiększenie wagi wierzchołka odpowiadającego<br />
przetwarzanemu symbolowi i jego rodzicom<br />
Dawid Duda<br />
<strong>Kodowanie</strong> <strong>Huffmana</strong>
Wstęp<br />
Statyczne kody <strong>Huffmana</strong><br />
Dynamiczne kody <strong>Huffmana</strong><br />
Praktyka<br />
Wstęp<br />
Algorytm FGK (Faller, Gallager i Knuth)<br />
Algorytm Vittera<br />
Pytanie: co zrobić z drzewem, aby można było po prostu<br />
zwiększyć wagi wierzchołków?<br />
Odpowiedź: zaczynając od wierzchołka, który odpowiada<br />
kodowanemu symbolowi, zamieniać aktualny wierzchołek<br />
z wierzchołkiem o najwyższym numerze (w sensie numeracji<br />
z własności sąsiedztwa) spośród wierzchołków o tej samej wadze<br />
Dawid Duda<br />
<strong>Kodowanie</strong> <strong>Huffmana</strong>
Wstęp<br />
Statyczne kody <strong>Huffmana</strong><br />
Dynamiczne kody <strong>Huffmana</strong><br />
Praktyka<br />
Wstęp<br />
Algorytm FGK (Faller, Gallager i Knuth)<br />
Algorytm Vittera<br />
Dawid Duda<br />
<strong>Kodowanie</strong> <strong>Huffmana</strong>
Wstęp<br />
Statyczne kody <strong>Huffmana</strong><br />
Dynamiczne kody <strong>Huffmana</strong><br />
Praktyka<br />
Wstęp<br />
Algorytm FGK (Faller, Gallager i Knuth)<br />
Algorytm Vittera<br />
Dawid Duda<br />
<strong>Kodowanie</strong> <strong>Huffmana</strong>
Wstęp<br />
Statyczne kody <strong>Huffmana</strong><br />
Dynamiczne kody <strong>Huffmana</strong><br />
Praktyka<br />
Wstęp<br />
Algorytm FGK (Faller, Gallager i Knuth)<br />
Algorytm Vittera<br />
procedure update;<br />
q := wierzchołek odpowiadający otrzymanej literze;<br />
if (q = wierzchołek 0) and (k < m - 1) then<br />
dodaj q dwoje dzieci (numeracja: lewe, prawe, rodzic)<br />
q := prawe dziecko<br />
if q jest sąsiadem wierzchołka 0 then<br />
zamień q z liściem o tej samej wadze i najw.<br />
zwiększ wagę q o 1<br />
q := rodzic q<br />
numerze<br />
while q nie jest korzeniem<br />
zamień q z wierz. o tej samej wadze i najw. num.<br />
zwiększ wagę q o 1<br />
q := rodzic q<br />
Dawid Duda<br />
<strong>Kodowanie</strong> <strong>Huffmana</strong>
Wstęp<br />
Statyczne kody <strong>Huffmana</strong><br />
Dynamiczne kody <strong>Huffmana</strong><br />
Praktyka<br />
Wstęp<br />
Algorytm FGK (Faller, Gallager i Knuth)<br />
Algorytm Vittera<br />
Obserwacje:<br />
◮ zamiany wierzchołków, wykonywane przez algorytm, nie<br />
powodują, że drzewo przestaje być drzewem <strong>Huffmana</strong> dla<br />
M t (co wynika z własności sąsiedztwa)<br />
◮ po zwiększeniu odpowiednich wag (w drzewie otrzymanym<br />
przez wykonanie zamian) dostaniemy drzewo <strong>Huffmana</strong> dla<br />
M t+1 (co ponownie wynika z własności sąsiedztwa)<br />
Dawid Duda<br />
<strong>Kodowanie</strong> <strong>Huffmana</strong>
Wstęp<br />
Statyczne kody <strong>Huffmana</strong><br />
Dynamiczne kody <strong>Huffmana</strong><br />
Praktyka<br />
Wstęp<br />
Algorytm FGK (Faller, Gallager i Knuth)<br />
Algorytm Vittera<br />
Ile nas to kosztuje? O ile więcej bitów wygeneruje algorytm FGK<br />
w porównaniu z klasycznymi kodami <strong>Huffmana</strong>?<br />
Odpowiedź: Jeżeli S jest ilością bitów wygenerowanych przez<br />
oryginalny algorytm <strong>Huffmana</strong>, S ′ ilością bitów wygenerowanych<br />
przez algorytm FGK, a m rozmiarem alfabetu, to zachodzi:<br />
S ′ ≤ 2S + m (4)<br />
Dawid Duda<br />
<strong>Kodowanie</strong> <strong>Huffmana</strong>
Wstęp<br />
Statyczne kody <strong>Huffmana</strong><br />
Dynamiczne kody <strong>Huffmana</strong><br />
Praktyka<br />
Wstęp<br />
Algorytm FGK (Faller, Gallager i Knuth)<br />
Algorytm Vittera<br />
Pytanie: Czy można lepiej?<br />
Odpowiedź: Tak, używając algorytmu Vittera można mieć:<br />
S ′ < S + m (5)<br />
Dawid Duda<br />
<strong>Kodowanie</strong> <strong>Huffmana</strong>
Wstęp<br />
Statyczne kody <strong>Huffmana</strong><br />
Dynamiczne kody <strong>Huffmana</strong><br />
Praktyka<br />
Wstęp<br />
Algorytm FGK (Faller, Gallager i Knuth)<br />
Algorytm Vittera<br />
Podstawowa idea:<br />
◮ ograniczyć ilość zamian, w których wierzchołek q porusza się<br />
w górę drzewa, do co najwyżej jednego przy każdym<br />
wywołaniu update<br />
◮ konstruować drzewo w ten sposób, aby minimalizowało nie<br />
tylko sumę ważoną długości ścieżek w drzewie ∑ j w jL j , ale<br />
również sumę nieważoną długości ścieżek ∑ j L j oraz długość<br />
najdłuższej ścieżki max j {L j } - intuicyjnie powinno to<br />
ograniczyć długość słowa kodowego dla następnej litery<br />
Dawid Duda<br />
<strong>Kodowanie</strong> <strong>Huffmana</strong>
Wstęp<br />
Statyczne kody <strong>Huffmana</strong><br />
Dynamiczne kody <strong>Huffmana</strong><br />
Praktyka<br />
Wstęp<br />
Algorytm FGK (Faller, Gallager i Knuth)<br />
Algorytm Vittera<br />
Klasyfikacja zamian:<br />
◮ ↑ wierzchołek q przesuwa się do góry o jeden poziom<br />
◮ → wierzchołek q zamieniamy z wierzchołkiem z tego samego<br />
poziomu<br />
◮ ↓ wierzchołek q zamieniamy z wierzchołkiem na niższym<br />
poziomie<br />
◮ ↑↑ wierzchołek q zamieniamy z wierzchołkiem położonym<br />
o dwa poziomy wyżej<br />
Dawid Duda<br />
<strong>Kodowanie</strong> <strong>Huffmana</strong>
Wstęp<br />
Statyczne kody <strong>Huffmana</strong><br />
Dynamiczne kody <strong>Huffmana</strong><br />
Praktyka<br />
Wstęp<br />
Algorytm FGK (Faller, Gallager i Knuth)<br />
Algorytm Vittera<br />
Niejawna numeracja<br />
Pomysł: numerować wierzchołki drzewa w sposób odpowiadający<br />
reprezentacji wizualnej:<br />
◮ wierzchołki numerujemy w sposób zgodny z poziomami<br />
drzewa: wierzchołki na tym samym poziomie mają numery<br />
niższe niż te na następnym, wyższym poziomie<br />
◮ wierzchołki na tym samym poziomie numerujemy rosnąco<br />
od lewej do prawej<br />
Gdy używamy niejawnej numeracji, nie będzie zamian typu ↓.<br />
Oprócz tego, jeżeli wierzchołek przesuwa się do góry w zamianie<br />
typu ↑, to ten, który przesuwa się w dół, jest liściem.<br />
Dawid Duda<br />
<strong>Kodowanie</strong> <strong>Huffmana</strong>
Wstęp<br />
Statyczne kody <strong>Huffmana</strong><br />
Dynamiczne kody <strong>Huffmana</strong><br />
Praktyka<br />
Wstęp<br />
Algorytm FGK (Faller, Gallager i Knuth)<br />
Algorytm Vittera<br />
Niezmiennik algorytmu<br />
Kluczem do polepszenia algorytmu jest uniknięcie zamian typu ↑<br />
poza pierwszą iteracją pętli while. Aby to zrobić będziemy<br />
utrzymywać następujący niezmiennik:<br />
◮ dla każdej wagi w, wszystkie liście o wadze w poprzedzają<br />
w niejawnej numeracji wszystkie wierzchołki wewnętrzne<br />
o wadze w<br />
Można pokazać, że drzewo <strong>Huffmana</strong>, które spełnia ten<br />
niezmiennik, minimalizuje ∑ j L j oraz max j {L j }.<br />
Dawid Duda<br />
<strong>Kodowanie</strong> <strong>Huffmana</strong>
Wstęp<br />
Statyczne kody <strong>Huffmana</strong><br />
Dynamiczne kody <strong>Huffmana</strong><br />
Praktyka<br />
Wstęp<br />
Algorytm FGK (Faller, Gallager i Knuth)<br />
Algorytm Vittera<br />
Kilka definicji:<br />
◮ blok - klasa równoważności relacji na wierzchołkach drzewa:<br />
wierzchołki v i x są w relacji, jeśli mają tą samą wagę oraz<br />
obydwa są wierzchołkami lub obydwa są liśćmi (w algorytmie<br />
FGK nie zwracaliśmy uwagi na liście/wierzch. wewn.)<br />
◮ lider bloku - wierzchołek o najwyższym numerze należący<br />
do bloku<br />
Bloki są połączone w listę w kolejności rosnącej wagi, blok liści<br />
zawsze poprzedza blok wierzchołków wewnętrznych o tej samej<br />
wadze.<br />
Dawid Duda<br />
<strong>Kodowanie</strong> <strong>Huffmana</strong>
Wstęp<br />
Statyczne kody <strong>Huffmana</strong><br />
Dynamiczne kody <strong>Huffmana</strong><br />
Praktyka<br />
Wstęp<br />
Algorytm FGK (Faller, Gallager i Knuth)<br />
Algorytm Vittera<br />
procedure update;<br />
leafToIncrement := 0;<br />
q := wierzchołek odpowiadający otrzymanej literze;<br />
if (q = wierzchołek 0) and (k < m - 1) then<br />
dodaj q dwoje dzieci, prawe odpowiadające literze<br />
q := wierzchołek, który właśnie został tatusiem<br />
leafToIncrement := prawe dziecko q<br />
else<br />
zamień q z liderem jego bloku<br />
if q jest sąsiadem wierzchołka 0 then<br />
leafToIncrement := q;<br />
q := rodzic q<br />
while q nie jest korzeniem<br />
slideAndIncrement(q);<br />
if leafToIncrement ≠ 0 then<br />
slideAndIncrement(leafToIncrement);<br />
Dawid Duda<br />
<strong>Kodowanie</strong> <strong>Huffmana</strong>
Wstęp<br />
Statyczne kody <strong>Huffmana</strong><br />
Dynamiczne kody <strong>Huffmana</strong><br />
Praktyka<br />
Wstęp<br />
Algorytm FGK (Faller, Gallager i Knuth)<br />
Algorytm Vittera<br />
procedure slideAndIncrement(p);<br />
wt := waga wierzchołka p;<br />
b := następny blok na liście po bloku wierzchołka p;<br />
if p jest liściem and<br />
b jest blokiem wierzch. wewn. o wadze wt<br />
or p jest wierzch. wewn. and<br />
b jest blokiem liści o wadze wt+1<br />
then<br />
zjedź wierzch. p w drzewie w kierunku wierzch. z b<br />
p.weight := wt + 1;<br />
if p jest liściem then<br />
p := nowy rodzic p<br />
else<br />
p := dawny rodzic p<br />
Dawid Duda<br />
<strong>Kodowanie</strong> <strong>Huffmana</strong>
Wstęp<br />
Statyczne kody <strong>Huffmana</strong><br />
Dynamiczne kody <strong>Huffmana</strong><br />
Praktyka<br />
Wstęp<br />
Algorytm FGK (Faller, Gallager i Knuth)<br />
Algorytm Vittera<br />
Dawid Duda<br />
<strong>Kodowanie</strong> <strong>Huffmana</strong>
Wstęp<br />
Statyczne kody <strong>Huffmana</strong><br />
Dynamiczne kody <strong>Huffmana</strong><br />
Praktyka<br />
Wstęp<br />
Algorytm FGK (Faller, Gallager i Knuth)<br />
Algorytm Vittera<br />
Podsumowanie<br />
◮ długość danych zakodowanych algorytmem Vittera może się<br />
różnić od długości danych zakodowanych statycznym<br />
algorytmem <strong>Huffmana</strong> co najwyżej o długość alfabetu<br />
◮ algorytm jest dosyć skomplikowany, ale Vitter opublikował<br />
jego wzorcową implementację<br />
◮ algorytm wymaga specyficznych struktur danych, opisanych<br />
dokładnie w pracach Vittera<br />
Dawid Duda<br />
<strong>Kodowanie</strong> <strong>Huffmana</strong>
Wstęp<br />
Statyczne kody <strong>Huffmana</strong><br />
Dynamiczne kody <strong>Huffmana</strong><br />
Praktyka<br />
Wyniki testów<br />
Typ Rozmiar Stat. kody FGK Vitter<br />
pliku początkowy <strong>Huffmana</strong><br />
Postscript 506197 334785 334907 334891<br />
BMP 481078 448533 448821 448739<br />
Poczta 1657081 1112169 1112278 1112264<br />
Źródła w C 1331200 778081 778207 778182<br />
WAV 1000000 763453 763933 763717<br />
Dawid Duda<br />
<strong>Kodowanie</strong> <strong>Huffmana</strong>
Wstęp<br />
Statyczne kody <strong>Huffmana</strong><br />
Dynamiczne kody <strong>Huffmana</strong><br />
Praktyka<br />
Współczynnik kompresji<br />
Typ Stat. kody FGK Vitter<br />
pliku <strong>Huffmana</strong><br />
Postscript 0,6614 0,6616 0,6616<br />
BMP 0,9323 0,9329 0,9328<br />
Poczta 0,6712 0,6712 0,6712<br />
Źródła w C 0,5845 0,5846 0,5846<br />
WAV 0,7635 0,7639 0,7637<br />
Średnio 0,7226 0,7229 0,7228<br />
Dawid Duda<br />
<strong>Kodowanie</strong> <strong>Huffmana</strong>
Wstęp<br />
Statyczne kody <strong>Huffmana</strong><br />
Dynamiczne kody <strong>Huffmana</strong><br />
Praktyka<br />
Dawid Duda<br />
<strong>Kodowanie</strong> <strong>Huffmana</strong>
Wstęp<br />
Statyczne kody <strong>Huffmana</strong><br />
Dynamiczne kody <strong>Huffmana</strong><br />
Praktyka<br />
Gdzie szukać dalszych informacji:<br />
◮ Khalid Sayood, „Kompresja danych - wprowadzenie”,<br />
wydawnictwo Read Me, kwiecień 2002.<br />
◮ Jeffrey S. Vitter, „Design and Analysis of Dynamic Huffman<br />
Codes”, JACM Vol. 34, październik 1987.<br />
◮ Jeffrey S. Vitter, „Dynamic Huffman Coding”, ACM<br />
Transactions on Mathematical Software Vol. 15, czerwiec<br />
1989.<br />
Dawid Duda<br />
<strong>Kodowanie</strong> <strong>Huffmana</strong>
Długość kodów <strong>Huffmana</strong><br />
Algorytm <strong>Huffmana</strong> generuje optymalny kod, ale jaka jest jego<br />
średnia długość l? Twierdzenie:<br />
H(S) ≤ l ≤ H(S) + 1 (6)<br />
Dawid Duda<br />
<strong>Kodowanie</strong> <strong>Huffmana</strong>
Długość kodów <strong>Huffmana</strong><br />
Lemat (Kraft, McMillan):<br />
◮ (McMillan) Niech C będzie jednoznacznie dekodowalnym<br />
kodem. Niech A = {a 1 , a 2 , . . . , a m } będzie alfabetem<br />
wejściowym oraz niech l i = |C(a i )|. Wówczas:<br />
m∑<br />
2 −l i<br />
≤ 1 (7)<br />
i=1<br />
◮ (Kraft) Dla dowolnego ciągu dodatnich liczb całkowitych<br />
{l i } m i=1<br />
spełniającego (7) istnieje jednoznacznie dekodowalny<br />
kod o długościach {l i } m i=1<br />
Dawid Duda<br />
<strong>Kodowanie</strong> <strong>Huffmana</strong>
Długość kodów <strong>Huffmana</strong><br />
Wpierw pokażemy, że H(S) ≤ l. Prawdopodobieństwo wystąpienia<br />
litery a i oznaczmy przez P(a i ). Wtedy mamy:<br />
m∑<br />
l = P(a i )l i (8)<br />
H(S) − l = −<br />
=<br />
=<br />
=<br />
i=1<br />
i=1<br />
m∑<br />
P(a i ) log P(a i ) −<br />
i=1<br />
m∑<br />
( [ 1<br />
P(a i ) log<br />
m∑<br />
i=1<br />
m∑<br />
i=1<br />
P(a i )<br />
( [ 1<br />
P(a i ) log<br />
P(a i )<br />
]<br />
[ 2<br />
−l i<br />
P(a i ) log<br />
P(a i )<br />
m∑<br />
P(a i )l i<br />
i=1<br />
]<br />
− l i<br />
)<br />
] [ ] )<br />
− log 2 l i<br />
Dawid Duda<br />
<strong>Kodowanie</strong> <strong>Huffmana</strong>
Długość kodów <strong>Huffmana</strong><br />
Nierówność Jensena: dla każdej wklęsłej funkcji (∩) f (x)<br />
zachodzi:<br />
E [f (X )] ≤ f (E[X ]) (9)<br />
Ponieważ funkcja log jest wklęsła, wobec tego:<br />
m∑<br />
[ 2<br />
−l i<br />
] [<br />
∑ m<br />
H(S) − l = P(a i ) log ≤ log<br />
P(a i )<br />
i=1<br />
i=1<br />
2 −l i<br />
]<br />
(10)<br />
Ponieważ kod jest optymalny, to z lematu Krafta-McMillana (7)<br />
mamy że ∑ m<br />
i=1 2−l i<br />
≤ 1, a więc<br />
H(S) − l ≤ 0<br />
co kończy pierwszą część dowodu.<br />
Dawid Duda<br />
<strong>Kodowanie</strong> <strong>Huffmana</strong>
Długość kodów <strong>Huffmana</strong><br />
Górna granica - wiemy, że kod jest optymalny, więc wystarczy<br />
pokazać istnienie kodu takiego, że l ≤ H(S) + 1. Zdefiniujmy:<br />
⌈ ⌉<br />
1<br />
l i = log<br />
(11)<br />
P(a i )<br />
Ponieważ ∀x. ∃ɛ ∈ [0, 1). ⌈x⌉ = x + ɛ to zgodnie z (11) mamy:<br />
log<br />
1<br />
P(a i ) ≤ l 1<br />
i ≤ log<br />
P(a i ) + 1 (12)<br />
Dawid Duda<br />
<strong>Kodowanie</strong> <strong>Huffmana</strong>
Długość kodów <strong>Huffmana</strong><br />
Zauważmy, że z lewej nierówności z (12) mamy:<br />
2 −l i<br />
≤ P(a i )<br />
wobec czego, sumując obustronnie, otrzymujemy:<br />
m∑<br />
2 −l i<br />
≤<br />
i=1<br />
m∑<br />
P(a i ) = 1<br />
i=1<br />
skąd z kolei, przez drugą część lematu Krafta-McMillana, istnieje<br />
jednoznacznie dekodowalny kod o długościach {l i }.<br />
Długość tego kodu możemy oszacować następująco:<br />
l =<br />
m∑<br />
P(a i )l i <<br />
i=1<br />
co kończy dowód. <br />
m∑<br />
i=1<br />
[<br />
]<br />
1<br />
P(a i ) log<br />
P(a i ) + 1 = H(S) + 1 (13)<br />
Dawid Duda<br />
<strong>Kodowanie</strong> <strong>Huffmana</strong>