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

歡迎訪問(wèn) 生活随笔!

生活随笔

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

编程问答

算法 - 赫夫曼编码(对字符串进行压缩 与 解压(解码)) - (对文件进行压缩解压)

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



1.壓縮:使用赫夫曼編碼進(jìn)行壓縮



題目

構(gòu)建赫夫曼樹(shù)

package tree.huffmantree;import java.util.*;public class HuffmanCode {public static void main(String[] args) {String content = "i like like like java do you like a java";byte [] contentBytes = content.getBytes();System.out.println(contentBytes.length);List<Node1> nodes = getNodes(contentBytes);//System.out.println(nodes);//測(cè)試創(chuàng)建二叉樹(shù)Node1 huffmanTree = createHuffmanTree(nodes);//前序遍歷preOrder(huffmanTree);}//前序遍歷public static void preOrder(Node1 root){if (root != null){root.preOrder();}else {System.out.println("赫夫曼樹(shù)為空");}}private static List<Node1> getNodes(byte [] bytes){//1.創(chuàng)建ArrayListArrayList<Node1> node1s = new ArrayList<>();//遍歷bytes 統(tǒng)計(jì)乜咯 byte出現(xiàn)的次數(shù),存儲(chǔ)每個(gè)byte出現(xiàn)的次數(shù) -> mapMap<Byte,Integer> counts = new HashMap<>();for (byte b : bytes){Integer count = counts.get(b);if (count == null){ //說(shuō)明map中還沒(méi)有這個(gè)字符counts.put(b,1);}else {counts.put(b,count+1);}}//把每個(gè)鍵值對(duì)轉(zhuǎn)成一個(gè)Node對(duì)象,并加入到nodes集合//遍歷mapfor (Map.Entry<Byte,Integer> entry : counts.entrySet()){node1s.add(new Node1(entry.getKey(),entry.getValue()));}return node1s;}//通過(guò)List創(chuàng)建赫夫曼樹(shù)private static Node1 createHuffmanTree(List<Node1> nodes){while (nodes.size() > 1){//排序 從小到大Collections.sort(nodes);//取出第一顆、第二顆最小的二叉樹(shù)Node1 leftNode = nodes.get(0);Node1 rightNode = nodes.get(1);//創(chuàng)建新的二叉樹(shù),新的二叉樹(shù)沒(méi)有數(shù)據(jù),只有權(quán)值Node1 parent = new Node1(null,leftNode.weight + rightNode.weight);parent.left = leftNode;parent.right = rightNode;//將0,1移除Listnodes.remove(leftNode);nodes.remove(rightNode);//parent加入Listnodes.add(parent);}//nodes最后剩余就是哈弗曼樹(shù)的根節(jié)點(diǎn)return nodes.get(0);} } class Node1 implements Comparable<Node1>{Byte data; //存放數(shù)據(jù) 按照asciiint weight; //權(quán)值,表示字符出現(xiàn)的次數(shù)Node1 left;Node1 right;//前序遍歷public void preOrder(){System.out.println(this);if (this.left != null){this.left.preOrder();}if (this.right != null){this.right.preOrder();}}@Overridepublic int compareTo(Node1 o) {return this.weight - o.weight;}public Node1(Byte data, int weight) {this.data = data;this.weight = weight;}@Overridepublic String toString() {return "Node1{" +"data=" + data +", weight=" + weight +'}';} }

//生成赫夫曼樹(shù)對(duì)應(yīng)的赫夫曼編碼//思路://1.將赫夫曼編碼表存放在Map<Byte,String> 形式//32->01 97->100 100->11000等等static Map<Byte,String> huffmanCodes = new HashMap<>();//2.在生成赫夫曼編碼表時(shí)需要拼接路徑,創(chuàng)建Stringbuilder存儲(chǔ)某個(gè)葉子節(jié)點(diǎn)的路徑static StringBuilder stringBuilder = new StringBuilder();/*** 功能:將傳入的node節(jié)點(diǎn)的所有葉子節(jié)點(diǎn)赫夫曼編碼得到,并放入到赫夫曼集合中* @param node 傳入節(jié)點(diǎn)* @param code 路徑:左子節(jié)點(diǎn)是0,右子節(jié)點(diǎn)是1* @param stringBuilder 是用于拼接路徑*/private static void getCondes(Node1 node,String code, StringBuilder stringBuilder){StringBuilder stringBuilder2 = new StringBuilder(stringBuilder);//將傳入的code加入到Stringbuilder2stringBuilder2.append(code);if (node != null){//判斷當(dāng)前node是葉子節(jié)點(diǎn)還是非葉子節(jié)點(diǎn)if (node.data == null){ //說(shuō)明是非葉子節(jié)點(diǎn)//遞歸處理//向左遞歸getCondes(node.left,"0",stringBuilder2);//向右遞歸getCondes(node.right,"1",stringBuilder2);}else {//說(shuō)明是葉子節(jié)點(diǎn)//就表示找到了某個(gè)葉子節(jié)點(diǎn)最后huffmanCodes.put(node.data,stringBuilder2.toString());}}}

//編寫(xiě)一個(gè)方法,將字符串對(duì)應(yīng)的byte[]數(shù)組,通過(guò)生成的赫夫曼編碼表,返回赫夫曼編碼壓縮后的byte[]/**** @param bytes 原始的字符對(duì)應(yīng)的byte[]* @param huffmanCodes 生成的赫夫曼編碼表map* @return 返回赫夫曼編碼處理后的byte[]* 舉例:String content = "i like like like java do you like a java";* 返回的是字符串"10101000"。。。等等* =>對(duì)應(yīng)byte[] huffmancodeBytes,即8位對(duì)應(yīng)一個(gè)byte,放入到huffmanCodeBytes* huffmancodeBytes[0] = 10101000(補(bǔ)碼) => byte [推導(dǎo) 10101000 => 10101000 -1 => 10100111(反碼) => 11011000(原碼)]* huffmancodeBytes[1] = -88*/private static byte[] zip(byte [] bytes, Map<Byte,String> huffmanCodes){//1.利用赫夫曼編碼表將傳進(jìn)來(lái)的byte數(shù)組轉(zhuǎn)成赫夫曼編碼字符串StringBuilder stringBuilder = new StringBuilder();//遍歷bytes數(shù)組for (byte b : bytes){stringBuilder.append(huffmanCodes.get(b));}//按照這個(gè)字符串發(fā)送肯定是變大了,不行,那么就要將字符串轉(zhuǎn)成byte數(shù)組System.out.println(stringBuilder.toString());//統(tǒng)計(jì)返回的byte[] huffmanCodeBytes 長(zhǎng)度//一句話搞定int len = (stringBuilder.length() + 7) / 8;int len;if (stringBuilder.length() % 8 == 0){len = stringBuilder.length() /8;}else {len = stringBuilder.length() /8 + 1;}//創(chuàng)建存儲(chǔ)壓縮后的byte數(shù)組byte [] huffmanCodeBytes = new byte[len];int index = 0;//記錄是第幾個(gè)bytefor (int i = 0; i < stringBuilder.length(); i += 8){//因?yàn)槊?位對(duì)應(yīng)一個(gè)byteString strByte;if (i+8 <= stringBuilder.length()){strByte = stringBuilder.substring(i,i+8);}else {strByte = stringBuilder.substring(i); //-88}//將StringByte轉(zhuǎn)成byte數(shù)組放入到huffmanCodeByteshuffmanCodeBytes[index] = (byte) Integer.parseInt(strByte,2);index++;}return huffmanCodeBytes;}

完整代碼

package tree.huffmantree;import java.util.*;public class HuffmanCode {public static void main(String[] args) {String content = "i like like like java do you like a java";byte [] contentBytes = content.getBytes();byte[] bytes = huffmanZip(contentBytes);System.out.println("壓縮后的結(jié)果: " + Arrays.toString(bytes));// System.out.println(contentBytes.length); // // List<Node1> nodes = getNodes(contentBytes); // //System.out.println(nodes); // // //測(cè)試創(chuàng)建二叉樹(shù) // Node1 huffmanTree = createHuffmanTree(nodes); // //前序遍歷 // preOrder(huffmanTree); // // //測(cè)試是否生成了對(duì)應(yīng)的哈夫曼編碼 // Map<Byte, String> huffmancondes = getCondes(huffmanTree); // System.out.println("生成的赫夫曼編碼表" + huffmancondes); // // //測(cè)試 // byte[] huffmanCodeBytes = zip(contentBytes, huffmancondes); // System.out.println("huffmanCodeBytes=" + Arrays.toString(huffmanCodeBytes));}//封裝前面所寫(xiě)的,便于調(diào)用/**** @param bytes 原始字符串對(duì)應(yīng)的字節(jié)數(shù)組* @return 返回的是經(jīng)過(guò)赫夫曼編碼處理后的字節(jié)數(shù)組(壓縮后的數(shù)組)*/private static byte[] huffmanZip(byte [] bytes){//第一步:創(chuàng)建節(jié)點(diǎn)List<Node1> nodes = getNodes(bytes);//第二步:創(chuàng)建赫夫曼樹(shù)Node1 huffmanTree = createHuffmanTree(nodes);//第三步:生成對(duì)應(yīng)的赫夫曼編碼(根據(jù)赫夫曼樹(shù))Map<Byte, String> hufumanCodes = getCondes(huffmanTree);//第四步:根據(jù)赫夫曼編碼壓縮,生成赫夫曼字節(jié)數(shù)組byte[] huffmanBytes = zip(bytes, hufumanCodes);return huffmanBytes;}//編寫(xiě)一個(gè)方法,將字符串對(duì)應(yīng)的byte[]數(shù)組,通過(guò)生成的赫夫曼編碼表,返回赫夫曼編碼壓縮后的byte[]/**** @param bytes 原始的字符對(duì)應(yīng)的byte[]* @param huffmanCodes 生成的赫夫曼編碼表map* @return 返回赫夫曼編碼處理后的byte[]* 舉例:String content = "i like like like java do you like a java";* 返回的是字符串"10101000"。。。等等* =>對(duì)應(yīng)byte[] huffmancodeBytes,即8位對(duì)應(yīng)一個(gè)byte,放入到huffmanCodeBytes* huffmancodeBytes[0] = 10101000(補(bǔ)碼) => byte [推導(dǎo) 10101000 => 10101000 -1 => 10100111(反碼) => 11011000(原碼)]* huffmancodeBytes[1] = -88*/private static byte[] zip(byte [] bytes, Map<Byte,String> huffmanCodes){//1.利用赫夫曼編碼表將傳進(jìn)來(lái)的byte數(shù)組轉(zhuǎn)成赫夫曼編碼字符串StringBuilder stringBuilder = new StringBuilder();//遍歷bytes數(shù)組for (byte b : bytes){stringBuilder.append(huffmanCodes.get(b));}//按照這個(gè)字符串發(fā)送肯定是變大了,不行,那么就要將字符串轉(zhuǎn)成byte數(shù)組System.out.println(stringBuilder.toString());//統(tǒng)計(jì)返回的byte[] huffmanCodeBytes 長(zhǎng)度//一句話搞定int len = (stringBuilder.length() + 7) / 8;int len;if (stringBuilder.length() % 8 == 0){len = stringBuilder.length() /8;}else {len = stringBuilder.length() /8 + 1;}//創(chuàng)建存儲(chǔ)壓縮后的byte數(shù)組byte [] huffmanCodeBytes = new byte[len];int index = 0;//記錄是第幾個(gè)bytefor (int i = 0; i < stringBuilder.length(); i += 8){//因?yàn)槊?位對(duì)應(yīng)一個(gè)byteString strByte;if (i+8 <= stringBuilder.length()){strByte = stringBuilder.substring(i,i+8);}else {strByte = stringBuilder.substring(i); //-88}//將StringByte轉(zhuǎn)成byte數(shù)組放入到huffmanCodeByteshuffmanCodeBytes[index] = (byte) Integer.parseInt(strByte,2);index++;}return huffmanCodeBytes;}//生成赫夫曼樹(shù)對(duì)應(yīng)的赫夫曼編碼//思路://1.將赫夫曼編碼表存放在Map<Byte,String> 形式//32->01 97->100 100->11000等等static Map<Byte,String> huffmanCodes = new HashMap<>();//2.在生成赫夫曼編碼表時(shí)需要拼接路徑,創(chuàng)建Stringbuilder存儲(chǔ)某個(gè)葉子節(jié)點(diǎn)的路徑static StringBuilder stringBuilder = new StringBuilder();//為了調(diào)用方便重載getCondesprivate static Map<Byte,String> getCondes(Node1 root){if (root == null){return null;}//處理rootgetCondes(root,"",stringBuilder);return huffmanCodes;}/*** 功能:將傳入的node節(jié)點(diǎn)的所有葉子節(jié)點(diǎn)赫夫曼編碼得到,并放入到赫夫曼集合中* @param node 傳入節(jié)點(diǎn)* @param code 路徑:左子節(jié)點(diǎn)是0,右子節(jié)點(diǎn)是1* @param stringBuilder 是用于拼接路徑*/private static void getCondes(Node1 node,String code, StringBuilder stringBuilder){StringBuilder stringBuilder2 = new StringBuilder(stringBuilder);//將傳入的code加入到Stringbuilder2stringBuilder2.append(code);if (node != null){//判斷當(dāng)前node是葉子節(jié)點(diǎn)還是非葉子節(jié)點(diǎn)if (node.data == null){ //說(shuō)明是非葉子節(jié)點(diǎn)//遞歸處理//向左遞歸getCondes(node.left,"0",stringBuilder2);//向右遞歸getCondes(node.right,"1",stringBuilder2);}else {//說(shuō)明是葉子節(jié)點(diǎn)//就表示找到了某個(gè)葉子節(jié)點(diǎn)最后huffmanCodes.put(node.data,stringBuilder2.toString());}}}//前序遍歷public static void preOrder(Node1 root){if (root != null){root.preOrder();}else {System.out.println("赫夫曼樹(shù)為空");}}private static List<Node1> getNodes(byte [] bytes){//1.創(chuàng)建ArrayListArrayList<Node1> node1s = new ArrayList<>();//遍歷bytes 統(tǒng)計(jì)乜咯 byte出現(xiàn)的次數(shù),存儲(chǔ)每個(gè)byte出現(xiàn)的次數(shù) -> mapMap<Byte,Integer> counts = new HashMap<>();for (byte b : bytes){Integer count = counts.get(b);if (count == null){ //說(shuō)明map中還沒(méi)有這個(gè)字符counts.put(b,1);}else {counts.put(b,count+1);}}//把每個(gè)鍵值對(duì)轉(zhuǎn)成一個(gè)Node對(duì)象,并加入到nodes集合//遍歷mapfor (Map.Entry<Byte,Integer> entry : counts.entrySet()){node1s.add(new Node1(entry.getKey(),entry.getValue()));}return node1s;}//通過(guò)List創(chuàng)建赫夫曼樹(shù)private static Node1 createHuffmanTree(List<Node1> nodes){while (nodes.size() > 1){//排序 從小到大Collections.sort(nodes);//取出第一顆、第二顆最小的二叉樹(shù)Node1 leftNode = nodes.get(0);Node1 rightNode = nodes.get(1);//創(chuàng)建新的二叉樹(shù),新的二叉樹(shù)沒(méi)有數(shù)據(jù),只有權(quán)值Node1 parent = new Node1(null,leftNode.weight + rightNode.weight);parent.left = leftNode;parent.right = rightNode;//將0,1移除Listnodes.remove(leftNode);nodes.remove(rightNode);//parent加入Listnodes.add(parent);}//nodes最后剩余就是哈弗曼樹(shù)的根節(jié)點(diǎn)return nodes.get(0);} } class Node1 implements Comparable<Node1>{Byte data; //存放數(shù)據(jù) 按照asciiint weight; //權(quán)值,表示字符出現(xiàn)的次數(shù)Node1 left;Node1 right;//前序遍歷public void preOrder(){System.out.println(this);if (this.left != null){this.left.preOrder();}if (this.right != null){this.right.preOrder();}}@Overridepublic int compareTo(Node1 o) {return this.weight - o.weight;}public Node1(Byte data, int weight) {this.data = data;this.weight = weight;}@Overridepublic String toString() {return "Node1{" +"data=" + data +", weight=" + weight +'}';} }

2.解壓(解碼)

//完成數(shù)據(jù)解壓//思路//1.將huffmanCodeBytes[-88,-65..]重寫(xiě)先轉(zhuǎn)成赫夫曼編碼對(duì)應(yīng)的二進(jìn)制字符串//2.赫夫曼編碼對(duì)應(yīng)的二進(jìn)制字符串根據(jù)赫夫曼編碼轉(zhuǎn)成字符//編寫(xiě)一個(gè)方法,對(duì)壓縮數(shù)據(jù)解碼/**** @param huffmanCodes 赫夫曼編碼表 map* @param huffmanBytes 需要解碼的字節(jié)數(shù)組* @return 返回原來(lái)字符串對(duì)應(yīng)的數(shù)組*/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++) {//判斷是否是最后一個(gè)字節(jié)boolean flag = (i == huffmanBytes.length - 1);stringBuilder.append(byteToBitString(!flag,huffmanBytes[i]));}System.out.println("赫夫曼 解碼后 對(duì)應(yīng)的二進(jìn)制字符串:" + stringBuilder.toString());//把字符串按照指定的赫夫曼編碼進(jìn)行解碼//把赫夫曼編碼表的k,v進(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è)集合存放byteList<Byte> list = new ArrayList<>();for (int i = 0; i < stringBuilder.length();) {int count = 1; //小的計(jì)數(shù)器boolean flag = true;Byte b = null;while (flag){//1010100010111。。。。String key = stringBuilder.substring(i, i + count);// i 不動(dòng)讓count移動(dòng),直到匹配到字符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中存放了所以的字符//把list放入到byte[] 并返回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)成二進(jìn)制字符串* @param b 傳入一個(gè)byte* @param flag 標(biāo)志是否需要補(bǔ)高位,true需要補(bǔ)高位,如果是最后一個(gè)字節(jié)不需要補(bǔ)高位* @return*/private static String byteToBitString(boolean flag, byte b){//使用變量保存bint temp = b;//將b轉(zhuǎn)成intif (flag){temp |= 256; //按位與256 1 0000 0000 | 0000 0001 =》1 0000 0001}String str = Integer.toBinaryString(temp);if (flag){return str.substring(str.length() - 8);}else {return str;}}

3.對(duì)文件進(jìn)行壓縮(加入io,通過(guò)對(duì)象流把赫夫曼編碼傳入,解壓的時(shí)候需要用)

//編寫(xiě)一個(gè)方法,進(jìn)行文件壓縮public static void zipFile(String srcFile, String dstFile){//創(chuàng)建輸出流FileInputStream is = null;//文件輸入流OutputStream os = null;ObjectOutputStream oos = null;try{is = new FileInputStream(srcFile);//創(chuàng)建一個(gè)和源文件大小一樣的btyte[]byte[] b = new byte[is.available()];//讀取文件is.read(b);//直接對(duì)源文件壓縮byte[] huffmanBytes = huffmanZip(b);//創(chuàng)建文件的輸出流,存放壓縮文件os = new FileOutputStream(dstFile);//創(chuàng)建一個(gè)和文件輸出流關(guān)聯(lián)的ObjectOutPutStream對(duì)象流oos = new ObjectOutputStream(os);//把赫夫曼編碼后的字節(jié)數(shù)組寫(xiě)入壓縮文件oos.writeObject(huffmanBytes);//這里我們以對(duì)象流的方式寫(xiě)入 赫夫曼編碼,為了恢復(fù)原文件時(shí)使用//!!!一定要把赫夫曼編碼也寫(xiě)入,要不然無(wú)法恢復(fù)oos.writeObject(huffmanCodes);}catch (Exception e){System.out.println(e.getMessage());}finally {try {is.close();os.close();oos.close();} catch (IOException ex) {System.out.println(ex);}}}

4.對(duì)文件進(jìn)行解壓

//編寫(xiě)一個(gè)方法,進(jìn)行解壓public static void unzipFile(String zipFile,String dstFile){//文件輸入流InputStream is = null;//創(chuàng)建輸出流OutputStream os = null;//對(duì)象輸入流ObjectInputStream ois = null;try {//創(chuàng)建文件輸入流is = new FileInputStream(zipFile);//場(chǎng)景和is關(guān)聯(lián)的對(duì)象輸入流ois = new ObjectInputStream(is);//讀取byte數(shù)組 huffmanBytesbyte [] huffmanBytes = (byte[]) ois.readObject();//讀取赫夫曼編碼表Map<Byte,String> huffmanCode = (Map<Byte,String>)ois.readObject();//解碼byte [] bytes = decode(huffmanCode,huffmanBytes);//將bytes數(shù)組寫(xiě)入到目標(biāo)文件os = new FileOutputStream(dstFile);//寫(xiě)出數(shù)據(jù)os.write(bytes);} catch (Exception e) {System.out.println(e.getMessage());}finally {try {os.close();ois.close();is.close();} catch (IOException e) {System.out.println(e.getMessage());}}}

赫夫曼編碼可以壓縮所有類型的文件,因?yàn)槭峭ㄟ^(guò)字節(jié)進(jìn)行壓縮

完整代碼

package tree.huffmantree.ZipFile;import java.io.*; import java.util.*;public class HuffmanZipFile {public static void main(String[] args) {//測(cè)試壓縮文件String srcFile = "D:\\薛艷春\\桌面\\新建文件夾 (3)\\薛艷春2.pdf";String dstFile = "D:\\薛艷春\\桌面\\新建文件夾 (3)\\薛艷春2.zip";zipFile(srcFile,dstFile);System.out.println("壓縮成功~~");String zipFile = "D:\\薛艷春\\桌面\\新建文件夾 (3)\\dst.zip";String dstFile2 = "D:\\薛艷春\\桌面\\新建文件夾 (3)\\src2.png";//unzipFile(zipFile,dstFile2);}//編寫(xiě)一個(gè)方法,進(jìn)行解壓public static void unzipFile(String zipFile,String dstFile){//文件輸入流InputStream is = null;//創(chuàng)建輸出流OutputStream os = null;//對(duì)象輸入流ObjectInputStream ois = null;try {//創(chuàng)建文件輸入流is = new FileInputStream(zipFile);//場(chǎng)景和is關(guān)聯(lián)的對(duì)象輸入流ois = new ObjectInputStream(is);//讀取byte數(shù)組 huffmanBytesbyte [] huffmanBytes = (byte[]) ois.readObject();//讀取赫夫曼編碼表Map<Byte,String> huffmanCode = (Map<Byte,String>)ois.readObject();//解碼byte [] bytes = decode(huffmanCode,huffmanBytes);//將bytes數(shù)組寫(xiě)入到目標(biāo)文件os = new FileOutputStream(dstFile);//寫(xiě)出數(shù)據(jù)os.write(bytes);} catch (Exception e) {System.out.println(e.getMessage());}finally {try {os.close();ois.close();is.close();} catch (IOException e) {System.out.println(e.getMessage());}}}//編寫(xiě)一個(gè)方法,進(jìn)行文件壓縮public static void zipFile(String srcFile, String dstFile){//創(chuàng)建輸出流FileInputStream is = null;//文件輸入流OutputStream os = null;ObjectOutputStream oos = null;try{is = new FileInputStream(srcFile);//創(chuàng)建一個(gè)和源文件大小一樣的btyte[]byte[] b = new byte[is.available()];//讀取文件is.read(b);//直接對(duì)源文件壓縮byte[] huffmanBytes = huffmanZip(b);//創(chuàng)建文件的輸出流,存放壓縮文件os = new FileOutputStream(dstFile);//創(chuàng)建一個(gè)和文件輸出流關(guān)聯(lián)的ObjectOutPutStream對(duì)象流oos = new ObjectOutputStream(os);//把赫夫曼編碼后的字節(jié)數(shù)組寫(xiě)入壓縮文件oos.writeObject(huffmanBytes);//這里我們以對(duì)象流的方式寫(xiě)入 赫夫曼編碼,為了恢復(fù)原文件時(shí)使用//!!!一定要把赫夫曼編碼也寫(xiě)入,要不然無(wú)法恢復(fù)oos.writeObject(huffmanCodes);}catch (Exception e){System.out.println(e.getMessage());}finally {try {is.close();os.close();oos.close();} catch (IOException ex) {System.out.println(ex);}}}//完成數(shù)據(jù)解壓//思路//1.將huffmanCodeBytes[-88,-65..]重寫(xiě)先轉(zhuǎn)成赫夫曼編碼對(duì)應(yīng)的二進(jìn)制字符串//2.赫夫曼編碼對(duì)應(yīng)的二進(jìn)制字符串根據(jù)赫夫曼編碼轉(zhuǎn)成字符//編寫(xiě)一個(gè)方法,對(duì)壓縮數(shù)據(jù)解碼/**** @param huffmanCodes 赫夫曼編碼表 map* @param huffmanBytes 需要解碼的字節(jié)數(shù)組* @return 返回原來(lái)字符串對(duì)應(yīng)的數(shù)組*/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++) {//判斷是否是最后一個(gè)字節(jié)boolean flag = (i == huffmanBytes.length - 1);stringBuilder.append(byteToBitString(!flag,huffmanBytes[i]));}//System.out.println("赫夫曼 解碼后 對(duì)應(yīng)的二進(jìn)制字符串:" + stringBuilder.toString());//把字符串按照指定的赫夫曼編碼進(jìn)行解碼//把赫夫曼編碼表的k,v進(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è)集合存放byteList<Byte> list = new ArrayList<>();for (int i = 0; i < stringBuilder.length();) {int count = 1; //小的計(jì)數(shù)器boolean flag = true;Byte b = null;while (flag){//1010100010111。。。。String key = stringBuilder.substring(i, i + count);// i 不動(dòng)讓count移動(dòng),直到匹配到字符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中存放了所以的字符//把list放入到byte[] 并返回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)成二進(jìn)制字符串* @param b 傳入一個(gè)byte* @param flag 標(biāo)志是否需要補(bǔ)高位,true需要補(bǔ)高位,如果是最后一個(gè)字節(jié)不需要補(bǔ)高位* @return*/private static String byteToBitString(boolean flag, byte b){//使用變量保存bint temp = b;//將b轉(zhuǎn)成intif (flag){temp |= 256; //按位與256 1 0000 0000 | 0000 0001 =》1 0000 0001}String str = Integer.toBinaryString(temp);if (flag){return str.substring(str.length() - 8);}else {return str;}}//封裝前面所寫(xiě)的,便于調(diào)用/**** @param bytes 原始字符串對(duì)應(yīng)的字節(jié)數(shù)組* @return 返回的是經(jīng)過(guò)赫夫曼編碼處理后的字節(jié)數(shù)組(壓縮后的數(shù)組)*/private static byte[] huffmanZip(byte [] bytes){//第一步:創(chuàng)建節(jié)點(diǎn)List<Node1> nodes = getNodes(bytes);//第二步:創(chuàng)建赫夫曼樹(shù)Node1 huffmanTree = createHuffmanTree(nodes);//第三步:生成對(duì)應(yīng)的赫夫曼編碼(根據(jù)赫夫曼樹(shù))Map<Byte, String> hufumanCodes = getCondes(huffmanTree);//第四步:根據(jù)赫夫曼編碼壓縮,生成赫夫曼字節(jié)數(shù)組byte[] huffmanBytes = zip(bytes, hufumanCodes);return huffmanBytes;}//編寫(xiě)一個(gè)方法,將字符串對(duì)應(yīng)的byte[]數(shù)組,通過(guò)生成的赫夫曼編碼表,返回赫夫曼編碼壓縮后的byte[]/**** @param bytes 原始的字符對(duì)應(yīng)的byte[]* @param huffmanCodes 生成的赫夫曼編碼表map* @return 返回赫夫曼編碼處理后的byte[]* 舉例:String content = "i like like like java do you like a java";* 返回的是字符串"10101000"。。。等等* =>對(duì)應(yīng)byte[] huffmancodeBytes,即8位對(duì)應(yīng)一個(gè)byte,放入到huffmanCodeBytes* huffmancodeBytes[0] = 10101000(補(bǔ)碼) => byte [推導(dǎo) 10101000 => 10101000 -1 => 10100111(反碼) => 11011000(原碼)]* huffmancodeBytes[1] = -88*/private static byte[] zip(byte [] bytes, Map<Byte,String> huffmanCodes){//1.利用赫夫曼編碼表將傳進(jìn)來(lái)的byte數(shù)組轉(zhuǎn)成赫夫曼編碼字符串StringBuilder stringBuilder = new StringBuilder();//遍歷bytes數(shù)組for (byte b : bytes){stringBuilder.append(huffmanCodes.get(b));}//按照這個(gè)字符串發(fā)送肯定是變大了,不行,那么就要將字符串轉(zhuǎn)成byte數(shù)組//System.out.println("赫夫曼 編碼后 對(duì)應(yīng)的二進(jìn)制字符串:" + stringBuilder.toString());//統(tǒng)計(jì)返回的byte[] huffmanCodeBytes 長(zhǎng)度//一句話搞定int len = (stringBuilder.length() + 7) / 8;int len;if (stringBuilder.length() % 8 == 0){len = stringBuilder.length() /8;}else {len = stringBuilder.length() /8 + 1;}//創(chuàng)建存儲(chǔ)壓縮后的byte數(shù)組byte [] huffmanCodeBytes = new byte[len];int index = 0;//記錄是第幾個(gè)bytefor (int i = 0; i < stringBuilder.length(); i += 8){//因?yàn)槊?位對(duì)應(yīng)一個(gè)byteString strByte;if (i+8 <= stringBuilder.length()){strByte = stringBuilder.substring(i,i+8);}else {strByte = stringBuilder.substring(i); //-88}//將StringByte轉(zhuǎn)成byte數(shù)組放入到huffmanCodeByteshuffmanCodeBytes[index] = (byte) Integer.parseInt(strByte,2);index++;}return huffmanCodeBytes;}//生成赫夫曼樹(shù)對(duì)應(yīng)的赫夫曼編碼//思路://1.將赫夫曼編碼表存放在Map<Byte,String> 形式//32->01 97->100 100->11000等等static Map<Byte,String> huffmanCodes = new HashMap<>();//2.在生成赫夫曼編碼表時(shí)需要拼接路徑,創(chuàng)建Stringbuilder存儲(chǔ)某個(gè)葉子節(jié)點(diǎn)的路徑static StringBuilder stringBuilder = new StringBuilder();//為了調(diào)用方便重載getCondesprivate static Map<Byte,String> getCondes(Node1 root){if (root == null){return null;}//處理rootgetCondes(root,"",stringBuilder);return huffmanCodes;}/*** 功能:將傳入的node節(jié)點(diǎn)的所有葉子節(jié)點(diǎn)赫夫曼編碼得到,并放入到赫夫曼集合中* @param node 傳入節(jié)點(diǎn)* @param code 路徑:左子節(jié)點(diǎn)是0,右子節(jié)點(diǎn)是1* @param stringBuilder 是用于拼接路徑*/private static void getCondes(Node1 node,String code, StringBuilder stringBuilder){StringBuilder stringBuilder2 = new StringBuilder(stringBuilder);//將傳入的code加入到Stringbuilder2stringBuilder2.append(code);if (node != null){//判斷當(dāng)前node是葉子節(jié)點(diǎn)還是非葉子節(jié)點(diǎn)if (node.data == null){ //說(shuō)明是非葉子節(jié)點(diǎn)//遞歸處理//向左遞歸getCondes(node.left,"0",stringBuilder2);//向右遞歸getCondes(node.right,"1",stringBuilder2);}else {//說(shuō)明是葉子節(jié)點(diǎn)//就表示找到了某個(gè)葉子節(jié)點(diǎn)最后huffmanCodes.put(node.data,stringBuilder2.toString());}}}//前序遍歷public static void preOrder(Node1 root){if (root != null){root.preOrder();}else {System.out.println("赫夫曼樹(shù)為空");}}private static List<Node1> getNodes(byte [] bytes){//1.創(chuàng)建ArrayListArrayList<Node1> node1s = new ArrayList<>();//遍歷bytes 統(tǒng)計(jì)乜咯 byte出現(xiàn)的次數(shù),存儲(chǔ)每個(gè)byte出現(xiàn)的次數(shù) -> mapMap<Byte,Integer> counts = new HashMap<>();for (byte b : bytes){Integer count = counts.get(b);if (count == null){ //說(shuō)明map中還沒(méi)有這個(gè)字符counts.put(b,1);}else {counts.put(b,count+1);}}//把每個(gè)鍵值對(duì)轉(zhuǎn)成一個(gè)Node對(duì)象,并加入到nodes集合//遍歷mapfor (Map.Entry<Byte,Integer> entry : counts.entrySet()){node1s.add(new Node1(entry.getKey(),entry.getValue()));}return node1s;}//通過(guò)List創(chuàng)建赫夫曼樹(shù)private static Node1 createHuffmanTree(List<Node1> nodes){while (nodes.size() > 1){//排序 從小到大Collections.sort(nodes);//取出第一顆、第二顆最小的二叉樹(shù)Node1 leftNode = nodes.get(0);Node1 rightNode = nodes.get(1);//創(chuàng)建新的二叉樹(shù),新的二叉樹(shù)沒(méi)有數(shù)據(jù),只有權(quán)值Node1 parent = new Node1(null,leftNode.weight + rightNode.weight);parent.left = leftNode;parent.right = rightNode;//將0,1移除Listnodes.remove(leftNode);nodes.remove(rightNode);//parent加入Listnodes.add(parent);}//nodes最后剩余就是哈弗曼樹(shù)的根節(jié)點(diǎn)return nodes.get(0);} } class Node1 implements Comparable<Node1>{Byte data; //存放數(shù)據(jù) 按照asciiint weight; //權(quán)值,表示字符出現(xiàn)的次數(shù)Node1 left;Node1 right;//前序遍歷public void preOrder(){System.out.println(this);if (this.left != null){this.left.preOrder();}if (this.right != null){this.right.preOrder();}}@Overridepublic int compareTo(Node1 o) {return this.weight - o.weight;}public Node1(Byte data, int weight) {this.data = data;this.weight = weight;}@Overridepublic String toString() {return "Node1{" +"data=" + data +", weight=" + weight +'}';} }

總結(jié)

以上是生活随笔為你收集整理的算法 - 赫夫曼编码(对字符串进行压缩 与 解压(解码)) - (对文件进行压缩解压)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

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