22.12.2013 Views

Kodowanie Huffmana

Kodowanie Huffmana

Kodowanie Huffmana

SHOW MORE
SHOW LESS

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>

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!