20182323 哈夫曼编码测试

孤街浪徒 提交于 2019-12-05 11:24:25

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);
        }
    }
  • 最终结果截图

其他(感悟、思考等)

要想进步,就只有吸取教训,成功的经验都是歪曲的,成功了,想怎么说都可以,失败者没有发言权,可是,你可以通过他的事例反思,总结。教训,不仅要从自己身上吸取,还要从别人身上吸取。
——马云

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!