データ量を操る圧縮/展開を究めよう:コーディングに役立つ! アルゴリズムの基本(8)(4/5 ページ)
プログラマたるものアルゴリズムとデータ構造は知っていて当然の知識です。しかし、教科書的な知識しか知らなくて、実践的なプログラミングに役立てることができるでしょうか(編集部)
ハフマン符号の実装―1
それでは実装していきましょう。長くなるのでいくつかに分割しながら解説します。
先ほどのコードの29行目、「末尾2」のコメントの下の行に以下のコードを追加してください。
<script type="text/javascript">
Array.prototype.clone = function(){
return this.slice(0);
}
function HuffmanTree(data, is_compressed_data) {
if (is_compressed_data) {
this.setCompressedData(data);
} else {
this.data = data;
var char_counter = this.getCharCounter();
this.setHeaderData(char_counter);
this.setTreeData();
}
}
HuffmanTree.prototype.getCharCounter = function() {
var char_counter = new Array();
for (var i = 0; i < this.data.length; i++) {
var ch_num = this.data.charCodeAt(i);
if (char_counter[ch_num] == undefined) {
char_counter[ch_num] = 0;
}
char_counter[ch_num]++;
}
return char_counter;
}
<!-- 末尾3 -->
コードを解説していきます。
2〜4行目
汎用メソッドです。配列のコピーを行うメソッドです。
6〜15行目
ハフマン符号の木構造を表すクラスです。圧縮機能も持ちます。コンストラクタに渡されたデータが圧縮していないものであれば圧縮し、圧縮したものであれば復元します。
8行目
圧縮されたデータを受け取った場合は復元します。
11行目
文字ごとの出現回数をカウントした表を作ります。データ構造は文字コードをキーとする配列になっています。
12行目
出現回数の表を、文字コード(ch_num)と出現回数(count)の組み合わせのデータに変換し、ヘッダデータとして保持します。
13行目
木構造を作成します。
17〜28行目
文字ごとの出現回数をカウントするメソッドです。
ハフマン符号の実装―2
引き続き実装していきます。次のコードは上のコードの続きです。29行目「末尾3」の下に続きます。
HuffmanTree.prototype.setHeaderData = function(char_counter) {
this.header_data = new Array();
for (var ch_num = 0; ch_num < char_counter.length; ch_num++) {
if (char_counter[ch_num] === undefined) { continue; }
var ch_count_data = { count:char_counter[ch_num], ch_num:ch_num };
this.header_data.push(ch_count_data);
}
}
Array.prototype.insert_count = function(value) {
for (var i = this.length-1; 0 <= i; i--) {
if (value.count < this[i].count) { break; }
this[i+1] = this[i];
}
this[i+1] = value;
}
HuffmanTree.prototype.setTreeData = function() {
var sort_data = this.header_data.clone();
sort_data.sort(function(a,b) { return b.count - a.count; });
while(true) {
var min1 = sort_data.pop();
var min2 = sort_data.pop();
if(min2 === undefined) {
this.tree_data = min1;
break;
}
var count = min1.count + min2.count;
var node = { count: count, left: min1, right: min2 };
sort_data.insert_count(node);
}
}
<!-- 末尾4 -->
1〜9行目
getCharCounter()で、作られたデータは文字コードをキーとする配列になっています。
char_counter[文字コード] =出現回数
これを文字コードと出現回数を持つオブジェクトに変換します。後で木構造を作るときに使うためです。
11〜17行目
出現回数の配列にオブジェクトを追加するメソッドです。出現回数が多い順にソートされている状態のときに、多い順が保たれるように追加します。
19〜35行目
木構造を作成します。
20、21行目
ヘッダデータをコピーしてソートします。多い順にソートします。
23行目
ループを開始します。
24、25行目
配列からデータを取り出します。popは末尾からデータを取得して配列から削除するので、min1には一番出現回数が少ないもの、min2にはその次に出現回数が少ないものが入ります。
26〜29行目
ループの終わりですが、後で解説します。
31、32行目
出現回数を足して、木構造のノードを作成します。ノードは左側(left)が出現回数が少なく、右側(right)が出現回数が多いものになります。
33行目
sort_dataにノードを追加します。
setTreeDataのループでは、配列からデータを取得してノードを作成し、それを元の配列に入れていきます。そのため、ループ2週目以降は配列の中に文字のデータと木構造の両方が入り、徐々に木構造に追加されていく形になっています。
最終的には、木構造が1つだけ入った形になります。こうなったら木構造をインスタンス変数として保持し、ループを終了します。
Copyright © ITmedia, Inc. All Rights Reserved.

