哈夫曼编码
基本介绍:
- 广泛应用于数据文件压缩,压缩率在20%~90%之间。
- 是可变字长编码(VLC)的一种,也称为最佳编码。
原理剖析步骤:
- I like like like java do you like a java
- d:1 y:1 u:1 j:2 v:2 o:2 l:4 k:4 e:4 i:5 a:5 :9
- 按照上面的字符出现的次数构建一颗哈夫曼树,次数作为权值。
- 哈夫曼树构建过程步骤看上篇
- 根据哈夫曼树给各个字符固定编码(前缀编码),左0又1。
例如:o:1000 v:0001
注意:
这个赫夫曼树根据排序方法不同,也可能不太一样,这样对应的赫夫曼编码也不完全一样,但是wpl是一样的,都是最小的,最后生成的赫夫曼编码的长度是一样。
代码:
package huffmancode;
import java.lang.reflect.Array;
import java.util.*;
public class HuffmanCode {
public static void main(String[] args) {
String content = "i like like like java do you like a java";
byte[] contentBytes = content.getBytes();
System.out.println(contentBytes.length);
List<Node> nodes = getNodes(contentBytes);
System.out.println("nodes = "+ nodes);
//构建哈夫曼树
System.out.println("哈夫曼树");
Node huffmanTreeRoot = createHuffmanTree(nodes);
huffmanTreeRoot.preOrder();
}
//前序遍历
public static void preOrder(Node root){
if (root != null){
root.preOrder();
}else {
System.out.println("哈夫曼树为空!");
}
}
/**
*
* @param byte 接收字节数组
* @return List形式Node
*/
private static List<Node> getNodes(byte[] bytes){
//nodes数组接受byte[]对象
ArrayList<Node> nodes = new ArrayList<>();
//存储每一个byte出现的次数->map[key,value]
Map<Byte,Integer> counts = new HashMap<>();
for (byte b: bytes){
Integer count = counts.get(b);
if (count == null){
counts.put(b,1);
}else {
counts.put(b,++count);
}
}
//把每个键值对转换成Node对象,并加入nodes集合
for (Map.Entry<Byte,Integer> entry: counts.entrySet()){
nodes.add(new Node(entry.getKey(),entry.getValue()));
}
return nodes;
}
//通过List,创建对应的哈夫曼树
private static Node createHuffmanTree(List<Node> nodes){
while(nodes.size() > 1){
//排序,从小到大
Collections.sort(nodes);
//取出最小和次小的二叉树
Node leftNode = nodes.get(0);
Node rightNode = nodes.get(1);
//创建一颗新的二叉树,没有data,只有权值
Node parent = new Node(null, leftNode.weigh+ rightNode.weigh);
parent.left = leftNode;
parent.right = rightNode;
//移除已经处理的这两颗二叉树
nodes.remove(leftNode);
nodes.remove(rightNode);
//将新的二叉树加入
nodes.add(parent);
}
//返回nodes结点,是哈夫曼树的跟结点
return nodes.get(0);
}
}
//创建Node,数据 和权值
class Node implements Comparable<Node>{
Byte data; //存放数据(字符)本身。例如:‘a’ => 97
int weigh;
Node left;
Node right;
public Node(Byte data, int weigh) {
this.data = data;
this.weigh = weigh;
}
@Override
public int compareTo(Node o) {
//从小到大排序
return this.weigh - o.weigh;
}
@Override
public String toString() {
return "Node{" +
"data=" + data +
", weigh=" + weigh +
'}';
}
public void preOrder(){
System.out.println(this);
if (this.left != null){
this.left.preOrder();
}
if (this.right != null){
this.right.preOrder();
}
}
}