哈夫曼编码压缩
压缩过程思路:
1、 统计文件中每个字节出现的次数,每一个字节由8bit组成,一个字节从0~255,分别统计每种字节的次数。
1、实现思路:创建一个长度为256的数组,数组的下标与byte的值对应,数组中的每一个数据元素表示一种字节出现的次数。
2、 根据每个字节出现的次数建一个哈夫曼树
1. 遍历前面建立的数组,判断数组元素的值是否为0
2. 如果数组元素的值不为0,则为该元素建立一个结点,并将该结点添加到结点队列中
3. 结点含有数据域(存储数组的下标值),频率值域(对应于下标的元素值,即某字节在文件中出现的次数),左子结点,右子结点
// 将文件中出现次数不为0 的字节存入结点中,并将结点添加到队列中,TreeNode是自定义的结点类 public void addNode2List() { for (int i = 0; i < frequent.length; i++) { if (frequent[i] != 0) { TreeNode node = new TreeNode(i, frequent[i]); nodeList.add(node); } } }
4. 生成一棵哈夫曼树(哈弗曼编码的思想)
1. 遍历结点队列,从中找到频率值最小和次小的两个结点
2. 新建一个结点,其左右子结点是刚才找到的两个结点
3. 将这个新结点添加到队列中
4. 将之前找到的两个结点从结点队列中移除
5. 跳到第1步,直至队列中只有一个结点,该结点即为哈弗曼树的根结点
// 将队列中的结点转化成哈夫曼树 public void changeTree() { int len = nodeList.size();// 取得初始队列的长度 for (int j = 0; j < len - 1; j++) { TreeNode minnode1 = nodeList.get(0);// 取得队列中的第一个结点 TreeNode minnode2 = nodeList.get(1);// 取得队列中的第二个结点 // 循环比较,找到最小两个结点 for (int i = 1; i < nodeList.size(); i++) { TreeNode node = nodeList.get(i);// 取得队列中的第i个结点 // 比较两个节点中frequent值的大小 if (minnode1.getFrequent() > node.getFrequent()) {// 如果minnode1结点的次数值大于node的 minnode2 = minnode1;// 将最小的结点赋给次小的节点 minnode1 = node;// 将新找到的最小结点赋给原来最小的结点 } else if (minnode2.getFrequent() > node.getFrequent()) {// 如果minnode2结点的次数值大于node的 minnode2 = node;// 将新找到的最小结点赋给原来最小的结点 } } int sum = minnode1.getFrequent() + minnode2.getFrequent(); TreeNode parent = new TreeNode(0, sum);// 新建一个父节点,其子节点为上面找到的最小和次小结点,其data值为0,表示它不是叶结点 parent.setLeft(minnode1); parent.setRight(minnode2); // 将新的父节点添加到原来的队列中 nodeList.add(parent); // 把最小和次小的两个结点队列中移除 nodeList.remove(minnode1); nodeList.remove(minnode2); } }
3、 根据上一步生成的哈夫曼树,对每个字节重新编码
1. 根据哈夫曼数,进行新编码
2. 每一个字节都用字符串表示,字符串中只含有字符’0’和’1’。
3. 具体编码实现:
// 根据哈夫曼树进行编码 public void encode(TreeNode root, String s) { // 如果遍历到该节点为叶结点 if (root.getLeft() == null && root.getRight() == null) { int key = root.getData();// 获得叶结点的data map.put(key, s);// 将data和它的新编码添加到map中 System.out.println((cnt++) + "<---->" + s); return; } // 如果该结点的左子节点不为空 if (root.getLeft() != null) { String s1 = s + "0"; encode(root.getLeft(), s1);//递归调用本方法 } // 如果该结点的右子节点不为空 if (root.getRight() != null) { String s2 = s + "1"; encode(root.getRight(), s2);//递归调用本方法 } }
4、 将源文件中的字节按照新编码转换成字符串
1. 遍历文件中的字节,并按照新编码转换成一个长字符串
2. 如果长字符串的长度不是8的倍数,则在长字符串末尾补'0'
// 将文件中的字节,按照新的编码存储到一个长字符串中 public void changeToString(String fileName) { try { FileInputStream fis = new FileInputStream(fileName); BufferedInputStream bis = new BufferedInputStream(fis); while (bis.available() > 0) { int i = bis.read(); longstr.append(getNewCode(i));// 新编码添加到长字符串结尾 } bis.close(); fis.close(); number = longstr.length() % 8;// 长字符串对8取余数的结果 // 给长字符串补'0' for (int i = 0; i < 8 - number; i++) { longstr.append('0'); } } catch (Exception e) { e.printStackTrace(); } }
5、 从上面的长字符串中,依次读取8个字符,将这8个字符转换成一个十进制数,并将其输出到文件中
1. 依次从长字符串中读取8个字符,将其转化成一个相应的十进制数
2. 将这个十进制数输出到文件中保存
压缩文件的结构:文件头和数据部分
1、 文件头包含的信息:
1. 用4个byte保存压缩文件的新编码数,即数组中元素值不为0的元素个数
2. 用1个byte保存字符串末尾补0的个数
3. 保存新编码规则
1、写入一个源码值,占1byte
2、写入新编码的长度,1byte
3、写入对应于源码值的新编码,新编码中的一个字符('0'或'1')用1byte节表示(不等 长存储,最坏情况下一个新码由255个'0'或'1'表示)
例子:原字节的值为20的新编码可能是0101010101
2、 文件数据部分
1. 压缩文件中数据部分的每一个字节都是由原来的8个字符转化而成的十进制数。
解压缩过程
就是将用上面的方法压缩的文件解压成源来可读的文件。
从压缩文件中读取数据的顺序及其含义
1、读取文件头信息
a) 读取4个byte,这4个字节表示压缩编码中新编码的个数
b) 读取1个byte:数据部分补'0'个数
c) 根据读取到的新编码的个数,循环进行d、e、f步骤的读取
d) 读取1个byte:源码值
e) 读取1个byte:该新编码的长度值
f) 读取对应于源码值的新编码,读取的字节数由d)步骤读取的字节所表示的新编码的长度值决定。将源码值与其对应的字符串编码添加到Map中
2、读取编码数据信息
a) 将读取到的每一个字节都转换成对应的8位字符,将其添加到长字符串中
b) 按照读取到的编码规则,即保存在Map中的编码规则信息,将长字符串中的字符码转换成源字节码,并将源字节码输出到解压缩文件中
<!--EndFragment-->
<!--EndFragment-->
分享到:
相关推荐
本项目通过C++编程语言并结合QT库实现文件压缩功能,具体应用了两种经典压缩算法:哈夫曼编码和游程编码。接下来,我们将详细讨论这两种编码方式以及它们在实际中的应用。 首先,哈夫曼编码是一种基于频率的无损...
利用哈夫曼编码思想,设计对一个文本文件(.txt)中的字符进行哈夫曼编码,生成编码压缩文件(.txt),并且还可将压缩后的文件进行解码还原为原始文本文件(.txt)。 实现的功能: (1)压缩:实现对文件的压缩,生成...
在“基于哈夫曼编码的文本文件压缩与解压缩.zip”这个压缩包中,很可能包含了用于演示或教学目的的哈夫曼编码实现代码、压缩和解压缩的示例文本以及相应的结果文件。学习和理解这个压缩包的内容,可以帮助我们更好地...
16. **CTrie类**:定义了一个类,用于构建Huffman树和进行文件压缩和解压缩操作。 17. **create函数**:用于根据字符频率创建Huffman树。 18. **insert函数**:用于在Huffman树中插入新的编码键值。 19. **...
标题中提到的"114243 用哈夫曼编码实现文件压缩 doc"是一份实验报告,描述了如何使用哈夫曼编码来实现文件的压缩。哈夫曼编码是一种数据编码方法,常用于无损数据压缩,它通过为出现频率较高的字符分配较短的编码,...
在提供的文件列表中,`main.c`可能是实现哈夫曼编码算法的C语言源代码,而`H.txt`和`A.txt`是待压缩的文本文件。`H.zip`可能是压缩后的结果,包含压缩后的文本和哈夫曼树信息。`2.cbp`和`2.layout`可能与开发环境或...
哈夫曼编码是一种高效的数据编码方法,主要用于无损数据压缩,尤其在文本文件的压缩中表现出色。这种编码方式基于频率最小的字符用最短的二进制代码表示的原理,能够有效地减少数据存储和传输时的位数,从而达到压缩...
对比二进制编码和哈夫曼编码后的文件字节大小,并计算压缩率 通过编写利用哈夫曼算法实现的文件编码解码小工具,可加深对哈夫曼算法的理解,以及编码的熟练度。本人的小工具仅针对英文大小字母及 ' '\n' ' ' 字符...
在这个名为“利用哈夫曼编码压缩文件的小工具”中,包含了实现哈夫曼编码和解码功能的代码。 1. **哈夫曼树的构建**: - 首先,我们需要统计输入文件中每个字符出现的频率。 - 接着,将这些频率作为权重,创建一...
数据结构课程设计用哈夫曼编码实现文件压缩: 一、实验题目: 用哈夫曼编码实现文件压缩 二、实验目的: 1、了解文件的概念。 2、掌握线性链表的插入、删除等算法。 3、掌握Huffman树的概念及构造方法。 4、掌握...
在C语言中实现基于哈夫曼编码的文件压缩解压程序,需要深入理解哈夫曼编码的基本原理以及C语言编程技巧。 首先,哈夫曼编码是根据字符出现频率进行编码的一种方法。它通过构建一棵特殊的二叉树——哈夫曼树(也称为...
实验目的:理解哈弗曼信源编码算法,并能应用于文件压缩中。 实验内容:写出程序,利用哈弗曼编码实现对文件的压缩,并能解压文件。 实验步骤: 1、压缩 (1) 统计原始文件中各字节出现的概率(次数); (2) 采用...
在这个基于哈夫曼编码的文件压缩器项目中,我们可以通过源代码和实验报告深入理解其工作原理和实现方式。 首先,哈夫曼编码的基本思想是将出现频率较高的字符用较短的二进制码表示,而出现频率较低的字符则用较长的...
下面我们将深入探讨哈夫曼编码的工作原理、构建过程以及在文件压缩与解压中的应用。 1. 哈夫曼编码工作原理: 哈夫曼编码的核心思想是“频繁的字符用短码,不频繁的字符用长码”。它基于贪心算法,通过构建一棵特殊...
本文将围绕Java实现哈夫曼编码的文件压缩与解压进行详细解析。 首先,我们看到`main`方法调用了`zipFile`和`unZipFile`两个静态方法,分别用于文件的压缩和解压缩操作。`zipFile`方法接收源文件路径和目标压缩文件...
在“哈夫曼编码压缩解压文件”中,我们将深入探讨如何利用哈夫曼编码实现文件的压缩和解压。 首先,哈夫曼树是哈夫曼编码的基础。它是一种特殊的二叉树,也称为最优二叉树或最小带权路径长度树。在构建哈夫曼树时,...
通过上述步骤,我们可以实现基于哈夫曼编码的文件压缩和解压缩功能,并结合QT5.12框架,创建出一个具备用户友好界面的工具。哈夫曼编码在文件压缩中的应用,不仅降低了文件的存储需求,还为数据传输和存储带来了显著...