图文详解JAVA实现哈夫曼树

图文详解JAVA实现哈夫曼树

1. 前言

本文介绍如何用Java实现哈夫曼树的构建和编码解码过程,主要讲解如何使用Java的数据结构和算法实现这一过程,通过图文详解,希望读者了解哈夫曼树的构建原理和实现步骤。

2. 哈夫曼树的概念

哈夫曼树是一种特殊的二叉树,从二叉树的基本性质出发,哈夫曼树是一种能够达到最小带权路径长度和的二叉树。

在哈夫曼树中,二叉树的叶子节点代表需要编码的字符,每个叶子节点附带了该字符出现的频率和字符本身,而非叶子节点则代表一个字符出现频率的合并,该节点附加一个频率,作为其左右子树中频率的和。

3. 哈夫曼树的构建

哈夫曼树的构建是一个自下而上的构建过程,主要是通过合并最小频率的节点构建出整个二叉树。具体实现的过程:

  1. 将待编码的字符和对应的频率读入内存。
  2. 将所有字符和频率对应成一个个单节点的二叉树。
  3. 将所有的单节点二叉树放入一个小根堆中,每个节点的权值是其对应字符的频率。
  4. 从小根堆中取出最小的两个二叉树,将它们合并成一个新的二叉树,合并后新的二叉树的权值是两个二叉树的权值之和。
  5. 将新的二叉树插入小根堆中。
  6. 重复步骤4和步骤5,直到小根堆中只剩下一个树,该树即为哈夫曼树。

下面是具体的Java代码实现:

import java.util.HashMap;
import java.util.Map;
import java.util.PriorityQueue;

public class HuffmanTree {
    private Node rootNode;

    private static class Node implements Comparable<Node> {
        private final char character;
        private final int frequency;
        private final Node leftChild;
        private final Node rightChild;

        Node(char character, int frequency, Node leftChild, Node rightChild) {
            this.character = character;
            this.frequency = frequency;
            this.leftChild = leftChild;
            this.rightChild = rightChild;
        }

        boolean isLeaf() {
            return leftChild == null && rightChild == null;
        }

        public int compareTo(Node o) {
            return frequency - o.frequency;
        }
    }

    public HuffmanTree(Map<Character, Integer> characterFrequencies) {
        PriorityQueue<Node> priorityQueue = new PriorityQueue<>();
        for (Map.Entry<Character, Integer> entry : characterFrequencies.entrySet()) {
            priorityQueue.offer(new Node(entry.getKey(), entry.getValue(), null, null));
        }

        while (priorityQueue.size() > 1) {
            Node leftChild = priorityQueue.poll();
            Node rightChild = priorityQueue.poll();
            Node parent = new Node('\0', leftChild.frequency + rightChild.frequency, leftChild, rightChild);
            priorityQueue.offer(parent);
        }

        rootNode = priorityQueue.poll();
    }
}

4. 哈夫曼编码的生成

哈夫曼编码是通过将需要编码的字符拼接在一起,经过压缩变换后得到的一串编码。编码过程中,哈夫曼编码通过字符在哈夫曼树中的路径得到,并对每对相邻的节点进行一个压缩。

具体的生成过程是:

  1. 遍历哈夫曼树,从根节点开始,每当向左或向右走时,编码追加0或者1,直到到达叶子节点。
  2. 每个叶子节点的编码便是对应字符的哈夫曼编码。
  3. 储存每个字符的哈夫曼编码并将其返回。

以下是具体Java代码实现:

public class HuffmanEncoding {
    private final Map<Character, String> characterCodeMap;

    public HuffmanEncoding(HuffmanTree huffmanTree) {
        characterCodeMap = new HashMap<>();
        generateEncodingMap(huffmanTree.rootNode, new StringBuilder());
    }

    private void generateEncodingMap(HuffmanTree.Node currentNode, StringBuilder stringBuilder) {
        if (currentNode.isLeaf()) {
            characterCodeMap.put(currentNode.character, stringBuilder.toString());
        } else {
            generateEncodingMap(currentNode.leftChild, stringBuilder.append('0'));
            stringBuilder.deleteCharAt(stringBuilder.length() - 1);
            generateEncodingMap(currentNode.rightChild, stringBuilder.append('1'));
            stringBuilder.deleteCharAt(stringBuilder.length() - 1);
        }
    }

    public String encode(String input) {
        StringBuilder stringBuilder = new StringBuilder();
        for (char character : input.toCharArray()) {
            stringBuilder.append(characterCodeMap.get(character));
        }
        return stringBuilder.toString();
    }

    public String decode(String input, HuffmanTree huffmanTree) {
        StringBuilder stringBuilder = new StringBuilder();
        HuffmanTree.Node currentNode = huffmanTree.rootNode;
        for (char character : input.toCharArray()) {
            currentNode = (character == '0') ? currentNode.leftChild : currentNode.rightChild;
            if (currentNode.isLeaf()) {
                stringBuilder.append(currentNode.character);
                currentNode = huffmanTree.rootNode;
            }
        }
        return stringBuilder.toString();
    }
}

5. 哈夫曼编码的应用

使用哈夫曼编码可以将需要压缩的数据变换成一段更短的二进制编码,从而达到数据压缩的目的。这个过程在网络传输、数据存储、音视频编码等领域有着广泛的应用。

示例一:将一串英文句子的字符进行编码。如“JAVA is Best Programming Language”,经过哈夫曼编码后变为“11111110000000011011010111000101100000001100110111110000110”,编码后长度仅为原来长度的一半。

示例二:对于一段频率可比的音频或视频,可以使用哈夫曼编码对音视频文件进行压缩存储,节省存储空间,加快读写速度。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:图文详解JAVA实现哈夫曼树 - Python技术站

(0)
上一篇 2023年5月18日
下一篇 2023年5月18日

相关文章

  • SpringBoot项目实现关闭数据库配置和springSecurity

    SpringBoot是一个非常流行的Java Web开发框架,它具有易用、快速开发、健壮性好等优点。在一些场景中我们需要关闭数据库配置或者关闭Spring Security,下面就具体介绍一下如何实现: 关闭数据库配置 在一些场景中,我们并不需要使用数据库,比如开发一个展示页面的网站,这时我们就可以关闭数据库配置。 步骤一:排除数据库依赖 在pom.xml文…

    Java 2023年5月20日
    00
  • Spring启动过程源码分析及简介

    下面是对于“Spring启动过程源码分析及简介”的完整攻略。 1. 概述 Spring是一个流行的基于Java的开源框架,其设计目标是为了提供一个全面的基础设施,使得开发人员可以快速构建企业级应用。Spring启动过程源码分析及简介是一个非常重要的主题,它可以帮助我们更好的理解Spring框架,并在实际应用中更好地使用。 2. Spring启动过程源码分析 …

    Java 2023年5月31日
    00
  • Java 自定义Spring框架与Spring IoC相关接口分析

    Java 自定义 Spring 框架与 Spring IoC 相关接口分析 什么是 Spring IoC Spring IoC 是 Spring 框架核心的实现,它通过使用依赖注入(Dependency Injection,DI)或反转控制(Inversion of Control,IoC)的方式管理类之间的关系,从而实现了松耦合、易测试、易维护的优秀设计,…

    Java 2023年5月31日
    00
  • mybatis中批量插入的两种方式(高效插入)

    在MyBatis中,批量插入是一种常见的高效插入方式,可以大大减少操作数据库的次数,提高插入效率。本文将详细讲解MyBatis中批量插入的两种方式及使用方法。 使用JDBC批量插入 MyBatis底层封装了JDBC,所以可以使用JDBC的批量操作功能进行批量插入。具体实现步骤如下: 创建数据库表 假设我们要插入的表是user,可以通过以下语句创建表: CRE…

    Java 2023年5月20日
    00
  • centos7安装Tomcat7的教程图解

    CentOS7安装Tomcat7的教程图解 第一步:安装JDK 首先,要安装JDK,可以使用CentOS默认仓库中的OpenJDK或者Oracle官网下载。 示例1:使用CentOS默认仓库中的OpenJDK安装 sudo yum install java-1.8.0-openjdk-devel 示例2:从Oracle官网下载JDK安装 # 下载二进制文件 …

    Java 2023年5月19日
    00
  • java中常用的字符串的比较方法(两种)

    在Java中,字符串比较是编程中常用到的操作,本文将会介绍两种常用的字符串比较方法。 1. 使用equals()方法进行字符串比较 Java提供了equals()方法来比较两个字符串是否相等,这种方法是最常见和最常用的字符串比较方法。该方法的基本使用方法如下: String str1 = "hello"; String str2 = &q…

    Java 2023年5月26日
    00
  • java基于jdbc实现简单学生管理系统

    首先需要明确几个概念: JDBC:Java数据库连接,是一个用于执行SQL语句的Java API。 MySQL:一个开源的关系型数据库。 IDEA:一个常用的Java开发工具。 下面是基于JDBC实现简单学生管理系统的步骤: 1. 创建表 首先需要创建一张学生表,表的结构可以由以下字段组成: 学生ID 学生姓名 学生年龄 学生性别 学生班级 可以使用以下SQ…

    Java 2023年5月19日
    00
  • CCF考试试题之门禁系统java解题代码

    关于“CCF考试试题之门禁系统java解题代码”的完整攻略,请看下面的详细讲解。 一、题目背景 这是一道CCF认证考试的试题,要求我们写一段代码实现一个门禁系统。门禁系统需要记录人员的姓名和进出时间,并按照时间排序输出人员进入和离开的记录。 二、解题思路 首先,我们需要定义一个类,来存储每位人员的姓名和进出时间。 class AccessRecord { S…

    Java 2023年5月24日
    00
合作推广
合作推广
分享本页
返回顶部