利用哈夫曼压缩与解压缩文件的C++代码
时间: 2023-12-10 13:04:10 浏览: 91
以下是利用哈夫曼压缩与解压缩文件的C++代码:
```cpp
#include <iostream>
#include <fstream>
#include <queue>
#include <unordered_map>
#include <bitset>
using namespace std;
class HuffmanNode {
public:
char c;
int freq;
HuffmanNode* left;
HuffmanNode* right;
HuffmanNode(char c, int freq) : c(c), freq(freq), left(nullptr), right(nullptr) {}
~HuffmanNode() { delete left; delete right; }
};
struct cmp {
bool operator()(HuffmanNode* a, HuffmanNode* b) {
return a->freq > b->freq;
}
};
class HuffmanTree {
public:
HuffmanNode* root;
HuffmanTree() : root(nullptr) {}
~HuffmanTree() { delete root; }
void build(unordered_map<char, int>& freq) {
priority_queue<HuffmanNode*, vector<HuffmanNode*>, cmp> pq;
for (auto& p : freq) {
pq.push(new HuffmanNode(p.first, p.second));
}
while (pq.size() > 1) {
auto a = pq.top(); pq.pop();
auto b = pq.top(); pq.pop();
pq.push(new HuffmanNode('\0', a->freq + b->freq));
a->left = b;
a->right = a->left;
}
this->root = pq.top();
}
};
unordered_map<char, int> getFreq(const string& filename) {
unordered_map<char, int> freq;
ifstream ifs(filename, ios::binary);
if (!ifs) {
cerr << "Error: cannot open file " << filename << endl;
exit(1);
}
char c;
while (ifs.get(c)) {
freq[c]++;
}
return freq;
}
void encode(const string& filename, const unordered_map<char, string>& codes) {
ifstream ifs(filename, ios::binary);
if (!ifs) {
cerr << "Error: cannot open file " << filename << endl;
exit(1);
}
string outputFilename = filename + ".huffman";
ofstream ofs(outputFilename, ios::binary);
if (!ofs) {
cerr << "Error: cannot create file " << outputFilename << endl;
exit(1);
}
ofs << codes.size() << endl;
for (auto& p : codes) {
ofs << p.first << " " << p.second << endl;
}
char c;
string bits;
while (ifs.get(c)) {
bits += codes.at(c);
while (bits.size() >= 8) {
bitset<8> byte(bits.substr(0, 8));
ofs.put(static_cast<char>(byte.to_ulong()));
bits.erase(0, 8);
}
}
if (bits.size() > 0) {
bits += string(8 - bits.size(), '0');
bitset<8> byte(bits);
ofs.put(static_cast<char>(byte.to_ulong()));
}
}
void decode(const string& filename) {
ifstream ifs(filename, ios::binary);
if (!ifs) {
cerr << "Error: cannot open file " << filename << endl;
exit(1);
}
string outputFilename = filename.substr(0, filename.find_last_of('.'));
ofstream ofs(outputFilename, ios::binary);
if (!ofs) {
cerr << "Error: cannot create file " << outputFilename << endl;
exit(1);
}
int n;
ifs >> n;
ifs.ignore();
unordered_map<string, char> codes;
for (int i = 0; i < n; i++) {
char c;
string code;
ifs >> c >> code;
codes[code] = c;
}
string bits;
char c;
while (ifs.get(c)) {
bits += bitset<8>(static_cast<unsigned char>(c)).to_string();
}
if (bits.size() > 0) {
int padding = stoi(bits.substr(bits.size() - 8), nullptr, 2);
bits.erase(bits.size() - padding, padding);
}
HuffmanNode* node = new HuffmanNode('\0', 0);
HuffmanNode* p = node;
for (char bit : bits) {
if (bit == '0') {
p = p->left == nullptr ? p->left = new HuffmanNode('\0', 0) : p->left;
} else {
p = p->right == nullptr ? p->right = new HuffmanNode('\0', 0) : p->right;
}
if (p->left == nullptr && p->right == nullptr) {
ofs.put(p->c);
p = node;
}
}
delete node;
}
int main(int argc, char* argv[]) {
if (argc != 3) {
cerr << "Usage: " << argv[0] << " compress/decompress filename" << endl;
return 1;
}
if (string(argv[1]) == "compress") {
auto freq = getFreq(argv[2]);
HuffmanTree tree;
tree.build(freq);
unordered_map<char, string> codes;
function<void(HuffmanNode*, string)> dfs = [&](HuffmanNode* node, string code) {
if (node->left == nullptr && node->right == nullptr) {
codes[node->c] = code;
}
if (node->left != nullptr) {
dfs(node->left, code + "0");
}
if (node->right != nullptr) {
dfs(node->right, code + "1");
}
};
dfs(tree.root, "");
encode(argv[2], codes);
} else if (string(argv[1]) == "decompress") {
decode(argv[2]);
} else {
cerr << "Usage: " << argv[0] << " compress/decompress filename" << endl;
return 1;
}
return 0;
}
```
代码中使用了一个 `HuffmanNode` 类来表示哈夫曼树的节点,使用了一个 `HuffmanTree` 类来表示哈夫曼树,使用了一个 `unordered_map` 来存储每个字符的出现频率,使用了一个优先队列来构建哈夫曼树,使用了一个递归函数来生成哈夫曼编码,使用了一个 `bitset` 来进行位运算,使用了一个文件流来读取和写入文件,使用了一些 C++11 的新特性。在使用时,运行程序时需要指定压缩或解压缩,并指定文件名。
阅读全文