Day14/15:哈夫曼树、哈弗曼编码(压缩与解压缩)

目录

   一、相关基础知识

   二、压缩     

        三、解压缩 

关键:如何将放在一起的0101进行区分成相应的字符

四、利用栈和堆---Huffman树的写法:

一、相关基础知识

        1.unsigned char与signed char 的区别:

         2.哈夫曼树(最优树、最佳搜索树):

①路径长度的概念


1.路径:从一个结点到另一个结点之间的分支序列
2.结点之间的路径长度:从一个结点到另一个结点之间的分支数目
3.树的路径长度(用PL表示):从树的根到每一个结点的路径长度之和  → 深度之和

 PL = 0+1+1+2+2+2+2+3=13

 

 WPL=7*2+5*2+2*2+4*2=36

②构建一颗Huffman树

以数据{5,6,7,8,15}为例

注意观察特征:原数据5\6\7\8\15均只会出现在叶子结点(自下而上构建新的节点) 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
是一种常用的压缩方法。是1952年为文本文件建立的,其基本原理是频繁使用的数据用较短的代码代替,很少使用的数据用较长的代码代替,每个数据的代码各不相同。这些代码都是二进制码,且码的长度是可变的。如: 有一个原始数据序列,ABACCDAA则编码为A(0),B(10),C(110),(D111),压缩后为010011011011100。产生霍编码需要对原始数据扫描两遍,第一遍扫描要精确地统计出原始数据中的每个值出现的频率,第二遍是建立霍并进行编码,由于需要建立二叉并遍历二叉生成编码,因此数据压缩和还原速度都较慢,但简单有效,因而得到广泛的应用。 哈编码是无损压缩当中最好的方法。它使用预先二进制描述来替换每个符号,长度由特殊符号出现的频率决定。常见的符号需要很少的位来表示,而不常见的符号需要很多为来表示。哈算法在改变任何符号二进制编码引起少量密集表现方面是最佳的。然而,它并不处理符号的顺序和重复或序号的序列 哈压缩,首先用ASCII值初始化511个哈节点,然后,计算在输入缓冲区数据中,每个ASCII码出现的频率。然后,根据频率进行排序,现在,构造哈,获取每个ASCII码对应的位序列,构造哈,将所有的节点放到一个队列中,用一个节点替换两个频率最低的节点,新节点的频率就是这两个节点的频率之和。这样,新节点就是两个被替换节点的父节点了。如此循环,直到队列中只剩一个节点(根)。压缩的最后一步是将每个ASCII编码写入输出缓冲区中 哈压缩,将输入缓冲区中的每个编码用对应的ASCII码逐个替换就可以了。只要记住,这里的输入缓冲区是一个包含每个ASCII值的编码的位流。因此,为了用ASCII值替换编码,我们必须用位流搜索哈,直到发现一个叶节点,然后将它的ASCII值添加到输出缓冲区中: 复制内容到剪贴板
编码是一种基于字符频率的压缩算法,可以在不丢失数据的情况下有效地减小文件大小。哈编码压缩过程需要先建立哈,再根据哈生成每个字符的编码表,最后将原文件中的字符替换为对应的编码即可。压过程则是将编码转换为原字符,最终还原原始文件。 以下是一个简单的哈编码文件压缩压缩的实现示例,使用 C++ 语言编写。 ### 哈的构建 ```cpp #include <iostream> #include <queue> #include <vector> #include <unordered_map> using namespace std; // 哈节点 struct Node { char ch; int freq; Node *left, *right; Node(char c, int f) : ch(c), freq(f), left(nullptr), right(nullptr) {} }; // 比较器,用于优先队列中的排序 struct cmp { bool operator()(Node* a, Node* b) { return a->freq > b->freq; } }; // 构建哈 Node* buildHuffmanTree(string str) { // 统计字符频率 unordered_map<char, int> freqMap; for (char c : str) { freqMap[c]++; } // 将所有字符及其频率转化为哈节点并加入优先队列 priority_queue<Node*, vector<Node*>, cmp> pq; for (auto it = freqMap.begin(); it != freqMap.end(); it++) { pq.push(new Node(it->first, it->second)); } // 构建哈 while (pq.size() > 1) { Node* left = pq.top(); pq.pop(); Node* right = pq.top(); pq.pop(); Node* parent = new Node('$', left->freq + right->freq); parent->left = left; parent->right = right; pq.push(parent); } // 返回根节点 return pq.top(); } ``` ### 哈编码的生成 ```cpp // 生成哈编码表 void generateEncodingTable(Node* root, unordered_map<char, string>& encodingTable, string code) { if (!root) return; if (!root->left && !root->right) { encodingTable[root->ch] = code; return; } generateEncodingTable(root->left, encodingTable, code + "0"); generateEncodingTable(root->right, encodingTable, code + "1"); } ``` ### 文件压缩 ```cpp #include <fstream> #include <bitset> // 压缩文件 void compressFile(string inputFile, string outputFile) { // 读取原文件 ifstream ifs(inputFile, ios::binary); string str((istreambuf_iterator<char>(ifs)), (istreambuf_iterator<char>())); ifs.close(); // 构建哈并生成编码表 Node* root = buildHuffmanTree(str); unordered_map<char, string> encodingTable; generateEncodingTable(root, encodingTable, ""); // 将编码表写入压缩文件头部 ofstream ofs(outputFile, ios::binary); for (auto it = encodingTable.begin(); it != encodingTable.end(); it++) { ofs << it->first << it->second << endl; } // 将压缩后的内容写入压缩文件 string compressedStr; for (char c : str) { compressedStr += encodingTable[c]; } while (compressedStr.length() % 8 != 0) compressedStr += "0"; // 补齐到8的倍数 for (int i = 0; i < compressedStr.length(); i += 8) { bitset<8> bits(compressedStr.substr(i, 8)); ofs << char(bits.to_ulong()); } ofs.close(); } ``` ### 文件压 ```cpp #include <sstream> // 压文件 void decompressFile(string inputFile, string outputFile) { // 读取压缩文件 ifstream ifs(inputFile, ios::binary); stringstream ss; ss << ifs.rdbuf(); string compressedStr = ss.str(); ifs.close(); // 从压缩文件头部读取编码表 unordered_map<string, char> decodingTable; int i = 0; while (i < compressedStr.length() && compressedStr[i] != '\n') { char c = compressedStr[i++]; string code; while (i < compressedStr.length() && compressedStr[i] != '\n') { code += compressedStr[i++]; } decodingTable[code] = c; i++; // 跳过换行符 } // 压缩内容 string decompressedStr; string code; for (; i < compressedStr.length(); i++) { bitset<8> bits(compressedStr[i]); code += bits.to_string(); if (decodingTable.find(code) != decodingTable.end()) { decompressedStr += decodingTable[code]; code.clear(); } } // 写入压后的内容 ofstream ofs(outputFile, ios::binary); ofs << decompressedStr; ofs.close(); } ``` 以上就是一个简单的哈编码文件压缩压缩的实现方法。需要注意的是,在实际应用中,还需要考虑一些细节问题,例如文件读写、编码表的存储方式和压缩文件头部的格式等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_Ocean__

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值