在上一期,我们介绍了一种特殊的数据结构 “哈夫曼树”,也被称为最优二叉树。没看过的小伙伴可以点击下方链接:

漫画:什么是 “哈夫曼树” ?

那么,这种数据结构究竟有什么用呢?我们今天就来揭晓答案。

计算机系统是如何存储信息的呢?

计算机不是人,它不认识中文和英文,更不认识图片和视频,它唯一“认识”的就是0(低电平)和1(高电平)。

因此,我们在计算机上看到的一切文字、图像、音频、视频,底层都是用二进制来存储和传输的。

从狭义上来讲,把人类能看懂的各种信息,转换成计算机能够识别的二进制形式,被称为编码。

编码的方式可以有很多种,我们大家最熟悉的编码方式就属ASCII码了。

在ASCII码当中,把每一个字符表示成特定的8位二进制数,比如:

显然,ASCII码是一种等长编码,也就是任何字符的编码长度都相等。

为什么这么说呢?让我们来看一个例子:

假如一段信息当中,只有A,B,C,D,E,F这6个字符,如果使用等长编码,我们可以把每一个字符都设计成长度为3的二进制编码:

如此一来,给定一段信息 “ABEFCDAED”,就可以编码成二进制的 “000 001 100 101 010 011 000 100 011”,编码总长度是27。

但是,这样的编码方式是最优的设计吗?如果我们让不同的字符对应不同长度的编码,结果会怎样呢?比如:

如此一来,给定的信息 “ABEFCDAED”,就可以编码成二进制的 “0 00 10 11 01 1 0 10 1”,编码的总长度只有14。

哈夫曼编码(Huffman Coding),同样是由麻省理工学院的哈夫曼博所发明,这种编码方式实现了两个重要目标:

1.任何一个字符编码,都不是其他字符编码的前缀。

2.信息编码的总长度最小。

哈夫曼编码的生成过程是什么样子呢?让我们看看下面的例子:

假如一段信息里只有A,B,C,D,E,F这6个字符,他们出现的次数依次是2次,3次,7次,9次,18次,25次,如何设计对应的编码呢?

我们不妨把这6个字符当做6个叶子结点,把字符出现次数当做结点的权重,以此来生成一颗哈夫曼树:

这样做的意义是什么呢?

哈夫曼树的每一个结点包括左、右两个分支,二进制的每一位有0、1两种状态,我们可以把这两者对应起来,结点的左分支当做0,结点的右分支当做1,会产生什么样的结果?

这样一来,从哈夫曼树的根结点到每一个叶子结点的路径,都可以等价为一段二进制编码:

上述过程借助哈夫曼树所生成的二进制编码,就是哈夫曼编码。

现在,我们面临两个关键的问题:

首先,这样生成的编码有没有前缀问题带来的歧义呢?答案是没有歧义。

因为每一个字符对应的都是哈夫曼树的叶子结点,从根结点到这些叶子结点的路径并没有包含关系,最终得到的二进制编码自然也不会是彼此的前缀。

其次,这样生成的编码能保证总长度最小吗?答案是可以保证。

哈夫曼树的重要特性,就是所有叶子结点的(权重 X 路径长度)之和最小。

放在信息编码的场景下,叶子结点的权重对应字符出现的频次,结点的路径长度对应字符的编码长度。

所有字符的(频次 X 编码长度)之和最小,自然就说明总的编码长度最小。

private Node root;private Node[] nodes;//构建哈夫曼树public void createHuffmanTree(int[] weights) {//优先队列,用于辅助构建哈夫曼树Queue nodeQueue = new PriorityQueue<>();    nodes = new Node[weights.length];//构建森林,初始化nodes数组for(int i=0; i 1) {//从结点队列选择权值最小的两个结点Node left = nodeQueue.poll();Node right = nodeQueue.poll();//创建新结点作为两结点的父节点Node parent = new Node(left.weight + right.weight, left, right);        nodeQueue.add(parent);}    root = nodeQueue.poll();}//输入字符下表,输出对应的哈夫曼编码public String convertHuffmanCode(int index) {return nodes[index].code;}//用递归的方式,填充各个结点的二进制编码public void encode(Node node, String code){if(node == null){return;}    node.code = code;    encode(node.lChild, node.code+"0");    encode(node.rChild, node.code+"1");}public static class Node implements Comparable{int weight;//结点对应的二进制编码String code;Node lChild;Node rChild;public Node(int weight) {this.weight = weight;}public Node(int weight, Node lChild, Node rChild) {this.weight = weight;this.lChild = lChild;this.rChild = rChild;}@Overridepublic int compareTo(Node o) {return new Integer(this.weight).compareTo(new Integer(o.weight));}}public static void main(String[] args) {char[] chars = {'A','B','C','D','E','F'};int[] weights = {2,3,7,9,18,25};HuffmanCode huffmanCode = new HuffmanCode();    huffmanCode.createHuffmanTree(weights);    huffmanCode.encode(huffmanCode.root, "");for(int i=0; i

这段代码中,Node类增加了一个新字段code,用于记录结点所对应的二进制编码。

当哈夫曼树构建之后,就可以通过递归的方式,从根结点向下,填充每一个结点的code值。

手机号段对应地区编码_漫画:“哈夫曼编码” 是什么鬼?相关推荐

  1. labview霍夫曼编码_为什么霍夫曼编码好?

    7 个答案: 答案 0 :(得分:3) 如果为最常用使用的符号指定较少的数字或位或较短的代码字词,则可以节省大量存储空间. 假设您要为英文字母分配26个唯一代码,并希望根据这些代码存储英文小说(仅限字 ...

  2. 可逼近信道容量编码技术之霍夫曼编码的实现

    可逼近信道容量编码技术之霍夫曼编码的实现 简介 在当今信息爆炸时代,如何采用有效的数据压缩技术来节省数据文件的存储空间和计算机网络的传送时间已越来越引起人们的重视.哈夫曼编码正是一种应用广泛且非常有效 ...

  3. 信息论霍夫曼编码c语言,霍夫曼编码

    <信息论与编码>课程实验报告 姓 名 学 号 单 位 专 业 2014 年 12 月 4 日 实验一 一.实验目的 1.理解信源编码的意义: 2.掌握霍夫曼编码的方法及计算机实现: 二.实 ...

  4. 创建霍夫曼树,霍夫曼编码以及使用霍夫曼编码压缩文件

    那么,什么是霍夫曼树(赫夫曼树)呢? 给定n个权值(权值就是每个节点里面存放的数据,但是根据业务需求不同,存放的数据类型有些差别)作为n个叶子结点,构造一棵二叉树,若该树的带权路径长度达到最小,称这样 ...

  5. 计算机编码问题总结——哈夫曼编码

    我是荔园微风,作为一名在IT界整整25年的老兵,今天总结一下计算机中的编码问题,来看第四部分,哈夫曼编码. 哈夫曼树,又叫霍夫曼树.最优二叉树,表示带权路径最短的树,什么意思呢,没听懂...... 唉 ...

  6. 霍夫曼编码实验matlab,哈夫曼编码 MATLAB程序

    clc clear fid=fopen( 'C:\Users\yichao\Desktop\新建文本文档.txt');%打开 txt 文件 [zimu]=fscanf(fid, '%c'); %读取二 ...

  7. 信息论霍夫曼编码c语言,霍夫曼编码C语言

    编译成功 /* Note:Your choice is C IDE */ #include #include #define N 15 #define M 2*N-1 typedef struct { ...

  8. 信息论与编码_哈夫曼编码

    哈夫曼树 哈夫曼树(Huffman Tree)也是一种特殊的二叉树,这种树的所有叶子结点都带有权值,从中构造出带权路径长度最短的二叉树,即哈夫曼树. 哈夫曼树的定义 ​ 设二叉树具有n个带权值的叶子结 ...

  9. labview霍夫曼编码_哈夫曼编解码压缩解压文件—C++实现

    前言 哈夫曼编码是一种贪心算法和二叉树结合的字符编码方式,具有广泛的应用背景,最直观的是文件压缩.本文主要讲述如何用哈夫曼编解码实现文件的压缩和解压,并给出代码实现. 哈夫曼编码的概念 哈夫曼树又称作 ...

  10. 哈夫曼编码压缩率计算_程序员的算法课(8)-贪心算法:理解霍夫曼编码

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/m0_37609579/article/ ...

最新文章

  1. Linux的epoll
  2. Linux的init进程(内核态到用户态的变化)
  3. WP老杨解迷:开发生态两极化和榜单乱象
  4. 《Adobe Illustrator CC 2014中文版经典教程(彩色版)》—第1课1.6节排列多个文档...
  5. EL表达式 jsp2.0 jsp1.2 与 tomcat
  6. php 物联网应用,蜂窝物联网的概念以及应用
  7. java实验10流_实验9 Java输入输出流
  8. python之rabbitMQ
  9. pgsql查表名_PostgreSQL 查询一个表
  10. UVA11107 Life Forms --- 后缀数组
  11. Bootstrap 按钮的使用
  12. 倩女幽魂7月20日服务器维护,倩女幽魂手游2021年7月22日更新公告
  13. echarts地图各种点位实现
  14. 小凯的疑惑(Noip 提高组 2017 d1 1)+[USACO4.1]麦香牛块Beef McNuggets
  15. mysql 1048_MySQL Error 1048 奇遇记-阿里云开发者社区
  16. python实现21根火柴游戏
  17. html语言中%3cp%3e%3cbr%3e,求一段弹出窗口代码
  18. 如何获取淘宝/天猫商品历史价格信息的API接口
  19. vivo智能手机产能
  20. 10年期国债利率笔记

热门文章

  1. 实践篇 | 推荐系统之矩阵分解模型
  2. nginx rtmp代码架构1 hook点总结
  3. 大剑无锋之DQL、DML、DDL、DCL,简单举个例子【面试推荐】
  4. 实时平台在趣头条的建设实践
  5. tmux 如何自定义背景颜色 | How does the tmux color palette work?
  6. IDEA如何设置鼠标滚轮调整字体大小
  7. 左神算法:用一个栈实现另一个栈的排序(Java版)
  8. JVM从入门到精通(四):内存屏障与JVM指令,对象的内存布局
  9. Echarts给坐标轴添加自定义属性
  10. 【Python】Flask框架系列(四):Flask-Migrate数据库迁移