20172323 2018-2019-1 《程序设计与数据结构》课堂测试报告

20172323 2018-2019-1 《程序设计与数据结构》课堂测试报告

课程:《程序设计与数据结构》
班级: 1723
姓名: 王禹涵
学号: 20172323
实验教师:王志强老师
测试日期:2018年12月10日
必修/选修: 必修

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)对编码文件进行解码,输出一个解码后的文件
(5)撰写博客记录实验的设计和实现过程,并将源代码传到码云
(6)把实验结果截图上传到云班课

2. 测试过程及结果

基本原理:

  • 哈夫曼树:给定n个权值作为n个叶子结点,构造一棵二叉树,若带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree)。哈夫曼树是带权路径长度最短的树,权值较大的结点离根较近。

    路径: 树中一个结点到另一个结点之间的分支构成这两个结点之间的路径。

    路径长度:路径上的分枝数目称作路径长度。

    树的路径长度:从树根到每一个结点的路径长度之和。

    结点的带权路径长度:在一棵树中,如果其结点上附带有一个权值,通常把该结点的路径长度与该结点上的权值之积称为该结点的带权路径长度(weighted path length)

    树的带权路径长度:如果树中每个叶子上都带有一个权值,则把树中所有叶子的带权路径长度之和称为树的带权路径长度。

具体实现:

  • 第一步需要定义哈夫曼树的结点类HuffmanNode,其中包含了每个结点的携带的信息name,它的权重weight,指向它左右孩子的指针以及表示编码的String值code。同时为了方便进行排序,声明了Comparable接口
    protected HuffmanNode left;
    protected HuffmanNode right;
    protected  String name;
    protected double weight;
    protected String code;

    public HuffmanNode(String name, double weight){
        this.name = name;
        this.weight = weight;
        code = "";
    }

    public int compareTo(HuffmanNode node) {
        if (weight >= node.weight){
            return 1;
        }
        else {
            return -1;
        }

    }
  • 接下来构造哈夫曼树
while(nodes.size() > 1){
            Collections.sort(nodes);
            Node<T> left = nodes.get(nodes.size()-1);
            Node<T> right = nodes.get(nodes.size()-2);
            Node<T> parent = new Node<T>(null, left.getWeight()+right.getWeight());
            parent.setLeft(left);
            parent.setRight(right);
            nodes.remove(left);
            nodes.remove(right);
            nodes.add(parent);
        }
        return nodes.get(0);

这里将所有的哈夫曼树的结点都存在了一个数组之中,判断数组1内是否有元素,进入while循环之后先将数组元素进行排序,然后取出数组中的最小元素和次小元素(即是数组中的末两位)分别作为左右孩子,二者之和作为父结点元素放入数组之中重新进行排序,直至数组中元素为一,哈夫曼树构造完成。紧接着是哈夫曼树的广度优先遍历方法

List<Node<T>> list = new ArrayList<Node<T>>();
        Queue<Node<T>> queue = new ArrayDeque<Node<T>>();

        if(root != null){
            queue.offer(root);
        }

        while(!queue.isEmpty()){
            list.add(queue.peek());
            Node<T> node = queue.poll();

            if(node.getLeft() != null){
                queue.offer(node.getLeft());
            }

            if(node.getRight() != null){
                queue.offer(node.getRight());
            }
        }
        return list;

基础的哈夫曼树构造好了,接着需要在此基础上进行哈夫曼编码。基本思路是,从根结点开始设二叉树的左子树编码为‘0’,右子树的编码为‘1’,依次编码下去直到叶结点,然后从根到每个叶结点依次写出叶结点的编码--哈夫曼编码,具体实现就是在构造哈夫曼树的同时,加上如下代码

left.setCode("0");
right.setCode("1");

因为这里设置的是String型,所以要加上“”,表示字符串。同时遍历方法也要相应加上“0”,“1”。当遍历到左孩子时,加上1,遍历到右孩子时,加上0.

  • 基本的方法已经构造好了,接下来需要进行的是读取文件进行编码,在指定目录下添加一个txt文件,里面是需要进行编码的文字。运用
File file = new File("此处填写文件路径");
     BufferedReader br = new BufferedReader(new FileReader(file));

读入文件内的信息。通过readline方法将信息成行读入,并重新拼接成字符串,逐个字符进行比对,统计出现的个数及概率并进行输出

List<String> list = new ArrayList<String>();
     list.add("a");
     list.add("b");
     list.add("c");
     list.add("d");
     list.add("e");
     list.add("f");
     list.add("g");
     list.add("h");
     list.add("i");
     list.add("j");
     list.add("k");
     list.add("l");
     list.add("m");
     list.add("n");
     list.add("o");
     list.add("p");
     list.add("q");
     list.add("r");
     list.add("s");
     list.add("t");
     list.add("u");
     list.add("v");
     list.add("w");
     list.add("x");
     list.add("y");
     list.add("z");
     list.add(" ");
     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};
     File file = new File("C:\\Users\\10673\\Desktop\\input.txt");
     BufferedReader br = new BufferedReader(new FileReader(file));
        String s;
        String message = "";
        while((s = br.readLine()) != null){
            message += s;
        }
        String[] result = message.split("");
        for (int n = 0;n < result.length; n++){
            for (int i = 0; i < 27; i++){
                if (result[n].equals(list.get(i))){
                    number[i] += 1;
                }
            }
        }
        List<HuffmanNode> nodeList = new ArrayList<HuffmanNode>();
        DecimalFormat df = new DecimalFormat( "0.0000000");
        double wei;
        double sum = result.length;
        for(int i = 0;i<27;i++){
            wei = ((double) number[i]/sum);
            System.out.println(list.get(i) + "出现" + number[i] + "次,概率为" + df.format(wei));
            nodeList.add(new HuffmanNode(list.get(i),number[i]));
        }
        Collections.sort(nodeList);
        HuffmanTree huffmanTree = new HuffmanTree();
        HuffmanNode node = huffmanTree.createTree(nodeList);
        List<HuffmanNode> inlist = new ArrayList<HuffmanNode>();
        inlist = huffmanTree.breadth(node);

以上代码并不是特别的复杂,我构造了一个字符列表,用以与得到的字符串进行比对,当某个字符比对成功之后,相应位置的数组的值加一,这样就可以统计到每个字符出现的次数。再然后计算得到每个字符出现的概率,将这些字符及其权重存储在HuffmanNode的列表中,通过此就可以调用哈夫曼树的构造方法。剩下的几个方法,就是将哈夫曼树的结点逐个进行编码解码,并输出到指定的文件之中
运行结果如图所示
[](https://img2018.cnblogs.com/blog/1332964/201812/1332964-20181211214511138-1894899771.png

3. 代码链接

4. 测试过程中遇到的问题和解决过程

问题1:运用除法计算字符出现的概率时,运算结果全部为0,如图

问题1解决方案:最开始以为是显示的只有小数点后一位,所以很多数据比较小,四舍五入之后就只剩下0.0,查阅资料重新控制double类型小数点后位数的方法
DecimalFormat df = new DecimalFormat( "0.00"); //设置double类型小数点后位数格式
               double d1 = 2.1;
               System.out.println(df.format(d1)); //将输出2.10

输出之后发现概率全部都为0.这里运用到的方法是number[i]/sum,sum是总的字符个数,number[i]依次是每个字符的出现次数。
问题就出在这个除法上,因为这是两个整型数相除,所以得到的依然会是一个整型数,即便再把它转换成double类型,最终出来的也是0.0,所以应该在相除之前就将两个除数转换为double类型,这样得出的结果就是正确的

参考资料

- [哈夫曼树的java实现](https://blog.csdn.net/jdhanhua/article/details/6621026)

原文地址:https://www.cnblogs.com/Lewandodoski/p/10105553.html

时间: 2024-10-14 04:02:33

20172323 2018-2019-1 《程序设计与数据结构》课堂测试报告的相关文章

20172323 2017-2018-2 《程序设计与数据结构》实验1报告

20172323 2017-2018-2 <程序设计与数据结构>实验1报告 课程:<程序设计与数据结构> 班级: 1723 姓名: 王禹涵 学号:20172323 实验教师:王志强 实验日期:2018年3月21日 必修/选修: 必修 1.实验内容 1.学习Java开发环境的熟悉(Linux + Eclipse)和Intellj IDEA 简易教程 2.练习(通过命令行和IDEA两种方式实现)换成前两周项目内容: 3.练习实验项目PP2.5,PP3.3,PP3.5,PP3.8, 实验

20172301 2017-2018-2 《程序设计与数据结构》课堂测试修改报告

20172301 2017-2018-2 <程序设计与数据结构>课堂测试修改报告 课程:<程序设计与数据结构> 班级: 1723 姓名: 郭恺 学号: 20172301 实验教师:王志强老师 测试日期:2018年4月11日 必修/选修: 必修 测试内容 书P241 PP7.4 首先,修改RationalNumber类, 实现 Comparable接口. 然后以0.0001为误差精度进行比较. 编写main驱动方法进行测试. 测试过程及结果 设计思路:我们要想实现Comparable

20172301 2017-2018-2 《程序设计与数据结构》第7周课堂测试修改报告

20172326 <程序设计与数据结构>课堂测试修改报告 课程:<程序设计与数据结构> 班级: 1723 姓名: 康皓越 学号: 20172326 实验教师:王志强老师 测试日期:2018年4月11日 必修/选修: 必修 测试内容 命令行参数测试 要求: 从命令行传入 学号.课程的成绩,计算平均成绩,并输出. 例如:输入 java computeAverage 20172301 98 99 100 输出:2017 2301' average score is :99 测试过程 分析

20172303 2018-2019-1 《程序设计与数据结构》第5周课堂实践报告

20172303 2018-2019-1 <程序设计与数据结构>第5周课堂实践报告 课程:<程序设计与数据结构> 班级: 1723 姓名: 范雯琪 学号:20172303 实验教师:王志强 助教:张师瑜/张之睿 实验日期:2018年10月12日 必修/选修: 必修 测试内容 ASL测试 已知线性表具有元素{5,13,19,21,37,56,64,75,80,88,92},如果使用折半查找法,ASL是多少? 要求:写出结题过程 测试原理 ASL(Average Search Leng

20172319 2018.03.05-2018.03.11 《程序设计与数据结构》第1周学习总结

学号20172319 2018.03.05-2018.03.11 <程序设计与数据结构>第1周学习总结 教材学习内容总结 复习上学期导论课所学知识 认识.了解与Java相关的基本知识:二符一字.四类编程语言.三种机器 程序中定义的标识符不能以数字开头且有&符号的标识符无效 教材学习中的问题和解决过程 问题1:什么是URL? 解决过程:上网查询相关资料:URL简单来说就是我们常说的网址,其实是统一资源定位符,包含协议与IP地址,其作用是定位资源及显示其所在位置 代码调试中的问题和解决过程

20172319 2018.03.12-19 《程序设计与数据结构》第2周学习总结

学号 20172319 2018.03.12-19 <程序设计与数据结构>第2周学习总结 教材学习内容总结 1.字符串:基本定义:print与println方法的区别:字符串的拼接:转义序列的应用. 2.变量与赋值:变量:常量:赋值语句. 3.基本数据类型:四整二浮点一字符一布尔. 4.表达式:运算符的种类及其使用规则. 5.数据类型转换:基本数据类型间的转换(扩展及压缩):数据转换方式:赋值(只能扩展).提升.强制. 6.交互式程序:Scanner 类. 教材学习中的问题和解决过程 问题1:

20172323 2017-2018-2 《程序设计与数据结构》第五周学习总结

教材学习内容总结 条件语句和循环语句可用于控制程序的执行流程 条件语句(选择语句)允许选择下一条执行的语句.Java中主要的条件语句有if.if-else.switch语句 循环语句可以是程序多次执行某些语句,主要的语句有while.do.for语句 相等性运算符和关系运算符:"=="和"!="用于判断两个值是否相等. 逻辑运算符:逻辑非"!",逻辑与"&&",逻辑或"||".逻辑运算符常用

20172305 2017-2018-2 《程序设计与数据结构》课堂测试报告

课程:<程序设计与数据结构> 班级: 1723 姓名: 谭鑫 学号: 20172305 实验教师:王志强老师 测试日期:2018年5月28日 必修/选修: 必修 1.测试内容 Android开发实践:Android平台上开发移动程序,模拟栈的操作:Push和Pop 2. 测试过程及结果 设计思路: 在Java环境下运用的stack栈的方法应用到Android开发环境 分别实现Push和Pop两个方法 合理优化Android界面 步骤: 建立活动的App名称,确定界面至少有两个Button,两个

20172323 2018-2019-1 《程序设计与数据结构》第一周学习总结

20172323 2018-2019-1 <程序设计与数据结构>第一周学习总结 教材学习内容总结 第一章--概述 1.1 软件质量 软件工程(Software Engineering)是一门关于高质量软件开发的技术和理论的学科. 解决的问题:控制开发过程,实现高质量的软件 软件工程的目标 高质量软件的特征 1.2 数据结构 数据结构:计算机存储.组织数据的形式. 程序 = 数据结构 + 算法 软件 = 程序 + 软件工程 栈会颠倒数据的顺序,而队列可以保持数据的顺序. 第二章--算法分析 算法