哈夫曼树的构造及应用

news2024/11/23 8:27:23

哈夫曼树的构造及应用

文章目录

  • 哈夫曼树的构造及应用
    • 带权路径长度
    • 哈夫曼树定义
    • 哈夫曼树的性质:
    • 构造哈夫曼树
    • 构造哈夫曼树存储及生成算法
    • 算法框架
    • 代码实操:
    • 应用: 哈夫曼编码

带权路径长度

image-20221218103753002

设二叉树具有n个带权值的叶子节点,那么从根节点到各个叶子节点的路径长度与相应节点权值的乘积之和,叫做二叉树的带权路径长度(WPL)。

image-20221218103827324

​ ▪ n 表示叶子结点的树木

​ ▪ wi 表示叶子结点ki 的权值

​ ▪ li分别表示根到ki之间的路径长度(即从叶子节点到达根节点的分指数)。

哈夫曼树定义

▪ 具有最小带权路径长度的二叉树称为哈夫曼树,或称为最优二叉树

哈夫曼树的性质:

n个叶子节点的二叉树,共有2n-1个节点.

证明:

设有二叉树有X个节点,则根据题意得叶子结点为n个,

由哈夫曼树的性质可得, 该树除了叶子节点的度数为零外, 其余节点度数都为2 ,所以

总度数 = (X - n) * 2 ①

并且根据总结点数 X , 和 除了根节点外,其他节点都有一个前驱分支,所以

总度数 = (X - 1) ②

上面① ② 两式联立: (X - n) * 2 = (X - 1)

得, X = 2n - 1

构造哈夫曼树

▪ 策略

​ 要使带权路径长度最小,须使权值越大的叶子节点越靠近根节点,而权值越小的叶子结点越远离根节点.

▪ 方法

​ (1)给定的n个权值(W1,W2,…Wn)构造n棵只有叶子节点的二叉树,从而得到一个二叉树的集合 F = {T1,T2,…,Tn};

​ (2)在F中选取根节点的权值最小和次小的两颗二叉树作为左、右子树,构造一棵新的二叉树,新的二叉树根节点的权值为其左、右子树根节点权值之和。

​ (3)在集合F中删除作为左、右子树的两颗二叉树,并将新建的二叉树加入到集合F中;

​ (4)重复(2)、(3)两步,当F中只剩下一颗二叉树时,这颗二叉树便是要建立的哈夫曼树。

image-20221218110019518

构造哈夫曼树存储及生成算法

#define N 5			//叶子节点数
typedef struct
{
    char data;		//节点值
    float weight;	//权重
    int  parent;	//双亲节点
    int  lchild;	//左孩子节点
    int  rchild;	//右孩子节点
}HTNode;
HTNode ht[2*N-1];

步骤1:初始化

n 个叶子节点只有data和weight域值,所有2n-1个节点的parent、lchild和rchild域置为初值-1.

步骤2:

开始构造,逐步选出两个最小和次小的权值节点,然后作为组合,形成哈夫曼树

重复处理每个非叶子节点ht[i] ,(ht[n] ~ ht[2n-2], i: n ~ 2n-2 )

▪ 从 ht[0] ~ h [i-1]中找出根节点(即其parent域为-1)最小的两个节点ht[lnode]和ht[rnode]

▪ ht[node]和ht[rnode]作为左右子树,增加他们的双亲节点ht[i],有: ht[i].weight = ht[node].weight + ht[rnode].weight

image-20221218113247596

算法框架

//传入

代码实操:

//传入构建所用数组和 叶子节点的个数,方便后续操作
void CreateHT(HTNode ht[],int n)
{
    //定义计数器,定义节点左右孩子的序号
    int i,j,k,lnode,rnode;
    //定义权值最小和次小的数组序号
    float min1,min2;
    //所有节点的数据区初始化,包括数组中记录节点双亲、左右孩子的数据区。
    for(i=0;i<2*n-1;i++)
    {
		ht[i].parent=ht[i].lchild = ht[i].rchild = -1;
    }
    //开始构建叶子节点的双亲节点,运用哈夫曼树的思想,先挑出权值最小和次小的节点,将他们合并成新节点,剔除选中后的节点,后续接着操作
    for(i = n; i<2*n-1; i++)
    {
        //找出权重最小的两个节点
		//先把两个变量变成超过所有权值的数值
        min1 = min2 = 32145;
        //构建的新节点,刚开始左右孩子置为 -1 ,表示无
        lnode = rnode = -1;
        //开始寻找最小和次小
        //开始遍历所有节点,
        for(k=0;k<=i-1;k++)		//注意细节, k<i-1 , 只遍历构建的新节点的前面的节点
        {
            if(ht[k].parent=-1)		//挑选不为 - 1 的节点,意思就是没有被挑选的
            {
                if(ht[k].weight<min1)		//比最小的还小 , 那就给老大
                {
                    min2 = min1;			//给老大之前, 老大穿过的给老二
                    rnode = lnode;			// 左孩子是上次最小的,找到更小的了,所以现在交给右孩子 
                    min1 = ht[k].weight;		//最小的序号给老大
                    lnode = k;				// 左孩子的序号 是 k, 是最小的节点的序号
                }             
                else if(ht[k].weight<min2)		//如果老大 , 有的节点没看上, 比老大大,又比老二小, 那我们老二不能放过了
                {
                    min2 = ht[k].weight;		//序号安排
                    rnode = k;				// 仍然是变成右孩子,因为是次小的
                }                    
            }                
        }                    
        //生成一个双亲节点
        ht[lnode].parent = i;		//现在生成最小和次小的双亲 , 左孩子的父母,右孩子的父母
        ht[rnode].parent = i;
        ht[i].weight = ht[lnode].weight + ht[rnode].weight;	//新节点的权重为两个孩子的和
        ht[i].lchild = lnode;			// 标记左右孩子
        ht[i].rchild = rnode;
    }            
}    

应用: 哈夫曼编码

• 问题: 符号编码问题

• 举例

​ ▪ 用于通信的电文(或一幅图像),有8个符号(设为’a’~‘h’)

​ ▪ 各符号出现的概率分别为:

​ 0.07、0.19、0.02、0.06、0.32、0.21、0.10

​ ▪ 如何确定各符号的二进制编码,使编码后的代码长度最短?

• 解决方法1

​ ▪ 等长编码: a:000 b:001 c:010 d:011 e:100 f:101 g:110 h:111

​ ▪ 平均码长:3

• 解决方法2

​ • 哈夫曼非等长编码:

​ a: 1010 b:00 c:10000 d:1001 e:11 f:10001 g:01 h:1011

​ • 遵循的原则

​ 出现概率高的,我们的编码尽可能的短, 出现频率低的,我们可以长一些

​ • 编码原则:

​ 把概率当做权值,把各个字母当做对应的叶子节点,变成哈夫曼树,然后左子树标记为0,右子树标记为1,来保证唯一性,从而降低代码长度,实现代码的压缩.

​ • 平均码长:

​ 各个字母的概率乘以其对应的哈夫曼树的路径长度之和, 所求得的即为平均码长.

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【图像分割】模糊聚类算法FCM图像分割【含Matlab源码 084期】

⛄一、模糊聚类算法FCM简介 1 前言 图像分割是图像进行后续分析处理的基础&#xff0c;它将图像分成不同特征部分并获得所需目标&#xff0c;广泛应用于诸多领域&#xff0e;彩色多目标图像具有更为丰富的图像信息&#xff0c;目标色彩较多&#xff0c;且同一色彩的目标有时具…

统计学习方法 | 感知机

感知机是二类分类的线性分类模型&#xff0c;其输入为实例的特征向量&#xff0c;输出为实例的类别&#xff0c;取1和-1二值 感知机对应于输入空间&#xff08;特征空间&#xff09;中将实例划分为正负两类的分离超平面&#xff0c;属于判别模型 一.模型介绍和学习策略 1.模…

牛客题霸sql入门篇之多表查询

牛客题霸sql入门篇之多表查询 1 子查询 1.1 浙江大学用户题目回答情况 1.1.1 题目内容 a 内容1 b 内容2 1.1.2 示例代码 SELECT device_id,question_id,result FROM question_practice_detail WHERE device_id(SELECT device_id FROM user_profile WHERE university浙江大…

[附源码]计算机毕业设计Python的个人理财系统(程序+源码+LW文档)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等…

pyqt 搭建深度学习训练界面(二)

炼丹软件 github链接: 有需要联系我 requirements: 测试在ubuntu18.04和Windows均可运行 ubuntu18.04 OS: Ubuntu 18.04.6 LTS Python version: 3.7 (64-bit runtime) Is CUDA available: True CUDA runtime version: 11.1.74 GPU models and configuration: GPU 0: NVI…

基于云的文档管理软件/文档管理系统(DMS)

基于云的文档管理软件 由于违反法规而导致的安全漏洞、数据丢失、版本管理等难题和诉讼已经变得非常普遍&#xff0c;以至于这一切都感觉像是“正常”的现象。使用文档管理系统&#xff0c;可以让您避免这些麻烦。安全标准的执行、信息的合规性和维护都在控制之中&#xff0c;只…

【人脸识别】SVM和PCA人脸识别【含GUI Matlab源码 369期】

⛄一、简介 1 PCA-SVM原理 1.1 主成分分析PCA 本文处理的所有原始图片都是112x 92大小的pgm格式图片&#xff0c; 每幅图片包含10304个像素点&#xff0c; 每一行代表一个样本&#xff0c;维数就是10304维。维数过大使得数据处理工作十分复杂&#xff0c;同时&#xff0c;图片…

axios传参的语法

请求方式 POST 向服务器新增数据 GET 从服务器获取数据 DELETE 删除服务器上的数据 PUT 更新服务器上的数据(侧重于完整更新:例如更新用户的完整信息) PATCH 更新服务器上的数据(侧重于部分更新:例如只更新用户的手机号 ) get axios({url: 请求地址,m…

制作自已的屏保动态

制作自已的屏保动态我的环境第一步&#xff1a;编写自己的屏保程序1、代码准备2、编译第二步&#xff1a;有了可运行程序&#xff0c;使用RAR压缩工具将资源和程序打包成独立可执行exe第三步&#xff1a;将dist.exe配置成系统屏幕保护参考我的环境 win10 python3.X pycharm 第…

Linux学习08-认识与学习BASH

1 认识BASH 我们必须要通过Shell将我们输入的命令与内核沟通&#xff0c;好让内核可以控制硬件来正确无误地工作。 Bash shell的功能 历史命令&#xff1a;命令行按“上下键”就可以找到前/后一个输入的指令。 命令与文件补全功能&#xff1a; [Tab] 接在一串指令的第一个…

大学生学习网站哪里找?收好这15个网站

1.学堂在线 地址:https://www.xuetangx.com/ 这里面的课程都是精选&#xff0c;以北大清华为首的高校汇聚于此 2.中国大学生MOOC 地址:https://www.icourse163.org/ 不多说都是精品 3.网易公开课 地址:https://open.163.com/ 网易公开课汇集清华、北大、哈佛、耶鲁等世界名…

全景分割~

Hinton组提出基于大型全景掩码的实例分割框架&#xff0c;图像视频场景丝滑切换 全景分割是一项基本的视觉任务&#xff0c;该任务旨在为图像的每个像素指定语义标签和实例标签。语义标签描述每个像素的类别&#xff08;例如天空、竖直物体等&#xff09;&#xff0c;实例标签…

408 | 考前知识拾遗

计网 二、物理层 各种编码图像 数据交换方式——怎么算时间 VLAN每个VLAN都是一个广播域 三、数据链路层 差错控制&#xff1a;检错、纠错 停等、GBN、SR差别 随机访问 VLAN的考点 交换机&#xff1a;转发、自学习 四、网错层 路由协议/算法 ☆☆☆IPV4分组 1、网关配置、路由…

JVM——常量池

目录一、常量池二、运行时常量池三、intern方法 1.8四、intern方法 1.6五、StringTable 垃圾回收六、StringTable调优通过解决以下问题可以更深入了解字符串创建过程中的原理 一、常量池 二进制字节码的组成&#xff1a;类的基本信息、常量池、类的方法定义&#xff08;包含…

集合的框架体系和Collection接口

1.集合的理解和好处 前面我们保存多个数据使用的是数组&#xff0c;那么数组有不足的地方&#xff0c;我们分析一下 1.1数组 1)长度开始时必须指定&#xff0c;而且一旦指定&#xff0c;不能更改 2)保存的必须为同一类型的元素 3)使用数组进行增加/删除元素的示例代码-比较麻烦…

调试3D渲染和3D可视化的五个好处

建筑和建筑环境是我们日常生活中不可避免的一部分&#xff0c;直接影响我们和我们的福祉。它可以是我们的家、办公室、附近的教堂或城市的商业综合体;所有这一切的设计和规划都是建筑。然而&#xff0c;具有讽刺意味的是&#xff0c;建筑的交流往往并不具有包容性。例如&#x…

玩以太坊链上项目的必备技能(函数及其可见性和状态可变性-Solidity之旅十三)

状态变量可见性 在这之前的文章里&#xff0c;给出的例子中&#xff0c;声明的状态变量都修饰为public&#xff0c;因为我们将状态变量声明为public后&#xff0c;Solidity 编译器自动会为我们生成一个与状态变量同名的、且函数可见性为public的函数&#xff01; 在 Solidity…

ASP.NET Core 3.1系列(19)——EFCore中的添加实体操作

1、前言 前面介绍了EFCore中关于查询和执行原生SQL的操作&#xff0c;这篇博客就来介绍一下EFCore中添加实体的相关操作。关于添加实体&#xff0c;EFCore提供了多种方法供开发者使用。但EFCore中针对实体的一系列操作最终都会被转换成SQL&#xff0c;因此这些方法之间也存在着…

设计模式之模版方法模式

Template method design pattern 模版方法模式的概念、模版方法模式的结构、模版方法模式的优缺点、模版方法模式的使用场景、模版方法模式的实现示例、模版方法模式的源码分析 1、模版方法模式的概念 模版方法模式&#xff0c;即定义一个算法骨架&#xff0c;而将一些步骤延迟…

ARM——指令集仿真环境搭建

目录 一、ARM指令集仿真环境搭建 1.1指令和指令集 指令 指令集 1.2汇编的本质 汇编 C语言 1.3为什么学习汇编 1.4仿真 硬件仿真 软件仿真 1.5Keil 1.6环境搭建 1.7汇编工程创建 二、汇编 2.1汇编中的符号 2.2ARM指令集 2.3简单的ARM程序 一、ARM指令集仿真环境搭…