图文详解JAVA实现哈夫曼树

yizhihongxing

图文详解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日

相关文章

  • Java对象的四种引用方式实例分析

    Java对象的四种引用方式实例分析 在Java中,对象的引用方式可以分为四种:强引用、软引用、弱引用和虚引用。每种引用方式有其特定的应用场景和特点。下面将详细介绍每一种引用方式以及其使用示例。 强引用 强引用是Java中最常用的引用方式。定义一个对象并将其赋值给一个引用变量时,这个引用变量就是强引用。只要强引用存在,对象就不会被垃圾回收机制回收。 例如:定义…

    Java 2023年5月26日
    00
  • springMVC框架下JQuery传递并解析Json数据

    下面是详细的攻略: 1. 概述 Spring MVC 是一个常用的 Java Web 开发框架,而 jQuery 是一个非常流行的 JavaScript 库。在前端和后端协作开发的过程中,我们常常需要通过 AJAX 来进行异步数据交互。传递 JSON 数据,并解析 JSON 数据是基于 AJAX 进行异步交互的常见需求之一。本文将详细介绍在 Spring M…

    Java 2023年6月15日
    00
  • SpringBoot Mybatis 配置文件形式详解

    讲解 “SpringBoot Mybatis 配置文件形式详解” 的完整攻略如下: 1. 概述 Spring Boot 是 Spring Framework 的一种快速开发框架,可以用于 Java 开发的各种 Web 应用程序的快速开发。MyBatis 是一种持久层框架,可以用于与数据库交互的对象映射。本文介绍了如何使用 MyBatis 在 Spring B…

    Java 2023年5月20日
    00
  • SpringBoot+Mybatis实现Mapper接口与Sql绑定几种姿势

    下面我将为你详细讲解“SpringBoot+Mybatis实现Mapper接口与Sql绑定几种姿势”的完整攻略。 1. 概述 在使用Mybatis时,我们需要将Mapper接口与SQL进行绑定,以便可以方便地在Java代码中调用。在SpringBoot项目中,我们可以采用多种方式来实现Mapper接口与SQL的绑定。 本文将介绍三种实现Mapper接口与SQ…

    Java 2023年5月20日
    00
  • java中下拉框select和单选按钮的回显操作

    在 Java 中,下拉框(select)和单选按钮(radio button)一般用于提供给用户多个选项中的一个选择。回显操作是一个非常常见的功能,在用户提交表单并进行验证之后,如果表单中有多个选项的输入框,那么就需要将用户选择的结果回显到表单上。在本文中,我们将讲解如何在 Java 中实现下拉框和单选按钮的回显操作。 回显下拉框中的值 下拉框是一种常用的表…

    Java 2023年6月15日
    00
  • JavaWeb 中 Filter过滤器

    Filter过滤器 每博一文案 师傅说:人生无坦途,累是必须的背负,看多了,人情人暖,走遍了离合聚散,有时会 在心里对自己说,我想,我是真的累了,小时候有读不完的书,长大后有赚不尽的力。 白天在外要奋斗打拼,把心事都藏起来,笑脸相迎,做一个合格的员工,晚上回家要照顾家人。 把家务都打理的井井有条,做一个称职的伴侣,习惯了所有事情,自己扛,习惯了所有委屈自己消…

    Java 2023年5月9日
    00
  • 必须了解的高阶JAVA枚举特性!

    必须了解的高阶JAVA枚举特性! 一、枚举简介 Java枚举是一种特殊的类,它定义了一个有限数目的常量,且这些常量都是类似于静态变量的东西,即它们在程序运行时是不可更改的。枚举最常用的特性是它可以帮助我们简化代码,并且增加程序的可读性。 二、JAVA基本枚举特性 1. 定义一个枚举 Java中使用关键字enum来定义一个枚举。 enum Color { RE…

    Java 2023年5月26日
    00
  • java 逐行读取txt文本如何解决中文乱码

    要想解决中文乱码问题,需要了解Java中文编码方式的特点。Java会默认使用UTF-8编码格式,而读取txt文本时可能会面对其他编码格式,因此需要进行适当的转码操作。 以下是逐行读取txt文本并解决中文乱码问题的步骤: 创建一个FileReader对象,用于读取txt文件,并指定编码格式为GBK。 FileReader fr = new FileReader…

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