踩过无数坑实现的哈夫曼压缩(JAVA)
2021-06-26 23:03
标签:哈夫曼 text res 路径 todo for targe art sys 最近可能又是闲着没事干了,就想做点东西,想着还没用JAVA弄过数据结构,之前搞过算法,就试着写写哈夫曼压缩了。 本以为半天就能写出来,结果,踩了无数坑,花了整整两天时间!!orz。。。不过这次踩坑,算是又了解了不少东西,更觉得在开发中学习是最快的了。 话不多说,进入正题 首先先来讲讲哈夫曼树 哈夫曼树属于二叉树,即树的结点最多拥有2个孩子结点。若该二叉树带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree)。哈夫曼树是带权路径长度最短的树,权值较大的结点离根较近。
哈夫曼树的构造 假设有n个权值,则构造出的哈夫曼树有n个叶子结点。 n个权值分别设为 w1、w2、…、wn,则哈夫曼树的构造规则为: (1) 将w1、w2、…,wn看成是有n 棵树的森林(每棵树仅有一个结点); (2) 在森林中选出两个根结点的权值最小的树合并,作为一棵新树的左、右子树,且新树的根结点权值为其左、右子树根结点权值之和; (3)从森林中删除选取的两棵树,并将新树加入森林; (4)重复(2)、(3)步,直到森林中只剩一棵树为止,该树即为所求得的哈夫曼树。 哈夫曼编码 在数据通信中,需要将传送的文字转换成二进制的字符串,用0,1码的不同排列来表示字符。例如,需传送的报文为“HELLO WORLD”,这里用到的字符集为“D,E,H,L,O,R,W”,各字母出现的次数为{1,1,1,3,2,1,1}。现要求为这些字母设计编码。要区别7个字母,最简单的二进制编码方式是等长编码,固定采用3位二进制,可分别用000、001、010、011、100、101、110对“D,E,H,L,O,R,W”进行编码发送,当对方接收报文时再按照三位一分进行译码。显然编码的长度取决报文中不同字符的个数。若报文中可能出现26个不同字符,则固定编码长度为5。然而,传送报文时总是希望总长度尽可能短。在实际应用中,各个字符的出现频度或使用次数是不相同的,如A、B、C的使用频率远远高于X、Y、Z,自然会想到设计编码时,让使用频率高的用短编码,使用频率低的用长编码,以优化整个报文编码。 此时D->0000 E->0001 W->001 H->110 R->111 L->01 0->02 固定三位时编码长度为30,而时候哈夫曼编码后,编码长度为27,很明显长度缩小了,得到优化。 下面就是代码实现 HuffmanCompress.java Compare.java 这里涉及到JAVA中优先对列的重载排序,我之前一直按照C++中的重载来写,结果发现发现压缩后的大小是原文件的3倍!!!!然后还一直以为是压缩过程的问题,疯狂看压缩过程哪里错了,最后输出了下各字符的编码才发现问题,耗了我整整一天TAT。。附上一个对优先队列重载讲解的链接https://blog.csdn.net/u013066244/article/details/78997869 HufTree.java test.java 踩过无数坑实现的哈夫曼压缩(JAVA) 标签:哈夫曼 text res 路径 todo for targe art sys 原文地址:https://www.cnblogs.com/csu-lmw/p/9655573.htmlpackage 哈夫曼;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.Arrays;
import java.util.HashMap;
import java.util.PriorityQueue;
public class HuffmanCompress {
private PriorityQueue
//这里为什么是&128呢?
//我们是按编码顺序走的,1向右,0向左,对于一串byte编码有8位,那最高位就是2^7,就是128
//所以通过位运算来判断该位是0还是1
//之前我想错了,从后面开始走,结果乱码,压缩在这块也卡了好久orz
if ((code_tmp&128)==128) {
root = root.rchild;
} else {
root = root.lchild;
}
if (root.lchild == null && root.rchild == null) {
fos.write(root.Byte);
++writen_len;
if (writen_len == file_len)
break;
root = queue.peek();
}
code_tmp 1;
}
if (writen_len == file_len)
break;
}
}
fis.close();
fos.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void createTree(PriorityQueuepackage 哈夫曼;
import java.util.Comparator;
public class Compare implements Comparator
package 哈夫曼;
public class HufTree{
public byte Byte; //以8位为单元的字节
public int weight;//该字节在文件中出现的次数
public String code; //对应的哈夫曼编码
public HufTree lchild,rchild;
}
//统计字符频度的临时节点
class TmpNode implements Comparable
package 哈夫曼;
import java.io.File;
public class test {
public static void main(String[] args) {
// TODO Auto-generated method stub
HuffmanCompress sample = new HuffmanCompress();
// File inputFile = new File("C:\\Users\\long452a\\Desktop\\opencv链接文档.txt");
// File outputFile = new File("C:\\Users\\long452a\\Desktop\\opencv链接文档.rar");
// sample.compress(inputFile, outputFile);
File inputFile = new File("C:\\Users\\long452a\\Desktop\\opencv链接文档.rar");
File outputFile = new File("C:\\Users\\long452a\\Desktop\\opencv链接文档1.txt");
sample.extract(inputFile, outputFile);
}
}
上一篇:SpringMVC--快速入门
下一篇:[记一辈子]java大数的读入