哈夫曼编码测试

实验目的

设有字符集: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)把实验结果截图上传到云班课
满分:6分。

实验过程

HuffmanNode设计

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;
} 
}

哈夫曼树构造分为以下几步:

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

    }
}

实验结果

码云链接

posted @ 2018-12-12 22:26  大雪将烬  阅读(222)  评论(0编辑  收藏  举报