帮我写一个C++用二叉树进行霍夫曼编码
时间: 2023-07-01 14:16:10 浏览: 63
好的,下面是一个简单的C++实现,包括字符频率的统计、霍夫曼树的构建、字符编码的生成和文件压缩解压等功能:
```c++
#include <iostream>
#include <fstream>
#include <queue>
#include <unordered_map>
#include <vector>
using namespace std;
struct Node {
char ch;
int freq;
Node *left, *right;
Node(char ch, int freq, Node *left = nullptr, Node *right = nullptr) {
this->ch = ch;
this->freq = freq;
this->left = left;
this->right = right;
}
~Node() {
delete left;
delete right;
}
};
struct Compare {
bool operator()(Node *a, Node *b) {
return a->freq > b->freq;
}
};
class Huffman {
public:
Huffman() {}
void compress(const string &in_file, const string &out_file) {
unordered_map<char, int> freq_map = count_freq(in_file);
Node *root = build_tree(freq_map);
unordered_map<char, string> code_map = generate_code(root);
ifstream fin(in_file, ios::binary);
ofstream fout(out_file, ios::binary);
int num_bits = 0;
char buffer = 0;
while (true) {
char ch = fin.get();
if (fin.eof()) break;
string code = code_map[ch];
for (char bit : code) {
buffer = (buffer << 1) | (bit - '0');
if (++num_bits == 8) {
fout.put(buffer);
buffer = 0;
num_bits = 0;
}
}
}
if (num_bits > 0) {
buffer <<= (8 - num_bits);
fout.put(buffer);
}
fin.close();
fout.close();
}
void decompress(const string &in_file, const string &out_file) {
ifstream fin(in_file, ios::binary);
ofstream fout(out_file, ios::binary);
Node *root = read_tree(fin);
Node *p = root;
int num_bits = 0;
char buffer = fin.get();
while (true) {
if (p->left == nullptr && p->right == nullptr) {
fout.put(p->ch);
p = root;
} else {
char bit = (buffer >> (7 - num_bits)) & 1;
p = (bit == 0) ? p->left : p->right;
if (++num_bits == 8) {
buffer = fin.get();
num_bits = 0;
}
}
if (fin.eof()) break;
}
delete root;
fin.close();
fout.close();
}
private:
unordered_map<char, int> count_freq(const string &in_file) {
unordered_map<char, int> freq_map;
ifstream fin(in_file, ios::binary);
while (true) {
char ch = fin.get();
if (fin.eof()) break;
freq_map[ch]++;
}
fin.close();
return freq_map;
}
Node *build_tree(const unordered_map<char, int> &freq_map) {
priority_queue<Node*, vector<Node*>, Compare> pq;
for (auto &p : freq_map) {
pq.push(new Node(p.first, p.second));
}
while (pq.size() > 1) {
Node *left = pq.top(); pq.pop();
Node *right = pq.top(); pq.pop();
Node *parent = new Node('\0', left->freq + right->freq, left, right);
pq.push(parent);
}
return pq.top();
}
unordered_map<char, string> generate_code(Node *root) {
unordered_map<char, string> code_map;
string code;
generate_code_helper(root, code, code_map);
return code_map;
}
void generate_code_helper(Node *p, string &code, unordered_map<char, string> &code_map) {
if (p == nullptr) return;
if (p->left == nullptr && p->right == nullptr) {
code_map[p->ch] = code;
return;
}
code.push_back('0');
generate_code_helper(p->left, code, code_map);
code.pop_back();
code.push_back('1');
generate_code_helper(p->right, code, code_map);
code.pop_back();
}
Node *read_tree(ifstream &fin) {
char ch = fin.get();
if (ch == 'L') {
return new Node(fin.get(), 0);
} else {
Node *left = read_tree(fin);
Node *right = read_tree(fin);
return new Node('\0', 0, left, right);
}
}
void write_tree(Node *p, ofstream &fout) {
if (p->left == nullptr && p->right == nullptr) {
fout.put('L');
fout.put(p->ch);
} else {
fout.put('I');
write_tree(p->left, fout);
write_tree(p->right, fout);
}
}
};
int main() {
Huffman huffman;
huffman.compress("input.txt", "output.bin");
huffman.decompress("output.bin", "output.txt");
return 0;
}
```
这里假设待压缩的文件为文本文件,输入输出文件名分别为`input.txt`和`output.txt`,压缩后的二进制文件为`output.bin`。在压缩时,首先统计每个字符出现的频率,然后利用优先队列构建霍夫曼树,生成每个字符的编码,将每个字符替换为其对应的编码,得到压缩后的文件。在解压时,读入压缩后的文件,根据编码逆向遍历霍夫曼树,得到原字符,依次输出即可。
阅读全文