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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

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



1.壓縮:使用赫夫曼編碼進行壓縮



題目

構建赫夫曼樹

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);//測試創建二叉樹Node1 huffmanTree = createHuffmanTree(nodes);//前序遍歷preOrder(huffmanTree);}//前序遍歷public static void preOrder(Node1 root){if (root != null){root.preOrder();}else {System.out.println("赫夫曼樹為空");}}private static List<Node1> getNodes(byte [] bytes){//1.創建ArrayListArrayList<Node1> node1s = new ArrayList<>();//遍歷bytes 統計乜咯 byte出現的次數,存儲每個byte出現的次數 -> mapMap<Byte,Integer> counts = new HashMap<>();for (byte b : bytes){Integer count = counts.get(b);if (count == null){ //說明map中還沒有這個字符counts.put(b,1);}else {counts.put(b,count+1);}}//把每個鍵值對轉成一個Node對象,并加入到nodes集合//遍歷mapfor (Map.Entry<Byte,Integer> entry : counts.entrySet()){node1s.add(new Node1(entry.getKey(),entry.getValue()));}return node1s;}//通過List創建赫夫曼樹private static Node1 createHuffmanTree(List<Node1> nodes){while (nodes.size() > 1){//排序 從小到大Collections.sort(nodes);//取出第一顆、第二顆最小的二叉樹Node1 leftNode = nodes.get(0);Node1 rightNode = nodes.get(1);//創建新的二叉樹,新的二叉樹沒有數據,只有權值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最后剩余就是哈弗曼樹的根節點return nodes.get(0);} } class Node1 implements Comparable<Node1>{Byte data; //存放數據 按照asciiint weight; //權值,表示字符出現的次數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 +'}';} }

//生成赫夫曼樹對應的赫夫曼編碼//思路://1.將赫夫曼編碼表存放在Map<Byte,String> 形式//32->01 97->100 100->11000等等static Map<Byte,String> huffmanCodes = new HashMap<>();//2.在生成赫夫曼編碼表時需要拼接路徑,創建Stringbuilder存儲某個葉子節點的路徑static StringBuilder stringBuilder = new StringBuilder();/*** 功能:將傳入的node節點的所有葉子節點赫夫曼編碼得到,并放入到赫夫曼集合中* @param node 傳入節點* @param code 路徑:左子節點是0,右子節點是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){//判斷當前node是葉子節點還是非葉子節點if (node.data == null){ //說明是非葉子節點//遞歸處理//向左遞歸getCondes(node.left,"0",stringBuilder2);//向右遞歸getCondes(node.right,"1",stringBuilder2);}else {//說明是葉子節點//就表示找到了某個葉子節點最后huffmanCodes.put(node.data,stringBuilder2.toString());}}}

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

//完成數據解壓//思路//1.將huffmanCodeBytes[-88,-65..]重寫先轉成赫夫曼編碼對應的二進制字符串//2.赫夫曼編碼對應的二進制字符串根據赫夫曼編碼轉成字符//編寫一個方法,對壓縮數據解碼/**** @param huffmanCodes 赫夫曼編碼表 map* @param huffmanBytes 需要解碼的字節數組* @return 返回原來字符串對應的數組*/private static byte[] decode(Map<Byte,String> huffmanCodes, byte[] huffmanBytes){//1.先得到huffmanBytes對應的二進制的字符串StringBuilder stringBuilder = new StringBuilder();//將byte數組轉成二進制字符串for (int i = 0; i < huffmanBytes.length; i++) {//判斷是否是最后一個字節boolean flag = (i == huffmanBytes.length - 1);stringBuilder.append(byteToBitString(!flag,huffmanBytes[i]));}System.out.println("赫夫曼 解碼后 對應的二進制字符串:" + stringBuilder.toString());//把字符串按照指定的赫夫曼編碼進行解碼//把赫夫曼編碼表的k,v進行調換;因為要反向查詢Map<String,Byte> map = new HashMap<>();for (Map.Entry<Byte,String> entry : huffmanCodes.entrySet()){map.put(entry.getValue(),entry.getKey());}//System.out.println(map);//創建一個集合存放byteList<Byte> list = new ArrayList<>();for (int i = 0; i < stringBuilder.length();) {int count = 1; //小的計數器boolean flag = true;Byte b = null;while (flag){//1010100010111。。。。String key = stringBuilder.substring(i, i + count);// i 不動讓count移動,直到匹配到字符b = map.get(key);if (b == null){count ++;}else {flag = false;}}list.add(b);i += count; //讓 i 移動到count}//for循環結束后list中存放了所以的字符//把list放入到byte[] 并返回byte b [] = new byte[list.size()];for (int i = 0; i < b.length; i++) {b[i] = list.get(i);}return b;}/*** 將一個byte轉成二進制字符串* @param b 傳入一個byte* @param flag 標志是否需要補高位,true需要補高位,如果是最后一個字節不需要補高位* @return*/private static String byteToBitString(boolean flag, byte b){//使用變量保存bint temp = b;//將b轉成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.對文件進行壓縮(加入io,通過對象流把赫夫曼編碼傳入,解壓的時候需要用)

//編寫一個方法,進行文件壓縮public static void zipFile(String srcFile, String dstFile){//創建輸出流FileInputStream is = null;//文件輸入流OutputStream os = null;ObjectOutputStream oos = null;try{is = new FileInputStream(srcFile);//創建一個和源文件大小一樣的btyte[]byte[] b = new byte[is.available()];//讀取文件is.read(b);//直接對源文件壓縮byte[] huffmanBytes = huffmanZip(b);//創建文件的輸出流,存放壓縮文件os = new FileOutputStream(dstFile);//創建一個和文件輸出流關聯的ObjectOutPutStream對象流oos = new ObjectOutputStream(os);//把赫夫曼編碼后的字節數組寫入壓縮文件oos.writeObject(huffmanBytes);//這里我們以對象流的方式寫入 赫夫曼編碼,為了恢復原文件時使用//!!!一定要把赫夫曼編碼也寫入,要不然無法恢復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.對文件進行解壓

//編寫一個方法,進行解壓public static void unzipFile(String zipFile,String dstFile){//文件輸入流InputStream is = null;//創建輸出流OutputStream os = null;//對象輸入流ObjectInputStream ois = null;try {//創建文件輸入流is = new FileInputStream(zipFile);//場景和is關聯的對象輸入流ois = new ObjectInputStream(is);//讀取byte數組 huffmanBytesbyte [] huffmanBytes = (byte[]) ois.readObject();//讀取赫夫曼編碼表Map<Byte,String> huffmanCode = (Map<Byte,String>)ois.readObject();//解碼byte [] bytes = decode(huffmanCode,huffmanBytes);//將bytes數組寫入到目標文件os = new FileOutputStream(dstFile);//寫出數據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());}}}

赫夫曼編碼可以壓縮所有類型的文件,因為是通過字節進行壓縮

完整代碼

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

總結

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

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。