上篇博客学习了哈夫曼树,也自己动手建立了一棵哈树。接下來,我们将在原本的基础上更进一步。通过哈弗曼编码来实现对文件的压缩与解压缩。----------- 下面进入正题。
要实现的目标 :利用哈夫曼编码思想,设计对一个文本文件(.txt)中的字符进行哈夫曼编码,生成编码压缩文件,并且还可将一个压缩后的文件进行解码还原为原始文本文件(.txt)。
对问题的分析:本程序我们只针对纯文本文件(.txt)的压缩。为了使文件尽可能的缩短,可以对文件中每个字符出现的次数进行统计。设法让出现次数多的字符的二进制码短些,而让那些很少出现的字符的二进制码长一些。若对字符集进行不等长编码,则要求字符集中任一字符的编码都不是其它字符编码的前缀。为了确保哈夫曼编码的唯一性,我们可以对它的左右子树的大小给予比较限定,如:左子树的权值小于右子树的权值。哈夫曼树中的左右分支各代表‘0’和‘1’,则从根节点到叶子节点所经历的路径分支的‘0’和‘1’组成的字符串,为该节点对应字符的哈夫曼编码。
那么,我们解决问题(压缩)的步骤大致分为如下几步:
1.读取源文件内容,统计各个字符所出现的次数。PS:这里可以采用HashMap来进行存储,当然,你也可以采用其他的数据结构进行存储。
2.统计完成后,接下来就是我们熟悉的构建哈夫曼树啦(上篇博客有写)。我们根据字符所出现的次数的多少进行构建。 构建完成后,我们会发现,出行频率多的处于比较靠上的层次,频率低的则集中在下层。 这是为什么呢? 呵呵,继续往下看你或许就会明白了。
3.哈树生成后,我们就该为他编码了。在整个哈树中,每个叶子节点的key值都是源文件中出现的,而他的value值则为频次。那么,我们定哈夫曼树中的左右分支各代表‘0’和‘1’,则从根节点到叶子节点所经历的路径分支的‘0’和‘1’组成的字符串,为该节点对应字符的哈夫曼编码。
什么意思?我们还是看个图吧》》》》》
假设对这段文字进行编码:abbcccdddd a:1次 b:2次 c:3次 d:4次
编码后我们会发现,这些字符都能用其哈弗曼编码来进行替代了,如:
a:000
b: 001
c: 01
d: 1
你是不是发现,出现频次越多的字符,其编码的长度越短呀!!!! 每次,我们在还原的时候,就能尽可能的将出现频率多的字符用相对短的编码来表示,出现频次少的用较长的编码表示,这样的话,我们的编码的总长度就能控制的相对较少。
通过这一步的操作,我们将获取一份可贵的码表呀(解压时也将用到它)!
4.对照码表,将文件的内容,用哈弗曼编码替换,形成一个编码串。
如:abbcccdddd —> 0000010010101011111
5.将编码串按每8位一组,转换成一个byte值,写入byte数组。
在分组的过程中要注意:我们在截取字串的时候,如果遇到不足八位的情况,就在其前面补零,并用byte的最后一个元素表示其补零的个数。
6.将码表和byte数组写入文件,压缩就此完成!~!~
例外: 解压缩正好是压缩的逆过程...
下面附上我的代码:
ps:楼主代码仅供参考,我想表达的主要是自己解决这个问题的思路,代码也未经过多优化。且解决问题的方法多种多样,有好有坏,有效率高的也有效率低的。你有更好的方法,欢迎提出来,欢迎吐槽,大家一起学习,一起进步!
import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.math.BigInteger; import java.util.ArrayList; import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.PriorityQueue; import java.util.Random; /** * 哈弗曼压缩 * * @author 吴泽鑫 2013.5.14 * */ public class HuffmanCompress { // 保存从文件中读取的内容 private static StringBuffer str = new StringBuffer(); // 编码的字串 private static StringBuffer code_string; // 对编码字串进行八位一组解析后,所生成byte数组 private static byte[] code_bytes; /** * * @param path * 目标文件的路径 * @return 将文件中的内容读入到StringBuffer中,并返回 */ public StringBuffer readfile(String path) { File file = new File(path); int temp; char c; // 创建文件输入流 try { // 创建文件如数流 FileInputStream fin = new FileInputStream(file); // 封装InputStreamReader InputStreamReader iread = new InputStreamReader(fin); // 创建文件输出流 FileOutputStream fou = new FileOutputStream(new File( "src\\新建 Microsoft Word 文档2.doc")); // 利用循环读取文件里面的内容 将内容保存至str中 while ((temp = iread.read()) != -1) { str.append((char) temp); } } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } public StringBuffer getStr() { return str; } public static void main(String[] args) { HuffmanCompress huffmancompress = new HuffmanCompress(); // 讀取文件內容,存入StringBuffered中 huffmancompress.readfile("src\\新建 文本文档.txt"); System.out.print(str + "长度:" + str.length()); // 新建一个HashMap String:统计的字符 Integer:出现的频次 Map<String, Integer> map = new HashMap<String, Integer>(); // 统计字符个数 map = huffmancompress.countchar(str, map); // 根据map,生成一课哈树 HuffmanNode root = huffmancompress.CreatHTree(map); // System.out.println("【map的大小】-> " + map.size()); // 创建一个码表 List<HuffmanNode> coad_list = new ArrayList<HuffmanNode>(); // 给哈树进行编码 coad_list = huffmancompress.SetCode(root, coad_list); // System.out.println("【coad_list的长度】-> " + coad_list.size()); // System.out.println("【叶子节点" + "个数】-> " + coad_list.size() // + "【数据内容如下:(key,count,coad)】"); for (int i = 0; i < coad_list.size(); i++) { // 小处理: 消除第一个根节点的0,这个0无用。 coad_list.get(i).setCode( coad_list.get(i).getCode() .substring(1, coad_list.get(i).getCode().length())); System.out.println(coad_list.get(i).getKey() + " " + coad_list.get(i).getValue() + " " + coad_list.get(i).getCode()); } // 将文件内容转换成编码字串 code_string = huffmancompress.ToCode(str, coad_list); // System.out.println("\n编码字串为:" + code_string); // 将编码字串按八位一组转换成byte,存入byte数组中区 code_bytes = HuffmanCompress.SaveToBytes(code_string, coad_list); // 压缩 HuffmanCompress.CompressFile("新建 文本文档2.txt", coad_list); // 解压缩 HuffmanCompress.UnZip("新建 文本文档2.txt", "src\\新建 文本文档3.txt"); // 打印所生成的哈树 // huffmancompress.printhuffman(root); } /** * 解压缩过程 * * @param path_source * 需要进行解压缩的文件的路径 * @param path_object * 转换后所形成的新的文件的路径 */ private static void UnZip(String path_source, String path_object) { try { // 创建文件输入流 ObjectInputStream ofin = new ObjectInputStream(new FileInputStream( path_source)); // 创建文件输出流 FileOutputStream ofout = new FileOutputStream(path_object); try { // 读取文件的码表——>需修改 本例测试 List<HuffmanNode> coad_list = new ArrayList<HuffmanNode>(); coad_list = (List<HuffmanNode>) ofin.readObject(); System.out.println("测试---获取码表的长度" + coad_list.size()); System.out.println("测试---获取码表的數字" + coad_list.get(0).getKey() + coad_list.get(0).getValue() + " " + coad_list.get(0).getCode()); // 读取压缩文件的内容 byte[] bytes = new byte[code_bytes.length]; ofin.read(bytes); System.out.println("测试---获取压缩文件内容的长度" + bytes.length); System.out.println("测试---获取压缩文件内容为:" + bytes[0]); System.out.println("测试---获取压缩文件内容为:" + bytes[1]); // System.out.println("测试---获取压缩文件内容为(补零个数):" + bytes[2]); // 将获取的压缩文件的内容转换成Sring编码二进制字串 賦予str StringBuffer str = new StringBuffer(); for (int i = 0; i < bytes.length; i++) { str.append(changetoString(bytes[i])); } System.out.println("还原字串编码为:" + str); // 根据码表,将二进制编码字串转换成对应的数据 changtoChar(str.toString(), ofout, coad_list); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * * @param str * @param ofout * @param coad_list */ private static void changtoChar(String str, FileOutputStream ofout, List<HuffmanNode> coad_list) { System.out.println("还原字串编码为:" + str); StringBuffer sb = new StringBuffer(); // 保存最后一个8位字串前面补零的个数 默认为0个 int count = 0; // 截取最后8为数据 最后八位数据表示补零的个数 String t = str.substring(str.length() - 8); count = changetobyte(t); System.out.println("源码:" + str + "最后8位:" + t + "\n补零个数为:" + changetobyte(t)); str = str.substring(0, str.length() - 8); System.out.println("取出最后8位后:" + str + "\n补零个数为:" + changetobyte(t)); // 根據count记录的补零个数,除去多余的0 String s1 = str.substring(0, str.length() - 8); String s2 = str.substring(str.length() - 8); s2 = s2.substring(count); System.out.print("最后一位" + s2); str = s1 + s2; System.out.print("最后" + str); for (int i = 0; i < str.length(); i++) { // 取出以为字串编码 char c = str.charAt(i); sb.append(c); String s = sb.toString(); int j; // 判断是否能在码表中找到对应的 for (j = 0; j < coad_list.size(); j++) { if (s.equals(coad_list.get(j).getCode())) { System.out.print(coad_list.get(j).getKey()); try { ofout.write(coad_list.get(j).getKey().getBytes()); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } sb.setLength(0); break; } } } } private static String changetoString(byte b) { int m = b; if (m < 0) { m *= -1; } // 用于保存转换后形成的二进制 String s = ""; // 用于不足8位是补0 StringBuffer s2 = new StringBuffer(); // 用于补符号位 0 (正数)或 1(负数) StringBuffer s3 = new StringBuffer(); // 补零位数 byte lack = 0; while (m > 0) { s = m % 2 + s; m = m / 2; } if (s.length() < 8) { lack = (byte) (8 - s.length()); for (int i = lack; i > 0; i--) { s2.append('0'); } } if (b < 0) { s2.setCharAt(0, '1'); } s = s2.append(s).toString(); // s += s2; System.out.println(b + " 二进制 " + s + "长度" + s.length()); return s; } /** * 文件压缩方法 * @param path 所产生的压缩文件的路径 * @param coad_list 码表 */ private static void CompressFile(String path, List<HuffmanNode> coad_list) { try { // 創建一個ObjectOutputStream對象輸出流 ObjectOutputStream ofout = new ObjectOutputStream( new FileOutputStream(path)); // 将码表写入文件 ofout.writeObject(coad_list); // 将压缩后的内容写入文件 ofout.write(code_bytes); // 强制写入 ofout.flush(); // 关闭流 ofout.close(); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * 将编码字串按八位一组转换成byte,存入byte数组中区 * * @param code_string * 字符编码串 * @param coad_list * 码表 * @return */ private static byte[] SaveToBytes(StringBuffer code_string, List<HuffmanNode> coad_list) { // 获取编码字串的长度 int length = code_string.length(); // 用于保存下表 int index = 0; // 统计补零的个数 默認為0個 byte lack = 0; String code = code_string.toString(); // 判断其长度是否为8(位)的倍数,确定byte数组的长度 if (length % 8 == 0) { code_bytes = new byte[length / 8 + 1]; } else { code_bytes = new byte[(length / 8) + 2]; } // System.out.println("code的长度" + code.length()); while (code.length() > 1) { if (code.length() >= 8) {// 当长度大于等于8时 // 直接截取 8位 装换成byte 存入code_byte数组中去 code_bytes[index] = changetobyte(code.substring(0, 8)); index++; // 将所取出来的8为字串,从字串中出去掉 code = code.substring(8); } else { // 当长度不足8位時 我们需要进行补零,补齐8位 // 算出需要补零的个数 lack = (byte) (8 - code.length()); StringBuffer tempstring = new StringBuffer(); // 开始补零 for (int i = lack; i > 0; i--) { tempstring.append('0'); } // 将补足8位的串补足(前面补零) code = tempstring.append(code).toString(); } } // 将补零的个数也加入到code_bytes数组中 , 为将来解压缩时提供依据 code_bytes[index] = lack; // 返回所生成的byte数组 return code_bytes; } /** * 将二进制字串转换成对应的byte(8位) * * @param s * 带转换成byte的字串 */ private static byte changetobyte(String s) { System.out.println("组装Byte:" + s); // // // /////////////// byte a = (byte) (((byte) s.charAt(1) - 48) * 64 + ((byte) s.charAt(2) - 48) * 32 + ((byte) s.charAt(3) - 48) * 16 + ((byte) s.charAt(4) - 48) * 8 + ((byte) s.charAt(5) - 48) * 4 + ((byte) s.charAt(6) - 48) * 2 + ((byte) s .charAt(7) - 48)); if ((s.charAt(0) - 48) == 1) { a *= -1; } return a; } /** * 将文件内容根据码表转换成编码(0,1)字串 * @param str 文件内容 * @param coad_list 码表 * @return 编码字串 */ private StringBuffer ToCode(StringBuffer str, List<HuffmanNode> coad_list) { // 创建一个缓冲字符串 StringBuffer str2 = new StringBuffer(); // 创建一个字符串 String t = new String(); // 利用循环 每读取一个字符,就对照码表,将其转换成编码,并加入到缓冲字符串str2中 for (int i = 0; i < str.length(); i++) { // 取出字符 char c = str.charAt(i); // 查码表 t = FindCodeTable(c, coad_list); // 存入编码串 str2.append(t); } return str2; } /** * 对照码表 * * @param c * 需要进行对照的字符 * @param coad_list * 码表 * @return */ private String FindCodeTable(char c, List<HuffmanNode> coad_list) { // 从码表中逐个去匹配 找到了就返回他所对应的编码 for (int i = 0; i < coad_list.size(); i++) { if (String.valueOf(c).equals(coad_list.get(i).getKey())) { return coad_list.get(i).getCode(); } } return null; } /** * 给哈树设置编码 * * @param root * 根节点 * @param coad_list * 保存叶子节点的队列(哈希编码有值) * @return coad_list 叶子节点的队列 */ private List<HuffmanNode> SetCode(HuffmanNode root, List<HuffmanNode> coad_list) { if ((root.getLeft_child() == null) && (root.getRight_child() == null)) { // 为叶子节点 coad_list.add(root); } else { // 获取当前节点的哈夫曼编码值 String str = root.getCode(); // 左节点的编码值加上当前节点的编码值 str += root.getLeft_child().getCode(); // 把加后的编码值赋值给左节点 root.getLeft_child().setCode(str); // 递归左节点 SetCode(root.getLeft_child(), coad_list); // 获取当前节点的编码值 String str1 = root.getCode(); // 右节点的编码值加上当前节点的编码值 str1 += root.getRight_child().getCode(); // 把加后的编码值赋值给右节点 root.getRight_child().setCode(str1); // 递归右节点 SetCode(root.getRight_child(), coad_list); } return coad_list; } /** * 打印哈夫曼树 ——> 使用先序遍历(根-左-右) * * @param rootnode * 哈树的根节点 */ private void printhuffman(HuffmanNode rootnode) { // 指定根节点,从根几点开始找 HuffmanNode temp = rootnode; // 打印根节点的值 System.out.println("【" + temp.getKey() + "】" + " " + temp.getValue() + " " + temp.getCode()); if (rootnode.getLeft_child() != null) { temp = rootnode.getLeft_child(); // 递归调用自己,表示只要左节点不为空,就把左节点作为新的根节点继续上边步奏 printhuffman(temp); } if (rootnode.getRight_child() != null) { temp = rootnode.getRight_child(); printhuffman(temp);// 同上 } } /** * 根据Map表中的权值,生成一颗哈树 * * @param map * Map表 * @return 返回哈树的根节点 */ private HuffmanNode CreatHTree(Map<String, Integer> map) { Comparator<HuffmanNode> comparator = new Comparator<HuffmanNode>() { @Override public int compare(HuffmanNode o1, HuffmanNode o2) { int numbera = o1.getValue(); int numberb = o2.getValue(); if (numberb < numbera) { return 1; } else if (numberb > numbera) { return -1; } else { return 0; } } }; PriorityQueue<HuffmanNode> queue = new PriorityQueue<HuffmanNode>( map.size(), comparator); Iterator iter = map.entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = (Map.Entry) iter.next(); HuffmanNode node = new HuffmanNode((String) entry.getKey(), (int) entry.getValue()); queue.add(node); } while (queue.size() != 1) { // 取得两个最小的节点 HuffmanNode node1 = queue.poll(); HuffmanNode node2 = queue.poll(); // 生成一个新的节点 HuffmanNode node3 = new HuffmanNode(node1.getValue() + node2.getValue(), "0"); node3.setLeft_child(node1); node1.setCode("0"); node3.setRight_child(node2); node2.setCode("1"); queue.add(node3); } // 获取哈树根节点 HuffmanNode root = queue.poll(); return root; } /** * 统计文件类容中,各个字符出现的频率,且用Map保存,并返回一个统计结果(Map值) * * @param str * 文件内容 * @param map * 統計結果 * @return map 即各个字符出现的频率情况 */ private Map<String, Integer> countchar(StringBuffer str, Map<String, Integer> map) { System.out.println(); char c; for (int i = 0; i < str.length(); i++) { c = str.charAt(i); String key = String.valueOf(c); if (map.containsKey(key)) { map.put(key, map.get(key) + 1); } else map.put(key, 1); } // map遍历输出 Iterator iter = map.entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = (Map.Entry) iter.next(); String s = (String) entry.getKey(); int n = (int) entry.getValue(); System.out.println(s + " " + n); } return map; } }
节点类:
import java.io.Serializable; /** * 哈夫曼树节点的定义 * * @author Administrator * */ public class HuffmanNode implements Serializable { // 成员属性 private HuffmanNode left_child = null; private HuffmanNode right_child = null; private HuffmanNode parend = null; // 权值 private int value; // key值 private String key; // 哈弗曼编码 private String code; public String getCode() { return code; } public void setCode(String code) { this.code = code; } // 构造函数 public HuffmanNode(String key, int value) { this.value = value; this.key = key; } public HuffmanNode(int value, String code) { this.value = value; this.code = code; } public int getValue() { return value; } public void setValue(int value) { this.value = value; } public String getKey() { return key; } public void setKey(String key) { this.key = key; } public HuffmanNode getLeft_child() { return left_child; } public void setLeft_child(HuffmanNode left_child) { this.left_child = left_child; } public HuffmanNode getRight_child() { return right_child; } public void setRight_child(HuffmanNode right_child) { this.right_child = right_child; } public HuffmanNode getParend() { return parend; } public void setParend(HuffmanNode parend) { this.parend = parend; } }
哈弗曼压缩程序写完之后你会发现,当文件内容不是很多的时候,或是重复的频次过于多的时候,压缩后的大小反倒比没压缩的时候大,尤其是重复的频次过多时,解压时反到可能会出错。当然哈弗曼编码的效率也很值得商榷。 以及我的这个程序只能针对TXT类型的文本,对于doc、xls、ppt又或是其他图片文件的压缩也是不支持的,还有多文件、文件夹的整合压缩都还没有实现的诸多问题,在日后的过程中需要慢慢的完善。
作为我们这种还在学校里面混的菜鸟,自信一定是要有的,要敢去想敢去写。大神牛人们花一天能弄好的程序,我们多花点时间,也能做好,不去尝试就永远都不会。也许我们的代码执行的效率没有他们高,程序也没有他们优化的好,程序结构也不明显,可维护性差,bug也很多...但这也是一个过程,哪个牛人不是从小菜鸟走过来的呢~!~
相关推荐
在Java编程语言中,文件的压缩与解压缩是常见的数据处理操作,特别是在数据传输、存储优化和备份场景中。本实践项目围绕这个主题展开,包括源代码和相关的论文,为学习者提供了深入理解和应用Java压缩库的机会。以下...
《基于Huffman编码的文件压缩与解压缩》 在数据结构课程设计中,Huffman编码是一种常见的用于数据压缩的技术,其原理是通过构建最优的二叉树(Huffman树)来为每个字符分配唯一的二进制编码,从而实现高效的数据...
在IT行业中,文件压缩与解压缩是日常工作中常见的操作,特别是在数据传输、存储优化和软件分发等领域。这里我们主要探讨的是一个简单的工具类,它支持zip、rar、tar等多种格式的压缩和解压缩功能,并且经过实际测试...
虽然这不是直接关于压缩解压缩的主题,但如果你的代码实例中包含使用FreeMarker生成压缩包的说明,这可能是一个重要的参考资源,例如,利用FreeMarker动态生成压缩文件内容。 至于“工作记录”,这可能包含你在实现...
JAVA文件压缩与解压缩实践(源代码+论文) JAVA文件压缩与解压缩实践(源代码+论文) JAVA文件压缩与解压缩实践(源代码+论文) JAVA文件压缩与解压缩实践(源代码+论文) JAVA文件压缩与解压缩实践(源代码+论文) JAVA文件...
JAVA文件压缩与解压缩实践(源代码).zipJAVA文件压缩与解压缩实践(源代码).zipJAVA文件压缩与解压缩实践(源代码).zipJAVA文件压缩与解压缩实践(源代码).zipJAVA文件压缩与解压缩实践(源代码).zipJAVA文件压缩与解压缩...
JAVA文件压缩与解压缩实践(源代码+LW)JAVA文件压缩与解压缩实践(源代码+LW)JAVA文件压缩与解压缩实践(源代码+LW)JAVA文件压缩与解压缩实践(源代码+LW)JAVA文件压缩与解压缩实践(源代码+LW)JAVA文件压缩与解压缩实践...
JAVA文件压缩与解压缩实践(源代码+论文)JAVA文件压缩与解压缩实践(源代码+论文)JAVA文件压缩与解压缩实践(源代码+论文)JAVA文件压缩与解压缩实践(源代码+论文)JAVA文件压缩与解压缩实践(源代码+论文)JAVA文件压缩与...
JAVA文件压缩与解压缩实践(源代码+lw).rarJAVA文件压缩与解压缩实践(源代码+lw).rarJAVA文件压缩与解压缩实践(源代码+lw).rarJAVA文件压缩与解...实践(源代码+lw).rarJAVA文件压缩与解压缩实践(源代码+lw).rarJAVA文件
(Java毕业设计)JAVA文件压缩与解压缩实践(Java毕业设计)JAVA文件压缩与解压缩实践(Java毕业设计)JAVA文件压缩与解压缩实践(Java毕业设计)JAVA文件压缩与解压缩实践(Java毕业设计)JAVA文件压缩与解压缩实践(Java毕业...
适合练手、课程设计、毕业设计的Java项目源码:文件压缩与解压缩实践(源代码+论文).rar 适合练手、课程设计、毕业设计的Java项目源码:文件压缩与解压缩实践(源代码+论文).rar 适合练手、课程设计、毕业设计的Java...
java毕业设计——java文件压缩与解压缩实践设计与开发(源代码+论文).zip java毕业设计——java文件压缩与解压缩实践设计与开发(源代码+论文).zip java毕业设计——java文件压缩与解压缩实践设计与开发(源代码+论文)....
javaweb毕业设计-JAVA文件压缩与解压缩实践(源代码+lw)(可做课程设计).rarjavaweb毕业设计-JAVA文件压缩与解压缩实践(源代码+lw)(可做课程设计).rarjavaweb毕业设计-JAVA文件压缩与解压缩实践(源代码+lw)(可做课程...
如果服务器上安装了RAR程序,那么asp.net可以调用RAR实现文件压缩与解压缩。 不过要注意的是,由于Web程序不能直接调用客户端的程序(除非用ActiveX,ActiveX几乎被废弃),所以如果要想实现让用户把本地文件用网页...
在"基于哈夫曼编码的文本文件压缩与解压缩"项目中,使用C语言实现这一过程。首先,我们需要分析文本文件中的字符频率,这通常通过遍历整个文本文件计算每个字符的出现次数来完成。接着,根据字符频率构建哈夫曼树。...
Java文件压缩与解压缩实践是指利用Java编程语言实现对文件或文件夹进行压缩和解压缩操作。以下是该实践的描述: 技术概述: Java文件压缩与解压缩是指将一个或多个文件或文件夹打包成一个压缩文件,或者将压缩文件...