0
点赞
收藏
分享

微信扫一扫

哈夫曼编码解码


代码

public class Main {
public static void main(String[] args) {
String datas = "i like like like java do you like a java";

//首先编码 得到字节数组
byte[] bytes = huffmanZip(datas.getBytes());
System.out.println(Arrays.toString(bytes));
//System.out.println(new String(decode(map,huffmanZip(bytes))));;

//然后解码
System.out.println(new String(decode(map,bytes)));;

}
static Map<Byte,String> map = new HashMap<Byte,String>();

/**
*
* @param bytes 原始的字节数组
* @return 经过赫夫曼编码后的字节数组
*/
public static byte[] huffmanZip(byte[] bytes){
//首先得到每个节点,封装成集合
List<Node> list = getList(bytes);

//然后利用节点集合,创建赫夫曼树
Node huffmanTree = createHuffmanTree(list);

//根据赫夫曼树,得到每个字符的编码,保存在map中
getCode(huffmanTree,new StringBuilder(),"");

//根据字符的编码,得到最终的字节数组
byte[] huffmanByte = getHuffmanByte(bytes);

return huffmanByte;
}

//得到每个字符与其权值,封装成集合返回
public static List<Node> getList(byte[] bytes){
List<Node> nodeList = new ArrayList<Node>();

//创建map集合 用作存储data 和 weight
HashMap<Byte, Integer> byteIntegerHashMap = new HashMap<>();
for (byte oneByte: bytes){
if (byteIntegerHashMap.get(oneByte) == null){
//说明是第一次添加
byteIntegerHashMap.put(oneByte,1);
}else {
//不是第一次添加
byteIntegerHashMap.put(oneByte,byteIntegerHashMap.get(oneByte) + 1);
}
}

//遍历map集合 将data和weight加到Node
for (Map.Entry<Byte,Integer> entry: byteIntegerHashMap.entrySet()){
nodeList.add(new Node(entry.getKey(),entry.getValue()));
}

return nodeList;
}

//得到哈夫曼树
public static Node createHuffmanTree(List<Node> nodeList){
while (nodeList.size() > 1){
Collections.sort(nodeList);

Node leftNode = nodeList.get(0);
Node rightNode = nodeList.get(1);

Node parent = new Node(null,leftNode.weight + rightNode.weight);
parent.left = leftNode;
parent.right = rightNode;
//System.out.println("leftNode=" + leftNode + "rightNode="+rightNode);
nodeList.remove(leftNode);
nodeList.remove(rightNode);
nodeList.add(parent);
}

return nodeList.get(0);
}

//得到哈夫曼编码值
public static void getCode(Node node,StringBuilder stringBuilder,String code){
//这个if是针对 根节点有可能是null
if (node != null){
//这里需要创建一个新的StringBuilder对象,我目前还不知道为啥 但是不创建就不对
StringBuilder stringBuilder1 = new StringBuilder(stringBuilder);
stringBuilder1.append(code);
//System.out.println("node="+node+"stringBuilder="+stringBuilder1);
if (node.data == null){
//说明是非叶子节点
//它的left和right一定不是null 这是哈夫曼树的特点
getCode(node.left,stringBuilder1,"0");

getCode(node.right,stringBuilder1,"1");
}else {
//把这个叶子节点加到map集合中
map.put(node.data,stringBuilder1.toString());
}
}
}

//返回得到的字节数组
public static byte[] getHuffmanByte(byte[] bytes){
StringBuilder stringBuilder = new StringBuilder();

//得到全是数的序列
for (byte oneByte: bytes){
stringBuilder.append(map.get(oneByte));
}

//将序列按8个一组(一个字节)进行划分
//首先得到分组的数目
int len;
if (stringBuilder.length() % 8 == 0){
//说明是8的整数倍
len = stringBuilder.length() / 8;
}else {
len = stringBuilder.length() / 8 + 1;
}

//然后根据得到的len创建数组
byte[] finalBytes = new byte[len];
int index = 0;

for (int i = 0;i < stringBuilder.length();i += 8){
//finalBytes[index] = stringBuilder.substring(i,i + 8) 这种是不对的 不能直接加
String oneByte;
if (i + 8 > stringBuilder.length()){
//说明有可能一共就少于8个数 也有可能是到了最后一个不足8个数的组
oneByte = stringBuilder.substring(i);
}else {
oneByte = stringBuilder.substring(i,i + 8);
}

finalBytes[index] = (byte)Integer.parseInt(oneByte,2);//这里还要转成byte类型,后面的参数中还有2
index++;
}

return finalBytes;

}

//将一个byte元素转成二进制
public static String byteToBitString(boolean flag,byte b){
int temp = b;//将字节类型转为int类型

if (flag){//需要补高位,如果是最后一个字节,无需补高位
temp |= 256;//按位或
}

String str = Integer.toBinaryString(temp);

if (flag){
return str.substring(str.length() - 8);
}else {
return str;
}
}

//进行解码

/**
*
* @param huffmanMap 表示哈夫曼编码表
* @param huffmanBytes 表示经过哈夫曼编码之后得到的字节数组 [-88,......]
* @return 返回原字节数组[i, ,l,i,.....]
*/
public static byte[] decode(Map<Byte,String> huffmanMap,byte[] huffmanBytes){
//首先将经过哈夫曼编码之后得到的字节数组,转成很长的一串数字
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0;i < huffmanBytes.length;i++){
if (i == huffmanBytes.length - 1){
//是最后一个 无需补高位
stringBuilder.append(byteToBitString(false,huffmanBytes[i]));
}else {
stringBuilder.append(byteToBitString(true,huffmanBytes[i]));
}
}
//这样就得到了 1010100010111111110010001011111111001000101111111100100101001101110001110000011011101000111100101000101111111100110001001010011011100

//得到key和value互换的 哈夫曼编码表
Map<String,Byte> reverseHuffmanMap = new HashMap<>();
for (Map.Entry<Byte,String> entry: huffmanMap.entrySet()){
reverseHuffmanMap.put(entry.getValue(),entry.getKey());
}

//根据反转之后的哈夫曼编码表,得到字节数组
List<Byte> arrayList = new ArrayList<Byte>();//这个地方要Byte 而不是 byte

int i = 0;
while (i < stringBuilder.length()){
//for (int i = 0;i < stringBuilder.length();){
int count = 1;
boolean flag = true;

while (true){
String binaryNum = stringBuilder.substring(i,i + count);

Byte oneByte = reverseHuffmanMap.get(binaryNum);

if (oneByte == null){
//说明没匹配到,那就将count++

count++;
}else {
//说明匹配到了
// System.out.println("oneByte="+oneByte);
arrayList.add(oneByte);
break;
}
}
i = i + count;
}

//}
System.out.println("集合为:"+ arrayList);
//将集合转为byte数组
byte[] finalBytes = new byte[arrayList.size()];
for (int j = 0;j < finalBytes.length;j++){
finalBytes[j] = arrayList.get(j);
}

return finalBytes;
}

}
class Node implements Comparable<Node>{
Byte data;//存放值
int weight;//存放权值
Node left;
Node right;

public Node(Byte data, int weight) {
this.data = data;
this.weight = weight;
}

//前序遍历
public void preList(Node root){
if (root == null){
System.out.println("树为空");
return;
}else {
this.preList();
}
}

public void preList(){
System.out.println(this);
if (this.left != null){
this.left.preList();
}
if (this.right != null){
this.right.preList();
}
}
@Override
public String toString() {
return "Node{" +
"data=" + data +
", weight=" + weight +
'}';
}

@Override
public int compareTo(Node o) {
return this.weight - o.weight;
}
}

结果

[-88, -65, -56, -65, -56, -65, -55, 77, -57, 6, -24, -14, -117, -4, -60, -90, 28]
集合为:[105, 32, 108, 105, 107, 101, 32, 108, 105, 107, 101, 32, 108, 105, 107, 101, 32, 106, 97, 118, 97, 32, 100, 111, 32, 121, 111, 117, 32, 108, 105, 107, 101, 32, 97, 32, 106, 97, 118, 97]
i like like like java do


举报

相关推荐

0 条评论