技术霍夫曼树の创建、编码、解码
Kitholt Frank开头
霍夫曼树的相关概念就不一一赘述了,直接上代码。放心,必要的地方我会加上我自己都看不懂的注释
Mr.Winterの实验要求:
- 读取一个文本文件,并统计出每个字符的出现次数。随后将一个字符的出现次数作为字符的权值(霍夫曼树中的叶子节点的权值)
- 将字符和其权值保存起来(链表?or动态数组?)
- 利用得到的所有字符,构建霍夫曼树(拿到霍夫曼树的根节点)
- 对每一个字符进行霍夫曼编码,并得到一张编码表
- 根据编码表,输入一个编码后能够对其进行解码并返回其所对应的字符
步骤
读取文本文件并统计各个字符的出现次数(权值)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| package readtxt;
import java.io.*; import java.util.HashMap; import java.util.Map;
public class ReadTxt {
public static HashMap<String, Integer> readTxtAndCount(String txtPath) throws IOException { File file = new File(txtPath); FileInputStream fileInputStream = new FileInputStream(file); InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream); BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
StringBuffer sb = new StringBuffer(); String text = null; while ((text = bufferedReader.readLine()) != null) { sb.append(text); } String txt = sb.toString(); char[] TXT = txt.toCharArray(); Map<String, Integer> m = new HashMap<String, Integer>(); for (char c : TXT) { String s = String.valueOf(c); if (null != m.get(s)) { int count = m.get(s); m.put(s, count + 1); } else { m.put(s, 1); } } return (HashMap<String, Integer>) m; }
public static void main(String[] args) throws IOException { HashMap<String,Integer> m=ReadTxt.readTxtAndCount("U:\\烂盘\\dark二\\带二第二学期\\程序设计综合实验\\实验3\\Demo.txt"); } }
|
值得一提的是,哈希表yyds。它的作用类似Python里面的字典(键值对),字符:出现次数
创建节点类Node保存字符信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
| package node;
public class Node implements Comparable<Node> { public String sign; String code; public int weight; public Node lchild; public Node rchild; Node next;
public Node(String sign, int weight) { this.sign = sign; this.weight = weight; }
public String getCode() { return code; }
@Override public int compareTo(Node o) { return this.weight - o.weight; }
@Override public String toString() { return "Node{" + "sign='" + sign + '\'' + ", weight=" + weight + '}'; }
public void CodingByPreOrder(String code, Node root) { if (!this.sign.equals("非叶子节点") && !this.sign.equals("根节点")) { this.code = code; System.out.println(this.sign + "的哈夫曼编码" + code); } if (this.lchild != null) { this.lchild.CodingByPreOrder(code += "0", root);
} StringBuilder sb = new StringBuilder(code); code = sb.replace(code.length() - 1, code.length(), "").toString(); if (this.rchild != null) { this.rchild.CodingByPreOrder(code + "1", root); } if (!this.sign.equals("非叶子节点") && !this.sign.equals("根节点")) { this.next = root; } }
public String Decoding(Node root, String code, int index) { Node ROOT=root; StringBuilder s = new StringBuilder(); while (index < code.length()) { if (code.charAt(index) == '0') { ROOT = ROOT.lchild; } if (code.charAt(index) == '1') { ROOT = ROOT.rchild; } if (ROOT.next == root) { s.append(ROOT.sign); ROOT=root; } index++; } if(ROOT==root){ System.out.println(code+ "解码后对应的字符为" + s.toString()); return s.toString(); } else if(!s.toString().equals("")&&ROOT.next==null){ System.out.println("输入的编码部分有误,仅能解码出部分字符"+s.toString()+"..."); return s.toString(); } else { System.out.println("输入的编码完全错误,无法解码..."); return null; } } }
|
利用得到的节点类构建霍夫曼树
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| package huffmantree; import node.Node; import java.util.*;
public class HuffmanTree {
public static Node createHuffmanTree(HashMap<String, Integer> arr) { List<Node> nodes = new ArrayList<Node>(); for (String key : arr.keySet()) { nodes.add(new Node(key, arr.get(key))); } Collections.sort(nodes); System.out.println("各个字符对应的权重:"); System.out.println("nodes =" + nodes); while (nodes.size() > 1) { Node leftNode = nodes.get(0); Node rightNode = nodes.get(1); Node parent = new Node("非叶子节点", leftNode.weight + rightNode.weight); parent.lchild = leftNode; parent.rchild = rightNode; nodes.remove(leftNode); nodes.remove(rightNode); nodes.add(parent); Collections.sort(nodes); } return nodes.get(0); }
public static void preOrder(Node root) { if (root != null) { root.CodingByPreOrder("", root); } else { System.out.println("空树无法遍历..."); } }
public static String deCoding(Node root, String code, int index) { return root.Decoding(root, code, index); } }
|
PS:另外,编码和解码的核心代码在Node类中
主程序的测试代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| import java.io.IOException; import java.util.Scanner; import huffmantree.HuffmanTree; import node.Node; import readtxt.ReadTxt;
public class Test { public static void main(String[] args) throws IOException { boolean flag=true; Scanner sc=new Scanner(System.in); int key=0; Node root=new Node(null,0); while(flag){ menu(); while(true) { key = sc.nextInt(); if(key<1||key>3){ System.out.println("请输入正确的序号..."); menu(); }else{ break; } }
switch (key){ case 1: root=HuffmanTree.createHuffmanTree(ReadTxt.readTxtAndCount("U:\\烂盘\\dark二\\带二第二学期\\程序设计综合实验\\实验3\\Demo.txt")); HuffmanTree.preOrder(root); break; case 2: System.out.println("请输入一个来自编码表的编码..."); String s=sc.next(); HuffmanTree.deCoding(root,s,0); break; case 3: flag=false; break; } } } public static void menu() { System.out.println("\n §※§※§※§※§※§ 霍夫曼编码与解码.§※§※§※§※§※§\t\n"); System.out.println("\t※◎※◎※◎※◎ 1. 霍夫曼の编码(获得编码表).※◎※◎※◎※◎\t"); System.out.println("\t※◎※◎※◎※◎ 2. 霍夫曼の解码.※◎※◎※◎※◎\t"); System.out.println("\t※◎※◎※◎※◎ 3. 退出程序.※◎※◎※◎※◎\t"); System.out.println("\n\t请选择:\t"); } }
|
结果截图:



结尾

各位爷,代码也看了注释也读了思路应该也理清一点点了,接下来应该做啥就不用我说了吧(可怜巴巴)