上一篇博文,提到了无前缀码满足克拉夫特不等式,为了使平均码长最小,我们可以用拉格朗日乘数法来验证,当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);
}
}