zoukankan      html  css  js  c++  java
  • 20182301 2019-2020-1 《数据结构与面向对象程序设计》哈夫曼实验报告

    20182301 2019-2020-1 《数据结构与面向对象程序设计》哈夫曼实验报告

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

    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. 实验过程及结果

    • 定义:
    • 哈夫曼树(霍夫曼树)又称为最优树.
      • 路径和路径长度
        在一棵树中,从一个结点往下可以达到的孩子或孙子结点之间的通路,称为路径。通路中分支的数目称为路径长度。若规定根结点的层数为1,则从根结点到第L层结点的路径长
      • 结点的权及带权路径长度
        若将树中结点赋给一个有着某种含义的数值,则这个数值称为该结点的权。结点的带权路径长度为:从根结点到该结点之间的路径长度与该结点的权的乘积。
      • 树的带权路径长度
        树的带权路径长度规定为所有叶子结点的带权路径长度之和,记为WPL
    • 第一步,了解文件读入和文件写入的方法
    //读取文件
    File file = new File("E:\idea\week_12s\input.txt");
    Scanner scan = new Scanner(file);//Scanner的新用法
    String s =scan.nextLine();//读取出来字符串
    //写入文件
    File file2 = new File("E:\idea\week_12s\put.txt");
    FileWriter fileWriter1 = new FileWriter(file1);
    fileWriter1.write(result2);
    
    • 第二步,打印频率
    System.out.println("打印各字母出现频率:");
    for (int i = 0; i < array.length; i++) {
            System.out.print((char) ('a' + i) + ":" + (double) array[i] / s.length() + "
    ");
            }//把26个字母的概率都打出来
    
    • 第三步:将数组转换为哈夫曼结点
    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);
            }
    
    • 第四步:构建哈夫曼树
    package com.company;
    
    
    
    import java.lang.reflect.Array;
    import java.util.ArrayList;
    import java.util.Stack;
    
    public class HuffmanTree {
        HuffmanTreeNode root; // 根结点
        private String[] codes = new String[26];
    
        public HuffmanTree(HuffmanTreeNode[] a) throws EmptyCollectionException {
            HuffmanTreeNode parent = null;
            ArrayHeap<HuffmanTreeNode> heap;
    
            // 建立数组a对应的最小堆
            heap = new ArrayHeap<>();
    
            for(int i=0; i<a.length; i++) {
                heap.addElement(a[i]);
            }
    
    
            for(int i=0; i<a.length-1; i++) {
                HuffmanTreeNode left = heap.removeMin();  // 最小节点是左孩子
                HuffmanTreeNode right = heap.removeMin();
    
    
                parent = new HuffmanTreeNode(left.weight+right.weight,' ',left,right,null);
                left.parent = parent;
                right.parent = parent;
    
                heap.addElement(parent);
            }
    
            root = parent;
        }
    
        public String printTree() throws EmptyCollectionException {
            UnorderedListADT<HuffmanTreeNode> nodes =
                    new ArrayUnorderedList();
            UnorderedListADT<Integer> levelList =
                    new ArrayUnorderedList<Integer>();
            HuffmanTreeNode current;
            String result = "";
            int printDepth = this.getHeight()-1;
            int possibleNodes = (int)Math.pow(2, printDepth + 1);
            int countNodes = 0;
    
            nodes.addToRear(root);
            Integer currentLevel = 0;
            Integer previousLevel = -1;
            levelList.addToRear(currentLevel);
    
            while (countNodes < possibleNodes)
            {
                countNodes = countNodes + 1;
                current = nodes.removeFirst();
                currentLevel = levelList.removeFirst();
                if (currentLevel > previousLevel)
                {
                    result = result + "
    
    ";
                    previousLevel = currentLevel;
                    for (int j = 0; j < ((Math.pow(2, (printDepth - currentLevel))) - 1); j++)
                        result = result + " ";
                }
                else
                {
                    for (int i = 0; i < ((Math.pow(2, (printDepth - currentLevel + 1)) - 1)) ; i++)
                    {
                        result = result + " ";
                    }
                }
                if (current != null)
                {
                    result = result + current.weight;
                    nodes.addToRear(current.left);
                    levelList.addToRear(currentLevel + 1);
                    nodes.addToRear(current.right);
                    levelList.addToRear(currentLevel + 1);
                }
                else {
                    nodes.addToRear(null);
                    levelList.addToRear(currentLevel + 1);
                    nodes.addToRear(null);
                    levelList.addToRear(currentLevel + 1);
                    result = result + " ";
                }
            }
            return result;
        }
    
        private int getHeight() {
            return height(root);
        }
    
        private int height(HuffmanTreeNode node)
        {
            if(node==null){
                return 0;
            }
            else {
                int leftTreeHeight = height(node.left);
                int rightTreeHeight= height(node.right);
                return leftTreeHeight>rightTreeHeight ? (leftTreeHeight+1):(rightTreeHeight+1);
            }
        }
    
        protected void inOrder( HuffmanTreeNode node,
                                ArrayList<HuffmanTreeNode> tempList)
        {
            if (node != null)
            {
                inOrder(node.left, tempList);
                if (node.element!=' ')
                    tempList.add(node);
    
                inOrder(node.right, tempList);
            }
        }
    
        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;
        }
    }
    
    
    • 第五步:进行加密
    //进行编码:二进制加法
            String result = "";
            for (int i = 0; i < s.length(); i++) {
                int x = s.charAt(i) - 'a';
                result += codes[x];
            }
            System.out.println("编码结果:" + result);
    
    • 第六步:解码
    //进行解码
            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();//移到上一个结点
                }
            }
    

    3. 实验过程中遇到的问题和解决过程

    • 问题1:为什么写入文件,但是文件不出现内容呢?
    • 问题1解决方案:
    • 可能是因为文件内容存于缓冲区中,不能写入,读取文件时可以从缓冲区中读取,于是我修改了写入的方法
    //类似
    FileOutputStream fop = null;
      File file;
      String content = "This is the text content";
     
      try {
     
       file = new File("c:/newfile.txt");
       fop = new FileOutputStream(file);
     
       // if file doesnt exists, then create it
       if (!file.exists()) {
        file.createNewFile();
       }
     
       // get the content in bytes
       byte[] contentInBytes = content.getBytes();
     
       fop.write(contentInBytes);
       fop.flush();
       fop.close();
     
       System.out.println("Done");
    
    • 问题2:我在学习中又看到解压加压的方法,学习一下
    • 问题2解决办法:
    • 写了压缩的程序
    package com.company;
    
    
    import java.io.BufferedInputStream;
    
    import java.io.File;
    
    import java.io.FileInputStream;
    
    import java.io.FileOutputStream;
    
    import java.io.InputStream;
    
    import java.io.OutputStream;
    
    import java.util.zip.CRC32;
    
    import java.util.zip.CheckedOutputStream;
    import java.util.zip.ZipEntry;
    import java.util.zip.ZipOutputStream;
    
    
    public class Test
    
    {
    
        static String filePath = "E:/idea/week_12s/zip";//需要压缩的文件夹完整路径
    
        static String fileName = "zip";//需要压缩的文件夹名
    
        static String outPath = "E:/idea/week_12s/zip/test.zip";//压缩完成后保存为Test.zip文件,名字随意
    
    
    
        public static void main(String args[]) throws Exception
    
        {
    
            OutputStream is = new FileOutputStream(outPath);//创建Test.zip文件
    
            CheckedOutputStream cos = new CheckedOutputStream(is, new CRC32());//检查输出流,采用CRC32算法,保证文件的一致性
    
            ZipOutputStream zos = new ZipOutputStream(cos);//创建zip文件的输出流
    
            zos.setComment("GBK");//设置编码,防止中文乱码
    
            File file = new File(filePath);//需要压缩的文件或文件夹对象
    
            ZipFile(zos,file);//压缩文件的具体实现函数
    
            zos.close();
    
            cos.close();
    
            is.close();
    
            System.out.println("压缩完成");
    
        }
    
    
    
        //递归,获取需要压缩的文件夹下面的所有子文件,然后创建对应目录与文件,对文件进行压缩
    
        public static void ZipFile(ZipOutputStream zos,File file) throws Exception
    
        {
    
            if(file.isDirectory())
    
            {
    
                //创建压缩文件的目录结构
    
                zos.putNextEntry(new ZipEntry(file.getPath().substring(file.getPath().indexOf(fileName))+File.separator));
    
    
    
                for(File f : file.listFiles())
    
                {
    
                    ZipFile(zos,f);
    
                }
    
            }
    
            else
    
            {
    
                //打印输出正在压缩的文件
    
                System.out.println("正在压缩文件:"+file.getName());
    
                //创建压缩文件
    
                zos.putNextEntry(new ZipEntry(file.getPath().substring(file.getPath().indexOf(fileName))));
    
                //用字节方式读取源文件
                InputStream is = new FileInputStream(file.getPath());
                //创建一个缓存区
                BufferedInputStream bis = new BufferedInputStream(is);
                //字节数组,每次读取1024个字节
                byte [] b = new byte[1024];
                //循环读取,边读边写
                while(bis.read(b)!=-1)
                {
                    zos.write(b);//写入压缩文件
                }
                //关闭流
                bis.close();
                is.close();
            }
        }
    }
    
    
    • 结果:压缩成功,解压也该也大同小异,就不在这里缀述了

    代码链接

    其他(感悟、思考等)

    到现在,我已经学习了很多树了,逐渐有了树的思维,以后也会多多运用的。

    参考资料

  • 相关阅读:
    One网络模拟器探索之七:路由模块的工作原理
    An Intuitive Explanation of GraphSAGE
    《k8s 源码分析》- Custom Controller 之 Informer
    《k8s-1.13版本源码分析》-抢占调度
    《k8s-1.13版本源码分析》- Informer 机制
    《k8s-1.13版本源码分析》-调度器初始化
    《k8s-1.13版本源码分析》-源码调试
    《k8s-1.13版本源码分析》-调度优选
    《k8s-1.13版本源码分析》-调度预选
    《k8s-1.13版本源码分析》-调度器框架
  • 原文地址:https://www.cnblogs.com/zhaopeining/p/11900292.html
Copyright © 2011-2022 走看看