哈夫曼编码是一种用于数据压缩的编码方法,它根据字符出现的频率来构建一棵二叉树,并将频率较高的字符赋予较短的编码,频率较低的字符赋予较长的编码。这样可以实现对数据进行高效压缩。
下面是哈夫曼编码的规则说明:
-
构建哈夫曼树:根据字符出现的频率构建一棵哈夫曼树。频率越高的字符离根节点越近,频率越低的字符离根节点越远。
-
分配编码:从根节点开始,沿着左子树走为0,沿着右子树走为1。每当到达一个叶子节点时,就得到了该字符的哈夫曼编码。注意,由于哈夫曼树的性质,任何一个字符的编码都不是另一个字符编码的前缀,这被称为“前缀码”。
-
唯一编码:通过构建的哈夫曼树,每个字符都有唯一的编码。这是因为在哈夫曼树中,每个字符的编码都是通过不同的路径得到的,而路径上的0和1是不重复的。
-
最优编码:哈夫曼编码是一种最优编码,即它可以实现最小的平均编码长度。这是因为频率较高的字符被赋予较短的编码,而频率较低的字符被赋予较长的编码,从而使得整体的编码长度最小化。
哈夫曼编码常用于数据压缩领域,可以将原始数据转换成较短的编码,从而减少存储空间或传输带宽的使用。在解码时,只需根据哈夫曼编码和对应的哈夫曼树进行解码,即可还原出原始数据。
#include <iostream>
#include <queue>
using namespace std;
// 哈夫曼树节点
struct HuffmanNode {
char data; // 字符
int frequency; // 频率
HuffmanNode* left;
HuffmanNode* right;
HuffmanNode(char d, int freq) : data(d), frequency(freq), left(nullptr), right(nullptr) {}
};
// 比较函数,用于优先队列中的排序
struct Compare {
bool operator()(HuffmanNode* a, HuffmanNode* b) {
return a->frequency > b->frequency;
}
};
// 构建哈夫曼树
HuffmanNode* buildHuffmanTree(char data[], int freq[], int n) {
priority_queue<HuffmanNode*, vector<HuffmanNode*>, Compare> pq;
// 创建叶子节点并加入优先队列
for (int i = 0; i < n; i++) {
HuffmanNode* node = new HuffmanNode(data[i], freq[i]);
pq.push(node);
}
// 通过合并节点构建哈夫曼树
while (pq.size() > 1) {
HuffmanNode* left = pq.top();
pq.pop();
HuffmanNode* right = pq.top();
pq.pop();
HuffmanNode* merged = new HuffmanNode('$', left->frequency + right->frequency);
merged->left = left;
merged->right = right;
pq.push(merged);
}
// 返回根节点
return pq.top();
}
// 打印哈夫曼编码
void printHuffmanCodes(HuffmanNode* root, string code) {
if (root == nullptr)
return;
if (root->data != '$') {
cout << root->data << ": " << code << endl;
}
printHuffmanCodes(root->left, code + "0");
printHuffmanCodes(root->right, code + "1");
}
int main() {
char data[] = { 'A', 'B', 'C', 'D', 'E' };
int freq[] = { 5, 1, 2, 4, 3 };
int n = sizeof(data) / sizeof(data[0]);
HuffmanNode* root = buildHuffmanTree(data, freq, n);
printHuffmanCodes(root, "");
return 0;
}
代码运行的输出:
E: 00
B: 010
C: 011
D: 10
A: 11