【数据结构】-哈夫曼树以及其应用

哈夫曼树(Huffman Tree)

1. 哈夫曼树的定义

哈夫曼树(Huffman Tree)是一种 带权路径长度最短的二叉树,常用于数据压缩和最优前缀编码。其目标是使得 带权路径长度(WPL)最小

在信息论和计算机科学中,哈夫曼编码是一种贪心算法,用于构造哈夫曼树,以实现最优前缀编码

2. 哈夫曼树的构造步骤

构造哈夫曼树的基本思想是每次选择当前权值最小的两个节点合并,形成新的节点,并重复该过程,直到形成一棵树。

步骤 1:确定权值

假设有如下字符及其权重(频率):

A(5)  B(9)  C(12)  D(13)  E(16)  F(45)

步骤 2:构造哈夫曼树

按照如下过程构造哈夫曼树:

  1. 选取权值最小的两个节点 A(5)B(9),合并形成新节点 AB(14)
  2. 选取权值最小的两个节点 C(12)D(13),合并形成新节点 CD(25)
  3. 选取权值最小的两个节点 AB(14)E(16),合并形成新节点 ABE(30)
  4. 选取权值最小的两个节点 CD(25)ABE(30),合并形成新节点 CDEAB(55)
  5. 选取最后两个节点 CDEAB(55)F(45),合并形成最终的哈夫曼树 Root(100)

步骤 3:生成哈夫曼树

最终形成的哈夫曼树如下:

         (100)/      \F(45)     (55)/     \(25)     (30)/    \    /    \C(12) D(13) (14) E(16)/    \A(5)   B(9)

3. 哈夫曼编码

使用哈夫曼树生成哈夫曼编码:

字符编码
A1100
B1101
C100
D101
E111
F0

哈夫曼编码的特点:

  • 前缀编码:任何一个编码都不是另一个编码的前缀。
  • 变长编码:高频字符使用短编码,低频字符使用长编码。

4. C 语言实现

#include <stdio.h>
#include <stdlib.h>typedef struct Node {char data;int weight;struct Node *left, *right;
} Node;Node* createNode(char data, int weight) {Node* node = (Node*)malloc(sizeof(Node));node->data = data;node->weight = weight;node->left = node->right = NULL;return node;
}void printHuffmanTree(Node* root, char* code, int depth) {if (!root->left && !root->right) {code[depth] = '\0';printf("%c: %s\n", root->data, code);return;}if (root->left) { code[depth] = '0'; printHuffmanTree(root->left, code, depth + 1); }if (root->right) { code[depth] = '1'; printHuffmanTree(root->right, code, depth + 1); }
}

5. 哈夫曼树的性质

哈夫曼树具有以下重要性质:

  1. 最优性:哈夫曼树保证了最短的带权路径长度(WPL),即它是最优二叉树。
  2. 唯一性:给定相同的权值集合,构造的哈夫曼树是唯一的(可能存在等权子树的不同组合)。
  3. 前缀编码:哈夫曼编码不含有歧义,因为不会出现某个编码是另一个编码的前缀。
  4. 贪心策略:哈夫曼算法使用贪心策略,每次合并权值最小的两个节点,确保局部最优,从而达到全局最优。

6. 哈夫曼树的应用

哈夫曼树广泛应用于数据压缩、最优前缀编码、图像和音频压缩等场景。

  • 数据压缩:如 ZIP、PNG、MP3 等使用哈夫曼编码减少存储空间。
  • 信息编码:在通信系统中,哈夫曼编码可用于最优数据传输。
  • 霍夫曼解码:使用哈夫曼树可以有效地解码压缩数据。
  • 网络传输:在数据传输过程中,哈夫曼编码减少了带宽消耗,提高传输效率。
  • AI 和机器学习:在特征编码、模式识别等领域,哈夫曼树也被广泛应用。

哈夫曼编码进行数据压缩的具体细节

哈夫曼编码用于数据压缩的核心思想是利用变长编码来减少数据存储空间,高频字符用短编码,低频字符用长编码,从而降低平均编码长度。以下是具体细节:


1. 哈夫曼编码压缩的基本流程

哈夫曼编码压缩数据的流程主要包括构造哈夫曼树、生成哈夫曼编码、编码数据、存储或传输、解码数据等步骤。

(1)统计字符频率

在进行压缩前,首先统计输入数据中各字符的出现次数。例如,对于字符串 ABRACADABRA,统计出现频率如下:

字符频率
A5
B2
R2
C1
D1

(2)构造哈夫曼树

  1. 将所有字符按照频率构建成叶子节点
  2. 选取频率最小的两个节点合并为一个新节点,并将其频率设为两个子节点的频率之和。
  3. 重复该过程,直到所有节点合并成一棵完整的二叉树。

示例(简化版)哈夫曼树:

        (11)/    \A(5)   (6)/     \B(2)    (4)/     \R(2)   (2)/    \C(1)   D(1)

(3)生成哈夫曼编码

按照哈夫曼树,给左子树赋 0,右子树赋 1,得到各字符的编码:

字符哈夫曼编码
A0
B10
R110
C1110
D1111

(4)编码数据

将输入数据转换为哈夫曼编码。例如:

原始字符串: ABRACADABRA
哈夫曼编码: 0 10 110 0 1110 0 1111 0 10 110 0

假设原始数据每个字符占 8-bit,共 11 个字符,总共 88-bit
哈夫曼编码后,压缩后数据长度为 26-bit,压缩率 = 26/88 ≈ 29.5%,大大减少了存储空间。


(5)存储或传输压缩数据

编码后的数据需要存储或传输。由于哈夫曼编码是变长编码,解码时需要哈夫曼树,因此通常会存储哈夫曼树结构或者编码表,以便解码。


2. 哈夫曼解码的过程

解码时,只需要从哈夫曼树根节点出发,按二进制流遍历,遇到叶子节点时即可确定对应字符。例如,解码 01011001110

0    -> A  
10   -> B  
110  -> R  
0    -> A  
1110 -> C  

还原出的字符串为 ABRAC


3. 哈夫曼编码在数据压缩中的应用

哈夫曼编码在实际应用中广泛用于无损数据压缩,包括:

  • 文件压缩:ZIP、RAR 使用哈夫曼编码作为部分压缩算法。
  • 图片压缩:PNG 使用哈夫曼编码进行无损压缩。
  • 音频压缩:MP3、FLAC 采用哈夫曼编码减少数据存储量。
  • 视频编码:H.264、JPEG 使用哈夫曼编码压缩像素信息。
  • 网络传输:HTTP/2 采用 HPACK 算法,其中使用哈夫曼编码来压缩头部数据,提高传输效率。

4. 哈夫曼编码数据压缩的优缺点

优点:

最优前缀编码,不会产生歧义。
无损压缩,数据不会损坏或丢失。
动态适应不同字符频率,比固定长度编码更高效。

缺点:

❌ 需要存储哈夫曼树,否则无法解码。
❌ 如果字符频率差别不大,压缩效果不明显(如均匀分布的 ASCII 文本)。
编码和解码速度相对较慢,尤其是在大规模数据上。


5. 结论

哈夫曼编码是一种高效的无损压缩算法,在文件、图片、音视频等领域被广泛使用。其核心原理是贪心策略构造最优前缀编码,使高频数据占用更少存储空间,提高压缩效率。然而,在某些均匀分布的数据集中,其压缩率可能不如更先进的算法(如 LZ77、LZ78 或 BWT 压缩)。

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

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

相关文章

Linux 命名管道

文章目录 &#x1f680; 深入理解命名管道&#xff08;FIFO&#xff09;及其C实现一、命名管道核心特性1.1 &#x1f9e9; 基本概念 二、&#x1f4bb; 代码实现解析2.1 &#x1f4c1; 公共头文件&#xff08;common.hpp&#xff09;2.2 &#x1f5a5;️ 服务器端&#xff08;s…

sap 内存管理与数据共享方式

SAP内存管理 内存是程序之间为了传递数据而使用的共享存储空间 SAP内存分类&#xff1a;1、SAP内存&#xff0c;2、ABAP内存 这两种内存都是针对同一登录用户实现数据共享。 SAP内存&#xff08;SAP Memory&#xff09;和ABAP内存&#xff08;ABAP Memory&#xff09;&…

数据结构与算法(哈希表——两个数组的交集)

原题 349. 两个数组的交集 - 力扣&#xff08;LeetCode&#xff09; 给定两个数组 nums1 和 nums2 &#xff0c;返回 它们的 交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。 示例 1&#xff1a; 输入&#xff1a;nums1 [1,2,2,1], nums2 […

python笔记2

变量&#xff1a;含义 一个容器&#xff0c;计算机当中的存储空间。 可以理解为一个用于标识或引用数据的名字或标签。 作用&#xff1a; 可以通过定义一个变量来给需要使用多次的数据命名&#xff0c;就像一个标签一样。下次需要使用这个数据时&#xff0c;只需要通过这个变…

【Linux系统编程】信号

目录 1、信号1.1、什么是信号1.2、进程对信号的处理1.3、信号的生命周期1.4、信号处理流程1.5、信号的发送 2、kill()、raise()函数 发送信号3、alarm函数 闹钟信号4、pause函数 挂起信号、暂停5、singal 函数 捕获信号5.1、为什么返回值是上一次的处理方式5.2、练习 6、sigact…

实用小工具——快速获取数据库时间写法

最近我遇到了一个比较棘手的问题&#xff1a;在工作中&#xff0c;各个项目所使用的数据库类型各不相同。这导致我习惯性地使用Oracle的SQL语句进行编写&#xff0c;但每次完成后都会遇到报错&#xff0c;最终才意识到项目的数据库并非Oracle。为了避免这种情况&#xff0c;我需…

数据类型及sizeof,进制转换

其实数据类型可以讲很多内容&#xff0c;这里看情况需要讲多久吧。 本篇基本都是理论。 目录 数据类型的分类 基本数据类型 构造数据类型 指针类型 空类型 计算数据类型或变量所占用的内存字节数 基本语法 进制转换 二进制 二进制的概念 二进制与十进制的转换 十六进…

pjsip dtmf发送和接收(pjsua)

DTMF(双音多频,Dual-Tone Multi-Frequency)是一种用于电话系统的信号技术,通过组合两个不同频率的音频信号来表示数字和符号。以下是DTMF的主要使用背景和应用场景: 电话拨号 DTMF最常见的用途是电话拨号。当用户按下电话键盘上的数字或符号时,电话会生成两个特定频率的音…

落雪音乐Pro 8.8.6 | 内置8条音源,无需手动导入,纯净无广告

洛雪音乐Pro版内置多组稳定音源接口&#xff0c;省去手动导入的繁琐操作&#xff0c;安装即可畅听海量音乐。延续原版无广告的纯净体验&#xff0c;支持歌单推荐与音源切换&#xff0c;满足个性化听歌需求。此版本仅支持在线播放&#xff0c;无法下载音乐&#xff0c;且与原版不…

mac安装navicat及使用

0.删除旧的 sudo rm -Rf /Applications/Navicat\ Premium.app sudo rm -Rf /private/var/db/BootCaches/CB6F12B3-2C14-461E-B5A7-A8621B7FF130/app.com.prect.NavicatPremium.playlist sudo rm -Rf ~/Library/Caches/com.apple.helpd/SDMHelpData/Other/English/HelpSDMIndexF…

【Unity】 HTFramework框架(六十二)Agent编辑器通用智能体(AI Agent)

更新日期&#xff1a;2025年3月14日。 Github源码&#xff1a;[点我获取源码] Gitee源码&#xff1a;[点我获取源码] 索引 编辑器通用智能体AIAgent类Friday&#xff08;星期五&#xff09;启用智能体设置智能体类型开放智能体权限智能体交互资源优化批处理运行代码联网搜索休闲…

EverArt MCP 服务器安装调试笔记 -cline

EverArt MCP 服务器安装调试笔记 问题描述 用户在使用 EverArt MCP 服务器时遇到报错&#xff1a;“MCP error -1: Connection closed”。 调试过程 检查配置文件 cline_mcp_settings.json: 确认 everart 服务器的配置信息&#xff0c;包括 command、args 和 env 是否正确。…

MFC中使用Create或CreateDialog创建对话框失败,GetLastError错误码为1813(找不到映像文件中指定的资源类型)

文章目录 创建对话框失败示例、原因分析及解决方案示例代码错误原因解决方案 AFX_MANAGE_STATE(AfxGetStaticModuleState())作用一、功能1. 模块状态切换2. 自动状态恢复 二、为什么要用该函数&#xff1f;三、必须使用该宏的典型场景1. MFC 扩展 DLL&#xff08;Extension DLL…

php进程管理

php-fpm(fastcgi process manager)是PHP 的FastCGI管理器&#xff0c;管理PHP的FastCGI进程&#xff0c;提升PHP应用的性能和稳定性 php-fpm是一个高性能的php FastCGI管理器&#xff0c;提供了更好的php进程管理方式&#xff0c;可以有效的控制内存和进程&#xff0c;支持平滑…

《MySQL数据库从零搭建到高效管理|表的增删改查(基础)》

目录 引言&#xff1a; 一、表的操作 1.1 创建学生表 1.2 查看表结构 1.3 删除表 1.4 修改表名 1.5 添加字段 1.6 修改字段 1.7 删除字段 1.8 小结 二、CRUD 2.1 新增&#xff08;Create&#xff09;数据 2.2 查询&#xff08;Retrieve&#xff09;数据 2.3 修改&…

建筑管理(2): 施工承包模式,工程监理,质量监督

文章目录 一. 施工承包模式1. 施工总承包模式1.1 施工总承包的特点1.2 施工总承包模式中的承包方 2. 平行承包模式3. 联合体与合作体承包模式 二. 工程监理1. 强制实行监理的工程范围1.1 国家重点建设工程1.2 大中型公用事业工程(重点)1.3 成片开发建设的住宅小区工程1.4 必须实…

Spring Boot与Apache Ignite集成:构建高性能分布式缓存和计算平台

1. 前言 1.1 什么是Apache Ignite Apache Ignite是一个高性能的分布式内存计算平台,支持内存缓存、分布式计算、流处理和机器学习等功能。它提供了低延迟的数据访问和强大的计算能力,适用于需要高性能和可扩展性的应用。 1.2 为什么选择Apache Ignite 高性能:Ignite利用内…

REST 请求返回 Invalid Credentials

REST 请求返回 “Invalid Credentials”&#xff08;无效凭据&#xff09;&#xff0c;通常表示身份验证失败。可能的原因和解决方案如下&#xff1a; 可能的原因 & 解决方案 用户名或密码错误 确保使用正确的用户名和密码。如果 API 需要 Base64 编码的 Authorization 头…

C++Primer学习(6.7 函数指针——难!)

6.7 函数指针 (这一章节比较难) 函数指针指向的是函数而非对象。和其他指针一样&#xff0c;函数指针指向某种特定类型。函数的类型由它的返回类型和形参类型共同决定&#xff0c;与函数名无关。例如: //比较两个 string 对象的长度 bool lengthCompare(const string &,co…

高级java每日一道面试题-2025年2月26日-框架篇[Mybatis篇]-Mybatis是如何将sql执行结果封装为目标对象并返回的?都有哪些映射形式 ?

如果有遗漏,评论区告诉我进行补充 面试官: Mybatis是如何将sql执行结果封装为目标对象并返回的?都有哪些映射形式 ? 我回答: 在Java高级面试中讨论MyBatis如何将SQL执行结果封装为目标对象并返回的过程时&#xff0c;我们可以从过程细节和映射形式两个方面来综合解答这个问…