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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

数据结构Java06【赫夫曼树、概述、原理分析、代码实现(数据压缩、创建编码表、解码、压缩文件、解压文件)】

發布時間:2024/9/30 java 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 数据结构Java06【赫夫曼树、概述、原理分析、代码实现(数据压缩、创建编码表、解码、压缩文件、解压文件)】 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

學習地址:【數據結構與算法基礎-java版】? ? ? ? ? ? ? ? ??🚀數據結構--Java專欄🚀

  • 筆記01【01-09】【概述、數組基本使用】【源碼、課件】
  • 筆記02【10-18】【棧、隊列、單鏈表(增刪節點)、循環鏈表、雙向循環鏈表、遞歸(斐波那契、漢諾塔)】
  • 筆記03【19-27】【(時間、空間復雜度);八大排序(冒泡、快速、插入、希爾、選擇、歸并、基數、隊列基數)】
  • 筆記04【28-33】【樹結構(二叉樹)概述、創建、遍歷、查找節點、刪除節點】
  • 筆記05【34-39】【順序存儲二叉樹概述、二叉樹遍歷、堆排序、線索二叉樹實現及遍歷】
  • 筆記06【40-48】【赫夫曼樹、概述、原理分析、代碼實現(數據壓縮、創建編碼表、解碼、壓縮文件、解壓文件)】
  • 筆記07【49-54】【二叉排序樹(添加、查找、刪除節點)】
  • 筆記08【55-57】【二叉平衡樹(AVL)-概述、單旋轉、雙旋轉】
  • 筆記09【58-60】【計算機中數據的存儲原理、2-3樹的插入原理、B樹和B+樹】
  • 筆記10【61-63】【哈希表概述、散列函數的設計、散列沖突解決方案】
  • 筆記11【64-67】【圖結構概述、圖遍歷原理(BFS\DFS)、圖遍歷代碼實現】

目? ?錄

P40-4.13 赫夫曼樹概述

P41-4.14 創建赫夫曼樹的流程分析

P42-4.15 代碼實現創建赫夫曼樹

1、Node.java

2、TestHuffmanTree.java

P43-4.16 赫夫曼編碼原理分析

1、通信領域中信息的處理1-定長編碼

2、通信領域中信息的處理2-非定長編碼

3、通信領域中信息的處理3-赫夫曼編碼

P44-4.17 數據壓縮之創建赫夫曼樹

1、Map從入門到性能分析

2、思路分析

3、代碼實現

3.1、Node.java

3.2、TestHuffmanCode44.java

P45-4.18 數據壓縮之創建編碼表&編碼

1、TestHuffmanCode45.java

P46-4.19 使用赫夫曼編碼進行解碼

P47-4.20 使用赫夫曼編碼壓縮文件

P48-4.21 使用赫夫曼編碼解壓文件


P40-4.13 赫夫曼樹概述

最優二叉樹(赫夫曼樹):它是n個帶權葉子結點構成的所有二叉樹中,帶權路徑長度最小的二叉樹。?

P41-4.14 創建赫夫曼樹的流程分析

赫夫曼樹

P42-4.15 代碼實現創建赫夫曼樹

Alt + Shift + S【快捷鍵】

1、Node.java

package demo9;public class Node implements Comparable<Node> {int value;Node left;Node right;public Node(int value) {this.value = value;}@Overridepublic int compareTo(Node o) {return -(this.value - o.value);// 加“-”,大在前}// Alt + Shift + S【快捷鍵】@Overridepublic String toString() {return "Node [value=" + value + "]";} }

2、TestHuffmanTree.java

package demo9;import java.util.ArrayList; import java.util.Collections; import java.util.List;public class TestHuffmanTree {public static void main(String[] args) {int[] arr = { 3, 7, 8, 29, 5, 11, 23, 14 };Node node = createHuffmanTree(arr);System.out.println(node);}// 創建赫夫曼樹public static Node createHuffmanTree(int[] arr) {// 1、先使用數組中所有的元素創建若干個二叉樹,(只有一個節點)List<Node> nodes = new ArrayList<>();// 創建數組集合,用來存二叉樹for (int value : arr) { // for循環的另外一種表達,遍歷數組元素用的nodes.add(new Node(value));}// Collections.sort(nodes);// System.out.println(nodes);// 循環處理!!!while (nodes.size() > 1) { // 只有1顆樹時, 結束處理!// 2、排序【排序前提:Node可以排序!】Collections.sort(nodes);// 需要Node實現接口// 3、取出來權值最小的兩個二叉樹// 3.1、取出最權值最小的二叉樹Node left = nodes.get(nodes.size() - 1);// 3.2、取出最權值次小的二叉樹Node right = nodes.get(nodes.size() - 2);// 4、創建一顆新的二叉樹Node parent = new Node(left.value + right.value);// 5、把取出來的兩個二叉樹移除nodes.remove(left);nodes.remove(right);// 6、放入原來的二叉樹集合中nodes.add(parent);}return nodes.get(0);}}

P43-4.16 赫夫曼編碼原理分析

1、通信領域中信息的處理1-定長編碼

赫夫曼編碼的運用

計算機并不能直接將字符發給別人。

先將 字符?按照某個標準(ASCII)轉換為數字?!綾-->99,a-->97】

【計算機只能識別0、1串,每一個數字都是一個byte(字節)】

再將 數字 轉換為 8位的字節,

【1100011--->99--->c】

將01串發給另一臺計算機B,計算機B按 8位 劃分 01串,
將 01串 轉換為 十進制數字,再將?十進制數字 根據 ASCII?轉換為 字母。

?

定長編碼方式,傳輸效率 極低!!!

固定長度~浪費空間 ==>?非定長編碼

https://tool.lu/hexconvert/

2、通信領域中信息的處理2-非定長編碼

先對計算串進行處理,統計字符串中每個字符出現了多少次,

令經常出現的字符長度長一些,不經常出現的字符長度短一些,【不按照ASCII進行處理】

次數當作權值構造哈夫曼!!!

3、通信領域中信息的處理3-赫夫曼編碼

字符出現次數少的,在樹底;

字符出現次數多的,在樹頂。?

?

左0 右1

將 字符串 按照 赫夫曼編碼表 進行編碼,

按照 編碼表 進行 解碼,無損壓縮!

P44-4.17 數據壓縮之創建赫夫曼樹

1、Map從入門到性能分析

Java---Map從入門到性能分析

https://blog.csdn.net/weixin_44949135/article/details/106862811

2、思路分析

1、統計字符出現次數,并排序

2、根據排序結果,將字符轉換為節點

3、將節點轉換為赫夫曼樹

?字符 可以轉換為 byte。

? ? // 節點 要存儲 字符(data) 與 權值(weight-字符出現的次數)
?? ?// 每個字符作為一個節點
?? ?// 按照 權值(weight-字符出現的次數) 進行 排序
?? ?Byte data;// 存儲節點代表的字符/英文字符可轉byte
?? ?int weight;// 權值
?? ?Node left;// 左節點
?? ?Node right;// 右節點
?? ?// 創建赫夫曼樹的時候,新創建的節點,無data,只有weight? ?data可為空

不 對 字符串 進行 編碼,對 字符串的byte數組 進行 編碼。?

所有的數據 都 可以 轉換為 byte數組。【將 數據 轉換為 byte數組--->文件操作!!!】

3、代碼實現

3.1、Node.java

package demo10;public class Node implements Comparable<Node> {// 節點 要存儲 字符(data) 與 權值(weight-字符出現的次數)// 每個字符作為一個節點// 按照 權值(weight-字符出現的次數) 進行 排序Byte data;// 存儲節點代表的字符/英文字符可轉byteint weight;// 權值Node left;// 左節點Node right;// 右節點// 創建赫夫曼樹的時候,新創建的節點,無data,只有weight|data可為空public Node(Byte data, int weight) {this.data = data;this.weight = weight;}@Overridepublic String toString() {return "Node [data=" + data + ", weight=" + weight + "]";}@Overridepublic int compareTo(Node o) {return o.weight - this.weight;//倒序} }

3.2、TestHuffmanCode44.java

package demo10;import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map;public class TestHuffmanCode44 {public static void main(String[] args) {String msg = "can you can a can as a can canner can a can.";/*** 赫夫曼編碼 不直接對字符串進行編碼。而是編碼字符串的byte數組。 * 所有的數據都可以轉換為byte數組。文件壓縮使用byte數組。* 文件讀取出來是一個byte數組。所以,將數據轉換為byte數組。*/byte[] bytes = msg.getBytes();byte[] b = huffmanZip(bytes);// 獲取使用赫夫曼編碼壓縮后的byte數組}/*** 進行赫夫曼編碼壓縮的方法* * @param bytes* @return*/private static byte[] huffmanZip(byte[] bytes) {// 1、先統計每一個byte出現的次數,并放入一個集合中【getNodes()】List<Node> nodes = getNodes(bytes);// 2、創建一棵赫夫曼樹Node tree = createHuffmanTree(nodes);System.out.println(tree);System.out.println(tree.right);System.out.println(tree.left);// 3、創建一個赫夫曼編碼表// 4、編碼return null;}/*** 1、把byte數組轉為node集合* * @param bytes* @return*/private static List<Node> getNodes(byte[] bytes) {List<Node> nodes = new ArrayList<>();// 存儲每一個byte出現了多少次。Map<Byte, Integer> counts = new HashMap<>();// 統計每一個byte出現的次數for (byte b : bytes) {Integer count = counts.get(b);if (count == null) {counts.put(b, 1);} else {counts.put(b, count + 1);}}//System.out.println(counts);//{32=11, 97=11, 114=1, 99=7, 115=1, 117=1, 101=1, 121=1, 110=8, 46=1, 111=1}// 32-空格、97-a// 把每一個鍵值對轉為一個node對象for (Map.Entry<Byte, Integer> entry : counts.entrySet()) {nodes.add(new Node(entry.getKey(), entry.getValue()));}return nodes;}/*** 2、創建赫夫曼樹* * @param nodes* @return*/private static Node createHuffmanTree(List<Node> nodes) {while (nodes.size() > 1) {// 排序Collections.sort(nodes);// System.out.println(nodes);// 取出兩個權值最低的二叉樹Node left = nodes.get(nodes.size() - 1);Node right = nodes.get(nodes.size() - 2);// 創建一顆新的二叉樹Node parent = new Node(null, left.weight + right.weight);// 把之前取出來的兩顆二叉樹設置為新創建的二叉樹的子樹parent.left = left;parent.right = right;// 把前面取出來的兩顆二叉樹刪除nodes.remove(left);nodes.remove(right);// 把新創建的二叉樹放入集合中nodes.add(parent);}return nodes.get(0);}}

P45-4.18 數據壓縮之創建編碼表&編碼

1、TestHuffmanCode45.java

package demo10;import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map;public class TestHuffmanCode45 {public static void main(String[] args) {String msg = "can you can a can as a can canner can a can.";/*** 赫夫曼編碼 不直接對字符串進行編碼。而是編碼字符串的byte數組。 * 所有的數據都可以轉換為byte數組。文件壓縮使用byte數組。* 文件讀取出來是一個byte數組。所以,將數據轉換為byte數組。*/byte[] bytes = msg.getBytes();byte[] b = huffmanZip(bytes);// 獲取使用赫夫曼編碼壓縮后的byte數組System.out.println(bytes.length);System.out.println(b.length);}/*** 進行赫夫曼編碼壓縮的方法* * @param bytes* @return*/private static byte[] huffmanZip(byte[] bytes) {// 1、先統計每一個byte出現的次數,并放入一個集合中【getNodes()】List<Node> nodes = getNodes(bytes);// 2、創建一棵赫夫曼樹Node tree = createHuffmanTree(nodes);System.out.println(tree);System.out.println(tree.right);System.out.println(tree.left);// 3、創建一個赫夫曼編碼表Map<Byte, String> huffCodes = getCodes(tree);System.out.println(huffCodes);// 4、編碼byte[] b = zip(bytes, huffCodes);return b;}/*** 1、把byte數組轉為node集合* * @param bytes* @return*/private static List<Node> getNodes(byte[] bytes) {List<Node> nodes = new ArrayList<>();// 存儲每一個byte出現了多少次。Map<Byte, Integer> counts = new HashMap<>();// 統計每一個byte出現的次數for (byte b : bytes) {Integer count = counts.get(b);if (count == null) {counts.put(b, 1);} else {counts.put(b, count + 1);}}//System.out.println(counts);//{32=11, 97=11, 114=1, 99=7, 115=1, 117=1, 101=1, 121=1, 110=8, 46=1, 111=1}// 32-空格、97-a// 把每一個鍵值對轉為一個node對象for (Map.Entry<Byte, Integer> entry : counts.entrySet()) {nodes.add(new Node(entry.getKey(), entry.getValue()));}return nodes;}/*** 2、創建赫夫曼樹* * @param nodes* @return*/private static Node createHuffmanTree(List<Node> nodes) {while (nodes.size() > 1) {// 排序Collections.sort(nodes);// System.out.println(nodes);// 取出兩個權值最低的二叉樹Node left = nodes.get(nodes.size() - 1);Node right = nodes.get(nodes.size() - 2);// 創建一顆新的二叉樹Node parent = new Node(null, left.weight + right.weight);// 把之前取出來的兩顆二叉樹設置為新創建的二叉樹的子樹parent.left = left;parent.right = right;// 把前面取出來的兩顆二叉樹刪除nodes.remove(left);nodes.remove(right);// 把新創建的二叉樹放入集合中nodes.add(parent);}return nodes.get(0);}// 用于臨時存儲路徑static StringBuilder sb = new StringBuilder();// 用于存儲赫夫曼編碼static Map<Byte, String> huffCodes = new HashMap<>();/*** 3、根據赫夫曼樹獲取赫夫曼編碼* 需要保存前面樹支的結果0、1* @param tree* @return*/private static Map<Byte, String> getCodes(Node tree) {if (tree == null) {return null;}getCodes(tree.left, "0", sb);getCodes(tree.right, "1", sb);return huffCodes;}private static void getCodes(Node node, String code, StringBuilder sb) {StringBuilder sb2 = new StringBuilder(sb);sb2.append(code);if (node.data == null) {getCodes(node.left, "0", sb2);getCodes(node.right, "1", sb2);} else {huffCodes.put(node.data, sb2.toString());}}/*** 4、進行赫夫曼編碼* * @param bytes* @param huffCodes2* @return*/private static byte[] zip(byte[] bytes, Map<Byte, String> huffCodes) {StringBuilder sb = new StringBuilder();// 把需要壓縮的byte數組處理成一個二進制的字符串for (byte b : bytes) {sb.append(huffCodes.get(b));}// System.out.println(sb.toString());// 定義長度int len;if (sb.length() % 8 == 0) {len = sb.length() / 8;} else {len = sb.length() / 8 + 1;}// 用于存儲壓縮后的bytebyte[] by = new byte[len];// 記錄新byte的位置int index = 0;for (int i = 0; i < sb.length(); i += 8) {String strByte;if (i + 8 > sb.length()) {strByte = sb.substring(i);} else {strByte = sb.substring(i, i + 8);}byte byt = (byte) Integer.parseInt(strByte, 2);//二進制轉十進制System.out.println(strByte + " : " + byt);by[index] = byt;index++;}return by;} }

P46-4.19 使用赫夫曼編碼進行解碼

package demo10;import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map;public class TestHuffmanCode45 {public static void main(String[] args) {String msg = "can you can a can as a can canner can a can.";/*** 赫夫曼編碼 不直接對字符串進行編碼。而是編碼字符串的byte數組。 * 所有的數據都可以轉換為byte數組。文件壓縮使用byte數組。* 文件讀取出來是一個byte數組。所以,將數據轉換為byte數組。*/byte[] bytes = msg.getBytes();//進行赫夫曼編碼壓縮byte[] b = huffmanZip(bytes);// 獲取使用赫夫曼編碼壓縮后的byte數組System.out.println(bytes.length);System.out.println(b.length);//使用赫夫曼編碼進行解碼byte[] newBytes = decode(huffCodes,b);System.out.println(new String(newBytes));}/*** 進行赫夫曼編碼壓縮的方法* * @param bytes* @return*/private static byte[] huffmanZip(byte[] bytes) {// 1、先統計每一個byte出現的次數,并放入一個集合中【getNodes()】List<Node> nodes = getNodes(bytes);// 2、創建一棵赫夫曼樹Node tree = createHuffmanTree(nodes);System.out.println(tree);System.out.println(tree.right);System.out.println(tree.left);// 3、創建一個赫夫曼編碼表Map<Byte, String> huffCodes = getCodes(tree);System.out.println(huffCodes);// 4、編碼byte[] b = zip(bytes, huffCodes);return b;}/*** 1、把byte數組轉為node集合* * @param bytes* @return*/private static List<Node> getNodes(byte[] bytes) {List<Node> nodes = new ArrayList<>();// 存儲每一個byte出現了多少次。Map<Byte, Integer> counts = new HashMap<>();// 統計每一個byte出現的次數for (byte b : bytes) {Integer count = counts.get(b);if (count == null) {counts.put(b, 1);} else {counts.put(b, count + 1);}}//System.out.println(counts);//{32=11, 97=11, 114=1, 99=7, 115=1, 117=1, 101=1, 121=1, 110=8, 46=1, 111=1}// 32-空格、97-a// 把每一個鍵值對轉為一個node對象for (Map.Entry<Byte, Integer> entry : counts.entrySet()) {nodes.add(new Node(entry.getKey(), entry.getValue()));}return nodes;}/*** 2、創建赫夫曼樹* * @param nodes* @return*/private static Node createHuffmanTree(List<Node> nodes) {while (nodes.size() > 1) {// 排序Collections.sort(nodes);// System.out.println(nodes);// 取出兩個權值最低的二叉樹Node left = nodes.get(nodes.size() - 1);Node right = nodes.get(nodes.size() - 2);// 創建一顆新的二叉樹Node parent = new Node(null, left.weight + right.weight);// 把之前取出來的兩顆二叉樹設置為新創建的二叉樹的子樹parent.left = left;parent.right = right;// 把前面取出來的兩顆二叉樹刪除nodes.remove(left);nodes.remove(right);// 把新創建的二叉樹放入集合中nodes.add(parent);}return nodes.get(0);}// 用于臨時存儲路徑static StringBuilder sb = new StringBuilder();// 用于存儲赫夫曼編碼static Map<Byte, String> huffCodes = new HashMap<>();/*** 3、根據赫夫曼樹獲取赫夫曼編碼* 需要保存前面樹支的結果0、1* @param tree* @return*/private static Map<Byte, String> getCodes(Node tree) {if (tree == null) {return null;}getCodes(tree.left, "0", sb);getCodes(tree.right, "1", sb);return huffCodes;}private static void getCodes(Node node, String code, StringBuilder sb) {StringBuilder sb2 = new StringBuilder(sb);sb2.append(code);if (node.data == null) {getCodes(node.left, "0", sb2);getCodes(node.right, "1", sb2);} else {huffCodes.put(node.data, sb2.toString());}}/*** 4、進行赫夫曼編碼* * @param bytes* @param huffCodes2* @return*/private static byte[] zip(byte[] bytes, Map<Byte, String> huffCodes) {StringBuilder sb = new StringBuilder();// 把需要壓縮的byte數組處理成一個二進制的字符串for (byte b : bytes) {sb.append(huffCodes.get(b));}// System.out.println(sb.toString());// 定義長度int len;if (sb.length() % 8 == 0) {len = sb.length() / 8;} else {len = sb.length() / 8 + 1;}// 用于存儲壓縮后的bytebyte[] by = new byte[len];// 記錄新byte的位置int index = 0;for (int i = 0; i < sb.length(); i += 8) {String strByte;if (i + 8 > sb.length()) {strByte = sb.substring(i);} else {strByte = sb.substring(i, i + 8);}byte byt = (byte) Integer.parseInt(strByte, 2);//二進制轉十進制System.out.println(strByte + " : " + byt);by[index] = byt;index++;}return by;}/*** 使用指定的赫夫曼編碼表進行解碼* * @param huffCodes2* @param b* @return*/private static byte[] decode(Map<Byte, String> huffCodes, byte[] bytes) {StringBuilder sb = new StringBuilder();// 把byte數組轉為一個二進制的字符串for (int i = 0; i < bytes.length; i++) {byte b = bytes[i];// 是否是最后一個。boolean flag = (i == bytes.length - 1);sb.append(byteToBitStr(!flag, b));}// 把字符串按照指定的赫夫曼編碼進行解碼// 把赫夫曼編碼的鍵值對進行調換Map<String, Byte> map = new HashMap<>();for (Map.Entry<Byte, String> entry : huffCodes.entrySet()) {map.put(entry.getValue(), entry.getKey());}// 創建一個集合,用于存byteList<Byte> list = new ArrayList<>();// 處理字符串for (int i = 0; i < sb.length();) {int count = 1;boolean flag = true;Byte b = null;// 截取出一個bytewhile (flag) {String key = sb.substring(i, i + count);b = map.get(key);if (b == null) {count++;} else {flag = false;}}list.add(b);i += count;}// 把集合轉為數組byte[] b = new byte[list.size()];for (int i = 0; i < b.length; i++) {b[i] = list.get(i);}return b;}/*** 轉為8位的字符串* @param flag* @param b* @return*/private static String byteToBitStr(boolean flag, byte b) {int temp = b;if (flag) {temp |= 256;//按位或 256}String str = Integer.toBinaryString(temp);//返回int變量的二進制表示的字符串。if (flag) {return str.substring(str.length() - 8);} else {return str;}} }

P47-4.20 使用赫夫曼編碼壓縮文件

運行項目后,選中項目,進行刷新。

package demo10;import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.ObjectOutputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map;public class TestHuffmanCode45 {public static void main(String[] args) { // String msg = "can you can a can as a can canner can a can."; // /** // * 赫夫曼編碼 不直接對字符串進行編碼。而是編碼字符串的byte數組。 // * 所有的數據都可以轉換為byte數組。文件壓縮使用byte數組。 // * 文件讀取出來是一個byte數組。所以,將數據轉換為byte數組。 // */ // byte[] bytes = msg.getBytes(); // //進行赫夫曼編碼壓縮 // byte[] b = huffmanZip(bytes);// 獲取使用赫夫曼編碼壓縮后的byte數組 // System.out.println(bytes.length); // System.out.println(b.length); // //使用赫夫曼編碼進行解碼 // byte[] newBytes = decode(huffCodes,b); // System.out.println(new String(newBytes));String src = "1.png";String dest = "2.zip";try{zipFile(src, dest);} catch(IOException e){e.printStackTrace();}}/*** 壓縮文件* * @param src* @param dst* @throws IOException*/public static void zipFile(String src, String dst) throws IOException {// 創建一個輸入流InputStream is = new FileInputStream(src);// 創建一個和輸入流指向的文件大小一樣的byte數組byte[] b = new byte[is.available()];//available()獲取讀的文件所有的字節個數// 讀取文件內容is.read(b);is.close();// 使用赫夫曼編碼進行編碼byte[] byteZip = huffmanZip(b);System.out.println(b.length);System.out.println(byteZip.length);// 輸出流OutputStream os = new FileOutputStream(dst);ObjectOutputStream oos = new ObjectOutputStream(os);// 把壓縮后的byte數組寫入文件oos.writeObject(byteZip);// 把赫夫曼編碼表寫入文件oos.writeObject(huffCodes);oos.close();os.close();}/*** 進行赫夫曼編碼壓縮的方法* * @param bytes* @return*/private static byte[] huffmanZip(byte[] bytes) {// 1、先統計每一個byte出現的次數,并放入一個集合中【getNodes()】List<Node> nodes = getNodes(bytes);// 2、創建一棵赫夫曼樹Node tree = createHuffmanTree(nodes);System.out.println(tree);System.out.println(tree.right);System.out.println(tree.left);// 3、創建一個赫夫曼編碼表Map<Byte, String> huffCodes = getCodes(tree);System.out.println(huffCodes);// 4、編碼byte[] b = zip(bytes, huffCodes);return b;}/*** 1、把byte數組轉為node集合* * @param bytes* @return*/private static List<Node> getNodes(byte[] bytes) {List<Node> nodes = new ArrayList<>();// 存儲每一個byte出現了多少次。Map<Byte, Integer> counts = new HashMap<>();// 統計每一個byte出現的次數for (byte b : bytes) {Integer count = counts.get(b);if (count == null) {counts.put(b, 1);} else {counts.put(b, count + 1);}}//System.out.println(counts);//{32=11, 97=11, 114=1, 99=7, 115=1, 117=1, 101=1, 121=1, 110=8, 46=1, 111=1}// 32-空格、97-a// 把每一個鍵值對轉為一個node對象for (Map.Entry<Byte, Integer> entry : counts.entrySet()) {nodes.add(new Node(entry.getKey(), entry.getValue()));}return nodes;}/*** 2、創建赫夫曼樹* * @param nodes* @return*/private static Node createHuffmanTree(List<Node> nodes) {while (nodes.size() > 1) {// 排序Collections.sort(nodes);// System.out.println(nodes);// 取出兩個權值最低的二叉樹Node left = nodes.get(nodes.size() - 1);Node right = nodes.get(nodes.size() - 2);// 創建一顆新的二叉樹Node parent = new Node(null, left.weight + right.weight);// 把之前取出來的兩顆二叉樹設置為新創建的二叉樹的子樹parent.left = left;parent.right = right;// 把前面取出來的兩顆二叉樹刪除nodes.remove(left);nodes.remove(right);// 把新創建的二叉樹放入集合中nodes.add(parent);}return nodes.get(0);}// 用于臨時存儲路徑static StringBuilder sb = new StringBuilder();// 用于存儲赫夫曼編碼static Map<Byte, String> huffCodes = new HashMap<>();/*** 3、根據赫夫曼樹獲取赫夫曼編碼* 需要保存前面樹支的結果0、1* @param tree* @return*/private static Map<Byte, String> getCodes(Node tree) {if (tree == null) {return null;}getCodes(tree.left, "0", sb);getCodes(tree.right, "1", sb);return huffCodes;}private static void getCodes(Node node, String code, StringBuilder sb) {StringBuilder sb2 = new StringBuilder(sb);sb2.append(code);if (node.data == null) {getCodes(node.left, "0", sb2);getCodes(node.right, "1", sb2);} else {huffCodes.put(node.data, sb2.toString());}}/*** 4、進行赫夫曼編碼* * @param bytes* @param huffCodes2* @return*/private static byte[] zip(byte[] bytes, Map<Byte, String> huffCodes) {StringBuilder sb = new StringBuilder();// 把需要壓縮的byte數組處理成一個二進制的字符串for (byte b : bytes) {sb.append(huffCodes.get(b));}// System.out.println(sb.toString());// 定義長度int len;if (sb.length() % 8 == 0) {len = sb.length() / 8;} else {len = sb.length() / 8 + 1;}// 用于存儲壓縮后的bytebyte[] by = new byte[len];// 記錄新byte的位置int index = 0;for (int i = 0; i < sb.length(); i += 8) {String strByte;if (i + 8 > sb.length()) {strByte = sb.substring(i);} else {strByte = sb.substring(i, i + 8);}byte byt = (byte) Integer.parseInt(strByte, 2);//二進制轉十進制System.out.println(strByte + " : " + byt);by[index] = byt;index++;}return by;}/*** 使用指定的赫夫曼編碼表進行解碼* * @param huffCodes2* @param b* @return*/private static byte[] decode(Map<Byte, String> huffCodes, byte[] bytes) {StringBuilder sb = new StringBuilder();// 把byte數組轉為一個二進制的字符串for (int i = 0; i < bytes.length; i++) {byte b = bytes[i];// 是否是最后一個。boolean flag = (i == bytes.length - 1);sb.append(byteToBitStr(!flag, b));}// 把字符串按照指定的赫夫曼編碼進行解碼// 把赫夫曼編碼的鍵值對進行調換Map<String, Byte> map = new HashMap<>();for (Map.Entry<Byte, String> entry : huffCodes.entrySet()) {map.put(entry.getValue(), entry.getKey());}// 創建一個集合,用于存byteList<Byte> list = new ArrayList<>();// 處理字符串for (int i = 0; i < sb.length();) {int count = 1;boolean flag = true;Byte b = null;// 截取出一個bytewhile (flag) {String key = sb.substring(i, i + count);b = map.get(key);if (b == null) {count++;} else {flag = false;}}list.add(b);i += count;}// 把集合轉為數組byte[] b = new byte[list.size()];for (int i = 0; i < b.length; i++) {b[i] = list.get(i);}return b;}/*** 轉為8位的字符串* @param flag* @param b* @return*/private static String byteToBitStr(boolean flag, byte b) {int temp = b;if (flag) {temp |= 256;//按位或 256}String str = Integer.toBinaryString(temp);//返回int變量的二進制表示的字符串。if (flag) {return str.substring(str.length() - 8);} else {return str;}} }

P48-4.21 使用赫夫曼編碼解壓文件

package demo10;import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map;public class TestHuffmanCode45 {public static void main(String[] args) { // String msg = "can you can a can as a can canner can a can."; // /** // * 赫夫曼編碼 不直接對字符串進行編碼。而是編碼字符串的byte數組。 // * 所有的數據都可以轉換為byte數組。文件壓縮使用byte數組。 // * 文件讀取出來是一個byte數組。所以,將數據轉換為byte數組。 // */ // byte[] bytes = msg.getBytes(); // //進行赫夫曼編碼壓縮 // byte[] b = huffmanZip(bytes);// 獲取使用赫夫曼編碼壓縮后的byte數組 // System.out.println(bytes.length); // System.out.println(b.length); // //使用赫夫曼編碼進行解碼 // byte[] newBytes = decode(huffCodes,b); // System.out.println(new String(newBytes));String src = "1.png";String dest = "2.zip"; // try { // zipFile(src, dest); // } catch (IOException e) { // e.printStackTrace(); // }try {unZip("2.zip", "3.png");} catch (Exception e) {e.printStackTrace();}}/*** 文件的解壓* * @param src* @param dst* @throws Exception*/public static void unZip(String src, String dst) throws Exception {// 創建一個輸入流InputStream is = new FileInputStream("2.zip");ObjectInputStream ois = new ObjectInputStream(is);// 讀取byte數組byte[] b = (byte[]) ois.readObject();// 讀取赫夫曼編碼表Map<Byte, String> codes = (Map<Byte, String>) ois.readObject();ois.close();is.close();// 解碼byte[] bytes = decode(codes, b);// 創建一個輸出流OutputStream os = new FileOutputStream(dst);// 寫出數據os.write(bytes);os.close();}/*** 壓縮文件* * @param src* @param dst* @throws IOException*/public static void zipFile(String src, String dst) throws IOException {// 創建一個輸入流InputStream is = new FileInputStream(src);// 創建一個和輸入流指向的文件大小一樣的byte數組byte[] b = new byte[is.available()];//available()獲取讀的文件所有的字節個數// 讀取文件內容is.read(b);is.close();// 使用赫夫曼編碼進行編碼byte[] byteZip = huffmanZip(b);System.out.println(b.length);System.out.println(byteZip.length);// 輸出流OutputStream os = new FileOutputStream(dst);ObjectOutputStream oos = new ObjectOutputStream(os);// 把壓縮后的byte數組寫入文件oos.writeObject(byteZip);// 把赫夫曼編碼表寫入文件oos.writeObject(huffCodes);oos.close();os.close();}/*** 進行赫夫曼編碼壓縮的方法* * @param bytes* @return*/private static byte[] huffmanZip(byte[] bytes) {// 1、先統計每一個byte出現的次數,并放入一個集合中【getNodes()】List<Node> nodes = getNodes(bytes);// 2、創建一棵赫夫曼樹Node tree = createHuffmanTree(nodes);System.out.println(tree);System.out.println(tree.right);System.out.println(tree.left);// 3、創建一個赫夫曼編碼表Map<Byte, String> huffCodes = getCodes(tree);System.out.println(huffCodes);// 4、編碼byte[] b = zip(bytes, huffCodes);return b;}/*** 1、把byte數組轉為node集合* * @param bytes* @return*/private static List<Node> getNodes(byte[] bytes) {List<Node> nodes = new ArrayList<>();// 存儲每一個byte出現了多少次。Map<Byte, Integer> counts = new HashMap<>();// 統計每一個byte出現的次數for (byte b : bytes) {Integer count = counts.get(b);if (count == null) {counts.put(b, 1);} else {counts.put(b, count + 1);}}//System.out.println(counts);//{32=11, 97=11, 114=1, 99=7, 115=1, 117=1, 101=1, 121=1, 110=8, 46=1, 111=1}// 32-空格、97-a// 把每一個鍵值對轉為一個node對象for (Map.Entry<Byte, Integer> entry : counts.entrySet()) {nodes.add(new Node(entry.getKey(), entry.getValue()));}return nodes;}/*** 2、創建赫夫曼樹* * @param nodes* @return*/private static Node createHuffmanTree(List<Node> nodes) {while (nodes.size() > 1) {// 排序Collections.sort(nodes);// System.out.println(nodes);// 取出兩個權值最低的二叉樹Node left = nodes.get(nodes.size() - 1);Node right = nodes.get(nodes.size() - 2);// 創建一顆新的二叉樹Node parent = new Node(null, left.weight + right.weight);// 把之前取出來的兩顆二叉樹設置為新創建的二叉樹的子樹parent.left = left;parent.right = right;// 把前面取出來的兩顆二叉樹刪除nodes.remove(left);nodes.remove(right);// 把新創建的二叉樹放入集合中nodes.add(parent);}return nodes.get(0);}// 用于臨時存儲路徑static StringBuilder sb = new StringBuilder();// 用于存儲赫夫曼編碼static Map<Byte, String> huffCodes = new HashMap<>();/*** 3、根據赫夫曼樹獲取赫夫曼編碼* 需要保存前面樹支的結果0、1* @param tree* @return*/private static Map<Byte, String> getCodes(Node tree) {if (tree == null) {return null;}getCodes(tree.left, "0", sb);getCodes(tree.right, "1", sb);return huffCodes;}private static void getCodes(Node node, String code, StringBuilder sb) {StringBuilder sb2 = new StringBuilder(sb);sb2.append(code);if (node.data == null) {getCodes(node.left, "0", sb2);getCodes(node.right, "1", sb2);} else {huffCodes.put(node.data, sb2.toString());}}/*** 4、進行赫夫曼編碼* * @param bytes* @param huffCodes2* @return*/private static byte[] zip(byte[] bytes, Map<Byte, String> huffCodes) {StringBuilder sb = new StringBuilder();// 把需要壓縮的byte數組處理成一個二進制的字符串for (byte b : bytes) {sb.append(huffCodes.get(b));}// System.out.println(sb.toString());// 定義長度int len;if (sb.length() % 8 == 0) {len = sb.length() / 8;} else {len = sb.length() / 8 + 1;}// 用于存儲壓縮后的bytebyte[] by = new byte[len];// 記錄新byte的位置int index = 0;for (int i = 0; i < sb.length(); i += 8) {String strByte;if (i + 8 > sb.length()) {strByte = sb.substring(i);} else {strByte = sb.substring(i, i + 8);}byte byt = (byte) Integer.parseInt(strByte, 2);//二進制轉十進制System.out.println(strByte + " : " + byt);by[index] = byt;index++;}return by;}/*** 使用指定的赫夫曼編碼表進行解碼* * @param huffCodes2* @param b* @return*/private static byte[] decode(Map<Byte, String> huffCodes, byte[] bytes) {StringBuilder sb = new StringBuilder();// 把byte數組轉為一個二進制的字符串for (int i = 0; i < bytes.length; i++) {byte b = bytes[i];// 是否是最后一個。boolean flag = (i == bytes.length - 1);sb.append(byteToBitStr(!flag, b));}// 把字符串按照指定的赫夫曼編碼進行解碼// 把赫夫曼編碼的鍵值對進行調換Map<String, Byte> map = new HashMap<>();for (Map.Entry<Byte, String> entry : huffCodes.entrySet()) {map.put(entry.getValue(), entry.getKey());}// 創建一個集合,用于存byteList<Byte> list = new ArrayList<>();// 處理字符串for (int i = 0; i < sb.length();) {int count = 1;boolean flag = true;Byte b = null;// 截取出一個bytewhile (flag) {String key = sb.substring(i, i + count);b = map.get(key);if (b == null) {count++;} else {flag = false;}}list.add(b);i += count;}// 把集合轉為數組byte[] b = new byte[list.size()];for (int i = 0; i < b.length; i++) {b[i] = list.get(i);}return b;}/*** 轉為8位的字符串* @param flag* @param b* @return*/private static String byteToBitStr(boolean flag, byte b) {int temp = b;if (flag) {temp |= 256;//按位或 256}String str = Integer.toBinaryString(temp);//返回int變量的二進制表示的字符串。if (flag) {return str.substring(str.length() - 8);} else {return str;}} }

11111111111111111~

總結

以上是生活随笔為你收集整理的数据结构Java06【赫夫曼树、概述、原理分析、代码实现(数据压缩、创建编码表、解码、压缩文件、解压文件)】的全部內容,希望文章能夠幫你解決所遇到的問題。

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