哈夫曼树的应用

2023-10-31

温馨提示:这篇文章是基于哈夫曼树的构建之上,来说说哈夫曼树的应用,强烈建议在学习http://124.222.190.191:8090/archives/%E5%93%88%E5%A4%AB%E6%9B%BC%E6%A0%91%E7%9A%84%E6%9E%84%E5%BB%BA—%E5%9F%BA%E4%BA%8Ejava
后再来阅读这篇博文哦

## 哈夫曼树的应用

哈夫曼树可以用于优化编码,这里先了解一下等长编码和不等长编码

等长编码
例如一段电文为 ‘A B A C C D A’, 它只有4种字符,只需要两个字符的串就可以分辨, 所以我们可以按等长编码的设计原则, 将A,B,C,D表示为00、01、10、11, 'A B A C C D A’就被编码为‘00010010101100’, 共14位。 它的优点是: 因为间隔相同, 译码时不存在二义性的问题。 但缺点在于, 有些字符本可以被设计为更短的编码, 也就是说,设计为等长编码, 我们实际上浪费了一部分编码的空间(长度)

不等长编码
同上, 如果采用不等长编码, 可以把A,B,C,D表示为0、00、1、01, 那么 'A B A C C D A’就可以被编码为‘000011010’, 总长只要9就够了! 比起等长编码我们节约了5位的长度。 但问题是: 由于长度间隔不一致, 译码时可能存在二义性,这导致无法翻译,例如 ‘00‘,到底是看成’00’还是’0‘ + ’0‘呢? 前者被翻译为B,而后者被翻译为A。

前缀编码
为了解决不等长编码产生的二义性问题,引出了前缀编码,即任意一个字符的编码都不是另一个字符的编码的前缀。

哈夫曼树编码
哈夫曼树就是一种前缀编码,它能解决不等长编码时的 译码问题,通过它,我们可以尽可能减少编码的长度,同时还能够避免二义性,实现正确译码

哈夫曼树如何实现前缀编码?
假设有一棵如下图所示的二叉树, 其4个叶结点分别表示A,B,C,D这4个字符,且约定左分支表示字符’0’, 右分支代表字符’1’, 则可以从根结点到叶子结点的路径上的各分支字符组成的字符串作为该叶子结点字符的编码。 从而得到A,B,C,D的二进制编码分别为0, 10, 110, 111。

哈夫曼编码实现

  1. 我们编写一个HuffmanCode内部类用于存放字符(data实例变量)和它对应的二进制字符串(bit实例变量)

  2. 要求所有字符对应的编码时,如果采用从根结点下行到叶结点的思路处理,逻辑会相对复杂一些, 所以我们用逆向的方式获取: 按照从叶子结点到根结点的路径累加二进制字符串

  3. 因为 2 的原因, 累加二进制字符串的时候也必须反向累加,例如写成bit= “0” + bit; 而不是写成bit= bit+ “0”;

  4. 上溯时候要做的工作是: 判断当前经过的是 0 还是 1, 判断的方法如下图所示:
    假设P是X的父节点:
    如果P.left==X在HT中的下标,则说明X是P的左分支,说明经过的是 0
    如果P.right==X在HT中的下标,则说明X是P的右分支,说明经过的是 1

## 代码如下:

import java.util.Arrays;

public class HuffmanTree {
  private class HuffmanCode {
    char data; // 存放字符,例如 'C'
    String bit; // 存放编码后的字符串, 例如"111"
    public HuffmanCode (char data, String bit) {
      this.data = data;
      this.bit  = bit;
    }
  }
 
  /**
   *  构建赫夫曼树
   */
  public  Node[] buildTree (Node [] nodes) {
    // 具体代码见哈夫曼树的构建--基于java这篇博文
  }
 
  /**
   *  进行赫夫曼编码
   */
  public  HuffmanCode [] encode(Node [] nodes) {
    Node [] HT = buildTree(nodes); // 根据输入的nodes数组构造赫夫曼树
    int n = nodes.length;
    HuffmanCode [] HC = new HuffmanCode [n];
    String bit;
    for (int i=0;i<n;i++) { // 遍历各个叶子结点
      bit = "";
      for (int c=i,f=HT[i].parent;f!=0;c=f,f=HT[f].parent) { // 从叶子结点上溯到根结点
        if(HT[f].left == c) bit= "0" + bit; // 反向编码
        else                bit= "1" + bit;
      }
      HC[i] = new HuffmanCode(HT[i].data,bit); // 将字符和对应的编码存储起来
    }
    return HC;
  }
 
  /**
   * encode方法的用例
   */
  public static void main (String [] args) {
    Node [] nodes = new Node[4];
    nodes[0] = new Node('A',7);
    nodes[1] = new Node('B',5);
    nodes[2] = new Node('C',2);
    nodes[3] = new Node('D',4);
    HuffmanTree ht = new HuffmanTree();
    HuffmanCode[] hc = ht.encode(nodes);
    // 对A,B,C,D进行编码
    for (int i=0;i<hc.length;i++) { // 将赫夫曼编码打印出来
      System.out.println(hc[i].data + ":" +hc[i].bit);
    }
  }
}

输出结果:

A:0
B:10
C:110
D:111

应用二
## 哈夫曼树译码

根据给定的字符和权值, 将输入的赫夫曼编码翻译回原字符串

译码的时候,从根结点HT[HT.length -1] 开始, 向下行走, 通过charAt方法取得字符串当前的字符, 如果为 '0’则向左走, 为’1’则向右走, 当下行到叶子结点时候,取得叶子结点包含的字符, 添加到当前的译码字符串中,同时回到根结点,继续循环。

代码如下:

import java.util.Arrays;

public class HuffmanTree {
  int selectStart = 0;
  private class HuffmanCode {
    char data; // 存放字符,例如 'C'
    String bit; // 存放编码后的字符串, 例如"111"
    public HuffmanCode (char data, String bit) {
      this.data = data;
      this.bit  = bit;
    }
  }
 
  /**
   * @description: 构建赫夫曼树
   */
  public  Node[] buildTree (Node [] nodes) {
     // 代码见哈夫曼树构建--基于java博文
  }
 
  /**
   * @description: 进行赫夫曼译码
   */
  public String decode (Node [] nodes, String code) {
    String str="";
    Node [] HT = buildTree(nodes);
    int n =HT.length -1;
    for (int i=0;i<code.length();i++) {
      char c = code.charAt(i);
      if(c == '1') {
        n = HT[n].right;
      }
      else {
        n = HT[n].left;
      }
      if(HT[n].left == 0) {
        str+= HT[n].data;
        n =HT.length -1; //回到根结点
      }
    }
    return str;
  }
  /**
   * @description: decode方法的用例
   */
  public static void main (String [] args) {
    Node [] nodes = new Node[4];
    nodes[0] = new Node('A',7);
    nodes[1] = new Node('B',5);
    nodes[2] = new Node('C',2);
    nodes[3] = new Node('D',4);
    HuffmanTree ht = new HuffmanTree();
    // 对 010110111 进行译码
    System.out.println(ht.decode(nodes,"010110111"));
  }
}

输出

ABCD

之后会继续更新哈夫曼树在深度学习中的应用~~~~~~~

参考博文:
哈夫曼树(赫夫曼树、最优树)及C语言实现
哈夫曼(huffman)树和哈夫曼编码-白红宇的个人博客
构造哈夫曼树和生成哈夫曼编码_静能生悟的博客-CSDN博客_构造哈夫曼树和生成哈夫曼编码
【算法】赫夫曼树(Huffman)的构建和应用(编码、译码) - 外婆的 - 博客园

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

哈夫曼树的应用 的相关文章

  • 为什么 __instancecheck__ 并不总是根据参数调用?

    有这样的代码 class Meta type def instancecheck self instance print instancecheck return True class A metaclass Meta pass a A i
  • Python Pandas to_sql,如何创建带有主键的表?

    我想使用 Pandas 的 to sql 函数创建一个 MySQL 表 该函数有一个主键 在 mysql 表中拥有主键通常是件好事 如下所示 group export to sql con db name config table grou
  • AngularJS 和 Django 的 DOM、JavaScript 和服务器端数据库之间是否存在三向数据绑定框架?

    AngularJS 爱好者兜售的功能之一是该框架提供的 DOM 内容和 JavaScript 数据之间的双向数据绑定 我目前正在开发几个集成 AngularJS 和 Django 的学习项目 其中一个痛点是 AngularJS 解决的 Ja
  • 在 Python 3.5 64 位上通过 pip 安装 OpenCV

    我尝试安装 OpenCV 但找不到任何合适的 pip 软件包 我决定上网查找有关如何安装它的官方文档 并发现this https opencv python tutroals readthedocs io en latest py tuto
  • 如何在 Linux 上调用 Python 中的内联机器代码?

    我正在尝试从 Linux 上的纯 Python 代码调用内联机器代码 为此 我将代码嵌入到字节文字中 code b x55 x89 xe5 x5d xc3 然后打电话mprotect http www kernel org doc man
  • python 线程是如何工作的?

    我想知道 python 线程是并发运行还是并行运行 例如 如果我有两个任务并在两个线程中运行它们 它们是同时运行还是计划同时运行 我知道GIL并且线程仅使用一个 CPU 核心 这是一个复杂的问题 需要大量解释 我将坚持使用 CPython
  • 将numpy字符串数组转换为int数组[重复]

    这个问题在这里已经有答案了 我有一个 numpy ndarray a 0 99 0 56 0 56 2 02 0 96 如何将其转换为int 输出 a 0 99 0 0 0 56 0 56 2 02 0 96 我想要 0 0 代替空白 im
  • Python 中意外的缩进错误[重复]

    这个问题在这里已经有答案了 我有一段简单的代码 我不明白我的错误来自哪里 解析器在第 5 行 if 语句 上用意外的缩进向我咆哮 有人看到这里的问题吗 我不 def gen fibs a b 0 1 while True a b b a b
  • 如何动态构造方法?

    我设计了一个类 它非常标准 具有一些方法属性 class foo def f1 self print f1 def f2 self print f2 def fn self print fn 现在我想创建一个包含一组 foo 实例的类 cl
  • 单击按钮时执行 python 脚本

    我有一个带有一个按钮的 HTML 页面 当我们单击该按钮时 我需要执行一个 python 脚本 并返回到包含结果的同一 HTML 页面 所以我需要对返回值进行一些验证并执行一些操作 这是我的代码 HTML
  • 使用 PyQt4 在 QWidget 上进行 eventFilter

    我有一个 QMainWindow 其中包含DrawingPointsWidget 该小部件随机绘制红点 我通过使用以下命令为 MouseHovering 事件安装事件过滤器 在 QMainWindow 的状态栏中显示鼠标坐标self ins
  • scikit-learn - 具有置信区间的 ROC 曲线

    我可以使用 ROC 曲线scikit learn with fpr tpr thresholds metrics roc curve y true y pred pos label 1 where y true是基于我的黄金标准的值列表 即
  • 用python计算网页大小

    我将如何使用 Python 计算网页 url 的大小 我尝试了 urllib2 并获取内容长度标头 但它不存在 import urllib2 url http www google com r urllib2 urlopen url Not
  • 将 Pandas 列转换为日期时间

    我在 pandas DataFrame 中有一个字段以字符串格式导入 它应该是一个日期时间变量 如何将其转换为日期时间列 然后根据日期进行过滤 Example raw data pd DataFrame Mycol 05SEP2014 00
  • UserDict 类的优点?

    使用有什么好处UserDict class 我的意思是 我真正得到的不是 class MyClass object def init self self a 0 self b 0 m MyClass m a 5 m b 7 我将写下以下内容
  • Python NET 调用具有返回值和输出参数的 C# 方法

    我有以下静态 C 方法 public static bool TryParse string s out double result 我想使用 Python NET 包从 Python 调用它 import clr from System
  • 带日志图的 Type 1 字体

    我正在尝试使用 Matplotlib 图表作为相机就绪的一部分 提交 出版社要求使用Type 1字体 仅有的 我发现 PDF 后端很乐意输出 Type 1 字体 具有线性 Y 轴的简单图形 但输出 Type 3 字体 对数 Y 轴 使用对数
  • Django - 在启动时执行代码

    我正在使用 Django 1 9 3 我有一个包含多个应用程序的项目 我想在项目启动时更新其中一个应用程序的表 用例 例如 假设我想在我的网站上销售商品 我有一个包含模型项目的应用程序 我在 Django 之外有一个网络服务 它提供服务 g
  • Mac OS X 上的 Python 框架和非框架构建之间的差异

    Question Mac OS X 上的 Python 框架构建和非框架构建 即标准 UNIX 构建 之间有什么区别 另外 各自的优点和缺点是什么 初步研究 以下是我在发布此问题之前找到的信息 Pythonmac SIG Why is Fr
  • 从tensorflow 2.0 beta中的tf.data.Dataset检索下一个元素

    在tensorflow 2 0 beta之前 要从tf data Dataset中检索第一个元素 我们可以使用迭代器 如下所示 usr bin python import tensorflow as tf train dataset tf

随机推荐

  • 2016.5.23

    2016 5 23 news from BBC China s Science Revolution 这篇文章非常棒 推荐阅读 今天只完成4个部分 明天继续mark introduction From building the bigges
  • 将 InputStream 流转成 MultipartFile

    MultipartFile是一个接口 有一个MockMultipartFile实现类 里面有构造方法可以直接将输入流转为MutipartFile对象 MultipartFile File new MockMultipartFile file
  • @angular前端项目代码优化:构建Api Tree

    前颜 yan 在前端项目的开发过程中 往往后端会给到一份数据接口 本文简称api 为了减少后期的维护以及出错成本 我的考虑是希望能够找到这么一种方法 可以将所有的api以某种方式统一的管理起来 并且很方便的进行维护 比如当后端修改了api名
  • 三维重建(单目、双目、多目、点云、SFM、SLAM)

    1 相机几何与标定 1 1 相机模型中的坐标系 1 2 四种坐标系之间的转换 1 3 相机内参 1 4 相机标定 2 传统三维重建 2 1 RGBD三维重建 2 1 1 KinectFusion 2 1 2 BundleFusion 2 1
  • CentOS7 Failed to start LSB: Bring up/down解决方法

    刚刚装好的虚拟机突然不能上网了 报错很诡异 具体报错如下 etc init d network restart Restarting network via systemctl Job for network service failed
  • three.js加载fbx并解析骨骼动画

    three js加载fbx并解析骨骼动画 话不多说 上代码
  • SpringBoot如何打包项目?

    我们打包SpringBoot项目一般是打包成jar包或者war包 jar包和war包最大的区别在于jar包打出来的可直接运行 我们可以直接进行访问 因为他内前置了tomcat服务器 但是war包在打包的时候会提前移除tomcat相关组件 我
  • Verilog入门——Quartus2基础使用

    一 新建工程 1 打开Quartus2 2 点击菜单栏中的 file 选择 New Project Wizard 3 点击Next 4 选择工程存储路径 5 输入工程名字 6 点击Next 7 选择fpga类型和型号 根据自己的板子型号选择
  • 最简单的DRM应用程序 (single-buffer)

    在上一篇DRM Direct Rendering Manager 学习简介 中 我们学习了DRM的基本概念以及基本组成元素 从本篇开始 我将以示例代码的形式 给大家分享学习DRM驱动开发的整个学习过程 在学习DRM驱动之前 应该首先了解如何
  • 【java】ssh the connection is not authenticated

    文章目录 1 概述 1 概述 首先参考 java java ssh 远程执行命令 并且获取执行的结果 然后讲述一下 这个问题 这是一段很久的代码 以前是能正常工作的 环境如下 Docker flink node 这里ssh kafka no
  • QT笔记-窗体设置

    1 窗体设置 个窗体初始运行最大化 setWindowState Qt WindowMaximized 获取屏幕分别率 并设置窗体固定大小 QScreen screen QGuiApplication primaryScreen QRect
  • MySQL 日期相减得到秒、分、天

    文章目录 一 MySQL中两个DateTime字段相减 二 MySQL中两个Time字段相减 一 MySQL中两个DateTime字段相减 这种方式两字段跨天 月 年都无问题 得到两个日期字段之间的秒数 selec t UNIX TIMES
  • 医学影像组学之病理切片分割(免费训练数据,标注数据,免费代码,免费教程)三天走完影像组学全部流程

    谁规定说影像组学只能从写代码 学语言耗费半年时间才能开始实验 三天让你走完影像组学完整流程 训练数据已经集成好 标注数据也已备好 代码也备好了 训练过程是这样的 另外笔者整理了其他影像组学的教学小视频 有兴趣的可以在下面评论
  • 华为HCIE云计算之部署Fusion Access及云桌面发放实战

    华为HCIE云计算之部署Fusion Access及云桌面发放实战 一 在FC上安装FA01虚拟机 1 选择创建类型 2 创建虚拟机基本配置 3 创建数据存储 4 选择虚拟机配置 5 虚拟机创建完成 二 安装FA01系统 1 进入系统安装界
  • 以太坊入门学习资料

    区块链分类 区块链按照访问和管理权限分为公有链 联盟链和私有链 公有链 完全开放 所有节点均可加入 代表链 比特币Bitcoin 以太坊Ethereum 联盟链 有多个组织和机构共同管理 获得组织和机构许可的节点可以加入 代表链 超级账本H
  • uniapp弹窗实现

  • java comparable与_详解Java中Comparable和Comparator接口的区别

    详解Java中Comparable和Comparator接口的区别 本文要来详细分析一下Java中Comparable和Comparator接口的区别 两者都有比较的功能 那么究竟有什么区别呢 感兴趣的Java开发者继续看下去吧 Compa
  • string.h的strcmp的性能比较

    string h基于汇编实现strcmp 和普通strcmp 针对循环调用次数和字符串查找长度2个纬度做了一次性能对比效测试 include
  • Windows 安装 nvm

    最近安装了最新版的node js之后 发现一个问题 版本太高 有些vue项目运行不起来了 于是找解决办法 发现安装 nvm 可以解决这个问题 nvm全名node js version management 是一个nodejs的版本管理工具
  • 哈夫曼树的应用

    温馨提示 这篇文章是基于哈夫曼树的构建之上 来说说哈夫曼树的应用 强烈建议在学习http 124 222 190 191 8090 archives E5 93 88 E5 A4 AB E6 9B BC E6 A0 91 E7 9A 84