利用赫夫曼编码
`package mzy.tree_c;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class HuffmanCode {
public static void main(String[] args) {
String context = “the sky is so beautiful”;
byte[] conArr = context.getBytes();
System.out.println(Arrays.toString(huffmanZip(conArr)));
}
private static byte[] huffmanZip(byte[] conArr) {
List<Node> nodes = getNodes(conArr);
// System.out.println("node:" + nodes);
// 测试一把
System.out.println("赫夫曼树");
Node huffmanNodeTreeRoot = createHuffmanTree(nodes);
// System.out.println("前序遍历" + huffmanNodeTreeRoot);
// huffmanNodeTreeRoot.preOrder();
getCodes(huffmanNodeTreeRoot);
System.out.println(huffmanCode);
byte[] zip = zip(conArr, huffmanCode);
return zip;
}
/**
* 编写一个方法,将字符串对应的byte[]数组,通过生成的赫夫曼编码表
*
* @param bytes 这是原始的字符对应的byte[]
* @param humanCodes 生成的赫夫曼编码map
* @return 返回赫夫曼编码处理后的byte[]
*/
private static byte[] zip(byte[] bytes, Map<Byte, String> humanCodes) {
StringBuilder sumBuilder = new StringBuilder();
for (byte b : bytes) {
sumBuilder.append(huffmanCode.get(b));
}
System.out.println(sumBuilder.toString());
int index = 0;
int len;
if (sumBuilder.length() % 8 == 0) {
len = sumBuilder.length() / 8;
} else {
len = sumBuilder.length() / 8 + 1;
}
// 创建数组
byte[] huffmanCodeByte = new byte[len];
for (int i = 0; i < sumBuilder.length(); i += 8) {// 步长为8
String tempByte;
if (i + 8 < sumBuilder.length()) {
tempByte = sumBuilder.substring(i, i + 8);
} else {
tempByte = sumBuilder.substring(i);
}
// 将tempByte转成一个byte,放入到huffmanCodeBytes
huffmanCodeByte[index] = (byte) Integer.parseInt(tempByte);
index++;
}
return huffmanCodeByte;
}
/*
* 生成赫夫曼树对应的赫夫曼编码 思路 a:将赫夫曼编码存放在Map<Byte,String>形式 32->01
* b:在生成赫夫曼树编码表示,需要去拼接路径,定义一个StringBuilder,存储某个叶子节点的路径
*/
public static Map<Byte, String> huffmanCode = new HashMap<Byte, String>();
public static StringBuilder builder = new StringBuilder();
// 为了调用方便,冲在一下
public static void getCodes(Node node) {
getcodes(node, "", builder);
}
/**
* 将传入的Node节点的叶子节点赫夫曼编码得到并放入到哈夫曼集合中
* @param node 节点,根节点
* @param code 代表路径 左0右1;
* @param builder 用于拼接路径
*/
private static void getcodes(Node node, String code, StringBuilder builder) {
StringBuilder stringBuilder2 = new StringBuilder(builder);
stringBuilder2.append(code);
if (node != null) {
if (node.date == null) {// 非叶子节点
// 递归处理,向左递归
getcodes(node.left, "0", stringBuilder2);
// 向右递归
getcodes(node.right, "1", stringBuilder2);
} else {
huffmanCode.put(node.date, stringBuilder2.toString());
}
}
}
// 通过List,创建赫夫曼树
public static Node createHuffmanTree(List<Node> nodes) {
while (nodes.size() > 1) {
// 排序
Collections.sort(nodes);
// 取出第一颗最小的二叉树
Node liftNode = nodes.get(0);
// 取出第二颗最小的二叉树
Node rightNode = nodes.get(1);
// 创建新的一个二叉树
Node newTree = new Node(null, liftNode.weight + rightNode.weight);
newTree.left = liftNode;
newTree.right = rightNode;
// 删除这两个二叉树
nodes.remove(rightNode);
nodes.remove(liftNode);
nodes.add(newTree);
}
return nodes.get(0);
}
// 前序遍历
public static void preOrder(Node rootNode) {
if (rootNode != null) {
rootNode.preOrder();
} else {
System.out.println("赫夫曼树为空!");
}
}
// 获取List
public static List<Node> getNodes(byte[] bytes) {
// 创建Array
List<Node> nodes = new ArrayList<Node>();
// 遍历bytes,统计每一个byte出现的次数 map<key,value>
Map<Byte, Integer> counts = new HashMap<Byte, Integer>();
for (byte b : bytes) {
Integer count = counts.get(b);
if (count == null) {
counts.put(b, 1);
} else {
counts.put(b, count + 1);
}
}
// 把每一个键值对转成一个Node对象,并加入nodes集合
// 遍历
for (Map.Entry<Byte, Integer> entry : counts.entrySet()) {
nodes.add(new Node(entry.getKey(), entry.getValue()));
}
return nodes;
}
}
// 创建节点,数据和权值
class Node implements Comparable {
Byte date;// 存放数据(字符)本身,比如‘b’ 98
int weight; // 权值 表示字符出现的次数
Node left;
Node right;
public Node(Byte date, int weight) {
super();
this.date = date;
this.weight = weight;
}
@Override
public String toString() {
return “Node [date=” + date + “, weight=” + weight + “]”;
}
public int compareTo(Node o) {
return this.weight - o.weight;
}
// 前序遍历
public void preOrder() {
System.out.println(this);
if (this.left != null) {
this.left.preOrder();
}
if (this.right != null) {
this.right.preOrder();
}
}
}
`