0

0

c++怎么实现哈夫曼树编码压缩_c++ 字符频率统计与变长编码【案例】

冰火之心

冰火之心

发布时间:2025-12-30 16:15:08

|

616人浏览过

|

来源于php中文网

原创

哈夫曼压缩核心是按频率构建最小堆二叉树并生成唯一变长编码:需以unsigned char统计0–255字节频次,自定义priority_queue升序比较器,合并时权重小者为左子树(编0),大者为右(编1),空文件或单字符需特判;编码表须按“字符+长度+对齐比特”二进制格式写入头部,并校验编码唯一性。

c++怎么实现哈夫曼树编码压缩_c++ 字符频率统计与变长编码【案例】

怎么用 C++ 构建哈夫曼树并生成变长编码

核心是:先统计字符频率,再用优先队列(最小堆)构建带权路径最短的二叉树,最后递归/迭代生成每个字符的编码。关键不在“写树”,而在「保证构建过程严格按权重合并」和「编码方向不能反」。

常见错误是把左子树当 1、右子树当 0(或反之),导致解码失败;或者没处理单字符输入(比如文件只含一个 'a'),堆里只剩一个节点时直接崩溃。

  • std::priority_queue 时必须自定义比较器,让它按 freq 升序——默认是大顶堆,得翻过来
  • 树节点建议用结构体而非类,避免虚函数开销;叶子节点需存原始字符(charint),内部节点设为 -10 标记
  • 编码生成推荐 DFS 递归:进左子树拼 "0",进右子树拼 "1";别用 BFS,容易乱序且难回溯路径
struct Node {
    int freq;
    char ch;
    Node* left;
    Node* right;
    Node(int f, char c) : freq(f), ch(c), left(nullptr), right(nullptr) {}
};
struct Compare {
    bool operator()(Node* a, Node* b) { return a->freq > b->freq; }
};
// 构建过程节选
std::priority_queue, Compare> pq;
// ... 插入所有叶子节点
while (pq.size() > 1) {
    Node* l = pq.top(); pq.pop();
    Node* r = pq.top(); pq.pop();
    Node* merged = new Node(l->freq + r->freq, '\0');
    merged->left = l;
    merged->right = r;
    pq.push(merged);
}

字符频率统计要注意哪些边界情况

不能简单用 std::map 然后 fstream.get()字节读——遇到空字符 '\0'、换行符 '\n'、高位字节(如 UTF-8 中文)会截断或误判。实际压缩对象是字节流,不是“字符流”。

  • 必须以 unsigned char 视角读取文件,映射到 int 范围 [0, 255],用 std::array 统计最稳
  • 文件末尾的 EOF 不算有效字节,istream::get() 返回 int,需判断是否等于 EOF 再转 unsigned char
  • 若输入为空文件,频率数组全零,后续建树要提前检查 total_count == 0 并跳过压缩
std::array freq{};
std::ifstream fin("input.bin", std::ios::binary);
int byte;
while ((byte = fin.get()) != EOF) {
    freq[static_cast(byte)]++;
}

怎么把编码表高效存进压缩文件头部

不能直接写字符串如 "a:010\nb:11\n"——这本身就在膨胀数据。标准做法是:先写字符(1 字节),再写其编码长度(1 字节),最后写编码比特(按字节对齐,高位在前)。

立即学习C++免费学习笔记(深入)”;

HaiSnap
HaiSnap

一站式AI应用开发和部署工具

下载

例如字符 'x' 编码是 "1011"(4 位),就写:0x78('x' 的 ASCII)、0x040xB010110000,后 4 位补零凑满 1 字节)。解压时靠长度字段截取有效比特。

  • 编码长度超过 8 位?正常,哈夫曼树深度可能达 256,但实际英文文本一般 ≤ 32
  • 务必在头部末尾写一个结束标记(如 0xFF),否则解压器无法知道头在哪结束
  • 别用 std::string 拼接编码比特——它按字节存,而你需要按位写入,得手写 bit writer 类或用 std::vector(注意它不是容器,别用 data()

为什么压缩后文件反而变大了

小文件(

  • 测试时用 >10 KB 的纯英文文本(如《The Raven》),才能看到 30%~40% 压缩率
  • 如果源文件已用 gzip 压过,再套哈夫曼只会更大——熵已经极低,变长编码失去优势
  • 真正工程中不会单独用哈夫曼,而是作为 DEFLATE(zip)的后端;自己实现时,至少加一层游程编码预处理,对付重复字节

最容易被忽略的是:没做「编码唯一性校验」。两个不同字符生成相同编码(比如都成了 "0"),整个压缩就不可逆。构建完树必须遍历所有叶子,确认无重复编码串——哪怕只是调试时用 std::set<:string> 临时塞一遍。

相关专题

更多
string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

312

2023.08.02

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

248

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

205

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1434

2023.10.24

字符串介绍
字符串介绍

字符串是一种数据类型,它可以是任何文本,包括字母、数字、符号等。字符串可以由不同的字符组成,例如空格、标点符号、数字等。在编程中,字符串通常用引号括起来,如单引号、双引号或反引号。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

609

2023.11.24

java读取文件转成字符串的方法
java读取文件转成字符串的方法

Java8引入了新的文件I/O API,使用java.nio.file.Files类读取文件内容更加方便。对于较旧版本的Java,可以使用java.io.FileReader和java.io.BufferedReader来读取文件。在这些方法中,你需要将文件路径替换为你的实际文件路径,并且可能需要处理可能的IOException异常。想了解更多java的相关内容,可以阅读本专题下面的文章。

546

2024.03.22

php中定义字符串的方式
php中定义字符串的方式

php中定义字符串的方式:单引号;双引号;heredoc语法等等。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

539

2024.04.29

go语言字符串相关教程
go语言字符串相关教程

本专题整合了go语言字符串相关教程,阅读专题下面的文章了解更多详细内容。

157

2025.07.29

桌面文件位置介绍
桌面文件位置介绍

本专题整合了桌面文件相关教程,阅读专题下面的文章了解更多内容。

0

2025.12.30

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
HTML5/CSS3/JavaScript/ES6入门课程
HTML5/CSS3/JavaScript/ES6入门课程

共102课时 | 6.5万人学习

前端基础到实战(HTML5+CSS3+ES6+NPM)
前端基础到实战(HTML5+CSS3+ES6+NPM)

共162课时 | 18.5万人学习

第二十二期_前端开发
第二十二期_前端开发

共119课时 | 12.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号