Huffman的应用背景:
在信息的编码中,由于信息表示使用的每个字母的使用频率不一样,若是每个字母都使用相同长度的编码,对于那些用的不多的字符,但是占据空间又较大的字符,就会造成很大的空间浪费,由此,想出了一种新的编码方式,根据字符的使用频率,平率较大的使用较短的编码,反之,使用较大的编码,但是,就又会出现一种新的问题,若是有的字符的编码是另外一个字符的前缀怎么办?例如a的编码是“001”,而b的编码是“0010”,对于这种情况,计算机怎么能辨别是a还是b呢,就此,就提出了Huffman编码。
Huffman的实现:
Huffman编码基于贪心思想,每次挑选权值最小的两个值进行组合成新的权值,参与下一轮的挑选,一次一次自底向上形成一棵树,根据占据树的左右填写对应的Huffman编码
为了方便实现每次选择最小值,自己定义了一个排序算法,实现了Comparable接口
public class MyPoint implements Comparable<MyPoint> {
private int freq ;
private String tag;
public int getFreq() {
return freq;
}
public void setFreq(int freq) {
this.freq = freq;
}
public String getTag() {
return tag;
}
public void setTag(String tag) {
this.tag = tag;
}
public int compareTo(MyPoint o) {
if(freq>o.freq){
return 1;
}
else if (freq<o.freq) {
return -1;
}
return 0;
}
}
Huffman测试程序:
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Huffman {
public static void main(String []args){
//每个节点的权值(频率)
int freq[] = new int[]{16,9,5,13,12,45};
//每个节点的标记
String tg[] = {"A","B","C","D","E","F"};
List<MyPoint> points =new ArrayList<MyPoint>();
//初始化每个节点,使其加在list中
for(int i=0;i<tg.length;i++){
MyPoint point = new MyPoint();
point.setFreq(freq[i]);
point.setTag(tg[i]);
points.add(point);
}
Collections.sort(points);
huffman(points);
}
public static void huffman(List<MyPoint> points){
//存放每个节点的Huffman编码
Map<String,String> map = new HashMap<String, String>();
map.put("A", "");
map.put("B", "");
map.put("C", "");
map.put("D", "");
map.put("E", "");
map.put("F", "");
int newfreq = 0;
String newtag = "";
while(points.size()>1){
MyPoint newpoint = new MyPoint();
int minfreq = points.get(0).getFreq();
for(char c : points.get(0).getTag().toCharArray()){
if(map.containsKey(c+"")){
String value =map.get(c+"");
map.put(c+"", "0"+value);
}
}
int minfreq2 = points.get(1).getFreq();
for(char c : points.get(1).getTag().toCharArray()){
if(map.containsKey(c+"")){
String value =map.get(c+"");
map.put(c+"", "1"+value);
}
}
System.out.println(points.get(0).getTag()+"和"+points.get(1).getTag()+"合并成"+points.get(0).getTag()+points.get(1).getTag());
newfreq = minfreq + minfreq2;
newtag = points.get(0).getTag()+points.get(1).getTag();
newpoint.setFreq(newfreq);
newpoint.setTag(newtag);
//移除后第二个就变成第一个
points.remove(0);
points.remove(0);
points.add(newpoint);
//重新进行排序,保证每次循环时使得List中第一和第二个的权值都是最小的
Collections.sort(points);
}
for(Map.Entry<String, String>entry:map.entrySet()){
System.out.println(entry.getKey()+"--->"+entry.getValue());
}
}
}
运行结果:
C和B合并成CB
E和D合并成ED
CB和A合并成CBA
ED和CBA合并成EDCBA
F和EDCBA合并成FEDCBA
A--->111
B--->1101
C--->1100
D--->101
E--->100
F--->0