RKI — Zajęcia 14 — Kodowanie Huffmana
Transkrypt
RKI — Zajęcia 14 — Kodowanie Huffmana
RKI — Zajęcia 14 — Kodowanie Huffmana Piersa Jarosław 2010-03-09 1 Wprowadzenie Kodowanie Huffmana jest jednym z najprostszych, co nie oznacza nieskutecznych, algorytmów kompresji. Wykorzystywany jest w między innymi w formatach JPEG oraz MP3. Sam algorytm jest bezstratny, to oznacza, że dane po zakodowaniu i odkodowaniu są identyczne z wejściowymi. Kodowanie można stosować do dowolnych danych, ale w tej lekcji ograniczymy się tylko do tekstów. Potrzebne wiadomości: • drzewa binarne, • listy lub kolejki priorytetowe, • znajomość typu znakowego, 2 Kodowanie O kodowaniu można myśleć jak o tłumaczeniu tekstu na obcy język. Zapewne każdy pisał opowiadanie na język angielski. Najłatwiejszą metodą jest kodowanie słownikowe. Zakładamy, że mamy dany słownik opisujący jaki symbol zamienić na jaki, przy czym ten nowy pownien być krótszy niż poprzedni. W tej sytuacji kodowanie sprowadza się do czytania jednego tekstu litery, sprawdzania w słowniku jej kodu i wpisywania go w drugim tekście. Gdyby wszystkie prace domowe były tak proste. „ABCD” Napis zajmuje 4 bajty. Zauważmy, że każda litera zajmuje po jednym bajcie (czyli ośmiu bitach) podczas gdy wystarczą po dwa bity na znak: • A = „00” • B = „01” • C = „10” • D = „11” Tak zakodowany napis „00011011”= 0x1B liczy tylko 8 bitów czyli 1 bajt. Wniosek: nie ma sensu kodować symboli, które w tekście nie występują. „AABC ABAD BACA ABAA” Spacje są tylko dla czytelności. Tekst ma 16 znaków, ale niektóre z nich występują częściej niż inne. litera ilość wystąpień A 8 Przy powyższym kodowaniu mamy 32 bity = 4 bajty. Ale można znaleźć jeszcze sprytniejsze kodowanie: • A = „0” • B = „10” 1 B 4 C 2 D 1 1 0 0 A 1 0 B 1 C D Rysunek 1: Drzewo słownikowe. • C = „110” • D = „111” Zauważyć można, że im częstsza litera tym krótszy ma kod. Po zakodowaniu mamy: „0010110 0100111 1001100 01000”. 7+7+7+5 = 26 bitów. Choć nadal trzeba 6 tę wartość zaokrąglić do 4B to licząc względnie zaoszczędziliśmy 32 czyli około 18%. 3 Dekodowanie Trzymając się porównania do języków obcych, dekodowanie jest tłumaczeniem tekstu z obcego języka na nasz. Spróbujmy przetłumaczyć tekst ’110111’ według słownika: • A = „0” • B = „1” • C = „10” • D = „01” Tu niestety pojawiaja się problem. fragment „101” można przetłumaczyć na dwa sposoby. Może być to „BD” albo też „CB”. Nie jest to problem niewłaściwego tekstu, a niewłaściwego słownika. Języku literką „C” można odczytać jako „BA”. Rozważmy inne kodowanie: • A = „0” • B = „10” • C = „110” • D = „111” oraz tekst ’110111’. Tłumaczy się on na „CD”. Po chwili zastanowienia dodamy, że jest to jedyne tłumaczenie. Własnością jaką spełnia dobry słownik jest to, że żaden kod nie jest prefiksem innego. W niepoprawnym słowniku widizmy, że „0” jest prefiksem „01”. Dobry słownik jest reprezentowany poprzez drzewo binarne, w którym: • każdy węzeł ma albo dwoje potomków, albo żadnego, • słowa kluczowe (litery) są w liściach, • przejście do prawego potomka oznacza dopisanie do koowania „1”, przejście do lewego — „0”. 2 Mając gotowe drzewo tekst odczytujemy: • czytamy znak, • schodzimy do właściwej gałęzi, • w wypadku dojścia do liścia — wypisujemy literę z liścia oraz wracamy do korzenia drzewa. 4 Drzewo Huffmana Doszliśmy zatem do pytania, jak stworzyć drzewo słownikowe, które do tygo było by optymalne pod kądem ilości bitów w skompresowanym tekście? Odpowiedzi udzielił David Huffman w roku 1952. 1. Dla każdego znaku policz ilość jego wystąpień w tekście do kompresji. 2. Usuń z dalszych rozważań znaki, które nie występują tekście. 3. Dla każdego ze znaków zbuduj drzewo binarne: • Drzewo składa się z jednego węzła, nie ma żadnego potomka, • Jedyny węzeł posiada zapisaną literę którą reprezentuje, • Dodatkowo posiada klucz, który jest ilością wystąpień litery w tekście. 4. Ustaw drzewa w kolejce priorytetowej niemalejącej według klucza (tj. im mniejsza ilość wystąpień tym bliżej początku kolejki). Na przykład można ustawić drzewa w posortowaną listę. 5. Dopuki w kolejce są przynajmniej dwa drzewa powtarzaj: (a) Zdejmij pierwsze drzewo z kolejki (tj. te które ma najmniejszy klucz). Oznacz ja jako A. (b) Zdejmij jeszcze jedno pierwsze drzewo z kolejki. Oznacz je jako B. (c) Stwórz nowe drzewo D takie że: • • • • D.klucz = A.klucz + B.klucz D.prawyP otomek = A D.lewyP otomek = B D.litera — nie będzie potrzebne (d) Wstaw nowoutworzone drzewo D do kolejki/listy tak aby nie zaburzyć porządku na kluczach, 6. Zwróć pozostałe jedyne drzewo w kolejce. Etapy działania algorytmy na rysunku 2 5 Zadanie 1 Napisz program, który wczyta liczbę znaków n, a następnie tekst długości n znaków. We wczytywanym tekście nie będzie spacji, znaków interpunkcyjnych ani cyfr, będą wyłącznie litery. Uwaga: małe i wielkie litery należy traktować jednakowo. Program powienien wyświetlić listę znaków występujących w tekście oraz liczbę wystąpień. Znaki powinny być posortowane niemalejąco. W przypadku znaków o jednakowej ilości wystąpień decyduje kolejność alfabetyczna (wcześniejsza litera w alfabecie będzie wyświetlona wcześciej). Przykładowe dane: 9 abbcaabdc D C A B 1 2 3 3 3 3 D1 C2 B4 A8 C2 (a) Krok 1 B4 A8 D1 (b) Krok 2 1 B4 A8 A8 3 C2 B4 D1 3 C2 (c) Krok 3 D1 (d) Krok 4 Rysunek 2: Działanie algorytmu. 6 Zadanie 2 Napisz program który wczyta liczbę znaków n, a następnie tekst sługości n znaków. Program powinien wypisać na ekran tekst skompresowany algorytmem Huffmana. 16 AABCABADBACAABAA 0010110010011110011000100 4