利用huffman编码对文本文件进行压缩与解压

输入:一个文本文件
输出:压缩后的文件

算法过程:
(1)统计文本文件中每个字符的使用频度
(2)构造huffman编码
(3)以二进制流形式压缩文件

采用哈夫曼编码进行文件的压缩和解压,主要原理是通过huffman编码来表示字符,出现次数多的编码短,出现次数少的编码长,这样整体而言,所需的总的比特位是最少的。但是当大部分字符出现的频率都差不多时,huffman压缩的压缩率就会很低。先统计出文件中各个字符出现的次数;构建哈夫曼树,生成每个字符对应的编码,然后将编码写入压缩文件中;解压缩是将压缩后的文件翻译过来,根据哈夫曼编码找到对应的字符。

package compress_file;import java.io.BufferedReader;
import java.io.FileReader;
import java.util.*;class HaffmanTree {//哈夫曼树类public static final int MAXVALUE = 1000;// 最大权值public int nodeNum; // 叶子结点个数public HaffmanTree(int n) {this.nodeNum = n;}public void haffman(char[] names, int[] weight, HaffNode[] nodes) {//构造哈夫曼树,weight 权值,nodes 叶子节点int n = this.nodeNum;int m1, m2, x1, x2;// m1,m2,表示最小的两个权值,x1、x2表示最小两个权值对应的编号,m1表示最小,m2表示次小for (int i = 0; i < 2 * n - 1; i++) {// 初始化所有的结点,对应有n个叶子结点的哈夫曼树,有2n-1个结点HaffNode temp = new HaffNode();// 初始化n个叶子结点,就是输入的节点。0、1、2、3是叶子节点也是输入的节点if (i < n) {temp.name = names[i];temp.weight = weight[i];} else {temp.name = ' ';temp.weight = 0;}temp.parent = 0;temp.flag = 0;temp.leftChild = -1;temp.rightChild = -1;nodes[i] = temp;}for (int i = 0; i < n - 1; i++) {// 初始化n-1个非叶子结点,n-1表示要循环n-1次求的n-1个数m1 = m2 = MAXVALUE;x1 = x2 = 0;// 求得这n-1个数时,每次都是从0到n+i-1,并且flag=0的,flag=1表示已经加入到二叉树。// 以下是找出权值最小的2个for (int j = 0; j < n + i; j++) {if (nodes[j].weight < m1 && nodes[j].flag == 0) {// m1,x1初始值为第一个元素,后面如果比m1要小,则m1指向更小的,原来m1指向的现在由m2指向,// 如果后面比m1大比m2小,则m2指向这个比m1大比m2小的,// 也就是说m1指向最小的,m2指向第2小的。m2 = m1;x2 = x1;m1 = nodes[j].weight;x1 = j;} else if (nodes[j].weight < m2 && nodes[j].flag == 0) {m2 = nodes[j].weight;x2 = j;}}// 将权值最小的2个组合成一个二叉树nodes[x1].parent = n + i;nodes[x2].parent = n + i;nodes[x1].flag = 1;nodes[x2].flag = 1;nodes[n + i].weight = nodes[x1].weight + nodes[x2].weight;nodes[n + i].leftChild = x1;nodes[n + i].rightChild = x2;}}public void haffmanCode(HaffNode[] nodes, Code[] haffCode) {//哈弗曼编码int n = this.nodeNum;Code code = new Code(n);int child, parent;for (int i = 0; i < n; i++) {// 给前面n个输入的节点进行编码code.start = n - 1;code.weight = nodes[i].weight;code.name = nodes[i].name;child = i;parent = nodes[child].parent;while (parent != 0) {// 从叶子节点向上走来生成编码。if (nodes[parent].leftChild == child) {code.bit[code.start] = 0;} else {code.bit[code.start] = 1;}code.start--;child = parent;parent = nodes[child].parent;}Code temp = new Code(n);for (int j = code.start + 1; j < n; j++) {temp.bit[j] = code.bit[j];}temp.weight = code.weight;temp.name = code.name;temp.start = code.start;haffCode[i] = temp;}}public void decode(String res, HaffNode[] nodes){int index = 2*this.nodeNum-2;// 从根节点出发for(int k = 0; k < res.length(); k++){// 依次读取哈夫曼编码,遇0则遍历当前节点的左孩子if(res.charAt(k)=='1'){// 遇1则遍历当前节点的右孩子index = nodes[index].rightChild;// 如果当前节点的右孩子为-1是证明其为叶子节点直接输出字符(由于哈夫曼树只存在出度为0或2的节点,因此只判断右孩子即可)if(nodes[index].rightChild==-1){System.out.print(nodes[index].name);index = 2*this.nodeNum-2;// 重新从根节点出发}}else{// 遇1则遍历当前节点的右孩子index = nodes[index].leftChild;// 如果当前节点的右孩子为-1是证明其为叶子节点直接输出字符(由于哈夫曼树只存在出度为0或2的节点,因此只判断右孩子即可)if(nodes[index].rightChild==-1){System.out.print(nodes[index].name);index = 2*this.nodeNum-2;// 重新从根节点出发}}}}
}class HaffNode {// 哈夫曼树的结点类public char name; // 字符名public int weight; // 权值public int parent; // 双亲public int flag; // 是否为叶子节点的标志public int leftChild; // 左孩子public int rightChild; // 右孩子public HaffNode() {}
}class Code {// 哈夫曼编码类public int[] bit; // 编码的数组public int start; // 编码的开始下标public int weight; // 权值public char name; // 字符名public Code(int n) {bit = new int[n];start = n - 1;}
}public class Compress_file {public char[] names;public int[] weights;public static void main(String[] args) throws Exception {Compress_file test = new Compress_file();while(true){String s = test.readfile();// 读取文本中的一行字符串Map<Character, Integer> map = test.getCharMaps(s);// 统计文本中不同字符出现的频率test.names = new char[map.size()];        // 创建数组用于储存字符及出现频率test.weights = new int[map.size()];int i = 0;Set set = map.keySet();// 将map转化为set 并将统计的字符及其对应的频次放入到数组中for (Iterator iter = set.iterator(); iter.hasNext();) {char key = (Character)iter.next();test.names[i] = key;test.weights[i] = map.get(key);i++;}System.out.println("文本中的字符及其出现的频率:");for (int j = 0; j < test.names.length; j++) {// 打印字符System.out.print(test.names[j] + " ");}System.out.println();for (int j = 0; j < test.weights.length; j++) {// 打印频次System.out.print(test.weights[j] + " ");}System.out.println();HaffmanTree haffTree = new HaffmanTree(map.size());// 建立哈夫曼树HaffNode[] nodes = new HaffNode[2 * map.size() - 1];Code[] codes = new Code[map.size()];haffTree.haffman(test.names, test.weights, nodes);// 构造哈夫曼树haffTree.haffmanCode(nodes, codes);// 生成哈夫曼编码System.out.println("哈夫曼编码:");// 打印哈夫曼编码for (int k = 0; k < map.size(); k++) {System.out.print("Name=" + codes[k].name + " Weight=" + codes[k].weight + " Code=");for (int j = codes[k].start + 1; j < map.size(); j++) {System.out.print(codes[k].bit[j]);}System.out.println();}System.out.print("原始文件:");System.out.println(s);System.out.print("压缩后的文件:");String res = s;String bit = "";// 根据哈夫曼编码表替换相应字符for(int k = 0; k < test.names.length; k++){for (int j = codes[k].start + 1; j < map.size(); j++) {bit += codes[k].bit[j];}res = res.replace(String.valueOf(test.names[k]), bit);bit = "";}System.out.println(res);System.out.print("解压后的文件:");haffTree.decode(res, nodes);System.out.println();}}public String readfile() throws Exception {System.out.println("请输入测试文件的编号(1~5):");Scanner sc = new Scanner(System.in);int num = sc.nextInt();BufferedReader br = new BufferedReader(new FileReader("D:/Program Files (x86)/MyStudy/src/compress_file/input/input_assign03_0" + num + ".dat"));return (br.readLine());       }public Map<Character, Integer> getCharMaps(String s) {//统计文本中不同字符对应的出现频率Map<Character, Integer> map = new HashMap<Character, Integer>();for (int i = 0; i < s.length(); i++) {Character c = s.charAt(i);Integer count = map.get(c);map.put(c, count == null ? 1 : count + 1);}return map;}
}

根据提示信息输入要测试的文件的编号(1-5),输入要压缩的文件的编号后程序开始运行,依次输出文本文件中的字符和字符出现的频率、哈夫曼编码结果、原始文件内容、压缩后的文件内容、解压后的文件内容。下图为第1组测试数据的结果。

利用huffman编码对文本文件进行压缩与解压(java实现)相关推荐

  1. 利用huffman编码对文本文件进行压缩与解压 Java

    exe4j的使用教程可以看这篇博客:https://blog.csdn.net/zzzgd_666/article/details/80756430 目录 一.问题描述 二.要求 三.提示 四.运行环 ...

  2. 基于哈夫曼编码完成的文件压缩及解压

    这几天在较为认真的研究基于哈夫曼编码的文件压缩及解压,费了点时间,在这分享一下: 这里用链式结构,非顺序表结构: 文件压缩: 1.获取文件信息(这里采用TXT格式文本): 2.压缩文件: 3.写配置文 ...

  3. Huffman二进制编码以及文本的压缩与解压

    目录 Huffman树转化成二进制编码 文本压缩 文本解压 Huffman树转化成二进制编码    在上一篇博客的末尾,将Huffman树转化成了01 构成的字符串,显然在实际应用中不是这种操作.我们 ...

  4. huffman算法实现文件的压缩与解压

            本文采用哈夫曼编码的方式进行文件的压缩和解压缩,主要原理是通过huffman编码来表示字符,出现次数多的编码短,出现次数少的编码长,这样整体而言,所需的总的bit位是减少的.但是当大部 ...

  5. winform 线程监听两个目录下的文件_vb.net 利用.net自带的GZipStream压缩或者解压文件的代码,不需要任何第三方控件...

    网上很少有用VB写的压缩文件的代码,但是,在网络传输,文件下载,打包发布等等方面的需求又比较多,所以,借鉴了一下C#代码的例子,改造成了VB用的类.另外加上了多层文件夹压缩解压.但是,因为时间有限,只 ...

  6. 使用GZIPInputStream和GZIPOutputStream压缩、解压java对象

    2019独角兽企业重金招聘Python工程师标准>>> 本例子演示怎样对java对象进行压缩和解压,主要用到java.util.zip包里的GZIPInputStream和GZIPO ...

  7. Java实现文件压缩与解压[zip格式,gzip格式]

    原文:http://www.cnblogs.com/visec479/p/4112881.html#3069573 Java实现ZIP的解压与压缩功能基本都是使用了Java的多肽和递归技术,可以对单个 ...

  8. java gzip 解压文件_Java实现文件压缩与解压[zip格式,gzip格式]

    原文:http://www.cnblogs.com/visec479/p/4112881.html#3069573 Java实现ZIP的解压与压缩功能基本都是使用了Java的多肽和递归技术,可以对单个 ...

  9. java文件压缩与解压_Java实现文件压缩与解压

    Java实现ZIP的解压与压缩功能基本都是使用了Java的多肽和递归技术,可以对单个文件和任意级联文件夹进行压缩和解压,对于一些初学者来说是个很不错的实例.(转载自http://www.puiedu. ...

最新文章

  1. HTML基础知识个人总结
  2. Windows远程桌面管理--功能强大的远程批量管理工具
  3. c语言pta按等级统计学生成绩,第九周作业
  4. tinyid 教程_tinyid
  5. 微众银行在联邦推荐算法上的探索及应用(文末附PPT下载链接)
  6. 京东与滁州达成战略合作,共建全国首座智慧型家电产地仓
  7. 20155229 2017-2018-1 《信息安全系统设计基础》课程总结
  8. 深入理解viewport及相关属性的关系
  9. DFM弹幕库在直播中的使用
  10. 中级计算机证书知识,计算机中级考哪些内容
  11. 二进制与十进制的转换
  12. kuangbin专题十二 HDU1069 Monkey and Banana
  13. Java获取本地ip地址
  14. IDEA编辑页面html jsp js java无法即时生效
  15. linux下查看vnc端口_Linux的VNCServer的默认端口是多少?
  16. 交换机-自动协商机制-auto-negotiation
  17. .Net 7里的函数.Ctor和.CCtor是干啥用的呢?你知道吗
  18. 大数据学习路线,如何学习大数据?
  19. 防止表单重复提交的问题
  20. SDRAM的工作原理

热门文章

  1. lombok get/set 方法未生效,解决办法
  2. 【Java数据结构与算法】Java如何实现环形队列
  3. matlab 轴系校中,轴系校中简介.ppt
  4. spacy POS 和 Syntactic Dependency Parsing 的标记
  5. 计算机原理探险系列(一)CPU
  6. php /x20有啥用,什么才是逆光摄影 用了全面屏vivo X20恍然大悟
  7. 高级查询组件下拉框联动(三)
  8. 【Spring Data ElasticSearch】高级查询,聚合
  9. seaborn颜色报错 ValueError: Invalid RGBA argument: [‘#f9802d‘, ‘#f26b15‘, ‘#fdc48f‘]
  10. 传智播客C语言视频第二季(第一季基础上增加诸多C语言案例讲解,有效下载期为10.5-10.10关闭