代码改变世界

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

2019-11-22 10:00  BBIowa  阅读(386)  评论(0编辑  收藏  举报

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

  • 课程:《程序设计与数据结构》
  • 班级: 1823
  • 姓名:赵天昊
  • 学号:20182327
  • 实验教师:王志强
  • 实验日期:2019年11月17日
  • 必修/选修: 必修

教材中的哈夫曼树

  • 1、在计算机数据处理中,哈夫曼编码使用变长编码表对源符号(如文件中的一个字母)进行编码,其中变长编码表是通过一种评估来源符号出现机率的方法得到的,出现机率高的字母使用较短的编码,反之出现机率低的则使用较长的编码,这便使编码之后的字符串的平均长度、期望值降低,从而达到无损压缩数据的目的。

  • 2、例如,在英文中,e的出现机率最高,而z的出现概率则最低。当利用哈夫曼编码对一篇英文进行压缩时,e极有可能用一个比特来表示,而z则可能花去25个比特(不是26)。用普通的表示方法时,每个英文字母均占用一个字节,即8个比特。二者相比,e使用了一般编码的1/8的长度,z则使用了3倍多。倘若我们能实现对于英文中各个字母出现概率的较准确的估算,就可以大幅度提高无损压缩的比例。

  • 3、哈夫曼树又称最优二叉树,是一种带权路径长度最短的二叉树。所谓树的带权路径长度,就是树中所有的叶结点的权值乘上其到根结点的路径长度(若根结点为0层,叶结点到根结点的路径长度为叶结点的层数)。树的路径长度是从树根到每一结点的路径长度之和,记为WPL=(W1XL1+W2XL2+W3XL3+...+WnXLn),N个权值Wi(i=1,2,...n)构成一棵有N个叶结点的二叉树,相应的叶结点的路径长度为Li(i=1,2,...n)。可以证明哈夫曼树的WPL是最小的。

哈夫曼树及测试的实现

  • 参考教材java创建哈夫曼树和实现哈夫曼——java实现哈夫曼编码,尝试读懂代码的同时加入自己的理解。

  • 首先建立哈夫曼树的结点类【HuffmanNode】利用泛型实现结点,定义左子树,右子树,权值和编码。

    public class HuffmanTreeNode implements Comparable<HuffmanTreeNode>{
    protected int weight;              // 权值
    protected HuffmanTreeNode left;     // 左孩子
    protected HuffmanTreeNode right;    // 右孩子
    protected HuffmanTreeNode parent;   // 父结点
    protected char element;
    protected HuffmanTreeNode(int weight, char element, HuffmanTreeNode left, HuffmanTreeNode right, HuffmanTreeNode parent) {
        this.weight = weight;
        this.element = element;
        this.left = left;
        this.right = right;
        this.parent = parent;
    }
    @Override
    public int compareTo(HuffmanTreeNode o) {
        if (this.weight > o.weight)
            return 1;
        else if (this.weight < o.weight)
            return -1;
        else
            return 0;
    }
    
    

···

  • 编写以下代码读取txt文件中的字母,用于将字母转化成哈夫曼编码。

    public static void main(String[] args) throws IOException {
       File file = new File("C:\\Users\\12441\\Desktop\\game\\input1.txt");
       Scanner scan = new Scanner(file);
       String s = scan.nextLine();
       System.out.println(s);
       int[] array = new int[26];
       for (int i = 0; i < array.length; i++) {
           array[i] = 0;
       }
       for (int i = 0; i < s.length(); i++) {
           char x = s.charAt(i);
           array[x - 'a']++;
    

···

  • 编写【getEnCoding】类将读取的字母转化成为哈夫曼编码,并且规定左子树为0,右子树为1
 public String[] getEncoding() {
        ArrayList<HuffmanTreeNode> arrayList = new ArrayList();
        inOrder(root,arrayList);
        for (int i=0;i<arrayList.size();i++)
        {
            HuffmanTreeNode node = arrayList.get(i);
            String result ="";
            int x = node.element-'a';
            Stack stack = new Stack();
            while (node!=root)
            {
                if (node==node.parent.left)
                    stack.push(0);
                if (node==node.parent.right)
                    stack.push(1);
                node=node.parent;
            }
            while (!stack.isEmpty())
            {
                result +=stack.pop();
            }
            codes[x] = result;
        }
        return codes;
    }
    public HuffmanTreeNode getRoot() {
        return root;
    }

  • 最后编写实现类【Huffman】从input1.txt中读取信息,转化为哈夫曼编码后将哈夫曼编码放入output.txt中后完成测试
public class RunHuffmanTree {
    public static void main(String[] args) throws IOException {
        File file = new File("C:\\Users\\12441\\Desktop\\game\\input1.txt");
        Scanner scan = new Scanner(file);
        String s = scan.nextLine();
        System.out.println(s);
        int[] array = new int[26];
        for (int i = 0; i < array.length; i++) {
            array[i] = 0;
        }
        for (int i = 0; i < s.length(); i++) {
            char x = s.charAt(i);
            array[x - 'a']++;
        }
        System.out.println("打印各字母出现频率:");
        for (int i = 0; i < array.length; i++) {
            System.out.print((char) ('a' + i) + ":" + (double) array[i] / s.length() + " ");
        }
        HuffmanTreeNode[] huffmanTreeNodes = new HuffmanTreeNode[array.length];
        for (int i = 0; i < array.length; i++) {
            huffmanTreeNodes[i] = new HuffmanTreeNode(array[i], (char) ('a' + i), null, null, null);
        }

        HuffmanTree huffmanTree = new HuffmanTree(huffmanTreeNodes);
        System.out.println("打印各字母的编码");
        String[] codes = huffmanTree.getEncoding();
        for (int i = 0; i < codes.length; i++) {
            System.out.println((char) ('a' + i) + ":" + codes[i]);
        }
        //进行编码:
        String result = "";
        for (int i = 0; i < s.length(); i++) {
            int x = s.charAt(i) - 'a';
            result += codes[x];
        }
        System.out.println("编码结果:" + result);
        //写入文件
        File file1 = new File("C:\\Users\\12441\\Desktop\\game\\output.txt");
        FileWriter fileWriter = new FileWriter(file1);
        fileWriter.write(result);
        fileWriter.close();
        //从文件读取
        Scanner scan1 = new Scanner(file1);
        String s1 = scan1.nextLine();
        HuffmanTreeNode huffmanTreeNode = huffmanTree.getRoot();
        //进行解码
        String result2 = "";
        for (int i = 0; i < s1.length(); i++) {
            if (s1.charAt(i) == '0') {
                if (huffmanTreeNode.left != null) {
                    huffmanTreeNode = huffmanTreeNode.left;
                }
            } else {
                if (s1.charAt(i) == '1') {
                    if (huffmanTreeNode.right != null) {
                        huffmanTreeNode = huffmanTreeNode.right;
                    }
                }
            }
            if (huffmanTreeNode.left == null && huffmanTreeNode.right == null) {
                result2 += huffmanTreeNode.element;
                huffmanTreeNode = huffmanTree.getRoot();
            }
        }
        System.out.println("解码结果:" + result2);
        //写入文件
        File file2 = new File("C:\\Users\\12441\\Desktop\\game\\file2.txt");
        FileWriter fileWriter1 = new FileWriter(file1);
        fileWriter1.write(result2);
        // 判断解码后原来是否一致
        System.out.println("编码解码后原来是否一致:" + result2.equals(s));
    }

}

实验结果