zoukankan      html  css  js  c++  java
  • 172322 2018-2019-1 《程序设计与数据结构》哈夫曼编码测试报告

    172322 2018-2019-1 《程序设计与数据结构》哈夫曼编码测试报告

    • 课程:《程序设计与数据结构》
    • 班级: 1723
    • 姓名: 张昊然
    • 学号:20172322
    • 教师:王志强
    • 助教:张之睿/张师瑜
    • 编码测试日期:2018年11月19日
    • 必修/选修: 必修

    哈夫曼树

    • 在计算机数据处理中,霍夫曼编码使用变长编码表对源符号(如文件中的一个字母)进行编码,其中变长编码表是通过一种评估来源符号出现机率的方法得到的,出现机率高的字母使用较短的编码,反之出现机率低的则使用较长的编码,这便使编码之后的字符串的平均长度、期望值降低,从而达到无损压缩数据的目的。
    • 例如,在英文中,e的出现机率最高,而z的出现概率则最低。当利用霍夫曼编码对一篇英文进行压缩时,e极有可能用一个比特来表示,而z则可能花去25个比特(不是26)。用普通的表示方法时,每个英文字母均占用一个字节,即8个比特。二者相比,e使用了一般编码的1/8的长度,z则使用了3倍多。倘若我们能实现对于英文中各个字母出现概率的较准确的估算,就可以大幅度提高无损压缩的比例。
    • 霍夫曼树又称最优二叉树,是一种带权路径长度最短的二叉树。所谓树的带权路径长度,就是树中所有的叶结点的权值乘上其到根结点的路径长度(若根结点为0层,叶结点到根结点的路径长度为叶结点的层数)。树的路径长度是从树根到每一结点的路径长度之和,记为WPL=(W1XL1+W2XL2+W3XL3+...+WnXLn),N个权值Wi(i=1,2,...n)构成一棵有N个叶结点的二叉树,相应的叶结点的路径长度为Li(i=1,2,...n)。可以证明霍夫曼树的WPL是最小的。

    哈夫曼树的应用

    • 对需要编码的数据进行两遍扫描:第一遍统计原数据中各字符出现的频率,利用得到的频率值创建哈夫曼树,并必须把树的信息保存起来,即把字符0-255(28=256)的频率值以2-4BYTES的长度顺序存储起来,(用4Bytes的长度存储频率值,频率值的表示范围为0至232-1,这已足够表示大文件中字符出现的频率了)以便解压时创建同样的哈夫曼树进行解压;第二遍则根据第一遍扫描得到的哈夫曼树进行编码,并把编码后得到的码字存储起来。

    哈弗曼树的实现

    //  哈夫曼节点类
    public class HuffmanNode<T> implements Comparable<HuffmanNode<T>> {
        private T data;  //  数据
        private double weight;  //  权重
        private HuffmanNode<T> left;
        private HuffmanNode<T> right;
        String code;  //  编码
    
        public HuffmanNode(T data, double weight){
            this.data = data;
            this.weight = weight;
            this.code = "";
    
        }
    
        public T getData() {
            return data;
        }
    
        public void setData(T data) {
            this.data = data;
        }
    
        public double getWeight() {
            return weight;
        }
    
        public void setWeight(double weight) {
            this.weight = weight;
        }
    
        public HuffmanNode<T> getLeft() {
            return left;
        }
    
        public void setLeft(HuffmanNode<T> left) {
            this.left = left;
        }
    
        public HuffmanNode<T> getRight() {
            return right;
        }
    
        public void setRight(HuffmanNode<T> right) {
            this.right = right;
        }
    
        public String getCode(){
            return code;
        }
    
        public void setCode(String str){
            code = str;
        }
    
        @Override
        public String toString(){
            return null;
        }
    
        @Override
        public int compareTo(HuffmanNode<T> other) {
            if(other.getWeight() > this.getWeight()){
                return 1;
            }
            if(other.getWeight() < this.getWeight()){
                return -1;
            }
    
            return 0;
        }
    }
    
    • 编写ReadTxt类读取txt文件中的字母,用于将字母转化成哈夫曼编码。
    //   读取文件类
    public class ReadTxt {
        char[] chars = new char[]{'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',' '};
    //    int[] nu = new int[26];
        int[] number = new int[]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
        public String txtString(File file){
            StringBuilder result = new StringBuilder();
            try{
                BufferedReader br = new BufferedReader(new FileReader(file));//构造一个BufferedReader类来读取文件
                String s = null;
                while((s = br.readLine())!=null){//  使用readLine方法,一次读一行
                    result.append(System.lineSeparator() + s);
                    num(s);
                }
                br.close();
            }catch(Exception e){
                e.printStackTrace();
            }
            return result.toString();
        }
    
    
        public void num(String string){
            //   26个字母加一个空格
            for(int i = 0;i<27;i++){
                int temp = 0;
                for(int j = 0;j<string.length();j++){
                    if(string.charAt(j) == chars[i]) {
                        temp++;
                    }
                }
                number[i] += temp;
            }
        }
    
    
        public int[] getNumber(){
            return number;
        }
    
        public char[] getChars(){
            return chars;
        }
    }
    
    • 编写HuffmanCoding类将读取的字母转化成为哈夫曼编码,并且规定左子树为0,右子树为1
    public class HuffmanCoding<T> {
        public HuffmanNode<T> createTree(List<HuffmanNode<T>> nodes) {
            while (nodes.size() > 1) {
                Collections.sort(nodes);
    
                HuffmanNode<T> left = nodes.get(nodes.size() - 2);
                left.setCode(0 + "");  //  左子树为否(0)
                HuffmanNode<T> right = nodes.get(nodes.size() - 1);
                right.setCode(1 + "");  //  右子树为是(1)
                HuffmanNode<T> parent = new HuffmanNode<>(null, left.getWeight() + right.getWeight()); //   双亲结点的权值为左右孩子相加
                parent.setLeft(left);
                parent.setRight(right);
                nodes.remove(left);
                nodes.remove(right);
                nodes.add(parent);
            }
            return nodes.get(0);  //  返回根结点
        }
    
        //   广度优先遍历以赋值
        public List<HuffmanNode<T>> BFS(HuffmanNode<T> root) {
            List<HuffmanNode<T>> list = new ArrayList<>();
            Queue<HuffmanNode<T>> queue = new ArrayDeque<>();
    
            if (root != null) {
                //  将元素入队列
                queue.offer(root);
                root.getLeft().setCode(root.getCode() + "0");
                root.getRight().setCode(root.getCode() + "1");
            }
    
            //  转化为0和1
            while (!queue.isEmpty()) {
                list.add(queue.peek());
                HuffmanNode<T> node = queue.poll();  //  获取头结点
                if (node.getLeft() != null) {
                    node.getLeft().setCode(node.getCode() + "0");  //  左为0
                }
                if (node.getRight() != null) {
                    node.getRight().setCode(node.getCode() + "1");  //  右为1
                }
    
                if (node.getLeft() != null) {
                    queue.offer(node.getLeft());
                }
    
                if (node.getRight() != null) {
                    queue.offer(node.getRight());
                }
            }
            return list;
        }
    }
    
    • 最后编写实现类Huffmaninput.txt中读取信息,转化为哈夫曼编码后将哈夫曼编码放入output.txt中后完成测试。
    public class Huffman {
    
        public static void main(String[] args) throws IOException {
            List<HuffmanNode<String>> list = new ArrayList<>();
            List<HuffmanNode<String>> list2;
            List<String> list3 = new ArrayList<>();
            List<String> list4 = new ArrayList<>();
            List<String> list5 = new ArrayList<>();
            String temp2 = "",temp3 = "";
            String result="";
            double num2 = 0;
    
    
            File file = new File("C:\Users\机械革命.000\Desktop\程序设计\大二上\哈夫曼\input.txt");
            ReadTxt read = new ReadTxt();
            String temp = read.txtString(file);
            System.out.println("读取的文件是:" + temp);
            int[] num = read.getNumber();  //  存放出现次数的数组
            char[] chars = read.getChars();  //  存放元素的数组
            for(int i = 0;i<27;i++){
                System.out.print(chars[i]+":"+num[i]+"   ");
                list.add(new HuffmanNode<>(chars[i]+"",num[i]));
            }
            Collections.sort(list);  //  按照自然顺序排序
    
            System.out.println();
            HuffmanCoding huffmanTree = new HuffmanCoding();
            HuffmanNode<String> root = huffmanTree.createTree(list);
    
            list2 = huffmanTree.BFS(root);//  利用广度优先遍历遍历整棵树后赋值
            for(int i = 0;i<list2.size();i++){
                if(list2.get(i).getData()!=null) {
                    list3.add(list2.get(i).getData());
                    list4.add(list2.get(i).getCode());
                }
            }
    
    
            for(int i = 0;i<list2.size();i++){
                num2 += list2.get(i).getWeight();
            }
    
            Collections.sort(list3);
            System.out.println("出现的概率中第一个代表空格。");
            for(int i = 0;i<list3.size();i++){
                System.out.print(list3.get(i) + "出现的概率为:" + list2.get(i).getWeight()/num2 + "  
    ");
            }
    
    
    
    
            System.out.println();
    
            for(int i = 0;i<list4.size();i++){
                System.out.print(list3.get(i)+"的编码为:"+list4.get(i)+" 
    ");
            }
            System.out.println();
    
            for(int i = 0;i<temp.length();i++){
                for(int j = 0;j<list3.size();j++){
                    if(temp.charAt(i) == list3.get(j).charAt(0)) {
                        result += list4.get(j);
                    }
                }
            }
    
    
    
    
    
            for(int i = 0;i<result.length();i++){
                list5.add(result.charAt(i)+"");
            }
    
    
            while (list5.size()>0){
                temp2 = temp2+"" +list5.get(0);
                list5.remove(0);
                for(int i=0;i<list4.size();i++){
                    if (temp2.equals(list4.get(i))) {
                        temp3 = temp3+""+list3.get(i);
                        temp2 = "";
                    }
                }
            }
            System.out.println();
    
            System.out.println("编码前:" + temp);
            System.out.println("编码后为:
    "+ result);
            System.out.println("解码后:"+"
    "+temp3);
    
            File file2 =new File("C:\Users\机械革命.000\Desktop\程序设计\大二上\哈夫曼\output.txt");
            Writer out =new FileWriter(file2);
            out.write(result);  //  将哈夫曼编码放入output.txt中
            out.close();
        }
    }
    

    实现时的问题

    • 问题一:在看到Collections.sort方法时不了解该方法,也不了解如何使用。
    • 问题一解决:在JAVA API中查询,查到了该方法,如图:

    该方法是一个排序方法,升序排序。

    • 问题二:Queue.offer方法不了解。
    • 问题二解决:查询JAVA API,如图:

      用于插入元素。
  • 相关阅读:
    php7.1安装
    nginx 的限制连接模块limit_zone与limit_req_zone
    selinux导致docker启动失败
    docker学习笔记
    kvm虚拟机
    ZooKeeper在线迁移
    启动EMQ(emqtt)时报错找不到libsctp.so.1
    Linux Samba服务主配文件smb.conf中文详解
    python-day7-字符串类型的内置方法
    python-day7-数字类型的内置方法
  • 原文地址:https://www.cnblogs.com/zhangyeye233/p/10100120.html
Copyright © 2011-2022 走看看