哈夫曼树实现数据压缩

用java代码实现哈夫曼树的构建,以及哈夫曼编码的数据压缩,同时也解决了数据恢复时出现与原字符串不同的问题。


前言

哈夫曼树是最优的二叉树,将带权的节点构建成一个带权路径WPL最小的二叉树。利用哈夫曼树的结构,对叶子节点进行编码,会得到一个哈夫曼编码集合,且这个集合里面任意两个元素的编码前缀都不一样,当数据匹配时能准确无误的找到对应的元素,因此哈夫曼编码适用于重复量多的数据进行压缩。


一、哈夫曼树的介绍

哈夫曼树:最优二叉树,也是带权路径长度最短的树。

以下是对一些带权二叉树的路径WPL计算:
在这里插入图片描述

可以看出,带权是指叶子节点是有值,当WPL的值小时,值大的叶子节点离根节点近,值小的叶子节点离根节点远。因此哈夫曼树是根据值的大小决定叶子节点的位置。

二、构建哈夫曼树

图解

给定数列{2,5,9,1,13,21},构建一颗哈夫曼树

  1. 寻找数列中最小的两个数作为叶子结点
  2. 将这两个元素从数列中移除,并将这两个节点的和放入数列中,此时数列为{5,9,13,21,3}
  3. 重复①②步骤,直到数列只剩下一个元素为止。
    在这里插入图片描述

代码实现

(1)节点Node的定义

/**
* 节点
*/
public class Node implements Comparable<Node>{
   
   private int value;
   // 左子树
   private Node left;
   // 右子树
   private Node right;

   public Node(int value) {
   
       this.value = value;
   }

   public int getValue() {
   
       return value;
   }

   public void setValue(int value) {
   
       this.value = value;
   }

   public Node getLeft() {
   
       return left;
   }

   public void setLeft(Node left) {
   
       this.left = left;
   }

   public Node getRight() {
   
       return right;
   }

   public void setRight(Node right) {
   
       this.right = right;
   }

   @Override
   public String toString() {
   
       return "Node{" +
               "value=" + value +
               '}';
   }

   /**
    * 重写Comparable接口的比较方法,将Node节点按照value的值从小到大排序
    * @param o
    * @return
    */
   @Override
   public int compareTo(Node o) {
   
       return this.value - o.value;
   }
}

(2)哈夫曼树的实现

/**
 * 数列转换成哈夫曼树
 */
public Node arrTransToHuffmanTree(int[] arr){
   
    if (arr == null || arr.length < 2) {
   
        return null;
    }
    List<Node> nodeList = new ArrayList<>();
    // 1. 将元素都转换成节点类型
    for (int i = 0; i < arr.length; i++) {
   
        nodeList.add(new Node(arr[i]));
    }
    while (nodeList != null && nodeList.size() > 1) {
   
        // 2. 对数据进行排序
        Collections.sort(nodeList);
        // 3. 取出最小的两个元素
        Node leftNode = nodeList.get(0);
        Node rightNode = nodeList.get(1);
        // 4. 两个元素之和作为这两个元素的父节点
        Node parentNode = new Node(leftNode.getValue()+rightNode.getValue());
        // 5. 这两个元素分别作为父节点的左右子节点
        parentNode.setLeft(leftNode);
        parentNode.setRight(rightNode);
        // 6. 从数列中去除这两个节点
        nodeList.remove(lef
综合实验: 1. 问题描述 利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。这要求在发送端通过一个编码系统对待传输数据预先编码,在接收端将传来的数据进行译码(复原)。对于双工信道(即可以双向传输信息的信道),每端都需要一个完整的编/译码系统。试为这样的信息收发站编写一个哈夫曼码的编/译码系统。 2. 基本要求 一个完整的系统应具有以下功能: (1) I:初始化(Initialization)。从终端读入字符集大小n,以及n个字符和n个权值,建立哈夫曼,并将它存于文件hfmTree中。 (2) E:编码(Encoding)。利用已建好的哈夫曼(如不在内存,则从文件hfmTree中读入),对文件ToBeTran中的正文进行编码,然后将结果存入文件CodeFile中。 (3) D:译码(Decoding)。利用已建好的哈夫曼将文件CodeFile中的代码进行译码,结果存入文件Textfile中。 (4) P:印代码文件(Print)。将文件CodeFile以紧凑格式显示在终端上,每行50个代码。同时将此字符形式的编码文件写入文件CodePrin中。 (5) T:印哈夫曼(Tree printing)。将已在内存中的哈夫曼以直观的方式(比如)显示在终端上,同时将此字符形式的哈夫曼写入文件TreePrint 中。 3. 测试数据 用下表给出的字符集和频度的实际统计数据建立哈夫曼,并实现以下报文的编码和译码:“THIS PROGRAME IS MY FAVORITE”。 字符 A B C D E F G H I J K L M 频度 186 64 13 22 32 103 21 15 47 57 1 5 32 20 字符 N O P Q R S T U V W X Y Z 频度 57 63 15 1 48 51 80 23 8 18 1 16 1
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值