3. 0. a 10 4. e 22 1. b 11 5. f 23 2. c 2 6. g 5 3. d 13 7. h 13 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 シンボルの数 n に対してサイズ 2n の配列 A を用意する。この配列で左上の表のハフマン木を表現することを考える 例 : シンボル d のシンボル番号 ( 文字コード相当 ) は 3 で出現回数が 13 回
4. 0. a 10 4. e 22 1. b 11 5. f 23 2. c 2 6. g 5 3. d 13 7. h 13 10 11 2 13 22 23 5 13 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 配列 A の右半分を出現回数で埋める。つまり、右半分の要素それぞれがハフマン木の葉に相当する。 シンボル番号を i 、 i の出現回数を c i とすると A[n + i] = c i 例えば、左上表からシンボル b は番号 1 、 c 1 = 11 なので A[n + 1] = 11 (n = 8)
5. 0. a 10 4. e 22 1. b 11 5. f 23 2. c 2 6. g 5 3. d 13 7. h 13 8 9 10 11 12 13 14 15 10 11 2 13 22 23 5 13 左半分を、各シンボルの葉へのポインタにする。具体的には、左側の要素の添え字がシンボル番号、値がポイントすべき右側の要素の添え字になる 例えば左上表からシンボル番号 i = 0 の 'a' を考える。 A[0] は右半分の要素の中で 'a' の出現頻度に相当している要素を指す。よって A[0] = 8 になる。 A[A[0]] = 10 とすれば 'a' の出現頻度 10 が得られる 一般化すると A[A[i]] = C i になるように配列の左半分を埋めるということ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
6. 0. a 10 4. e 22 1. b 11 5. f 23 2. c 2 6. g 5 3. d 13 7. h 13 10 9 14 11 12 13 8 15 10 11 2 13 22 23 5 13 次に出現頻度の値を比較キーにして二分木ヒープ (※) を構成する。このとき右半分の出現頻度の配列、つまり葉で直接ヒープを構成するのではなく、左半分のポインタで間接的にヒープを構成する。右半分の値 ( 葉 ) は変更せず、左半分だけが必要に応じて入れ替わる。 これにより A[0] がヒープの根になる。つまり、 A[0] は出現頻度最小の値をポイントすることになる ※ 配列で二分木ヒープを構成する場合、親の添え字を i とすると左の子は 2i + 1, 右の子は 2i + 2 。「親の指す値が常に子のそれよりも小さい」という制約を満たすのがヒープの条件 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
7. 0. a 10 4. e 22 1. b 11 5. f 23 2. c 2 6. g 5 3. d 13 7. h 13 9 14 11 12 13 8 15 10 11 13 22 23 5 13 いよいよハフマン木の構築を始める。通常のハフマン木構築アルゴリズム同様、出現頻度が最も小さい二つの値を (greedy に ) 見つけたい。ひとつは、ヒープの根である A[0] がポイントする最小値である。 10 2 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
8. 0. a 10 4. e 22 1. b 11 5. f 23 2. c 2 6. g 5 3. d 13 7. h 13 9 14 11 12 13 8 15 10 11 13 22 23 5 13 一時変数 m1 に A[0] を取り出し、 10 2 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 10 m1
9. 0. a 10 4. e 22 1. b 11 5. f 23 2. c 2 6. g 5 3. d 13 7. h 13 9 14 11 12 13 8 15 10 11 13 22 23 5 13 左半分の配列の末尾の値を先頭にコピー ( 上書き ) し、 15 2 10 m1 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
10. 0. a 10 4. e 22 1. b 11 5. f 23 2. c 2 6. g 5 3. d 13 7. h 13 9 8 11 12 13 15 15 10 11 13 22 23 5 13 [0, n -1] だった左半分の配列の範囲を一つ減らして [0, n - 2] の範囲でヒープを構成しなおす。 これで最初の最小値である 2 ( を指しているポインタ ) をヒープから取り出して、ヒープを再構成したことになる。 14 2 10 m1 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
11. 0. a 10 4. e 22 1. b 11 5. f 23 2. c 2 6. g 5 3. d 13 7. h 13 9 8 11 12 13 15 15 10 11 13 22 23 5 13 次の最小値は構成しなおしたヒープの根 A[0] にある。よって次の最小値は A[A[0]] = A[14] = 5 14 2 10 m1 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
12. 0. a 10 4. e 22 1. b 11 5. f 23 2. c 2 6. g 5 3. d 13 7. h 13 9 8 11 12 13 15 15 10 11 13 22 23 5 13 二つ目の最小値を一次変数 m2 に取り出す。 ( 今回はヒープの再構成はまだ走らせないことに注意 ) 14 2 10 m1 14 m2 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
13. 0. a 10 4. e 22 1. b 11 5. f 23 2. c 2 6. g 5 3. d 13 7. h 13 9 8 11 12 13 15 7 10 11 13 22 23 5 13 ここまでで最小の出現頻度の値二つが分かった。通常のハフマンアルゴリズムではここでこの二値の和を取ってできた節をハフマン木の新しい内部節 = 親とするわけだが、それと同等のことを行う。 ヒープから要素を一つ取り出して空いた領域 A[7] があるので、そこに二値の和 A[m1] + A[m2] = 7 の値を入れる 14 2 10 m1 14 m2 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
14. 0. a 10 4. e 22 1. b 11 5. f 23 2. c 2 6. g 5 3. d 13 7. h 13 9 8 11 12 13 15 7 10 11 13 22 23 5 13 A[0] の値は既に m2 にコピーしてあり要らないので、そこから新しい要素をポイントする。 7 2 10 m1 14 m2 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15