/**
* @author Yoshino
* 实现赫夫曼编码
*/
public class HuffmanCode {
static Map<Byte, String> codeMap = new HashMap<>();
public static void main(String[] args) {
String content = "i like like like java do you like a java";
byte[] bytes = content.getBytes();
byte[] huffmanZip = huffmanZip(bytes);
System.out.println(Arrays.toString(huffmanZip));
}
public static byte[] huffmanZip(byte[] bytes)
{
//1创建哈夫曼树
//1.1 得到节点链表
List<HuffmanCodeNode> nodes = getNodes(bytes);
//1.2 得到哈夫曼数的根节点
HuffmanCodeNode root = getHuffmanTree(nodes);
//2.获取哈夫曼编码
StringBuilder builder = new
StringBuilder();
getNodeCode(root, "", builder);
//3.用哈夫曼编码来编码原始的数据
StringBuilder s = new StringBuilder();
for (byte b:bytes)
{
s.append(codeMap.get(b));
}
//4.压缩,得到压缩后的数据
return zip(s.toString());
}
/**
* 构造赫夫曼树节点
* @param bytes
* @return 赫夫曼树节点的链表
*/
public static List<HuffmanCodeNode> getNodes(byte[] bytes) {
List<HuffmanCodeNode> nodes = new LinkedList<>();
Map<Byte, Integer> nodeMap = new HashMap<>();
for (byte b : bytes) {
//记录每个数据出现的次数,作为节点的权重
nodeMap.put(b, nodeMap.getOrDefault(b, 0) + 1);
}
//遍历封装成HuffmanCodeNode
for (Map.Entry<Byte, Integer> entry : nodeMap.entrySet()) {
nodes.add(new HuffmanCodeNode(entry.getKey(), entry.getValue()));
}
return nodes;
}
/**
* 构造赫夫曼树
* @param nodes
* @return 哈夫曼树的根节点
*/
public static HuffmanCodeNode getHuffmanTree(List<HuffmanCodeNode> nodes) {
while (nodes.size() > 1) {
//排序
Collections.sort(nodes);
//每次取出最小的两个
HuffmanCodeNode left = nodes.get(0);
HuffmanCodeNode right = nodes.get(1);
//构造新的节点
HuffmanCodeNode root = new HuffmanCodeNode(null, left.weight + right.weight);
root.left = left;
root.right = right;
nodes.remove(left);
nodes.remove(right);
nodes.add(root);
}
return nodes.get(0);
}
/**
* 获取节点对应的哈夫曼编码
* @param node 进行编码的节点
* @param singleCode 0,1 向左遍历为0 向右遍历为1
* @param s 最终的该节点的编码
*/
public static void getNodeCode(HuffmanCodeNode node, String singleCode, StringBuilder s) {
StringBuilder stringBuilder = new StringBuilder(s);
stringBuilder.append(singleCode);
if (node != null) {
//data!=null 说明为叶子节点 即为原始数据
if (node.data != null) {
codeMap.put(node.data, stringBuilder.toString());
} else {
//data == null 说明为哈夫曼树中我们人为构造出来的节点,继续进行编码
getNodeCode(node.left, "0", stringBuilder);
getNodeCode(node.right, "1", stringBuilder);
}
}
}
/**
* 将编码后的二进制字符串压缩为byte数组
* @param byteStr 编码后的二进制字符串
* @return 压缩后的byte数组
*/
public static byte[] zip(String byteStr){
int len;
int index = 0;
StringBuilder s = new StringBuilder(byteStr);
//每8位为一个子节
if (byteStr.length()%8 ==0)
{
len = byteStr.length()/8;
}else
{
len = byteStr.length()/8 + 1;
}
byte[] zipBytes = new byte[len];
for (int i = 0; i < byteStr.length(); i +=8) {
String substring;
//当长度足够截取8位时,直接截取
if (i+8 <= byteStr.length())
{
substring = s.substring(i, i + 8);
}else
//长度不足8位时,截取到最后
{
substring = s.substring(i);
}
zipBytes[index] = (byte) Integer.parseInt(substring,2);
index++;
}
return zipBytes;
}
}
class HuffmanCodeNode implements Comparable<HuffmanCodeNode> {
Byte data;
int weight;
HuffmanCodeNode left;
HuffmanCodeNode right;
public HuffmanCodeNode(Byte data, int weight) {
this.data = data;
this.weight = weight;
}
@Override
public String toString() {
return "HuffmanCodeNode{" +
"data=" + data +
", weight=" + weight +
'}';
}
public void preShow() {
System.out.println(this);
if (this.left != null) {
this.left.preShow();
}
if (this.right != null) {
this.right.preShow();
}
}
@Override
public int compareTo(HuffmanCodeNode o) {
return this.weight - o.weight;
}
}
哈夫曼编码 java实现
最新推荐文章于 2024-07-08 00:01:13 发布