前言我们利用前面写的哈夫曼树哈夫曼编码实现一个文本压缩工具我们将文本转化为0,1二进制编码这些编码数字都是比特单位一个字节转化为八个比特从而实现文本的压缩但是得注意最后的几个编码不满8位得用0补齐。整体流程读取文件-统计字符频次→构建哈夫曼树→生成字符编码→原文转二进制码流→二进制串转字节写入压缩文件。1.利用main函数去点用各个函数在上次的文本读取之上有所改善publicstaticvoidmain(String[]args){CompresshfmnewCompress();hfm.readData();hfm.setCode(hfm.root,);hfm.dataToCode();}2.在readData中添加一个data保存原始数据datastringBuilder.toString();避免原始数据编码统计被污染3.dataToCode () bitToByte ()可以实现01编码的拼接以及比特编码转化为字节实现压缩//把源文件数据替换成编码数据publicvoiddataToCode(){StringBuilderstringBuildernewStringBuilder();for(inti0;idata.length();i){charcdata.charAt(i);//取出对应字符的编码StringcodecodeMap.get(c);stringBuilder.append(code);}System.out.println(data:stringBuilder.toString());try{bitToByte(stringBuilder);}catch(Exceptione){thrownewRuntimeException(e);}}//把编码数据(二进制数据)每8个一组转成byte写入文件//除了保存编码数据还需要保存字典(每个字符对应的编码)publicvoidbitToByte(StringBuilderstringBuilder)throwsException{//创建文件字符流把压缩后的字节数据写入文件FilefilenewFile(D:\\IdeaProjects\\java02\\src\\hfm0718\\data.txt);//文件字节流FileOutputStreamfosnewFileOutputStream(file);intlenstringBuilder.length();//计算最后一个字节是否需要补位intlast(8-len%8)%8;//补齐最后的数据for(inti0;ilast;i){stringBuilder.append(0);}//计算有多少字节数据intbyteLenstringBuilder.length()/8;//从stringBuilder分割出所有的字节数据for(inti0;ibyteLen;i){StringstrstringBuilder.substring(i*8,(i1)*8);//左开(包含) 右闭(不包含)//把二进制数据转成byteintdataInteger.parseInt(str,2);//把当前数据写入文件fos.write(data);fos.flush();}//把最后补位的长度写入文件fos.write(last);fos.flush();}//计算最后一个字节是否需要补位intlast(8-len%8)%8;//补齐最后的数据for(inti0;ilast;i){stringBuilder.append(0);}这个值得记忆性学习可以最外面这个取余8直接处理刚好整除的边界情况即不用补位的时候否则需要写if去分类讨论。//创建文件字节流把压缩后的字节数据写入文件FilefilenewFile(D:\\IdeaProjects\\java02\\src\\hfm0718\\data.txt);//文件字节流FileOutputStreamfosnewFileOutputStream(file);创建的字节流用于接受压缩后的文件数据。以下为压缩前后的对比实现了一定的压缩。但是效率并不算高还需要改进。以下为完整代码publicclassCompress{publicTreeNoderoot;publicStringdata;//读取到源文件数据publicMapString,StringcodeMapnewHashMap();//码表//统计字符的频率publicvoidreadData(){//读取指定文件的数据StringpathC:\\Users\\52073\\Downloads\\数据结构模拟题一 (1).doc;FilefilenewFile(path);try{//每次读取文件的一行字符BufferedReaderbrnewBufferedReader(newFileReader(file));StringBuilderstringBuildernewStringBuilder();Stringline;while((linebr.readLine())!null){stringBuilder.append(line).append(\r\n);}datastringBuilder.toString();// System.out.println(data: data);}catch(Exceptione){thrownewRuntimeException(e);}//读取数据MapString,IntegermapnewHashMap();//遍历data的每个字符for(inti0;idata.length();i){charcdata.charAt(i);//检查是否存在当前keyif(map.containsKey(c)){map.put(c,map.get(c)1);}else{map.put(c,1);}}//保存所有的节点对象ListTreeNodenodeListnewArrayList();//遍历map,创建对应的节点for(Map.EntryString,Integerentry:map.entrySet()){TreeNodenodenewTreeNode(entry.getValue(),entry.getKey());nodeList.add(node);}//建树createTree(nodeList);}//对象nodeList排序(升序):插入排序冒泡排序快排publicvoidsort(ListTreeNodenodeList){for(inti0;inodeList.size();i){for(intj0;jnodeList.size()-1;j){if(nodeList.get(j).datanodeList.get(j1).data){TreeNodetempnodeList.get(j);nodeList.set(j,nodeList.get(j1));nodeList.set(j1,temp);}}}}publicvoidcreateTree(ListTreeNodenodeList){while(nodeList.size()1){//先对nodeList排序sort(nodeList);//找出最小的两个节点TreeNodeleftnodeList.remove(0);TreeNoderightnodeList.remove(0);//构建子树TreeNodenodenewTreeNode(left.dataright.data);node.leftleft;node.rightright;//把新节点添加到集合中nodeList.add(node);}rootnodeList.remove(0);}//设置编码:左0 右1publicvoidsetCode(TreeNodenode,Stringcode){if(nodenull)return;//记录叶子节点上的编码if(node.rightnullnode.leftnull){node.codecode;codeMap.put(node.c,node.code);// System.out.println(node.c node.code);}setCode(node.left,code0);setCode(node.right,code1);}//把源文件数据替换成编码数据publicvoiddataToCode(){StringBuilderstringBuildernewStringBuilder();for(inti0;idata.length();i){charcdata.charAt(i);//取出对应字符的编码StringcodecodeMap.get(c);stringBuilder.append(code);}System.out.println(data:stringBuilder.toString());try{bitToByte(stringBuilder);}catch(Exceptione){thrownewRuntimeException(e);}}//把编码数据(二进制数据)每8个一组转成byte写入文件//除了保存编码数据还需要保存字典(每个字符对应的编码)publicvoidbitToByte(StringBuilderstringBuilder)throwsException{//创建文件字符流把压缩后的字节数据写入文件FilefilenewFile(D:\\IdeaProjects\\java02\\src\\hfm0718\\data.txt);//文件字节流FileOutputStreamfosnewFileOutputStream(file);//对象流写入一个整个java 对象到文件中//对象化序化把对象转换成流式数据// ObjectOutputStream oos new ObjectOutputStream(fos);// oos.writeObject(codeMap);// oos.flush();intlenstringBuilder.length();//计算最后一个字节是否需要补位intlast(8-len%8)%8;//补齐最后的数据for(inti0;ilast;i){stringBuilder.append(0);}//计算有多少字节数据intbyteLenstringBuilder.length()/8;//从stringBuilder分割出所有的字节数据for(inti0;ibyteLen;i){StringstrstringBuilder.substring(i*8,(i1)*8);//左开(包含) 右闭(不包含)//把二进制数据转成byteintdataInteger.parseInt(str,2);//把当前数据写入文件fos.write(data);fos.flush();}//把最后补位的长度写入文件fos.write(last);fos.flush();}publicstaticvoidmain(String[]args){CompresshfmnewCompress();hfm.readData();hfm.setCode(hfm.root,);hfm.dataToCode();}}//树的节点classTreeNodeimplementsSerializable{publicintdata;//字符的次publicStringcode;//编码publicStringc;//对应的字符publicTreeNodeleft;publicTreeNoderight;publicTreeNode(){}publicTreeNode(intdata){this.datadata;}publicTreeNode(intdata,Stringc){this.datadata;this.cc;}}