# 20182317 2019-2020-1 哈夫曼测试

20182317 2019-2020-1 哈夫曼测试

课程:《程序设计与数据结构》

班级: 1823

姓名: 彭衍泰

学号:20182317

实验教师:王志强

实验日期:2019年10月22日

必修/选修: 必修

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. 统计出现的字符及频率
  2. 将各个字符创建为叶子结点,频率为结点的权值,用链表保存这些叶子结点
  3. 将结点队列中的结点按权值升序排列
  4. 取出权值最小的两个结点构建父节点(要从链表中删除取出的结点),将新生成的父节点添加到结点链表,并从新排序
  5. 重复4步骤,直到只剩下一个结点
  6. 返回最后的结点,即为哈夫曼树的根节点。

主要代码:

public class Node { 
    public String code = "";
public String data = ""; 
public int count;
public Node lChild; 
public Node rChild; 
public Node() { 
    
}
 public Node(String data, int count) { 
    this.data = data; 
this.count = count; 
} 
public Node(int count, Node lChild, Node rChild) 
    { 
    this.count = count; 
    this.lChild = lChild;
    this.rChild = rChild; 
    } 
public Node(
      String data, 
      int count, 
      Node lChild,
      Node rChild) { 
    this.data = data; 
    this.count = count; 
    this.lChild = lChild; 
    this.rChild = rChild;
} 
}
 public void creatHfmTree(String str) {
        this.str = str;

        NodeList = new LinkedList<HNode>();
        charList = new LinkedList<CharData>();

        // 1.统计字符串中字符以及字符的出现次数
        // 以CharData类来统计出现的字符和个数
        getCharNum(str);

        // 2.根据第一步的结构,创建节点
        creatNodes();

        // 3.对节点权值升序排序
        Sort(NodeList);

        // 4.取出权值最小的两个节点,生成一个新的父节点
        // 5.删除权值最小的两个节点,将父节点存放到列表中
        creatTree();

        // 6.重复第四五步,就是那个while循环
        // 7.将最后的一个节点赋给根节点
        root = NodeList.get(0);
    }
private String hfmCodeStr = "";// 哈夫曼编码连接成的字符串

    /**
     * 编码
     * @param str
     * @return
     */
    public String toHufmCode(String str) {

        for (int i = 0; i < str.length(); i++) {
            String c = str.charAt(i) + "";
            search(root, c);
        }

        return hfmCodeStr;
    }

    /**
     * 
     * @param root 哈夫曼树根节点
     * @param c 需要生成编码的字符
     */
    private void search(HNode root, String c) {
        if (root.lChild == null && root.rChild == null) {
            if (c.equals(root.data)) {
                hfmCodeStr += root.code; // 找到字符,将其哈夫曼编码拼接到最终返回二进制字符串的后面
            }
        }
        if (root.lChild != null) {
            search(root.lChild, c);
        }
        if (root.rChild != null) {
            search(root.rChild, c);
        }
    }


    // 保存解码的字符串
    String result="";
    boolean target = false; // 解码标记
    /**
     * 解码
     * @param codeStr
     * @return
     */
    public String CodeToString(String codeStr) {

        int start = 0;
        int end = 1;

        while(end <= codeStr.length()){
            target = false;
            String s = codeStr.substring(start, end);
            matchCode(root, s); // 解码
            // 每解码一个字符,start向后移
            if(target){
                start = end;
            }
            end++;
        }

        return result;
    }

    /**
     * 匹配字符哈夫曼编码,找到对应的字符
     * @param root 哈夫曼树根节点
     * @param code 需要解码的二进制字符串
     */
    private void matchCode(HNode root, String code){
        if (root.lChild == null && root.rChild == null) {
            if (code.equals(root.code)) {
                result += root.data; // 找到对应的字符,拼接到解码字符穿后
                target = true; // 标志置为true
            }
        }
        if (root.lChild != null) {
            matchCode(root.lChild, code);
        }
        if (root.rChild != null) {
            matchCode(root.rChild, code);
        }

    }
}

实验结果

其他(感悟、思考等)

通过这次实验,我对曾经学过的知识有了更深一步的了解同时对一些类的应用也更加熟悉,同时也弄懂了一些过去不是很懂的知识点可谓是受益匪浅。

参考资料

  • 《Java程序设计与数据结构教程(第二版)》

  • 《Java程序设计与数据结构教程(第二版)》学习指导

posted @ 2019-11-22 22:03  20182317彭衍泰  阅读(124)  评论(0编辑  收藏  举报