【算法】记录一下最近实现的哈夫曼编码压缩文本

本贴最后更新于 470 天前,其中的信息可能已经时移世易
#include <iostream> #include <queue> #include <unordered_map> #include <vector> #include <fstream> using namespace std; struct HuffmanTreeNode{ char ch_; int freq_; HuffmanTreeNode* left_,* right_; HuffmanTreeNode(char ch, int freq): ch_(ch), freq_(freq) { left_ = nullptr; right_ = nullptr; } bool isLeaf() const { return left_ == nullptr && right_ == nullptr; } }; //用于HuffmanTreeNode在优先队列的比较 struct Compare { bool operator()(HuffmanTreeNode* l, HuffmanTreeNode* r) { return l->freq_ > r->freq_; } }; struct BitCharBuffer { vector<char>* buffer; int bit_length; }; HuffmanTreeNode* buildTree(string str) { int freq[256]{0}; for (auto it = str.begin(); it != str.end(); ++it) { freq[(*it) + 128]++; } priority_queue<HuffmanTreeNode*, vector<HuffmanTreeNode*>, Compare> que; for (int i = 0; i < 256; i++) { if (freq[i] != 0) { que.push(new HuffmanTreeNode(i - 128, freq[i])); } } while (que.size() > 1) { HuffmanTreeNode* left = que.top(); que.pop(); HuffmanTreeNode* right = que.top(); que.pop(); HuffmanTreeNode* node = new HuffmanTreeNode('\0', left->freq_ + right->freq_); node->left_ = left; node->right_ = right; que.push(node); } return que.top(); } void treeToMap(HuffmanTreeNode* root, vector<bool>& code, unordered_map<char, vector<bool>>& code_map) { if (root == nullptr) return; if (!root->left_ && !root->right_) { code_map[root->ch_] = code; } code.push_back(0); treeToMap(root->left_, code, code_map); code.pop_back(); code.push_back(1); treeToMap(root->right_, code, code_map); code.pop_back(); } void treeToMap(HuffmanTreeNode* root, unordered_map<char, vector<bool>>& code_map) { vector<bool> code; treeToMap(root, code, code_map); } void writeBuffer(const vector<bool>& code, BitCharBuffer& char_buffer, int offset, int length) { int index = char_buffer.bit_length / 8; int alpha = char_buffer.bit_length % 8; for (int i = offset; i < offset + length; i++) { if (alpha == 0) { char_buffer.buffer->push_back(0); } (*(char_buffer.buffer))[index] += ((char)code[i] << (7 - alpha)); char_buffer.bit_length++; alpha++; if (alpha == 8) { index++; alpha = 0; } } } void writeBuffer(const vector<bool>& code, BitCharBuffer& char_buffer, int offset = 0) { writeBuffer(code, char_buffer, offset, code.size() - offset); } void encode(const string& str, ostream& os, unordered_map<char, vector<bool>>& code_map) { int max_length = 1 << 15; //缓冲区大小,单位bit,需要为 1 << 4 的整数倍,小于int最大值 BitCharBuffer char_buffer; char_buffer.buffer = new vector<char>(0); char_buffer.bit_length = 0; for (auto it = str.begin(); it != str.end(); ++it) { char ch = *it; const vector<bool>& code = code_map[ch]; //如果达到长度上限,写入output stream,然后重开缓冲区 if (max_length - code.size() < char_buffer.bit_length) { int temp = char_buffer.bit_length; //先把当前的buffer写满 writeBuffer(code, char_buffer, 0, max_length - char_buffer.bit_length); //输出到os os.write(char_buffer.buffer->data(), char_buffer.buffer->size()); //释放旧缓冲区,分配新缓冲区 delete char_buffer.buffer; char_buffer.buffer = new vector<char>(0); char_buffer.bit_length = 0; //将超长的部分写进新缓冲区 writeBuffer(code, char_buffer, max_length - temp); } else writeBuffer(code, char_buffer); } os.write(char_buffer.buffer->data(), char_buffer.buffer->size()); } void decode(const string& str, ostream& os, HuffmanTreeNode* root) { HuffmanTreeNode* current = root; char camp = 1 << 7; for (auto it = str.begin(); it != str.end(); ++it) { char byte = *it; for (int i = 0; i < 8; i++) { if (camp & byte) { current = current->right_; } else { current = current->left_; } if (current->isLeaf()) { os << current->ch_; if (current->ch_ == '\0') return; //特殊地,输出结尾标记后停止译码 current = root; } byte = byte << 1; } } } int main() { ifstream ifs("source.txt"); if (!ifs.is_open()) { cout << "打开sources.txt输入流失败" << endl; return 0; } string str((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>()); str += '\0'; //哈夫曼编码是变长的,但文件操作的最小单位是byte(定长8bit),因此需要一个结尾标记。 HuffmanTreeNode* root = buildTree(str); unordered_map<char, vector<bool>> map; treeToMap(root, map); ofstream ofs("code.dat", ios::binary); if (!ofs.is_open()) { cout << "打开code.dat输出流失败" << endl; } else{ encode(str, ofs, map); ofs.close(); } ifstream difs("code.dat", ios::binary); if (!difs.is_open()) { cout << "打开code.dat输入流失败" << endl; } else { string code_str((std::istreambuf_iterator<char>(difs)), std::istreambuf_iterator<char>()); decode(code_str, cout, root); difs.close(); } delete root; ifs.close(); }

是快速实现,没有弄接口,直接用 main 函数测试的。转发随意。

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • Office

    Office 现已更名为 Microsoft 365. Microsoft 365 将高级 Office 应用(如 Word、Excel 和 PowerPoint)与 1 TB 的 OneDrive 云存储空间、高级安全性等结合在一起,可帮助你在任何设备上完成操作。

    5 引用 • 34 回帖
  • React

    React 是 Facebook 开源的一个用于构建 UI 的 JavaScript 库。

    192 引用 • 291 回帖 • 384 关注
  • 小说

    小说是以刻画人物形象为中心,通过完整的故事情节和环境描写来反映社会生活的文学体裁。

    31 引用 • 108 回帖
  • Thymeleaf

    Thymeleaf 是一款用于渲染 XML/XHTML/HTML5 内容的模板引擎。类似 Velocity、 FreeMarker 等,它也可以轻易的与 Spring 等 Web 框架进行集成作为 Web 应用的模板引擎。与其它模板引擎相比,Thymeleaf 最大的特点是能够直接在浏览器中打开并正确显示模板页面,而不需要启动整个 Web 应用。

    11 引用 • 19 回帖 • 388 关注
  • GraphQL

    GraphQL 是一个用于 API 的查询语言,是一个使用基于类型系统来执行查询的服务端运行时(类型系统由你的数据定义)。GraphQL 并没有和任何特定数据库或者存储引擎绑定,而是依靠你现有的代码和数据支撑。

    4 引用 • 3 回帖 • 5 关注
  • AWS
    11 引用 • 28 回帖 • 12 关注
  • abitmean

    有点意思就行了

    37 关注
  • Vim

    Vim 是类 UNIX 系统文本编辑器 Vi 的加强版本,加入了更多特性来帮助编辑源代码。Vim 的部分增强功能包括文件比较(vimdiff)、语法高亮、全面的帮助系统、本地脚本(Vimscript)和便于选择的可视化模式。

    29 引用 • 66 回帖
  • App

    App(应用程序,Application 的缩写)一般指手机软件。

    91 引用 • 384 回帖
  • golang

    Go 语言是 Google 推出的一种全新的编程语言,可以在不损失应用程序性能的情况下降低代码的复杂性。谷歌首席软件工程师罗布派克(Rob Pike)说:我们之所以开发 Go,是因为过去 10 多年间软件开发的难度令人沮丧。Go 是谷歌 2009 发布的第二款编程语言。

    498 引用 • 1395 回帖 • 249 关注
  • 微软

    微软是一家美国跨国科技公司,也是世界 PC 软件开发的先导,由比尔·盖茨与保罗·艾伦创办于 1975 年,公司总部设立在华盛顿州的雷德蒙德(Redmond,邻近西雅图)。以研发、制造、授权和提供广泛的电脑软件服务业务为主。

    8 引用 • 44 回帖
  • SpaceVim

    SpaceVim 是一个社区驱动的模块化 vim/neovim 配置集合,以模块的方式组织管理插件以
    及相关配置,为不同的语言开发量身定制了相关的开发模块,该模块提供代码自动补全,
    语法检查、格式化、调试、REPL 等特性。用户仅需载入相关语言的模块即可得到一个开箱
    即用的 Vim-IDE。

    3 引用 • 31 回帖 • 119 关注
  • Swagger

    Swagger 是一款非常流行的 API 开发工具,它遵循 OpenAPI Specification(这是一种通用的、和编程语言无关的 API 描述规范)。Swagger 贯穿整个 API 生命周期,如 API 的设计、编写文档、测试和部署。

    26 引用 • 35 回帖
  • 链书

    链书(Chainbook)是 B3log 开源社区提供的区块链纸质书交易平台,通过 B3T 实现共享激励与价值链。可将你的闲置书籍上架到链书,我们共同构建这个全新的交易平台,让闲置书籍继续发挥它的价值。

    链书社

    链书目前已经下线,也许以后还有计划重制上线。

    14 引用 • 257 回帖 • 1 关注
  • RIP

    愿逝者安息!

    8 引用 • 92 回帖 • 395 关注
  • Quicker

    Quicker 您的指尖工具箱!操作更少,收获更多!

    36 引用 • 155 回帖
  • JSON

    JSON (JavaScript Object Notation)是一种轻量级的数据交换格式。易于人类阅读和编写。同时也易于机器解析和生成。

    52 引用 • 190 回帖
  • uTools

    uTools 是一个极简、插件化、跨平台的现代桌面软件。通过自由选配丰富的插件,打造你得心应手的工具集合。

    7 引用 • 27 回帖
  • Mobi.css

    Mobi.css is a lightweight, flexible CSS framework that focus on mobile.

    1 引用 • 6 回帖 • 758 关注
  • Netty

    Netty 是一个基于 NIO 的客户端-服务器编程框架,使用 Netty 可以让你快速、简单地开发出一个可维护、高性能的网络应用,例如实现了某种协议的客户、服务端应用。

    49 引用 • 33 回帖 • 35 关注
  • JRebel

    JRebel 是一款 Java 虚拟机插件,它使得 Java 程序员能在不进行重部署的情况下,即时看到代码的改变对一个应用程序带来的影响。

    26 引用 • 78 回帖 • 678 关注
  • PostgreSQL

    PostgreSQL 是一款功能强大的企业级数据库系统,在 BSD 开源许可证下发布。

    22 引用 • 22 回帖
  • 浅吟主题

    Jeffrey Chen 制作的思源笔记主题,项目仓库:https://github.com/TCOTC/Whisper

    1 引用 • 28 回帖 • 2 关注
  • CAP

    CAP 指的是在一个分布式系统中, Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可兼得。

    12 引用 • 5 回帖 • 636 关注
  • OkHttp

    OkHttp 是一款 HTTP & HTTP/2 客户端库,专为 Android 和 Java 应用打造。

    16 引用 • 6 回帖 • 85 关注
  • Windows

    Microsoft Windows 是美国微软公司研发的一套操作系统,它问世于 1985 年,起初仅仅是 Microsoft-DOS 模拟环境,后续的系统版本由于微软不断的更新升级,不但易用,也慢慢的成为家家户户人们最喜爱的操作系统。

    227 引用 • 476 回帖
  • Markdown

    Markdown 是一种轻量级标记语言,用户可使用纯文本编辑器来排版文档,最终通过 Markdown 引擎将文档转换为所需格式(比如 HTML、PDF 等)。

    170 引用 • 1529 回帖