【数据结构】哈夫曼树
哈夫曼树
在学习哈夫曼树之前,先了解以下几个概念:
一:**路径长度:**在一棵树中,从一个节点到另一个节点所经过的“边”的数量,被我们称为两个节点之间的路径长度。
二:**树的路径长度:**这是指从树根到每一个节点的路径长度的总和对于节点数相同的树来说,路径长度最短的是完全二叉树。
三:**节点带权的路径长度:这是指树的根节点到该节点的路径长度和该节点权重的乘积。
四:树的带权路径长度:**在一棵树中,所有叶子节点的带权路径长度之和,被称为树的带权路径长度,也被简称为WPL,这是每一个节点的对应的权值乘以对应的路径长度之和。
如图所示:

对于该图:
树路径长度就为1+1+2+2+3+3+4+4=20
A节点带权的路径长度=1*5=5
树的带权路径长度WPL=5×1+15×2+40×3+30×4+10×4=315
我们可以试想,同样的两颗二叉树,一个WPL小,一个WPL大,那么小的一定会在性能上优于大的,所以我们引出另外一个名词——哈夫曼树,即WPL最小的二叉树。
那我们如何才知道一棵树是不是哈夫曼树呢?
构造哈夫曼树:
首先,假如我们有5个节点,它们的权值分别是:A5, E10, B15, D30, C40。
在这些节点中,我们找到权值最小的两个节点,这里是A5和E10。我们将这两个节点合并,生成一个新的节点,新节点的权值是A5和E10的权值之和,即15。这样,我们就得到了新的节点列表:AE15, B15, D30, C40。
我们再次在新的节点列表中找到权值最小的两个节点,这次是AE15和B15。我们将这两个节点合并,生成一个新的节点,新节点的权值是AE15和B15的权值之和,即30。这样,我们就得到了新的节点列表:AEB30, D30, C40。
我们继续在新的节点列表中找到权值最小的两个节点,这次是AEB30和D30。我们将这两个节点合并,生成一个新的节点,新节点的权值是AEB30和D30的权值之和,即60。这样,我们就得到了新的节点列表:AEBD60, C40。
最后,我们将剩下的两个节点合并,生成一个新的节点,新节点的权值是AEBD60和C40的权值之和,即100。这样,我们就得到了最终的哈夫曼树。
比如这两个图,就是第一步的操作的举例:

当完成后,我们只需要比较一下当前WPL和我们的WPL,若相等,则就是哈夫曼树。
对于一颗哈夫曼树,有:
哈夫曼树中权越大的叶子离根越近
具有相同带权结点的哈夫曼树不唯一
哈夫曼树只有度为0或2的结点,没有度为1的结点
包含n个叶子结点的哈夫曼树共有2n-1个结点(如上图,叶子节点为3,总共2*3-1==5个节点)
n棵二叉树要经历n-1次合并可以形成哈夫曼树
哈夫曼编码:
哈夫曼编码是一种用于无损数据压缩的熵编码(即编码效率最高)算法。它是一种可变字长编码方式,比起定长编码的ASCII编码来说,哈夫曼编码能节省很多的空间,因为每一个字符出现的频率不是一致的。
哈夫曼编码的基本原理和流程如下:
将字符集C作为叶子节点;
将频率集W作为叶子节点的权值;
使用C和W构造哈夫曼树;
对哈夫曼树的所有分支,左子树分支编码为0,右子树分支编码为1;
通过上述流程,即完成了哈夫曼编码。
下面我们来用代码实现一颗哈夫曼树:
首先是结构体的定义:
struct haftree {double weight;//节点权值char c;//节点名字int lchild, rchild, parent;
};
接下来是各个函数的定义:
1.找出各权值中最小的两个:
void selcet(struct haftree* array, int x, int* m1, int* m2) {double min1 = DBL_MAX;double min2 = DBL_MAX;for (int i = 1; i <= x; i++) {if (array[i].weight < min1 && array[i].parent == 0) {//在构建哈夫曼树的过程中,我们需要选择权重最小的两个结点进行合并,构建出新的结点。为了避免重复选择已经合并过的结点,我们需要在选择最小权重结点的时候排除已经合并的结点。因此,需要通过array[i].parent == 0来判断结点是否已经是其他结点的子结点,如果是,则不考虑这个结点。min1 = array[i].weight;*m1 = i;}}for (int j = 1; j <= x; j++) {if (array[j].weight < min2 && j != *m1 && array[j].parent == 0) {min2 = array[j].weight;*m2 = j;}}
}
2.构建哈夫曼树:
void createhaftree(struct haftree*array,int n) {for (int i = n + 1; i <= 2 * n - 1; i++) {int m1,m2;Select(array, i - 1, &m1, &m2);array[i].weight = array[m1].weight + array[m2].weight;array[i].lchild = m1;array[i].rchild = m2;array[m1].parent = i;array[m2].parent = i;}
}
3.哈夫曼编码:
void HuffmanCoding(struct haftree* array, int n) {// 一个自定义的数据结构,用于存储哈夫曼树的节点char cd[n + 1];int start;cd[n] = '\0';for (int i = 1; i <= n; i++) {start = n;int c = i;int f = array[i].parent;while (f != 0) {if (array[f].lchild == c)cd[--start] = '0';elsecd[--start] = '1';c = f;f = array[f].parent;}printf("%s\n", &cd[start]);}
}
4.初始化与预处理:
for (int i = 1; i <= n; i++) {array[i].weight = weights[i - 1];array[i].c = chars[i - 1];array[i].parent = 0;array[i].lchild = 0;array[i].rchild = 0;
}
// 初始化非叶子节点
for (int i = n + 1; i < 2 * n; i++) {array[i].weight = 0;array[i].c = '\0'; // 非叶子节点没有字符array[i].parent = 0;array[i].lchild = 0;array[i].rchild = 0;
}
完整代码如下:
#include <stdio.h>
#include <float.h>
#include <limits.h>
struct haftree {double weight;//节点权值char c;//节点名字int lchild, rchild, parent;
};
void Select(struct haftree* array, int x, int* m1, int* m2) {double min1 = DBL_MAX;double min2 = DBL_MAX;for (int i = 1; i <= x; i++) {if (array[i].weight < min1 && array[i].parent == 0) {min1 = array[i].weight;*m1 = i;}}for (int j = 1; j <= x; j++) {if (array[j].weight < min2 && j != *m1 && array[j].parent == 0) {min2 = array[j].weight;*m2 = j;}}
}
void createhaftree(struct haftree* array, int n) {for (int i = n + 1; i <= 2 * n - 1; i++) {int m1, m2;Select(array, i - 1, &m1, &m2);array[i].weight = array[m1].weight + array[m2].weight;array[i].lchild = m1;array[i].rchild = m2;array[m1].parent = i;array[m2].parent = i;}
}
void HuffmanCoding(struct haftree* array, int n) {char cd[n + 1];int start;cd[n] = '\0';for (int i = 1; i <= n; i++) {start = n;int c = i;int f = array[i].parent;while (f != 0) {if (array[f].lchild == c)cd[--start] = '0';elsecd[--start] = '1';c = f;f = array[f].parent;}printf("%s\n", &cd[start]);}
}
int main() {int n = 5; // 假设有5个字符struct haftree array[2 * n]; // 创建哈夫曼树数组double weights[] = { 0.1, 0.15, 0.2, 0.25, 0.3 }; // 假设这是每个字符的权重char chars[] = { 'a', 'b', 'c', 'd', 'e' }; // 这是每个字符
// 初始化叶子节点
for (int i = 1; i <= n; i++) {array[i].weight = weights[i - 1];array[i].c = chars[i - 1];array[i].parent = 0;array[i].lchild = 0;array[i].rchild = 0;
}
// 初始化非叶子节点
for (int i = n + 1; i < 2 * n; i++) {array[i].weight = 0;array[i].c = '\0'; // 非叶子节点没有字符array[i].parent = 0;array[i].lchild = 0;array[i].rchild = 0;
}
createhaftree(array, n);
HuffmanCoding(array, n);
return 0;
}相关文章:
【数据结构】哈夫曼树
哈夫曼树 在学习哈夫曼树之前,先了解以下几个概念: 一:**路径长度:**在一棵树中,从一个节点到另一个节点所经过的“边”的数量,被我们称为两个节点之间的路径长度。 二:**树的路径长度…...
HCIP(TCP)(2)
1. TCP三次握手 SYN (同步序列编号) 报文: 客户端发送 SYN 报文,开始建立连接,并初始化序列号。 SYN-ACK (同步序列编号-确认) 报文: 服务器收到 SYN 报文后,回复 SYN-ACK 报文,确认连接请求,并初始化自己的序列号和确…...
VMware Ubuntu 网络配置全攻略:从断网到畅通无阻
一、网络连接模式选择(先搞懂原理) VMware提供三种网络模式,就像手机的不同网络套餐: 模式适用场景特点类比NAT个人上网/新手首选虚拟机共享主机IP,能上网但隐身家用WiFi桥接服务器/需要被局域网访问虚拟机会获得独立…...
基于Web的交互式智能成绩管理系统设计
目录 摘要 绪论 一、应用背景 二、行业发展现状 三、程序开发的重要意义 四、结语 1 代码 2 数据初始化模块 3 界面布局模块 4 核心功能模块 5 可视化子系统 6 扩展功能模块 7 架构设计亮点 功能总结 一、核心数据管理 二、智能分析体系 三、可视化系统 四、扩…...
第 12 章(番外)| Solidity 安全前沿趋势 × 审计生态 × 职业路径规划
🌐 第 12 章(番外)| Solidity 安全前沿趋势 审计生态 职业路径规划 ——做得了审计,也接得了项目,走进 Web3 安全工程师的职业实战地图 ✅ 本章导读 Solidity 安全,不只是代码安全、业务安全、审计安全…...
输出3行3列矩阵的鞍点
【问题描述】在矩阵中,一个数在所在行中是最大值,在所在列中是最小值,则被称为鞍点。任意输入一个3行3列矩阵,请设计程序输出其鞍点。 【输入形式】每行3个数,输入3列 【输出形式】输出所有鞍点;如果没有…...
k8s日志管理
k8s日志管理 k8s查看日志查看集群中不是完全运行状态的pod查看deployment日志查看service日志进入pod的容器内查看日志 管理k8s组件日志kubectl logs查看日志原理 管理k8s应用日志收集k8s日志思路收集标准输出收集容器中日志文件 k8s查看节点状态失败k8s部署prometheus监控 k8s…...
【数据结构】顺序表-元素去重
数据元素 结点定义,复杂数据类型,可用作整体性的管理系统。如果单独研究某些数据,比如只看学号或成绩,那么直接使用int之类的简单数据类型亦可。对应修改:typedef int Elemtype; typedef struct student{ //定义学生…...
物理安全——问答
目录 1、计算机的物理安全包含哪些内容 1. 设备保护 2. 访问控制 3. 电力与环境安全 4. 数据存储保护 5. 硬件防护 6. 监控与审计 7. 灾难恢复与应急响应 8. 拆卸与维修安全 2、物理安全有哪些需要关注的问题 1、计算机的物理安全包含哪些内容 1. 设备保护 防止盗窃&…...
element-plus中,Loading 加载组件的使用
一.基本使用 给一个组件,如:table表格,加上v-loading"true"即可。 举例:复制如下代码。 <template><el-table v-loading"loading" :data"tableData" style"width: 100%"><…...
Mybatis_Plus中的常用注解
目录 1、TableName TableId TableId的type属性 TableField 1、TableName 经过以上的测试,在使用MyBatis-Plus实现基本的CRUD时,我们并没有指定要操作的表,只是在 Mapper接口继承BaseMapper时,设置了泛型User,而操…...
云数据库概念
1.云数据库概念 云数据库是部署和虚拟化在云计算环境中的数据库。云数据库是在云计算的大背景下发展起来的一种新兴的共享基础架构的方法,它极大地增强了数据库的存储能力,消除了人员、硬件、软件的重复配置,让软、硬件升级变得更加容易。云…...
高并发金融系统,“可观测-可追溯-可回滚“的闭环审计体系
一句话总结 在高并发金融系统中,审计方案设计需平衡"观测粒度"与"系统损耗",通过双AOP实现非侵入式采集,三表机制保障操作原子性,最终形成"可观测-可追溯-可回滚"的闭环体系。 业务痛点与需求 在…...
UDP视频传输中的丢包和播放花屏处理方法
在处理UDP视频传输中的丢包和花屏问题时,需要结合编码优化、网络传输策略和接收端纠错技术。以下是分步骤的解决方案: 1. 前向纠错(FEC,Forward Error Correction) 原理:在发送数据时附加冗余包,接收方通过冗余信息恢复丢失的数据包。 实现方法: 使用Reed-Solomon、XO…...
企业内训|DeepSeek技术革命、算力范式重构与场景落地洞察-某头部券商
3月19日北京,TsingtaoAI公司负责人汶生受邀为某证券公司管理层和投资者举办专题培训,围绕《DeepSeek技术革命、算力范式重构与场景落地洞察》主题,系统阐述了当前AI技术演进的核心趋势、算力需求的结构性变革,以及行业应用落地的关…...
K8S学习之基础五十二:k8s配置jenkins
k8s配置jenkins...
VS Code C/C++项目设置launch.json中的environment参数解决支持库路径问题
问题描述 Windows 11 VS Code C/C 开发环境搭建分别写了c和cpp两个示例代码,在运行过程中c代码没有发现问题(可能简单,没有用到太多支持),但使用了stl的cpp代码并没有运行出来,如下图: 出问题…...
怎样解决 Windows 11 上的 DirectX 错误,最新DX 问题解决方法
在使用 Windows 11 操作系统的过程中,大家可能会遇到 DirectX 错误的情况,这可能会给游戏体验、多媒体应用甚至是系统的整体性能带来负面影响。不过别担心,本文将为大家详细介绍如何解决 Windows 11 上的 DirectX 错误,让您的系统…...
Spring AOP中为所有类型通知传递参数的完整示例,包含详细注释和参数传递方式
以下是Spring AOP中为所有类型通知传递参数的完整示例,包含详细注释和参数传递方式: // 1. 目标类(被增强的类) package com.example;public class TargetService {public void doTask(String param) {System.out.println("…...
.net平台C#对于2D/二维点云处理用哪些库?
对于单线激光雷达生成的2D点云数据的处理, 虽然比较简单, 但网上的资料比较少, PCL是避不开的, 但它主要处理的是3D点云, 对2D也可以处理, 但它是C语言的, 如果使用的是C语言开发&#x…...
PH热榜 | 2025-03-30
1. Deepcord 标语:Discord 数据分析:获取指标洞察与受众研究 介绍:Deepcord:为社区建设者提供的Discord分析工具。跟踪超过50万个服务器的指标,发现热门社区,监控竞争对手,找到你的目标受众。…...
STM32H743学习记录
2025/03/30 SRAM速率计算方式 MCU主频 乘以 单片机位数 除以 每个字节的位数(8)即可得出单片机的SRAM速率 如72M主频32位单片机速率 72 * 32 / 8 288 M/s FLASH速率计算方式 FLASH大小 乘以 单片机位数 除以 每个字节位数(8)…...
Open webui的使用
问题 之前本地量化模型管理器ollama的文章,我们知道可以通过ollama来管理本地量化模型,也能够在命令行中与相关模型进行对话。现在我们想要在有个web页面通过浏览器来与本地模型对话。这里我们就使用Open webui作为界面来与本地模型对话。 安装启动 这…...
swagger上传图片请求报错
1.如下是上传图片的接口 ApiOperation(value "WF开卡审核-关店换卡信用卡证明")PostMapping(value "/uploadPhoto/{id}")public Result<?> uploadPhoto(List<MultipartFile> file,PathVariable Long id) {return wfAuditService.uploadPhot…...
STM32单片机的桌面宠物机器人(基于HAL库)
效果 基于STM32单片机的桌面宠物机器人 概要 语音模块:ASR PRO,通过天问block软件烧录语音指令 主控芯片:STM32F103C8T6 使用HAL库 屏幕:0.96寸OLED屏,用来显示表情 4个舵机,用来当作四只腿 底部一个面…...
python 语法篇(一)
目录 1 正则匹配注意点11.1 正则匹配字符串写法1.2 创建re函数(1)re.search()--搜索第一个匹配项(2)re.match() - 从字符串开头匹配(3)re.findall() - 返回所有匹配项的列表(4)re.fi…...
【记录自己第一个github 100星项目】采用flask框架构建一个前端页面,进行OpenManus的调用,对OpenManus生成的文件进行预览。
OpenManus-WebUI...
flutter android端抓包工具
flutter做的android app,使用fiddler抓不了包,现介绍一款能支持flutter的抓包工具Reqable,使用方法如下: 1、下载电脑端安装包 下载地址为【https://reqable.com/zh-CN/download/】 2、还是在上述地址下载 android 端apk…...
求矩阵某列的和
设计函数sum_column( int A[E1(n)][E2(n)], int j ),E1(n)和E2(n)分别为用宏定义的行数和列数,j为列号。在该函数中,设计指针ptr&A[0][j],通过*ptr及ptrptrE2(n)访问第j列元素,从而求得第j列元素的和。在主函数中定…...
Ubuntu 22 Linux上部署DeepSeek R1保姆式操作详解(ollama方式)
操作系统:Ubuntu Linux 22.04 一、安装模型运行环境 打开链接https://ollama.com/download/linux 1.安装ollama (1)一条指令即可实现的简易版安装方法(也可称为在线安装) curl -fsSL https://ollama.com/install.s…...
