20182323 哈夫曼编码测试
课程:《程序设计与数据结构》
班级: 1823
姓名: 曹骞
学号: 20182323
实验教师:王志强
实验日期:2019年10月21日
必修/选修: 必修
1.实验内容
设有字符集:S={a,b,c,d,e,f,g,h,i,j,k,l,m,n.o.p.q,r,s,t,u,v,w,x,y,z}。
给定一个包含26个英文字母的文件,统计每个字符出现的概率,根据计算的概率构造一颗哈夫曼树。
并完成对英文文件的编码和解码。
要求:
1.准备一个包含26个英文字母的英文文件(可以不包含标点符号等),统计各个字符的概率
2.构造哈夫曼树
3.对英文文件进行编码,输出一个编码后的文件
4.对编码文件进行解码,输出一个解码后的文件
2.实现过程
哈夫曼树的建立
(1) 8个结点的权值大小如下:
(2). 从19,21,2,3,6,7,10,32中选择两个权小结点。选中2,3。同时算出这两个结点的和5。
(3). 从19,21,6,7,10,32,5中选出两个权小结点。选中
5,6。同时计算出它们的和11。
(4). 从19,21,7,10,32,11中选出两个权小结点。选中7,10。同时计算出它们的和17。(PS:这时选出的两个数字都不是已经构造好的二叉树里面的结点,所以要另外开一棵二叉树;或者说,如果两个数的和正好是下一步的两个最小数的其中的一个,那么这个树直接往上生长就可以了,如果这两个数的和比较大,不是下一步的两个最小数的其中一个,那么就并列生长。)
(5). 从19,21,32,11,17中选出两个权小结点。选中11,17。同时计算出它们的和28。
(6). 从19,21,32,28中选出两个权小结点。选中19,21。同时计算出它们的和40。另起一颗二叉树。
(7). 从32,28, 40中选出两个权小结点。选中28,32。同时计算出它们的和60。
(8). 从 40, 60中选出两个权小结点。选中40,60。同时计算出它们的和100。 好了,此时哈夫曼树已经构建好了。
以下为核心代码:
Node createTree(List<Node> nodes) { while (nodes.size() > 1) { quickSort(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.leftChild = left; parent.rightChild = right; nodes.remove(nodes.size() - 1); nodes.remove(nodes.size() - 1); nodes.add(parent); } return nodes.get(0);
- 以左为0,右为1,给字母编码
public void setCode(Node root) { if (root.leftChild != null) { root.leftChild.code = root.code + "0"; setCode(root.leftChild); } if (root.rightChild != null) { root.rightChild.code = root.code + "1"; setCode(root.rightChild); } } public class Node<E> { E data; public String code = ""; double weight; Node leftChild; Node rightChild; public Node(E data, double weight) { super(); this.data = data; this.weight = weight; } }
- 对英文文件进行编码
private String hfmCodeStr = ""; public String toHufmCode(String str,Node root) { for (int i = 0; i < str.length(); i++) { char c = str.charAt(i) ; search(root, c); } return hfmCodeStr; } private void search(Node root, char c) { if (root.leftChild == null && root.rightChild == null) { if (c == (char)root.data) { hfmCodeStr += root.code; // 找到字符,将其哈夫曼编码拼接到最终返回二进制字符串的后面 } } if (root.leftChild != null) { search(root.leftChild, c); } if (root.rightChild != null) { search(root.rightChild, c); } }
- 对编码文件进行解码
String result=""; boolean target = false; public String CodeToString(String codeStr,Node root) { int start = 0; int end = 1; while(end <= codeStr.length()){ target = false; String s = codeStr.substring(start, end); matchCode(root, s); if(target){ start = end; } end++; } return result; } private void matchCode(Node root, String code){ if (root.leftChild == null && root.rightChild == null) { if (code.equals(root.code)) { result += root.data; // 找到对应的字符,拼接到解码字符穿后 target = true; // 标志置为true } } if (root.leftChild != null) { matchCode(root.leftChild, code); } if (root.rightChild != null) { matchCode(root.rightChild, code); } }
- 最终结果截图
其他(感悟、思考等)
要想进步,就只有吸取教训,成功的经验都是歪曲的,成功了,想怎么说都可以,失败者没有发言权,可是,你可以通过他的事例反思,总结。教训,不仅要从自己身上吸取,还要从别人身上吸取。
——马云