解答如下:
#include <iostream>
#include <queue>
#include <vector>
#include <map>
#include <iomanip>
using namespace std;
class HuffmanNode
{
int value; // 灰度值
int frequency; // 频率
public:
HuffmanNode* left; // 左子树
HuffmanNode* right; // 右子树
HuffmanNode(int v, int f) : value(v), frequency(f), left(nullptr), right(nullptr) {}
int getValue() const { return value; }
int getFrequency() const { return frequency; }
HuffmanNode* getLeft() const { return left; }
HuffmanNode* getRight() const { return right; }
};
class CompareNodes
{
public:
bool operator()(HuffmanNode* a, HuffmanNode* b)
{
return a->getFrequency() > b->getFrequency();
}
};
HuffmanNode* build(map<int, int> f)
{
priority_queue<HuffmanNode*, vector<HuffmanNode*>, CompareNodes> pq;
for (map<int, int>::iterator it = f.begin(); it != f.end(); ++it)
{
int key = it->first;
int value = it->second;
pq.push(new HuffmanNode(key, value));
}
while (pq.size() > 1) {
HuffmanNode* left = pq.top();
pq.pop();
HuffmanNode* right = pq.top();
pq.pop();
HuffmanNode* parent = new HuffmanNode(-1, left->getFrequency() + right->getFrequency());
parent->left = left;
parent->right = right;
pq.push(parent);
}
return pq.top();
}
void make(HuffmanNode* root, string code, map<int, string>& codes) {
if (!root) {
return;
}
if (root->getValue() != -1) {
codes[root->getValue()] = code;
}
make(root->getLeft(), code + "0", codes);
make(root->getRight(), code + "1", codes);
}
int main() {
int h, w;
while (cin >> h >> w && h != 0 && w != 0) {
map<int, int> f;
for (int i = 0; i < h; ++i) {
for (int j = 0; j < w; ++j) {
int value;
cin >> value;
f[value]++;
}
}
HuffmanNode* root = build(f);
map<int, string> huffmanCodes;
make(root, "", huffmanCodes);
int before = 0;
int after = 0;
for (map<int,int>::iterator it=f.begin();it!=f.end();it++)
{
int value = (*it).first;
int frequency = (*it).second;
before += 8 * frequency;
after += frequency * huffmanCodes[value].length();
}
double rate = static_cast<double>(before) /after;
cout << fixed << setprecision(2) << "Huffman编码的压缩比为 " << rate << ":1" << endl;
}
return 0;
}