package com.eleven.binaryTree.huffman.code;
import java.util.*;
/**
* @Description 用赫夫曼编码进行压缩和解码
* @auther Eleven
* @create 2020-04-07 23:12
**/
public class HuffManCodeCus {
public static void main(String[] args) {
HuffManCodeCus huffManCodeCus = new HuffManCodeCus();
String msg = " can you think about it . ";
huffManCodeCus.huffManCodeCus(msg);
}
//创建赫夫曼编码
public void huffManCodeCus(String str){
byte[] bytes = str.getBytes();
System.out.println("压缩前:"+bytes.length);
System.out.println(Arrays.toString(bytes));
//将byte数字转化为赫夫曼树的node(这里要注意所有权重的计算,是以每个数出现的次数)
List<Node> nodes = createNodeList(bytes);
//将nodes转化为赫夫曼树
Node tree = createTree(nodes);
//创建赫夫曼编码表(所谓的编码表就是指从根节点到叶子节点的路径 左边为0右边用1标示)
Map<Byte,String> huffManCodeTable = createCode(tree);
// System.out.println(huffManCodeTable);
//根据编码表进行压缩
byte[] zipBytes = zip(huffManCodeTable,bytes);
//System.out.println("压缩前:"+zipBytes.length);
//解码
byte[] unZipBytes = unZip(huffManCodeTable,zipBytes);
System.out.println(new String(unZipBytes));
}
//解码
private byte[] unZip(Map<Byte, String> huffManCodeTable, byte[] zipBytes) {
Map<String, Byte> map = new HashMap<>();
StringBuilder sb = new StringBuilder();
//首先将编码表的键值对互换位置
for (Map.Entry<Byte, String> entry:huffManCodeTable.entrySet()){
map.put(entry.getValue(),entry.getKey());
}
//转化为8位二进制数据
for(int i = 0;i<zipBytes.length;i++){
byte bty = zipBytes[i];
boolean flag=(i==zipBytes.length-1);
String str = byteToString(!flag,bty);
sb.append(str);
}
System.out.println(sb.toString());
//将数据转化为byte
int count =0;
List<Byte> list = new ArrayList<Byte>();
for (int i = 0;i<sb.length();i++){
String b = sb.substring(count,i);
if (map.get(b) !=null){
list.add(map.get(b));
count=i;
}
}
//转成数组
byte[] bytes = new byte[list.size()];
for (int m=0;m<list.size();m++){
bytes[m] = list.get(m);
}
return bytes;
}
/**
* 转成8位二进制数据
* @param flag 判断是否为最后一位
* @param b 数组
* @return
*/
private String byteToString(boolean flag ,byte b) {
int by = b;
if (flag){
by|=256;
}
String temp = Integer.toBinaryString(by);
if (flag){
temp = temp.substring(temp.length()-8);
}else{
temp = temp;
}
return temp;
}
private byte[] zip(Map<Byte, String> huffManCodeTable, byte[] bytes) {
//转化为二进制编码
StringBuilder zipSb = new StringBuilder();
for (int i=0;i<bytes.length;i++){
zipSb.append(huffManCodeTable.get(bytes[i]));
}
System.out.println(zipSb.toString());
//再变成压缩后的byte数组
//使用8为二进制数标示所以存储压缩后byte的长度计算方式如下
int len;
if (zipSb.length()%8 ==0){
len = zipSb.length()/8;
}else {
len = zipSb.length()/8+1;
}
byte[] zipResbytes = new byte[len];
int index = 0;
//每8位一截取
for (int i=0;i<zipSb.length();i=i+8){
String temp = "";
if (zipSb.length()-i<8){
temp = zipSb.substring(i);
}else {
temp = zipSb.substring(i,i+8);
}
//转换为二进制
byte b = (byte) Integer.parseInt(temp,2);
zipResbytes[index] = b;
index++;
}
return zipResbytes;
}
static StringBuilder sb = new StringBuilder();
static Map<Byte, String> huffManMap = new HashMap<>();
private Map<Byte, String> createCode(Node tree) {
if (tree == null){
return null;
}
//创建路径编码
createCodes(tree.left,"0",sb);
createCodes(tree.right,"1",sb);
return huffManMap;
}
private void createCodes(Node node, String s, StringBuilder sb) {
StringBuilder stringBuilder = new StringBuilder(sb);
stringBuilder.append(s);
if (node.data==null){
createCodes(node.left,"0",stringBuilder);
createCodes(node.right,"1",stringBuilder);
}else {
huffManMap.put(node.data,stringBuilder.toString());
}
}
/**
* 创建赫夫曼树
* @param nodes
* @return
*/
private Node createTree(List<Node> nodes) {
//首先要对集合进行排序
while (nodes.size()>1) {
Collections.sort(nodes);
//取出最小的左右的节点
Node left = nodes.get(nodes.size() - 1);
Node right = nodes.get(nodes.size() - 2);
//新建一个父节点 并且设置好左右节点
Node parent = new Node(null, left.weight + right.weight);
parent.left = left;
parent.right = right;
//将左右节点移除
nodes.remove(left);
nodes.remove(right);
//将父节点添加进去
nodes.add(parent);
//再接着排序循环以上步骤
}
//返回根节点
return nodes.get(0);
}
/**
* 转化为赫夫曼树的叶子节点
* @param bytes
* @return
*/
private List<Node> createNodeList(byte[] bytes) {
List<Node> nodes = new ArrayList<>();
//计算数组中每个数出现的次数,作为权重
Map<Byte,Integer> map = new HashMap<>();
for (int i=0;i<bytes.length;i++){
if (map.get(bytes[i])==null){
map.put(bytes[i],1);
}else {
int count = map.get(bytes[i]);
map.put(bytes[i],count+1);
}
}
//根据权重和数据创建叶子节点集合
for (Map.Entry<Byte,Integer> entry:map.entrySet()){
Node node = new Node(entry.getKey(),entry.getValue());
nodes.add(node);
}
return nodes;
}
}
赫夫曼编码进行压缩和解码
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.