共计 3112 个字符,预计需要花费 8 分钟才能阅读完成。
赫夫曼算法类 Huffman.java
/**
- @Author: ltx
- @Description: 赫夫曼编码
*/
public class Huffman {
Map<Character, String> codeMap = new HashMap<>(); | |
/** | |
* 中序遍历 (前序或后序也行) | |
* 失去 huffman 编码 | |
* | |
* @param node 节点 | |
* @param sb StringBuilder | |
*/ | |
public void getCodeByMidOrder(Node node, StringBuilder sb) {if (node.left != null) { | |
// 往左走 +'0' | |
sb.append("0"); | |
getCodeByMidOrder(node.left, sb); | |
} | |
// 叶子节点 | |
if (node.left == null && node.right == null) { |
// System.out.print(node + “:” + sb + “, “);
codeMap.put(node.value, sb.toString()); | |
} | |
if (node.right != null) { | |
// 往右走 +'1' | |
sb.append("1"); | |
getCodeByMidOrder(node.right, sb); | |
} | |
// 回溯向上走缩小一个字符 | |
if (sb.length() > 0) {sb.deleteCharAt(sb.length() - 1); | |
} | |
} | |
public Node getHuffmanTree(List<Node> nodes) {Collections.sort(nodes); |
// System.out.println(nodes);
while (nodes.size() > 1) { | |
// 左叶子 - 数组最小值 | |
Node leafLeft = nodes.remove(0); | |
// 右叶子 - 数组次小值 | |
Node leafRight = nodes.remove(0); | |
// 父节点 = 数组最小值 + 数组次小值 | |
Node parentNode = new Node(null, leafLeft.weight + leafRight.weight); | |
parentNode.left = leafLeft; | |
parentNode.right = leafRight; | |
// 新的节点增加到 list 外面 | |
nodes.add(parentNode); | |
Collections.sort(nodes); | |
} | |
return nodes.get(0); | |
} | |
/** | |
* 获取各个字符权重 (字符个数) | |
* | |
* @param str | |
* @return | |
*/ | |
public List<Node> getCharWight(String str) {Map<Character, Integer> charNumMap = new HashMap<>(); | |
char[] chs = str.toCharArray(); | |
for (char c : chs) { | |
// 数量 | |
Integer count = charNumMap.get(c); | |
if (count == null) {charNumMap.put(c, 1); | |
} else {charNumMap.put(c, count + 1); | |
} | |
} |
// System.out.println(charNumMap);
List<Node> nodes = new ArrayList<>(); | |
// 创立节点 List | |
for (char c : charNumMap.keySet()) {nodes.add(new Node(c, charNumMap.get(c))); | |
} | |
return nodes; | |
} | |
/** | |
* 编码 | |
* 依据赫夫曼编码表,对原始数据做转换 | |
* | |
* @param str 原始字符串 | |
* @return | |
*/ | |
public String encoding(String str) {StringBuilder sb = new StringBuilder(); | |
char[] chs = str.toCharArray(); | |
for (char c : chs) {sb.append(codeMap.get(c)); | |
} | |
return sb.toString();} | |
/** | |
* 解码 | |
* | |
* @return | |
*/ | |
public String decode(String encodStr) { | |
// 翻转 codeMap | |
Map<String, Character> encodeMap = new HashMap<>(); | |
for (char c : codeMap.keySet()) {encodeMap.put(codeMap.get(c), c); | |
} | |
char[] chs = encodStr.toCharArray(); | |
int j = 0; | |
StringBuilder res = new StringBuilder(); | |
while (j < encodStr.length() - 1) {StringBuilder sb = new StringBuilder(); | |
Character cr; | |
// 匹配出字符串 | |
while ((cr = encodeMap.get(sb.toString())) == null) {sb.append(chs[j]); | |
j++; | |
} | |
res.append(cr); | |
} | |
return res.toString();} | |
public static void main(String[] args) {Huffman huffman = new Huffman(); | |
System.out.println("原始数据:"); | |
// 须要压缩的串 | |
String str = "i like like like java do you like a java"; | |
System.out.println(str); | |
//1. 取得字符权重 List | |
List<Node> nodes = huffman.getCharWight(str); | |
//[:9, a:5, d:1, e:4, u:1, v:2, i:5, y:1, j:2, k:4, l:4, o:2] | |
System.out.println("节点权重列表:"); | |
System.out.println(nodes); | |
//2.[PerfectMoney 下载](https://www.gendan5.com/wallet/PerfectMoney.html) 结构赫夫曼树 | |
Node root = huffman.getHuffmanTree(nodes); | |
//3. 取得赫夫曼编码表 | |
huffman.getCodeByMidOrder(root, new StringBuilder("")); | |
System.out.println("赫夫曼编码表:"); | |
// 失去赫夫曼编码表 | |
//{=01, a=100, d=11000, u=11001, e=1110, v=11011, i=101, y=11010, j=0010, k=1111, l=000, o=0011} | |
System.out.println(huffman.codeMap); | |
//4. 压缩编码 | |
String encodStr = huffman.encoding(str); | |
System.out.println("压缩后数据:"); |
//1010100010111111110010001011111111001000101111111100100101001101110001110000011011101000111100101000101111111100110001001010011011100
System.out.println(encodStr); | |
//5. 解压 | |
String res = huffman.decode(encodStr); | |
System.out.println("解压后数据:"); | |
// 打印最终后果 | |
//i like like like java do you like a java | |
System.out.println(res); | |
} |
}
正文完