日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

用赫夫曼树进行文件的压缩

發(fā)布時(shí)間:2023/12/3 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 用赫夫曼树进行文件的压缩 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

思路分析

代碼實(shí)現(xiàn)

package com.atguigu.huffmancode;import com.sun.org.glassfish.external.statistics.CountStatistic; import com.sun.org.glassfish.external.statistics.StringStatistic;import javax.xml.bind.SchemaOutputResolver; import java.io.*; import java.security.AlgorithmConstraints; import java.util.*;/*** @創(chuàng)建人 wdl* @創(chuàng)建時(shí)間 2021/3/27* @描述*/ public class HuffmanCode {public static void main(String[] args) {//測試壓縮文件String srcFile="C://Users//王東梁//Desktop//88888888.png";String dstFile="C://Users//王東梁//Desktop//dst.zip";zipFile(srcFile,dstFile);System.out.println("壓縮文件成功");// String content="i like like like java do you like a java"; // byte[] contentBytes = content.getBytes(); // System.out.println(contentBytes.length);//40 // // byte[] huffmanCodesBytes = huffmanZip(contentBytes); // System.out.println("壓縮后的結(jié)果"+Arrays.toString(huffmanCodesBytes)+huffmanCodesBytes.length); // // //測試一把byteToBitString方法 // byte[] sourceBytes = decode(huffmanCodes, huffmanCodesBytes); // System.out.println(new String(sourceBytes));// // List<Node> nodes = getNodes(contentBytes); // System.out.println(nodes); // // //測試一把,創(chuàng)建的二叉樹 // System.out.println("赫夫曼樹"); // Node huffmanTreeRoot = createHuffmanTree(nodes); // System.out.println("前序遍歷"); // huffmanTreeRoot.preOrder(); // // //測試一把是否生成了對(duì)應(yīng)的赫夫曼編碼 // Map<Byte, String> huffmanCodes = getCodes(huffmanTreeRoot); // System.out.println("生成的赫夫曼編碼表"+huffmanCodes); // // //測試 // byte[] huffmanCodeBytes = zip(contentBytes, huffmanCodes); // System.out.println(Arrays.toString(huffmanCodeBytes));//17}//編寫方法,將一個(gè)文件進(jìn)行壓縮/**** @param srcFile 你傳入的希望壓縮的文件的全路徑* @param dstFile 我們壓縮后將壓縮文件放到哪個(gè)目錄*/public static void zipFile(String srcFile,String dstFile){//創(chuàng)建輸出流ObjectOutputStream oos=null;OutputStream os=null;FileInputStream is=null;try {//創(chuàng)建文件的輸入流is = new FileInputStream(srcFile);//創(chuàng)建一個(gè)和源文件大小一樣的byte[]byte[] b = new byte[is.available()];//讀取文件is.read(b);//直接對(duì)源文件進(jìn)行壓縮byte[] huffmanBytes = huffmanZip(b);//創(chuàng)建文件的輸出流,存放壓縮文件os = new FileOutputStream(dstFile);//創(chuàng)建一個(gè)和文件輸入流關(guān)聯(lián)的ObjectOutputStreamoos = new ObjectOutputStream(os);//我們赫夫曼編碼后的字節(jié)數(shù)組寫入壓縮文件oos.writeObject(huffmanBytes);//這里我們以對(duì)象流的方式寫入赫夫曼編碼,是為了以后我們回復(fù)源文件時(shí)使用//注意一定要包赫夫曼編碼寫入壓縮文件oos.writeObject(huffmanCodes);} catch (Exception e) {System.out.println(e.getMessage());} finally {try {is.close();oos.close();os.close();} catch (Exception e) {System.out.println(e.getMessage());}}}//完成數(shù)據(jù)的解壓//思路//1.將huffmanCodeBytes//重現(xiàn)先轉(zhuǎn)成赫夫曼編碼對(duì)應(yīng)的二進(jìn)制的字符串“0100000//2.、將“111"對(duì)照赫夫曼編碼=》i like/**** @param huffmanCodes 哈夫曼編碼表map* @param huffmanBytes 赫夫曼編碼的到的字節(jié)數(shù)組* @return 原來的字符串對(duì)應(yīng)的數(shù)組*///編寫一個(gè)方法,完成對(duì)壓縮數(shù)據(jù)的解碼private static byte[] decode(Map<Byte,String> huffmanCodes,byte[] huffmanBytes){//1.先得到huffmanBytes 對(duì)應(yīng)的二進(jìn)制字符串StringBuilder stringBuilder = new StringBuilder();//將byte數(shù)組轉(zhuǎn)成二進(jìn)制的字符串編碼for (int i = 0; i < huffmanBytes.length; i++) {byte b = huffmanBytes[i];//判斷是不是最后一個(gè)字節(jié)boolean flag=(i==huffmanBytes.length-1);stringBuilder.append( byteToBitString(!flag,b));}//吧字符串按照指定的赫夫曼編碼進(jìn)行解碼//把赫夫曼編碼表進(jìn)行調(diào)換,因?yàn)橐聪虿樵?/span>Map<String, Byte> map = new HashMap<>();for(Map.Entry<Byte, String> entry:huffmanCodes.entrySet()){map.put(entry.getValue(),entry.getKey());} // System.out.println(map);//創(chuàng)建一個(gè)集合,存放byteArrayList<Byte> list = new ArrayList<>();for (int i = 0; i < stringBuilder.length();) {//i可以理解成就是一個(gè)索引,掃描stringBuilderint count=1;//小的計(jì)數(shù)器boolean flag=true;Byte b=null;while (flag){//遞增的取出key 1//取出一個(gè)字符'1' '0'String key = stringBuilder.substring(i, i + count);//i不動(dòng),讓count移動(dòng),直到匹配到一個(gè)字符b=map.get(key);if(b==null){//說明沒有匹配到count++;}else {//匹配到flag=false;}}list.add(b);i+=count;//i直接移動(dòng)到count}//for循環(huán)結(jié)束后,我們list中就存放了所有的字符"i like"//吧list中的數(shù)據(jù)放入到byte數(shù)組并返回byte[] b = new byte[list.size()];for (int i = 0; i < b.length; i++) {b[i]=list.get(i);}return b;}/*** 將一個(gè)byte轉(zhuǎn)成一個(gè)二進(jìn)制的字符串* @param b* @param flag 表示是否需要補(bǔ)高位,如果是true,表示需要補(bǔ)高位,如果是false表示不補(bǔ),如果是最后一個(gè)字節(jié),無需補(bǔ)高位* @return 是該b 對(duì)應(yīng)的二進(jìn)制的字符串,(注意是按補(bǔ)碼返回)*/private static String byteToBitString(boolean flag,byte b){//使用變量保存bint temp=b;//b轉(zhuǎn)成int//如果是正數(shù)我們還存在補(bǔ)高位的問題if(flag){temp|=256;}String str = Integer.toBinaryString(temp);//返回的是temp對(duì)應(yīng)的二進(jìn)制補(bǔ)碼if(flag){return str.substring(str.length()-8);}else {return str;}}//使用一個(gè)方法,將前面的方法封裝起來,便于我們的調(diào)用/**** @param bytes 原始的字符串對(duì)應(yīng)的字節(jié)數(shù)組* @return 是經(jīng)過赫夫曼編碼處理后的子節(jié)數(shù)組(壓縮后的數(shù)組)*/private static byte[] huffmanZip(byte[] bytes){List<Node> nodes = getNodes(bytes);//根據(jù)nodes創(chuàng)建赫夫曼樹Node huffmanTreeRoot = createHuffmanTree(nodes);//生成了對(duì)應(yīng)的赫夫曼編碼Map<Byte, String> huffmanCodes = getCodes(huffmanTreeRoot);//根據(jù)生成的赫夫曼編碼,壓縮的到壓縮后的赫夫曼編碼字節(jié)數(shù)組byte[] huffmanCodeBytes = zip(bytes, huffmanCodes);return huffmanCodeBytes;}/**** @param bytes 這時(shí)原始的字符串對(duì)應(yīng)的byte[]* @param huffmanCodes 生成的赫夫曼編碼map* @return 返回赫夫曼編碼表處理后的byte[]*///編寫一個(gè)方法,將字符串對(duì)應(yīng)的byte[]數(shù)組,通過生成的赫夫曼編碼表,返回一個(gè)赫夫曼編碼壓縮有的byte[]private static byte[] zip(byte[] bytes,Map<Byte,String> huffmanCodes){//1.先利用huffmanCodes將bytes轉(zhuǎn)成赫夫曼編碼對(duì)應(yīng)的字符串StringBuilder stringBuilder = new StringBuilder();//遍歷bytes數(shù)組for(byte b:bytes){stringBuilder.append(huffmanCodes.get(b));}System.out.println("測試stringBuilder="+stringBuilder.toString());//將1010111011 轉(zhuǎn)成byte數(shù)組//統(tǒng)計(jì)返回byte[] huffmanCodeBytes 長度//一句話 int len=(stringBuilder.length()+7)/8int len;if(stringBuilder.length()%8==0){len=stringBuilder.length()/8;}else {len=stringBuilder.length()/8+1;}//創(chuàng)建存儲(chǔ)壓縮有的byte[]byte[] huffmanCodeBytes=new byte[len];int index=0;//記錄是第幾個(gè)bytefor (int i = 0; i < stringBuilder.length(); i+=8) {//因?yàn)槊?位對(duì)應(yīng)一個(gè)byte,所以步長+8String strByte;if(i+8>stringBuilder.length()){//不夠8位strByte = stringBuilder.substring(i);}else {strByte = stringBuilder.substring(i, i + 8);}//將strByte轉(zhuǎn)成一個(gè)byte,放入到huffmanCodeByteshuffmanCodeBytes[index]= (byte) Integer.parseInt(strByte,2);index++;}return huffmanCodeBytes;}//生成赫夫曼樹對(duì)應(yīng)的赫夫曼編碼//思路://1.將赫夫曼編碼表存放在Map<Byte,String>形式static Map<Byte,String> huffmanCodes= new HashMap<Byte,String>();// 32->01 97->100...//2.在生成赫夫曼編碼表示,需要去拼接璐姐,定義一個(gè)StringBuilder存儲(chǔ)某個(gè)葉子結(jié)點(diǎn)的路徑static StringBuilder stringBuilder=new StringBuilder();//這里為了調(diào)用方便,我們重載getCodesprivate static Map<Byte,String> getCodes(Node root){if(root==null){return null;}//處理root的左子樹getCodes(root.left,"0",stringBuilder);//處理root的右子樹getCodes(root.right,"1",stringBuilder);return huffmanCodes;}/*** 功能:將傳入的node節(jié)點(diǎn)的所有葉子節(jié)點(diǎn)的赫夫曼編碼的到,并放入到huffmanCodes集合* @param node 傳入節(jié)點(diǎn)* @param code 路徑:左子節(jié)點(diǎn)是0,右子節(jié)點(diǎn)是1* @param stringBuilder 是用于拼接路徑*/private static void getCodes(Node node,String code,StringBuilder stringBuilder){StringBuilder stringBuilder2 = new StringBuilder(stringBuilder);//將code加入到stringBuild2stringBuilder2.append(code);if(node!=null){//如果node==null不處理//判斷當(dāng)前node是葉子結(jié)點(diǎn)還是非葉子節(jié)點(diǎn)if(node.data==null){//非葉子節(jié)點(diǎn)//遞歸處理//向左getCodes(node.left,"0",stringBuilder2);//向右getCodes(node.right,"1",stringBuilder2);}else {//說明是一個(gè)葉子結(jié)點(diǎn)//表示找到了某個(gè)葉子節(jié)點(diǎn)的最后huffmanCodes.put(node.data,stringBuilder2.toString());}}}//前序遍歷的方法private static void preOrder(Node root){if(root!=null){root.preOrder();}else {System.out.println("赫夫曼樹為空");}}/**** @param bytes 接收字節(jié)數(shù)組* @return 返回的就是List形式*/private static List<Node> getNodes(byte[] bytes){//1.創(chuàng)建一個(gè)ArrayListArrayList<Node> nodes = new ArrayList<>();//遍歷bytes 統(tǒng)計(jì)每一個(gè)byte出現(xiàn)的次數(shù)->map[key,value]HashMap<Byte, Integer> counts = new HashMap<>();for(byte b:bytes){Integer count=counts.get(b);if (count==null){//map中還沒有這個(gè)字符數(shù)據(jù),第一次counts.put(b,1);}else {counts.put(b,count+1);}}//把每一個(gè)鍵值對(duì)轉(zhuǎn)成Node對(duì)象,并加入到nodes集合//遍歷mapfor(Map.Entry<Byte,Integer> entry:counts.entrySet()){nodes.add(new Node(entry.getKey(),entry.getValue()));}return nodes;}//可以通過List創(chuàng)建對(duì)應(yīng)的赫夫曼樹private static Node createHuffmanTree(List<Node> nodes){while (nodes.size()>1){//排序,從小到大Collections.sort(nodes);//取出第一顆最小的二叉樹Node leftNode = nodes.get(0);//取出第二顆最小的二叉樹Node rightNode = nodes.get(1);//創(chuàng)建一顆新的二叉樹,它的根節(jié)點(diǎn)沒有data,只有權(quán)值Node parent=new Node(null,leftNode.weight+rightNode.weight);parent.left=leftNode;parent.right=rightNode;//將已經(jīng)處理的兩顆二叉樹從nodes刪除nodes.remove(leftNode);nodes.remove(rightNode);//將新的二叉樹,加入到nodesnodes.add(parent);}//nodes最后的節(jié)點(diǎn),就是哈夫曼樹的根節(jié)點(diǎn)return nodes.get(0);}}//創(chuàng)建Node,待數(shù)據(jù)和權(quán)值 class Node implements Comparable<Node>{Byte data;//存放數(shù)據(jù)(字符)本身,比如'a'=>97 ' '=>32int weight;//權(quán)值,表示字符出現(xiàn)的次數(shù)Node left;Node right;public Node(Byte data, int weight) {this.data = data;this.weight = weight;}@Overridepublic int compareTo(Node o) {//從小到大排序return this.weight-o.weight;}@Overridepublic String toString() {return "Node{" +"data=" + data +", weight=" + weight +'}';}//前序遍歷public void preOrder(){System.out.println(this);if(this.left!=null){this.left.preOrder();}if (this.right!=null){this.right.preOrder();}}}

總結(jié)

以上是生活随笔為你收集整理的用赫夫曼树进行文件的压缩的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。