数据结构学习记录——哈夫曼树(什么是哈夫曼树、哈夫曼树的定义、哈夫曼树的构造、哈夫曼树的特点、哈夫曼编码)

目录

什么是哈夫曼树

哈夫曼树的定义

哈夫曼树的构造 

图解操作

代码实现

代码解析

哈夫曼树的特点

哈夫曼编码 

不等长编码

二叉树用于编码

哈夫曼编码实例 


什么是哈夫曼树

我们先举个例子:

要将百分制的考试成绩转化成五分制的成绩

if(score < 60)
    grade = 1;
else if(score < 70)
    grade = 2;
else if(score < 80)
    grade = 3;
else if(score < 90)
    grade = 4;
else
    grade = 5;

这种情况其实是一棵判定树:

这种方式要看各成绩段的学生分布,如果60以下的同学比较多,那么判断的次数就会很少;但是如果90多的同学比较多的情况下,那么要判断4次的情况就会很多,整体的判断效率不高。

我们考虑学生成绩分布的概率:

分数段0-5960-6970-7980-8990-100
比例0.050.150.400.300.10

那么判断效率就为:0.05\times 1+0.15\times 2+0.40\times 3+0.30\times 4+0.10\times 4 =\mathbf{3.15}

现在我们想要让判断的效率更高一点,修改一下判定树:

这样的判断效率就为:0.05\times 3+0.15\times 3+0.4\times 2+0.3\times 2+0.1\times 2 = \textbf{​{\color{Red} 2.2}} 

写成代码就为:

if(score < 80)
{
    if(score < 70)
    {
        if(score < 60)
        {
            grade = 1;
        }
        else
        {
            grade = 2;
        }
    }
    else
    {
        grade = 3;
    }
}
else if(score < 90)
{
    grade = 4;
}
else
{   
    grade = 5;
}

如何根据结点不同的查找频率构造更有效的搜索树? 

就涉及到了我们要讲的哈夫曼树

哈夫曼树的定义

带权路径长度(WPL):设二叉树有n个叶子结点,每个叶子结点带有权值w_{k},从根结点到每个叶子结点的长度为l_{k},则每个叶子结点的带权路径长度之和就为:WPL = \sum_{k = 1}^{n}w_{k}l_{k}

最优二叉树哈夫曼树WPL最小的二叉树。

例:有五个叶子结点,它们的权值为{1,2,3,4,5},用此权值序列可以构造出形状不同的多个二叉树。

哈夫曼树的构造 

给出一个权值序列,构造出一棵哈夫曼树。

例:{1,2,3,4,5}

每次把权值最小的两棵二叉树合并,具体:

图解操作

哈夫曼树的构造是比较简单的,要找出两个最小值,就可以运用我们前面学过的最小堆来找了,这比从小到大排好序的效率会更高。下面我们来看一下代码的实现。

代码实现

typedef struct TreeNode *HuffmanTree;
struct TreeNode
{
    int Weight;
    HuffmanTree Left,Right;
}

HuffmanTree Huffman(MinHeap H)
{    /*假设H->Size个权值已经存在H->Elements[]->Weight里*/
    int i;
    HuffmanTree T;
    BuildMinHeap(H);/*将H->Elements[]按权值调整为最小堆*/
    for (i=1;i<H->Size;i++)
    {
        /*做H->Size-1次合并*/
        T=malloc( sizeof( struct TreeNode));/*建立新结点*/ 
        T->Left=DeleteMin(H);
        /*从最小堆中删除一个结点,作为新T的左子结点*/
        T->Riqht=DeleteMin(H);
        /*从最小堆中删除一个结点,作为新T的右子结点*/
        T->Weight=T->Left->Weiqht + T->Right->Weight;
            /*计算新权值*/
        Insert(H,T);/*将新T插入最小堆*/
    }
    T=DeleteMin(H);
    return T;  
}

代码解析

这段代码定义了一个结构体类型TreeNode和一个指向TreeNode类型的指针HuffmanTree。TreeNode结构体包含三个成员变量:Weight表示权值,Left表示左子树指针,Right表示右子树指针。

HuffmanTree指针类型可以指向TreeNode类型的对象,用于表示哈夫曼树的结点。

函数的输入参数是一个最小堆H,其中存储了每个字符出现的频率。

变量 i 的作用是用于循环合并最小堆中的结点,每次循环合并两个权值最小的结点,直到只剩下一个根结点。

T的作用是用于创建新的Huffman树结点,每次合并两个最小权值的结点时,都会创建一个新的结点T,并将两个最小权值结点作为T的左右子结点,然后将T插入到最小堆中。

最终,最小堆中只剩下一个根结点,即为Huffman树的根结点,返回该结点即可。

函数首先调用BuildMinHeap函数将H中的元素按照权值调整为最小堆。

然后进入for循环,将最小堆中的所有结点合并成一棵哈夫曼树:

首先,建立一个新的结点T,作为合并后的新结点。

然后,从最小堆中删除两个权值最小的结点,分别作为新结点T的左子结点和右子结点。

接着,计算新结点T的权值,即左子结点和右子结点的权值之和。

最后,将新结点T插入最小堆中。

这个过程会重复执行H->Size-1次,因为最终的哈夫曼树只有一个根结点,所以需要将所有结点合并成一个。

最后,从最小堆中删除最后一个结点,即哈夫曼树的根结点,

并返回该结点作为哈夫曼树的根。

哈夫曼树构造完成。整体的时间复杂度为O(N{log_{2}}^{N})

哈夫曼树的特点

  • 没有度为1的结点

哈夫曼树是一棵最优二叉树,每个叶子结点都对应着一个字符,

而每个非叶子结点都是两个子结点的父结点,表示两个字符的合并。

如果存在度为1的结点,那么这个结点只有一个子结点,就不能表示两个字符的合并,因此不符合哈夫曼树的定义。

  • n个叶子结点的哈夫曼树共有2n-1个结点

我们最开始学二叉树时,在其中提到了二叉树的几个重要性质。

对任何非空二叉树T,若n0表示叶节点的个数,n2是度为2的非叶节点个数,那么两者满足关系n0 = n2 +1

因为哈夫曼树没有度为1的结点,叶结点为n个,那么度为2的非叶结点个数就为n-1个;

故而总结点数就等于n + (n - 1) = 2n - 1

  • 哈夫曼树的任意非叶结点的左右子树交换之后仍是哈夫曼树

交换哈夫曼树中任意非叶结点的左右子树时,它的深度和权值并没有发生改变,因此仍然满足哈夫曼树的定义。

  • 对同一组权值{w_{1},w_{2},......,w_{n}},存在不同构的两棵哈夫曼树

对一组权值{1,2,3,3},不同构的两棵哈夫曼树:

哈夫曼编码 

不等长编码

抛出问题:给定一段字符串,如何对字符进行编码,可以使得该字符串的编码存储空间最少

【例】假设有一段文本,包含58个字符,并由以下7个字符构成:a,e,i,s,t,空格(sp),换行(nl);这7个字符出现的次数不同。如何对这7个字符进行编码,使得总编码空间最少?

【分析】

(1)用等长ASCII编码(ASCII占1个字节,8个比特位):58 * 8 = 464位;

(2)用等长3位编码(因为只有7个字符,3位的编码足够表达8个对象):58 * 3 = 174位;

(3)不等长编码:出现频率高的字符用的编码短些,出现频率低的字符则可以编码长些

怎么进行不等长编码呢?

我们不妨假设:

a:0

e:0

s:10

t:11

......

那么在这样的不等长编码下,1011是什么字符串的编码?

a e a a1 0 1 1

a e t:1 0 1 1

s t:1 0 1 1

这样就出现了同一个编码,却译出不同的几个字符串了,即存在二义性

要避免二义性,就要满足一个条件:前缀码

前缀码prefix code:任何字符的编码都不是另一字符编码的前缀

例如,s的前缀为1,而1就可以理解为a,这就不符合前缀码的条件了。

二叉树用于编码

为了保证我们的编码不出现二义性,我们可以用二叉树来编码。

用二叉树编码:

(1)左分支:0

(2)右分支:1

(3)字符只在叶结点上

【例】现有四个字符的频率:a:4,u:1,x:2,z:1。

前面说过的前缀码,是当字符出现在叶结点时;如果字符出现在非叶结点上,就说明它不满足前缀码的条件:

 所以这就是为什么用二叉树来编码时,字符只在叶结点上。

接下来的问题是,怎么样构造才能使得付出的代价最小?

看到刚才举的例子: 

这就和我们讲哈夫曼树时是差不多的情况,我们根据频率来把二叉树重构一下: 

这样不存在二义性,代价也最小。

哈夫曼编码实例 

【例】

C_{i}aeistspnl
f_{i}10151234131

用上面学过的构造哈夫曼树的方法,每次选取最小的两个值构造二叉树,整个过程如下

 最终构造出来的哈夫曼编码树:


end 


学习自:MOOC数据结构——陈越、何钦铭 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/18402.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

固态继电器的优点

固态继电器的优点包括紧凑性、抗冲击性和长寿命。以下是这些 SSR 优势中最重要的优势&#xff0c;让您了解为什么这项技术最适合您的应用&#xff1a; 开关速度快 固态继电器器件的主要优点之一是其开关速度。由于无需移动机械部件&#xff0c;SSR 可以在几微秒内切换。这是对…

【Java笔试强训 35】

&#x1f389;&#x1f389;&#x1f389;点进来你就是我的人了博主主页&#xff1a;&#x1f648;&#x1f648;&#x1f648;戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔&#x1f93a;&#x1f93a;&#x1f93a; 目录 一、选择题 二、编程题 &#x1f525;年会抽奖…

小红书达人等级有哪些,达人种草力度判断

小红书对于产品及品牌的传播作用&#xff0c;来自于达人自身的分享。以笔记为媒介&#xff0c;对产品进行情景化展示&#xff0c;从而吸引消费&#xff0c;就被称作是种草。而种草力度的强弱&#xff0c;则与达人等级息息相关。下面&#xff0c;就来跟详细为大家解读。 一、小红…

设计模式——适配器模式(类适配器、对象适配器)

是什么&#xff1f; 我们平时的有线耳机接口分为USB的和Type-C的接口&#xff0c;但是手机的耳机插口却只有一个&#xff0c;像华为的耳机插口现在基本都是Type-c的&#xff0c;那如果我们现在只有USB接口的耳机怎么办呢&#xff0c;这个时候就需要使用到一个转换器&#xff0c…

公路交通气象站——提供及时的交通气象信息服务

我国幅员辽阔&#xff0c;跨经纬度广&#xff0c;气候多样。从气候类型划分&#xff1a;可以分为季风气候、温带大陆性气候和高寒气候。 气象的变化也在直接影响着我国各个地区的道路建设及通行&#xff0c;由于部分路段地势险峻伴随恶劣的气象变化&#xff0c;会直接影响驾驶人…

Java 10 字符串

1.API 1.1API 概述 什么是API ​ API (Application Programming Interface) &#xff1a;应用程序编程接口 java 中的 API ​ 指的就是 JDK 中提供的各种功能的 Java 类&#xff0c;这些类将底层的实现封装了起来&#xff0c;我们不需要关心这些类是如何实现的&#xff0c;只…

LeetCoed 2, 23, 25, 112, 113

文章目录 1. 两数相加2. K 个一组翻转链表3. 合并 K 个升序链表4. 路径总和I5. 路径总和II 1. 两数相加 题目详情见: LeetCode2. 两数相加 题目描述相对来说比较绕, 我们可以直接理解为两个多位的整数相加, 只不过整数的每一位都是通过链表进行存储; 比如, 整数 342, 通过链表…

三分钟教你Mac下安装VmWare虚拟机

大数据课程课前环境准备&#xff1a;mac中安装三台linux服务器 一、课前准备 准备一台内存最少8G&#xff08;建议16G&#xff09;、cpu i7 4核的电脑 二、课堂主题 安装虚拟化软件VMware准备3台linux虚拟机 三、课堂目标 完成mac下3个虚拟机的安装 四、知识要点 文档说…

浅析智慧充电桩云平台的技术设计方案

自从我国提出“新基建”以来&#xff0c;充电基础设施产业也成为行业的话题与关注焦点。据数据统计&#xff0c;2021年&#xff0c;中国新能源汽车保有量达到784万辆&#xff0c;预计2025年&#xff0c;中国新能源汽车保有量达到2672万辆&#xff0c;2025年充电桩数量将达到654…

【沐风老师】一步一步教你在3dMax中进行UVW贴图和展开UVW的方法

将简单或程序材质应用于对象并不难。但是当表面需要在其上显示某种纹理时&#xff0c;它会变得更加复杂。任何纹理贴图都放在材质的 Diffuse 插槽中&#xff0c;但渲染的结果可能无法预测。这就是为什么我们需要了解 3DMAX 如何将纹理应用于 3D 对象&#xff0c;什么是 UVW 贴图…

weblogic ssrf 漏洞复现

一.前言 Weblogic中存在一个SSRF漏洞&#xff0c;利用该漏洞可以发送任意HTTP请求&#xff0c;进而攻击内网中redis、fastcgi等脆弱组件。 二.环境搭建 在docker中开启环境 sudo docker-compose up -d sudo docker-compose ps #查看状态访问http://your-ip:7001/uddiexpl…

【数码】收音机,德生PL380使用教程与注意事项

文章目录 1、主界面功能介绍&#xff08;注意闹钟和自动关机&#xff09;2、电池和电池模式的匹配3、收音机天线与信号&#xff0c;耳机与噪音F、参考资料 1、主界面功能介绍&#xff08;注意闹钟和自动关机&#xff09; 红色的按钮&#xff1a;power 按一下开机&#xff0c;按…

25个著名的WordPress网站案例

想创建免费网站吗&#xff1f;从易服客建站平台开始 500M免费空间&#xff0c;可升级为20GB电子商务网站 创建免费网站 WordPress 内容管理系统为全球35%的网站提供支持。鉴于目前有 17 亿个站点&#xff0c;并且还在增加&#xff0c;您可以算出每秒向网站访问者提供内容的W…

牛客网剑指offer|中等题day2|JZ22链表中倒数最后k个结点(简单)、JZ35复杂链表的复制(复杂)、JZ77按之字形顺序打印二叉树(中等)

JZ22链表中倒数最后k个结点(简单) 链接&#xff1a;链表中倒数最后k个结点_牛客题霸_牛客网 /*** struct ListNode {* int val;* struct ListNode *next;* ListNode(int x) : val(x), next(nullptr) {}* };*/ class Solution { public:/*** 代码中的类名、方法名、参数名已经指…

一、PEMFC基础之热力学

一、PEMFC基础之热力学 1.内能U、焓H、熵S、吉布斯自由能G、赫姆霍兹自由能F关系图2.可逆电压与温度和压力的关系3.能斯特方程4.燃料电池效率 1.内能U、焓H、熵S、吉布斯自由能G、赫姆霍兹自由能F关系图 2.可逆电压与温度和压力的关系 标准状态可逆电压Er计算&#xff1a; E …

基于springboot的4S店车辆管理系统(源码等)

摘 要 随着信息技术和网络技术的飞速发展&#xff0c;人类已进入全新信息化时代&#xff0c;传统管理技术已无法高效&#xff0c;便捷地管理信息。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的管理系统应运而生&#xff0c;各行各业相继进入信息管理时代&…

Linux进程状态及优先级

本文已收录至《Linux知识与编程》专栏&#xff01; 作者&#xff1a;ARMCSKGT 演示环境&#xff1a;CentOS 7 进程状态及优先级 前言正文进程状态就绪运行状态R阻塞睡眠状态 S休眠状态D挂起 暂停状态T前台与后台进程待追踪暂停状态t 死亡状态 X僵尸状态 Z 孤儿进程进程优先级查…

美颜SDK的隐私保护与安全性分析

随着智能手机和移动应用的普及&#xff0c;美颜SDK已经成为了很多应用的标配。美颜SDK的使用可以让用户在拍照或者视频聊天时&#xff0c;实现自拍美颜、滤镜、磨皮、瘦脸等效果。但是&#xff0c;在享受美颜SDK带来的便利的同时&#xff0c;我们也需要关注美颜SDK的隐私保护与…

配置文件Application.properties

配置文件Application.properties 属性配置配置文件的多种格式yaml的数据格式读取yaml文件中的属性值读取yaml文件中的全部属性yaml文件 数据库的属性 属性配置 在application.properties中添加server.port端口号即可 # 服务器端口配置 server.port80# 修改banner 关闭banner …

两分钟成为 ChatGPT 国内高手【不要再拿ChatGPT当百度用了】

不要再问ChatGPT那些问百度的问题了&#xff0c;有更进阶的用法 更高效的编写prompts&#xff0c;以便ChatGPT给出更精准的回答 但是需要注意的是&#xff1a;国内现在根本没有GPT-4使用&#xff0c;但凡是说有GPT-4的都是骗子。 GPT 可以写文章&#xff0c;可以写诗&#x…
最新文章