哈夫曼编码的实现
对教材P167中习题5.18,编码实现哈夫曼编码树,并对“Chapter Graphs surveys the most important graph processing problems including depth-first search breadth first search minimum spanning trees and shortest paths ”语句使用构造的哈夫曼编码进行压缩(不区分大小写),对压缩后的数据进行解压缩。
构建节点类
public class BTNode {
private char key;
private BTNode left, right;
private int weight;
public BTNode(char key,int weight) {
this(key,weight,null, null);
}
public BTNode(char key,int weight, BTNode left, BTNode right) {
this.key = key;
this.weight=weight;
this.left = left;
this.right = right;
}
public char getKey() {
return key;
}
public void setKey(char key) {
this.key = key;
}
public int getWeight(){
return weight;
}
public void setWeight(int weight){
this.weight=weight;
}
public BTNode getLeft() {
return left;
}
public void setLeft(BTNode left) {
this.left = left;
}
public BTNode getRight() {
return right;
}
public void setRight(BTNode right) {
this.right = right;
}
}
构建哈夫曼树,进行哈夫曼编码
public class BinTree {
protected BTNode root;
public static int lif=0,rig=0;
public static long hfbm[][]=new long[27][12]; //用于存放字母对应的哈夫曼编码
public static char af[]=new char[27]; //存放前序遍历哈夫曼树的顺序字母,af[i]与hfbm[i][]对应
public BinTree(BTNode root) {
this.root = root;
}
public BTNode getRoot() {
return root;
}
/** 构造树 */
public static void init() {
int wt[]={183,102,77,68,59,58,55,51,49,48,35,34,26,
24,21,19,18,17,16,16,13,9,6,2,2,1,1}; //字母对应的频率转化为整数权值
int w[]=new int[53]; //定义数组w[]存放节点的权值
for(int i=0;i<w.length;i++)
w[i]=10000; //初始化w[]
for(int j=0;j<wt.length;j++)
w[j]=wt[j];
char s[]={' ','e','t','a','o','i','n','s','h','r','d','l','c',
'u','m','w','f','g','y','p','b','v','k','j','x','q','z'};
BTNode hf[]=new BTNode[53]; //建立53个节点用于构造哈夫曼树
BTNode root=new BTNode('T',0); //初始化根节点
for(int j=0;j<hf.length;j++){
hf[j]=new BTNode('*',0); //初始化所有节点,节点字符为“*”,权值为0,左右子树为空
}
for(int i=0;i<27;i++){ //将27个字符放入对应的节点中,并赋予权值
hf[i].setKey(s[i]);
hf[i].setWeight(wt[i]);
}
// 构造哈夫曼树
int i1=0,i2=0,lin=0;
for(int k=27;k<53;k++){
i1=select(w); //搜索w[]中最小的值,并将对应的序号值赋予i1
lin=w[i1];
w[i1]=10000; //w[]中的i1的值,使之退出下一次搜索
hf[k].setLeft(hf[i1]);
i2=select(w); //搜索w[]中最小的值,并将对应的序号值赋予i2
lin=lin+w[i2];
hf[k].setRight(hf[i2]);
hf[k].setWeight(lin); //将i1,i2的权值之和存入hf[i1],hf[i2]的父节点中
w[i2]=10000;
w[k]=lin; //w[]中的i2的值,使之退出下一次搜索,将k的值加入下一次搜索
i1=0;i2=0;lin=0; //临时数据清零
root=hf[k];
}
preorder(root,10); //前序遍历哈夫曼树
}
public static void main(String args[]){
String s="chapter graphs surveys the most "
+"important graph processing problems"
+"including depth-first search breadth "
+"first search minimum spanning trees and shortest paths";
try{
for(int i=0;i<27;i++){
af[i]=' ';
for(int j=0;j<12;j++)
hfbm[i][j]=2;
} //初始化 af[],hfbm[][]
init();
for(int i=0;i<27;i++){
System.out.print(" "+af[i]+": ");
for(int j=0;j<12;j++)
if(hfbm[i][j]!=2)
System.out.print(hfbm[i][j]);
if((i+1)%3==0)
System.out.println();
} //输出字母与对应的哈夫曼编码
changehf(s);
}catch(Exception e){
e.printStackTrace();
}
}
public static void changehf(String s){
char cs[]=s.toCharArray();
System.out.println("该字符串转化为零一代码的结果是:");
for(int i=0;i<cs.length;i++){
for(int j=0;j<af.length;j++)
if(cs[i]==af[j]){ //在af[]寻找与cs[i]相同的字母
for(int n=0;n<12;n++)
if(hfbm[j][n]!=2)//将对应的哈夫曼编码输出
System.out.print(hfbm[j][n]);
}
if((i+1)%10==0) //每输出9个字母的
System.out.println();
}
}
//搜索w[]中最小的值,并将对应的序号返回
public static int select(int w[]){
int ts=w[0],i1=0;
for(int i=1;i<w.length;i++){
if(ts>w[i]){
ts=w[i];
i1=i;
}
}
return i1;
}
/** 访问节点 */
public static void visit(BTNode p,long q) {
if(p.getKey()=='*') //对
System.out.print("");
else{
long temp=0; int b=11;
while(q>=100){ //计算字母的哈夫曼编码 并去除前缀10
temp=q%10;
q=q/10;
hfbm[lif][b]=temp;
b=b-1;
}
af[lif]=p.getKey();//将节点的字母存入与hfbm[lif][]对应的字符数组af[lif]中
lif=lif+1;
}
}
/** 递归实现前序遍历 */
protected static void preorder(BTNode p,long q) {
if (p != null) {
visit(p,q);
preorder(p.getLeft(),q*10+1); //访问左子树 q后面增加一个1
preorder(p.getRight(),q*10); //访问左子树 q后面增加一个0
}
}
}
运行结果图