package org.structure.hoffmanCode;
import java.util.*;
/**
* hoffman 字符串压缩与解压压缩编码,
* @author cjj_1
* @date 2020-08-26 11:39
*/
public class HoffmanCode {
public static void main(String[] args) {
String str = "i like like like like you";
byte[] bytes = str.getBytes();//获取字符串的字节数组
List<Node> nodes = getByteNodes(bytes);//把每个字节包装成一个node,则字节数组转换为一个list<Node>
Node node = realizeHoffman(nodes);//把node节点转换成hoffman 树
Map<Byte,String> map = getHoffmanCode(node,"",stringBuilders);//获取字符的hoffman编码表;
System.out.println("hoffman 编码序列:"+stringBuilders.toString());
byte[] res= zip(bytes,map);
byte[] restoreBytes = decode(res,map,bytes.length);
System.out.println(new String(restoreBytes));
}
static Map<Byte,String> charPath = new HashMap<>();
static StringBuilder stringBuilders = new StringBuilder();
/**
* 把byte 转换成hoffman编码序列,根据hoffman编码序列还原出对应的字符串
* @param bs
* @param map
* @param length
* @return
*/
public static byte[] decode(byte[] bs, Map<Byte, String> map, int length){
StringBuilder sb = new StringBuilder();
boolean flag;
//构建hoffman编码序列
for(int i =0;i<bs.length;i++){
flag = (i==bs.length);
sb.append(byte2BitString(bs[i],!flag));
}
System.out.println("hoffman序列:"+sb.toString());
//hoffman序列 转换 成对应的字符串
//Map<Byte,String> 反转 key 与 value
Map<String,Byte> hoffmanCodeToByte = new HashMap<>();
for(Map.Entry<Byte,String> entry:map.entrySet()){
hoffmanCodeToByte.put(entry.getValue(),entry.getKey());
}
byte[] bytes = new byte[length+1];
int index =0;
for (int j=0;j<sb.length();){
int count=j+1;
String str= "";
Byte b;
boolean flag1 = Boolean.TRUE;
while (flag1){
str = sb.substring(j,count);
b= hoffmanCodeToByte.get(str);
if(b==null){
count++;
}else {
flag1 = Boolean.FALSE;
}
}
byte ch = hoffmanCodeToByte.get(str);
bytes[index] = ch;
index++;
j=count;
}
return bytes;
}
/**
* 字节转换成二进制字符串(0与1表示)
* @param b
* @param flag
* @return
*/
public static String byte2BitString(byte b,boolean flag){
String bitString;
int temp = b;
if(flag) {
temp |= 256;
}
bitString = Integer.toBinaryString(temp);
if(flag)
return bitString.substring(bitString.length()-8);
else return bitString;
}
//把赫夫曼编码 开始压缩
public static byte[] zip(byte[] bytes, Map<Byte,String> hoffmancode){
StringBuilder sb = new StringBuilder();
for(Byte b:bytes){
String hoffmanpath = hoffmancode.get(b);
sb.append(hoffmanpath);
}
System.out.println(sb);
int len;
if(sb.length()%8==0)
len = sb.length()/8;
else
len = sb.length()/8 +1;
byte[] hoffmanByte = new byte[len];
int index =0;
for (int i =0;i<sb.length();i+=8){
byte b;
if((i+8)>sb.length()){
b = (byte)Integer.parseInt(sb.substring(i,sb.length()),2);
}else {
b = (byte)Integer.parseInt(sb.substring(i,i+8),2);
}
hoffmanByte[index++]= b;
}
return hoffmanByte;
}
/**
* hoffMan编码字典
* @param root
* @param code
* @param stringBuilder
* @return
*/
public static Map<Byte, String> getHoffmanCode(Node root, String code, StringBuilder stringBuilder){
StringBuilder sb = new StringBuilder();
sb.append(stringBuilder.toString()).append(code);
if(root.data == null){
getHoffmanCode(root.left,"0",sb);
getHoffmanCode(root.right,"1",sb);
}else {
charPath.put(root.data,sb.toString());
stringBuilders.append(sb.toString());
}
return charPath;
}
/**
* 获取每个字符的个数
* @param bytes
* @return
*/
public static List<Node> getByteNodes(byte[] bytes){
List<Node> nodes = new ArrayList<>();
Map<Byte,Integer> nodeCounts = new HashMap<>();
for (Byte b:bytes){
Integer byteCount = nodeCounts.get(b);
if(byteCount == null){
nodeCounts.put(b,1);
}else {
nodeCounts.put(b,++byteCount);
}
}
for(Map.Entry<Byte,Integer> entry:nodeCounts.entrySet()){
nodes.add(new Node(entry.getKey(),entry.getValue()));
}
System.out.println(nodes);
return nodes;
}
public static Node realizeHoffman(List<Node> nodes){
while (nodes.size()>1){
Collections.sort(nodes);
Node leftNode = nodes.get(0);
Node rightNode = nodes.get(1);
Node parent = new Node(leftNode.weight+rightNode.weight);
parent.left = leftNode;
parent.right = rightNode;
nodes.add(parent);
nodes.remove(0);
nodes.remove(0);
}
return nodes.get(0);
}
}
class Node implements Comparable<Node>{
Byte data;
int weight;
Node left;
Node right;
public Node(int weight){
this.weight = weight;
}
public Node(Byte data,int weight){
this.data = data;
this.weight = weight;
}
@Override
public String toString() {
return "Node{" +
"data=" + data +
", weight=" + weight +
'}';
}
/**
* 实现接口
* @param o
* @return
*/
@Override
public int compareTo(Node o) {
return this.weight - o.weight;
}
public void preOrder(){
System.out.println(this.toString());
if(this.left!=null){
this.left.preOrder();
}
if(this.right!=null){
this.right.preOrder();
}
}
}
hoffman编码压缩,解压字符串
最新推荐文章于 2022-06-16 21:25:31 发布