#!/usr/bin/perl -w # 演算法: Huffman Encoding # 作者: 洪朝貴 http://www.cyut.edu.tw/~ckhung # 授權: public domain (但如果您要將我的程式改寫成有用的大程式, # 強烈建議將您的版本施以 GPL) use strict; use Heap; sub huffman { my ($text) = @_; my (%freq, $out, $hp); map { ++$freq{$_} } split //, $text; foreach (sort keys %freq) { $out->[0] .= " $_"; $out->[1] .= sprintf " %2d", $freq{$_}; } printf "$out->[0] tot\n$out->[1] %3d\n", length($text); $hp = Heap->new([map {"$_:$freq{$_}"} keys %freq], -compare=>sub { my ($a, $b); (undef, $a) = split ":", $_[0]; (undef, $b) = split ":", $_[1]; return $a <=> $b; } ); my ($n, $i, $codebook, $root); $n = $hp->size(); print "init: $hp\n"; for ($i=1; $i<$n; ++$i) { my ($a, $a_freq, $b, $b_freq, $c, $c_freq); ($a, $a_freq) = split ":", $hp->remove(); ($b, $b_freq) = split ":", $hp->remove(); $c = "*$i"; $c_freq = $a_freq + $b_freq; $hp->insert("$c:$c_freq"); $codebook->{$c} = { left=>$a, right=>$b }; printf "%-9s $hp\n", "[$a $b]"; } ($root, undef) = split ":", $hp->remove(); print_code_tree($root, 0, "", $codebook); $n = join '', map { $codebook->{$_}{code} } split //, $text; printf "$n\ntotal %d bits\n", length($n); } sub print_code_tree { my ($c, $level, $code, $codebook) = @_; print " " x $level, substr($code, -1); if (length $c == 1) { print " $c\n"; $codebook->{$c}{code} = $code; } else { print "\n"; print_code_tree($codebook->{$c}{left}, $level+1, "${code}0", $codebook); print_code_tree($codebook->{$c}{right}, $level+1, "${code}1", $codebook); } } my ($text) = defined $ARGV[0] ? $ARGV[0] : "a simple string to be encoded using a minimal number of bits"; $text =~ s/ /_/g; print "$text\n"; huffman($text);