Kody Huffmana

by Jerry Sky

2020-10-29



1. Overview

X={x1,x2,,xN}p1p2pNX = \{x_1, x_2, \dots, x_N\} \quad p_1 \ge p_2 \ge \dots \ge p_N

  1. Budujemy las o drzewach jednoelementowych:

    p1x1p2x2p3x3pNxN. \underset{x_1}{\overset{p_1}{\circ}}\quad \underset{x_2}{\overset{p_2}{\circ}}\quad \underset{x_3}{\overset{p_3}{\circ}}\quad \dots\quad \underset{x_N}{\overset{p_N}{\circ}}.

  2. Wybieramy dwa drzewa o najmniejszych „wagach” i robimy z nich drzewo.

  3. Dostajemy las o drzewach:

    p1x1p2x2pN2xN2 \underset{x_1}{\overset{p_1}{\circ}}\quad \underset{x_2}{\overset{p_2}{\circ}}\quad \dots\quad \underset{x_{N-2}}{\overset{p_{N-2}}{\circ}} oraz
    .

  4. Sortujemy las względem „wag” i kończymy, jeśli zostało tylko jedno drzewo lub idziemy do kroku 1.

Na „dowidzenia” dostaniemy drzewo binarne (o wadze 11) i liściach etykietowanych {x1,x2,,xN}\{x_1, x_2, \dots, x_N\}. Możemy z tego odczytać kody!

Gratis: owe kody są prefiksowe.


2. Przykład

Mamy

Czyli mamy las początkowy: 12x113x2118x3118x4118x5. \underset{x_1}{\overset{\frac{1}{2}}{\circ}}\quad \underset{x_2}{\overset{\frac{1}{3}}{\circ}}\quad \underset{x_3}{\overset{\frac{1}{18}}{\circ}}\quad \underset{x_4}{\overset{\frac{1}{18}}{\circ}}\quad \underset{x_5}{\overset{\frac{1}{18}}{\circ}}.

Iterujemy:


Czyli teraz możemy policzyć kody poszczególnych symboli:


3. Fakt o słowach kodowych Huffmana

  1. l1l2l3lNl_1 \le l_2 \le l_3 \le \dots \le l_N (li=c(xi)l_i = |c(x_i)|)
  2. lN1=lNl_{N-1} = l_N
  3. c(xN)c(x_N) oraz c(xN1)c(x_{N-1}) różnią się tylko ostatnim bitem.

3.1. D-d

Punkty 2. oraz 3. są oczywiste.
(patrz przykład — pierwsze połączone wisienki)

  1. mniej oczywiste, zaraz zostanie wyjaśnione

4. Fakt o własnościach optymalnych kodów

  1. l1l2l3lNl_1 \le l_2 \le l_3 \le \dots \le l_N
  2. lN1=lNl_{N-1} = l_N

4.1. D-d

  1. Załóżmy, że li>ljl_i > l_j dla pewnego i<ji<j

    c(xk)=lk|c(x_k)| = l_k.
    Robimy kodowanie c~\tilde{c}:

    lc~=k=1Npkl~k=ki,jpkl~k+pil~i+pjl~j=kj,ipklk+pilj+pjli<kpklkl_{\tilde{c}} = \sum_{k=1}^N p_k \tilde{l}_k = \sum_{k \neq i,j} p_k \tilde{l}_k + p_i \tilde{l}_i + p_j \tilde{l}_j = \sum_{k \neq j,i} p_k l_k + p_i l_j + p_j l_i < \sum_{k} p_k l_k,
    ponieważ
    pilj+pjli<pili+pjljp_i l_j + p_j l_i < p_i l_i + p_j l_j,
    pi(ljli)<pj(ljli)p_i (l_j - l_i) < p_j (l_j - l_i),
    pi>pjp_i > p_j
    (ostrość!)

    generalnie pi<pj    liljp_i < p_j \implies l_i \le l_j

  2. Jeśli lNlN1l_N \neq l_{N-1}, to ln>lN1l_n > l_{N-1} oraz lNl_N jedyna;
    tzn. {N}={i:li=lN}\{N\} = \{i: l_i = l_N\}

    c(xN)=ε1ε2εlNc~(xN)=ε1ε2εN1c(x_N) = \varepsilon_1 \varepsilon_2 \dots \varepsilon_{l_N} \qquad \tilde{c}(x_N) = \varepsilon_1 \varepsilon_2 \dots \varepsilon_{N-1}
    c~(xk)=c(xk)\tilde{c}(x_k) = c(x_k) dla k<Nk < N
    L~<L\tilde{L} < L \quad sprzeczność

    Eureka: c~\tilde{c} jest prefiksowy!


5. Fakt#3

Istnieje kod optymalny cc (dla p1p2p3pNp_1 \ge p_2 \ge p_3 \ge \dots \ge p_N) spełniający warunki:

  1. l1l2lNl_1 \le l_2 \le \dots l_N
  2. lN1=lNl_{N-1} = l_N
  3. c(xN)c(x_N) oraz c(xN1)c(x_{N-1}) różnią się tylko ostatnim bitem.

5.1. D-d

Punkty 1. i 2. OK.

Aby zrobić 3., trzeba zmodyfikować kod optymalny, który mamy cc'.

Liczby l1,,lNl_1, \dots, l_N spełniają nierówność Kraft’a. Można zrobić kod prefiksowy spełniający dodatkowo punkt 3.

\square


6. Twierdzenie o kodach Huffmana

— Kody Huffmana są optymalne!

6.1. D-d

(przez indukcję względem NN; N=1,2N=1,2 nie sprawia problemu)

Mamy {p1,p2,,pN}\{p_1, p_2, \dots, p_N\} i robimy {q1,q2,,qN1}\{q_1, q_2, \dots, q_{N-1}\} gdzie qi=piq_i = p_i dla iN2i \le N-2; qN1=pN1+pNq_{N-1} = p_{N-1} + p_N.

Niech:

LNL_N — średnia długość kodu Huffmana dla pp.

LN=i=1NpilI=i=1N2pili+pN1lN1+pNlN(pN1+pN)lN=()L_N = \sum_{i=1}^N p_i l_I = \sum_{i=1}^{N-2} p_i l_i + \underbrace{p_{N-1} l_{N-1} + p_N l_N}_{(p_{N-1} + p_N) l_N} = (*)
i niech:

Dalej: ()=ikqili+qk(lk+1)=LN1+pN1+pN. (*) = \sum_{i\neq k}q_i' l_i' + q_k- (l_k' + 1) = \bold{L_{N-1}^* + p_{N-1} + p_N}.


Weźmy teraz optymalne kodowanie dla układu {p1,,pN}\{p_1,\dots,p_N\}. Ma ono średnią długość LNL_N^*.

Wiemy, że optymalne kodowanie można zrobić tak, aby kody odpowiadające pN1p_{N-1} i pNp_N były bliźniakami (czyli stanowiły jedną wisienkę).

drzewa niebieskie i różowe: niebieskie to układ stary, różowe to układ z połączonymi wisienkami  i  w jeden

Optymalne „drzewa kodów” („*”) {p1,,pN}\{p_1,\dots,p_N\} przerabiamy robiąc pewne drzewo kodów dla {p1,,pN2,pN1+pN}={q1,,qN1}\{p_1,\dots, p_{N_2}, p_{N-1} + p_N\} = \{q_1, \dots, q_{N-1}\}.

LN=i=1NlipiLN1=i=1N1liqi=i=1N2lipi+(lN11)lN(pN1+pN)=i=1NlipipN1pN L_N^* = \sum_{i=1}^N l_i^* p_i \\[10pt] L_{N-1}' = \sum_{i=1}^{N-1} l_i' q_i = \sum_{i=1}^{N-2} l_i* p_i + \underbrace{(l_{N-1}^* - 1)}_{l_N^*} (p_{N-1} + p_N) =\\[5pt] \sum_{i=1}^N l_i^* p_i - p_{N-1} - p_N

Czyli LN1+pN1+pN=LN. L_{N-1}' + p_{N-1} + p_N = L_N^*.

Wcześniej mieliśmy LN1+pN1+pN=LNL_{N-1}^* + p_{N-1} + p_N = L_N

Co jest dobre, ponieważ LNLNL_{N}^* \le L_N, bo LNL_{N}^* jest tym kodem idealnym. To samo się dzieje dla (N1)(N-1): LN1LN1L_{N-1}^* \le L_{N-1}'.

Zatem (z powyższych nierówności i równości), mamy LN=LN(oraz LN1=LN1) L_N = L_N^* \quad (\text{oraz } L_{N-1}' = L_{N-1}^*)

\square