这篇博客主要讲解如何用java实现哈夫曼编码(Huffman)。
概念
首先,我来简单说一下哈夫曼编码(Huffman),它主要是数据编码的一种方式,也是数据压缩的一种方法,将某些特定的字符转化为二进制字符,并在转换过程中降低原有字符串的存储量。其具体方法是先按出现的概率大小排队,把两个最小的概率相加,作为新的概率 和剩余的概率重新排队,再把最小的两个概率相加,再重新排队,直到最后变成1。每次相 加时都将“0”和“1”赋与相加的两个概率,读出时由该符号开始一直走到最后的“1”, 将路线上所遇到的“0”和“1”按最低位到最高位的顺序排好,就是该符号的哈夫曼编码。
java实现
方法一:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import static java.lang.System.out;
/* 设某信源有5种符号x={A1,A2,A3,A4,A5}。在数据中出现的概率p={0.25,0.22,0.20,0.18,0.15},试给出Huffman编码方案,写出每个符号对应的Huffman编码。*/
/* 答案1:A1:10 A2:01 A3:00 A4:111 A5:110
答案2:A1:01 A2:10 A3:11 A4:000 A5:001*/
/**
* 哈夫曼树构造类:
*/
public class OtherPersonMethodHuffman {
public static void main(String[] args) {
List<Node> nodes = Arrays.asList(
new Node(0.25d),
new Node(0.22d),
new Node(0.20d),
new Node(0.18d),
new Node(0.15d)
);
Node node = OtherPersonMethodHuffman.build(nodes);
PrintTree(node);
}
/**
* 构造哈夫曼树
* @param nodes 结点集合
* @return 构造出来的树的根结点
*/
private static Node build(List<Node> nodes) {
nodes = new ArrayList<Node>(nodes);
sortList(nodes);
while (nodes.size() > 1) {
createAndReplace(nodes);
}
return nodes.get(0);
}
/**
* 组合两个权值最小结点,并在结点列表中用它们的父结点替换它们
* @param nodes 结点集合
*/
private static void createAndReplace(List<Node> nodes) {
Node left = nodes.get(0);
Node right = nodes.get(1);
Node parent = new Node(left.getValue() + right.getValue());
parent.setLeftChild(left);
parent.setRightChild(right);
nodes.remove(0);
nodes.remove(0);
nodes.add(parent);
sortList(nodes);
}
/**
* 将结点集合由大到小排序
*/
private static void sortList(List<Node> nodes) {
Collections.sort(nodes);
}
/**
* 打印树结构,显示的格式是node(left,right)
* @param node
*/
static String[] strs = {"1","1","1","1","1"};
public static void PrintTree(Node node) {
Node left = null;
Node right = null;
double[] probDoubles={0.25d,0.22d,0.20d,0.18d,0.15d};
if(node!=null) {
out.print(node.getValue());
left = node.getLeftChild();
right = node.getRightChild();
out.println("("+(left!=null?left.getValue():" ") +","+ (right!= null?right.getValue():" ")+")");
if(left!=null){
for(int i=0;i<strs.length;i++){
strs[i]+="0";
}
}
if(right!=null){
for(int i=0;i<strs.length;i++){
strs[i]+="1";
}
}
}
if(left!=null){ PrintTree(left); }
if(right!=null){ PrintTree(right); }
if(left==null&right==null){
out.println(node.getValue());
for(int i=0;i<probDoubles.length;i++){
if(probDoubles[i]==node.getValue()){
out.println(strs[i]);
}
}
}
}
}
/**
* 二叉树节点
*/
class Node implements Comparable {
private double value;
private Node leftChild;
private Node rightChild;
public Node(double value) {
this.value = value;
}
public double getValue() {
return value;
}
public void setValue(double value) {
this.value = value;
}
public Node getLeftChild() {
return leftChild;
}
public void setLeftChild(Node leftChild) {
this.leftChild = leftChild;
}
public Node getRightChild() {
return rightChild;
}
public void setRightChild(Node rightChild) {
this.rightChild = rightChild;
}
@Override
public int compareTo(Object o) {
Node that = (Node) o;
double result = this.value - that.value;
return result > 0 ? 1 : result == 0 ? 0 : -1;
}
}