山东大学项目实训树莓派提升计划二期(十四)哈夫曼编码

目录

实验七 哈夫曼编码

实验目的

实验内容

实验代码框架

实验设计的思路与考量

哈夫曼编码的概念

哈夫曼树的构建

程序的实现


实验七 哈夫曼编码

实验目的

设计并实现二叉搜索树。

在二叉搜索树中查找元素。

在二叉搜索树中插入元素

遍历二叉树中的元素。

从二叉搜索树中删除元素。

使用二叉搜索树实现用于压缩数据的霍夫曼编码。

实验内容

使用实验六中的Heap类,实现HuffmanCode类中的方法,实现对一个字符串的编码和解码。具体要求如下:

输入输出要求:

  1. 输入为一个字符串,字符在ASCII字符集范围内。
  2. 控制台输出为①字母及对应字母的出现次数和哈夫曼编码②编码后的加密字符串③通过加密字符串解码后得到的字符串(要与输入字符串相同才为正确)。示例:

 代码实现要求:

  1. 实现wordToCode(String text)方法,输入为程序需要为之编码的字符串,返回HashMap<Character,String>类型的对象,保存字符串中的字符及其对应的哈夫曼编码。
  2. 实现code(HashMap<Character,String> wordToCode)方法,输入为上个方法中输出的字符及其哈夫曼编码的HashMap对象,返回编码后得到的字符串。

测试方法:

在本实验的测试类HuffmanCodeTest中,实现对本实验的测试首先输入测试字符串,再调用wordToCode(String text)、code(HashMap<Character,String> wordToCode)生成哈夫曼编码,使用得到的编码后字符串进行解码,如果得到的字符串与输入一致,即可通过测试。测试类的代码见代码框架。

实验代码框架

HuffmanCode类

import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;

public class HuffmanCode {
    String input="";
    public static void main(String[] args) {
    }
    public String code(HashMap<Character,String> wordToCode){
    }

    public HashMap<Character,String> wordToCode(String text){
    }

    public class Tree implements Comparable<Tree>{
    }

    public class Node{
    }
}

HuffmanCodeTest类

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.util.HashMap;
import java.util.Set;
import org.junit.Test;
import static org.junit.Assert.*;

public class HuffmanCodeTest {
    @Before
    public void setUp() throws Exception {
        System.out.println("begin");
    }

    @After
    public void tearDown() throws Exception {
        System.out.println("End and success");
    }
    @Test
    public void huffmanCode(){
        HuffmanCode x=new HuffmanCode();
        String inputString="abbcccddddeeeeeffffffggggggg";
        HashMap<Character,String> map=x.wordToCode(inputString);
        System.out.println(x.code(map));
        String code=x.code(map);

        String decode="";
        HashMap<String,Character> map2=new HashMap<>();
        Set<Character> set=map.keySet();
        int maxCodeLength=0;
        for(Character key:set){
            map2.put(map.get(key),key);
            if(map.get(key).length()>maxCodeLength)
                maxCodeLength=map.get(key).length();
        }

        int i=0;
        int len=Math.min(maxCodeLength,code.length());
        while (i<code.length()){
            String s=code.substring(i,i+len);
            Character character=map2.get(s);
            if(character==null)
                len--;
            else {
                decode+=character;
                i+=len;
                len=Math.min(maxCodeLength,code.length()-i);
            }
        }
        System.out.println(decode);
        assertEquals(inputString,decode);
    }

}

实验设计的思路与考量

哈夫曼编码的概念

哈夫曼编码通过使用更少的比特对更长出现的字符编码,从而压缩数据。字符的编码是基于字符在文本中出现的次数使用二叉树来构建的,该树称为霍夫曼编码。节点的左边和右边分别被赋值0和1。每个字符都是树中的一个叶节点,字符的编码从根节点到叶子结点的路径上变得值所组成。

哈夫曼树的构建

为了构建一棵哈夫曼树,使用如下算法:

  1. 从由树构成的森林开始。每棵树都包含一个表示字符的节点。每个结点的权重为该字符在文本中出现的次数。
  2. 重复以下步骤来合并树,直到只有一棵树为止:选择两棵有最小权重的树,创建一个新的节点作为它们的父节点。这棵新树的权重是子树的权重和。
  3. 对于每个内部节点,给它的做编制赋值为0,右边赋值为1。所有的叶子节点都表示文本中的个字符。

其中没有编码是另一个编码的前缀,这个属性保证了流可以无二义性地解码。

这里使用的算法是贪婪算法的一个实例。贪婪算法经常用于解决优化问题。算法做出局部最优的选择,并希望这样的选择会导致全局最优。

程序的实现

  1. 需要自行实现一个内部类表示节点,有左子树、右子树、节点权重值和它代表的字符。
  2. 需要自行实现一个内部类表示树,有根节点,并且可以代表初始生成的树(以权重和字符生成叶节点),也可以表示结合生成新树的节点(以左子树和右子树生成新树,权重为两棵树的权重之和)。
  3. 生成哈夫曼树的时候需要用到实验六实现的Heap类。当时实现的是大根堆,而我们需要每次选出权重值最小和次小的树进行合并,所以需要重载compare方法,实现逆转,可以在实现内部类Tree的时候进行重载(因为对比的是树的根节点的值,而内部类Tree中就有根节点)。示例如下:
    public class Tree implements Comparable<Tree>{
        Node root;

        public Tree(Tree t1,Tree t2){
            root=new Node();
            root.left= t1.root;
            root.right=t2.root;
            root.weight=t1.root.weight+t2.root.weight;
        }

        public Tree(int weight,char element){
            root=new Node(weight,element);
        }
        @Override
        public int compareTo(Tree t) {
            if(root.weight<t.root.weight)
                return 1;
            else if(root.weight==t.root.weight)
                return 0;
            else
                return -1;
        }
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值