上一篇博文,提到了无前缀码满足克拉夫特不等式,为了使平均码长最小,我们可以用拉格朗日乘数法来验证,当Li=-logPi时达到极限,接近与H(x).由于是个整数优化问题,当时认为求最小解很困难。但是霍夫曼‘跳出盒子思考’,意思是他先没太在意克拉夫特不等式的限制,而是以另一种方式观察问题,给出了一种算法,也就是大家熟知的Huffman编码。
Huffman算法最初是在1950年,霍夫曼在麻省理工学院罗伯特.菲诺的信息论课堂上以学期论文的形式提出了这个算法。其实也就相当于我们现在的实验报告之类的东西(鄙人观点),但是就是课堂论文这样的作业,却能诞生这么有意义的想法,我想这也是我们值得学习和敬佩的地方。
霍夫曼算法核心:通过观察二叉树建立了最佳无前缀码所应具有的一些特性,他采用了简单的递归方法来实现最佳编码。递归的思想,在前面的博文中也有提到,也正是因为对递归算法感兴趣,萌生了采用简单数组方式来实现该算法。
递归算法中有一个基本思想:往前追溯。在信息论中我们很容易理解,当{p1,p2.....pn}(升序排列)这组符号的最优编码其实等价与缩减符号{p1+p2,p3,p4....pn}这组符号的编码。那么递归就可以起作用了:我们一直往前追溯到当符号个数为2时,我们就直接可以给出编码。然后在往已经编号的码树上添加 叶节点 即可。
同时,由于Huffman编码已经有各种各样优秀的实现方法,这篇文章是结合自己的探索,采用纯数组的方法来实现,也纯粹是为了加深自己对递归的理解。
import java.util.*; public class Huffman { public static void printStr(String a[],String b[]) { int i = 0; for(i=0;i<a.length&&a[i]!=null;i++) { System.out.println(b[i]+"----"+a[i]); } } /***********************************************/ /* tiao_zheng函数,目的是产生缩减符合序列,并且为了使编码后的方差最小 我们把 概率和 这个新符号 尽量放在高位。 */ public static String[] tiao_zheng(String a[]) { String b[] ; int i = 0; Double d = 0.0; b = Arrays.copyOfRange(a,2,a.length+2); d = Double.parseDouble(a[0]) + Double.parseDouble(a[1]); b[b.length-2] = Double.toString(d); Arrays.sort(b,0,b.length-1); for(i=b.length-2;i>=0;i--) { if(Double.parseDouble(b[i]) == d) break; } b[b.length-1] = Integer.toString(i); return b; } /*********************************************/ /* bian_ma函数的核心就是递归到n=2,然后回溯! */ public static void bian_ma(String a[]) { String b[]; int i = 0,j = 0; int num = 0; if(a.length == 2) { Arrays.sort(a,0,a.length-1); a[0] = "0"; a[1] = "1"; } else { b = tiao_zheng(a);//n-1阶 int t = Integer.parseInt(b[b.length-1]); b = Arrays.copyOfRange(b,0,b.length-1); bian_ma(b);//递归 //当我们把缩减符号编码完成后,就是一些 “修饰” 工作了 a[0] = b[t]+ "0";//添加 叶节点1 a[1] = b[t] + "1";//添加 叶节点2 //其它部分保持不变 int k = 2; for(j=0;j<b.length;j++) { if(j==t) continue; a[k] =b[j]; k++; } } } /**********************************************/ public static void main(String args[]) { String str[] = {"0.1","0.1","0.2","0.2","0.4"};//按升序输入 String str1[] = Arrays.copyOfRange(str,0,str.length); bian_ma(str); printStr(str,str1); } }