ハフマン符号
[Wikipedia|▼Menu]
.mw-parser-output .ambox{border:1px solid #a2a9b1;border-left:10px solid #36c;background-color:#fbfbfb;box-sizing:border-box}.mw-parser-output .ambox+link+.ambox,.mw-parser-output .ambox+link+style+.ambox,.mw-parser-output .ambox+link+link+.ambox,.mw-parser-output .ambox+.mw-empty-elt+link+.ambox,.mw-parser-output .ambox+.mw-empty-elt+link+style+.ambox,.mw-parser-output .ambox+.mw-empty-elt+link+link+.ambox{margin-top:-1px}html body.mediawiki .mw-parser-output .ambox.mbox-small-left{margin:4px 1em 4px 0;overflow:hidden;width:238px;border-collapse:collapse;font-size:88%;line-height:1.25em}.mw-parser-output .ambox-speedy{border-left:10px solid #b32424;background-color:#fee7e6}.mw-parser-output .ambox-delete{border-left:10px solid #b32424}.mw-parser-output .ambox-content{border-left:10px solid #f28500}.mw-parser-output .ambox-style{border-left:10px solid #fc3}.mw-parser-output .ambox-move{border-left:10px solid #9932cc}.mw-parser-output .ambox-protection{border-left:10px solid #a2a9b1}.mw-parser-output .ambox .mbox-text{border:none;padding:0.25em 0.5em;width:100%;font-size:90%}.mw-parser-output .ambox .mbox-image{border:none;padding:2px 0 2px 0.5em;text-align:center}.mw-parser-output .ambox .mbox-imageright{border:none;padding:2px 0.5em 2px 0;text-align:center}.mw-parser-output .ambox .mbox-empty-cell{border:none;padding:0;width:1px}.mw-parser-output .ambox .mbox-image-div{width:52px}html.client-js body.skin-minerva .mw-parser-output .mbox-text-span{margin-left:23px!important}@media(min-width:720px){.mw-parser-output .ambox{margin:0 10%}}

この記事は検証可能参考文献や出典が全く示されていないか、不十分です。出典を追加して記事の信頼性向上にご協力ください。(このテンプレートの使い方
出典検索?: "ハフマン符号" ? ニュース ・ 書籍 ・ スカラー ・ CiNii ・ J-STAGE ・ NDL ・ dlib.jp ・ ジャパンサーチ ・ TWL(2011年9月)

ハフマン符号(ハフマンふごう、: Huffman coding)とは、1952年にデビッド・ハフマンによって開発された符号で、文字列をはじめとするデータの可逆圧縮などに使用される[1][2]

ほかのエントロピー符号と同様、よく出現する文字には短いビット列を、あまり出現しない文字には長いビット列を割り当てることで、メッセージ全体の符号化に使われるデータ量を削減することを狙っている。

コンパクト符号エントロピー符号の一つ。JPEGZIP (Deflate) などの圧縮フォーマットで使用されている。

シャノン符号化が最適ではない場合が存在する不完全な符号であったのに対し、ハフマン符号は(整数の符号語長という制約のもとでは、)常に最適な符号を構成できる。擬似的に実数の符号語長を割り振る算術符号と比較すれば、データ圧縮効率は劣る。ただし、算術符号やその他の高効率の符号化法と異なり、特許の問題が無い。
種類

符号化の原理上、木を構成する前に各記号の出現頻度をあらかじめ知っておく必要がある。

ファイルなど固定長のデータに対し、1度全部読み込んで、データのすべての記号を調べて符号木を構築しておき、もう1度頭から読み直して符号化を行う方法が、静的ハフマン符号 (Static Huffman coding) である。

deflateでは、データの全部ではなく、ブロック毎に符号を作っている。これをdeflateではダイナミックハフマン符号(英: Dynamic Huffman coding)と呼んでいる。

一方、最初の状態では頻度情報を持たず、記号を1個読み込むごとに符号木を作り直す方法は適応型ハフマン符号 (Adaptive Huffman coding) である。これを指して日本では動的ハフマン符号と呼ぶことが多い。
符号化の原理

例として DAEBCBACBBBC という12文字からなるメッセージを考える。

このメッセージ中には5種類の文字が使われているので、もしそれぞれの文字を固定長のビット列で表すとすれば、1文字につき最低3ビット必要となる。

文字とビット列の対応表として、 A B C D E 000 001 010 011 100

を使い、それぞれの文字をビット列に置き換えたとすると、メッセージ全体は次のビット列で表される。 D A E B C B A C B B B C 011 000 100 001 010 001 000 010 001 001 001 010

12文字 x 3ビットで全体のビット数は36ビットとなる。

もし、よく出現する文字には短いビット列を、あまり出現しない文字には長いビット列を割り当てることができれば、メッセージ全体の符号化に必要なビット数を抑えることが期待できる。そこで、文字とビット列の対応表として、 A B C D E 110 0 10 1110 1111

を使ったとすると、メッセージ全体は D A E B C B A C B B B C 1110 110 1111 0 10 0 110 10 0 0 0 10

となり、全体のビット数は25ビットとなる。固定長の方式に比べると 70% ほどのデータ量に抑えられている。
ハフマン符号の構成

文字とビット列の対応表を作るには、まずデータに出現する文字の出現回数を求め、それをもとにハフマン木と呼ばれるバイナリツリーを構成するという手順を踏む。

ハフマン木の構成の仕方は、次のようなアルゴリズムになる。
まず、葉を含むすべての節点のうち、親を持たないものを集める。

その中から、最小の値を持つものと2番目に小さい値を持つものを取り出す。

それらを子供に持つ新しい節点を作る。このとき、新しい節点の値は、両方の子供の値の和とする。

以上を根節点に到達するまで繰り返すと、木が完成する。次に、根から順に左右に0と1の値を割り振っていく(左右のどちらに0と1を与えるかは任意)。すると、それぞれの葉(記号)に対して、一意にビット列が与えられる。この記号とビット列の関係をもとに、もとのデータの記号をビット列に変換していくことで符号化が行われる。
ハフマン木

入力 DAEBCBACBBBC に対して上記のアルゴリズムを適用すると、

出現頻度と割り当てられた符号

文字個数符号
B50
C310
A2110
D11110
E11111

が得られ、個数の多い文字ほど短い符号が割り当てられていることがわかる。
接頭符号

ハフマン符号は、接頭符号である。つまり、ある文字に対応するビット列が、他の文字に対応するビット列の接頭辞になることはない。この特徴のおかげで、デコーダはビット列を先頭から一度読むだけで元のメッセージを一意にデコードできる。
利用例

算術符号やその他の高効率の符号化法と異なり、特許の問題が無い。 そのため、JPEGZIPなどの圧縮フォーマットで使用されている。
実装

Groovyで実装を説明する。まず、符号情報とハフマン木のクラスを作る。class CodeInfo { int code, codeSize }class TreeNode implements Comparable<TreeNode> { byte value; int occurrence; List<TreeNode> children; int compareTo(TreeNode that) { this.occurrence - that.occurrence }}

すると、バイト値→符号情報のテーブルは以下のようにして作れる。CodeInfo[] createValue2Code(byte[] data) { // 各バイト値の発生回数を数える TreeNode[] nodes = new TreeNode[256] for (int i in 0..<256) { nodes[i] = new TreeNode(value: i) } for (byte v in data) { nodes[v].occurrence++ } // ハフマン木を作成 PriorityQueue<TreeNode> queue = new PriorityQueue<TreeNode>(nodes as List) while (queue.size() > 1) { TreeNode n1 = queue.poll(), n2 = queue.poll() queue << new TreeNode(occurrence: n1.occurrence + n2.occurrence, children: [n1, n2]) } TreeNode root = queue.poll() // 深さ優先探索でバイト値→符号情報を作成 CodeInfo[] value2code = new CodeInfo[256] dfs(value2code, root, 0, 0) return value2code}void dfs(CodeInfo[] value2code, TreeNode node, int code, int codeSize) { if (node.children == null) { value2code[node.value] = new CodeInfo(code: code, codeSize: codeSize) } else { dfs(value2code, node.children[0], code << 1, codeSize + 1) dfs(value2code, node.children[1], (code << 1) + 1, codeSize + 1) }}

圧縮のために以下のようなビットストリームのクラスを作る。class BitStream { BitSet bs = new BitSet(); int len = 0, pos = 0; void write(int v, int bits) { for (int i in 0..<bits) { bs[len++] = ((v >>> i) & 1) != 0 } } int read(int bits) { int v = 0; for (int i in 0..<bits) { if (bs[pos++]) { v |= 1 << i } } return v } String toString() { "length = $len, {" + (0..<len).findAll({ bs[it] }).join(", ") + "}" }}

すると、バイト値→符号情報のテーブルを使い以下のようにして圧縮できる。void compress(BitStream bs, byte[] data, CodeInfo[] value2code) { for (byte v in data) { CodeInfo codeInfo = value2code[v] bs.write(codeInfo.code, codeInfo.codeSize) }}
脚注^ David A. Huffman, " ⇒A method for the construction of minimum-redundancy codes" (PDF), Proceedings of the I.R.E., Sept. 1952, pp. 1098-1102 (ハフマンのオリジナル論文)
^ 『誰が音楽をタダにした?』早川書房、2016、22頁。 

関連項目

シャノン符号化

接頭符号

算術符号
.mw-parser-output .asbox{position:relative;overflow:hidden}.mw-parser-output .asbox table{background:transparent}.mw-parser-output .asbox p{margin:0}.mw-parser-output .asbox p+p{margin-top:0.25em}.mw-parser-output .asbox{font-size:90%}.mw-parser-output .asbox-note{font-size:90%}.mw-parser-output .asbox .navbar{position:absolute;top:-0.90em;right:1em;display:none}

この項目は、コンピュータに関連した書きかけの項目です。この項目を加筆・訂正などしてくださる協力者を求めていますPJ:コンピュータ/P:コンピュータ)。
.mw-parser-output .hlist ul,.mw-parser-output .hlist ol{padding-left:0}.mw-parser-output .hlist li,.mw-parser-output .hlist dd,.mw-parser-output .hlist dt{margin-right:0;display:inline-block;white-space:nowrap}.mw-parser-output .hlist dt:after,.mw-parser-output .hlist dd:after,.mw-parser-output .hlist li:after{white-space:normal}.mw-parser-output .hlist li:after,.mw-parser-output .hlist dd:after{content:" ・ ";font-weight:bold}.mw-parser-output .hlist dt:after{content:": "}.mw-parser-output .hlist-pipe dd:after,.mw-parser-output .hlist-pipe li:after{content:" 。";font-weight:normal}.mw-parser-output .hlist-hyphen dd:after,.mw-parser-output .hlist-hyphen li:after{content:" - ";font-weight:normal}.mw-parser-output .hlist-comma dd:after,.mw-parser-output .hlist-comma li:after{content:"、 ";font-weight:normal}.mw-parser-output .hlist-slash dd:after,.mw-parser-output .hlist-slash li:after{content:" / ";font-weight:normal}.mw-parser-output .hlist dd:last-child:after,.mw-parser-output .hlist dt:last-child:after,.mw-parser-output .hlist li:last-child:after{content:none}.mw-parser-output .hlist dd dd:first-child:before,.mw-parser-output .hlist dd dt:first-child:before,.mw-parser-output .hlist dd li:first-child:before,.mw-parser-output .hlist dt dd:first-child:before,.mw-parser-output .hlist dt dt:first-child:before,.mw-parser-output .hlist dt li:first-child:before,.mw-parser-output .hlist li dd:first-child:before,.mw-parser-output .hlist li dt:first-child:before,.mw-parser-output .hlist li li:first-child:before{content:" (";font-weight:normal}.mw-parser-output .hlist dd dd:last-child:after,.mw-parser-output .hlist dd dt:last-child:after,.mw-parser-output .hlist dd li:last-child:after,.mw-parser-output .hlist dt dd:last-child:after,.mw-parser-output .hlist dt dt:last-child:after,.mw-parser-output .hlist dt li:last-child:after,.mw-parser-output .hlist li dd:last-child:after,.mw-parser-output .hlist li dt:last-child:after,.mw-parser-output .hlist li li:last-child:after{content:") ";font-weight:normal}.mw-parser-output .hlist ol{counter-reset:listitem}.mw-parser-output .hlist ol>li{counter-increment:listitem}.mw-parser-output .hlist ol>li:before{content:" "counter(listitem)" ";white-space:nowrap}.mw-parser-output .hlist dd ol>li:first-child:before,.mw-parser-output .hlist dt ol>li:first-child:before,.mw-parser-output .hlist li ol>li:first-child:before{content:" ("counter(listitem)" "}.mw-parser-output .navbar{display:inline;font-size:75%;font-weight:normal}.mw-parser-output .navbar-collapse{float:left;text-align:left}.mw-parser-output .navbar-boxtext{word-spacing:0}.mw-parser-output .navbar ul{display:inline-block;white-space:nowrap;line-height:inherit}.mw-parser-output .navbar-brackets::before{margin-right:-0.125em;content:"[ "}.mw-parser-output .navbar-brackets::after{margin-left:-0.125em;content:" ]"}.mw-parser-output .navbar li{word-spacing:-0.125em}.mw-parser-output .navbar-mini abbr{font-variant:small-caps;border-bottom:none;text-decoration:none;cursor:inherit}.mw-parser-output .navbar-ct-full{font-size:114%;margin:0 7em}.mw-parser-output .navbar-ct-mini{font-size:114%;margin:0 4em}.mw-parser-output .infobox .navbar{font-size:88%}.mw-parser-output .navbox .navbar{display:block;font-size:88%}.mw-parser-output .navbox-title .navbar{float:left;text-align:left;margin-right:0.5em}


次ページ
記事の検索
おまかせリスト
▼オプションを表示
ブックマーク登録
mixiチェック!
Twitterに投稿
オプション/リンク一覧
話題のニュース
列車運行情報
暇つぶしWikipedia

Size:24 KB
出典: フリー百科事典『ウィキペディア(Wikipedia)
担当:undef