问题描述:
使用贪心算法求解Huffman编码问题,具体来说就是,根据每个字符的出现频率,使用最小堆构造最小优先队列,构造出字符的最优二进制表示,即前缀码。
【输入形式】在屏幕上输入字符个数和每个字符的频率。
【输出形式】每个字符的Huffman编码。字符从a开始,依次为b, c, ...
样例输入:
6 45 13 12 16 9 5
【样例输出】
a 0 b 101 c 100 d 111 e 1101 f 1100
【样例说明】
输入:字符个数为6,a至f每个字符的频率分别为:45, 13, 12, 16, 9, 5。
输出:a至f每个字符对应的Huffman编码。
说明:为了保证每个字符对应的Huffman编码的唯一性,对于所有测试样例,得到的Huffman编码树中,对于任何一个除叶结点以外的结点,其左儿子结点的频率小于其右儿子结点的频率(两者不会相等)。
c++代码
#include <iostream>
#include <queue>
#include <vector>
#include <map>
using namespace std;
struct node {
char ch;
int w;
int flag;
string s;
node *left;
node *right;
node(char c, int weight, int f) : ch(c), w(weight), flag(f), s(""),left(nullptr), right(nullptr) {}
bool operator>(const node &b) const {
return this->w > b.w;
}
};
// 自定义比较器,用于优先队列
struct CompareNode {
bool operator()(node* const& n1, node* const& n2) {
return n1->w > n2->w;
}
};
// 自定义优先队列类型
priority_queue<node*, vector<node*>, CompareNode> q;
node *root; // 定义根节点
void hafuman() {
while (q.size() > 1) {
node *node1 = q.top();
q.pop();
node *node2 = q.top();
q.pop();
node *node3 = new node('\0', node1->w + node2->w, 0); // \0 作为非叶子节点的占位符
node3->left = node1;
node3->right = node2;
q.push(node3);
}
root = q.top();
}
void printt(node *node,string ss, map<char, string> &codes) {
if (node == nullptr) return;
node->s=ss;
if (node->flag == 1) {
codes[node->ch]=node->s;
}
printt(node->left,ss+"0",codes);
printt(node->right,ss+"1",codes);
}
int main() {
int n;
//cout << "输入字符个数: ";
cin >> n;
int f[11];
//cout << "输入频率: ";
for (int i = 0; i < n; i++) {
cin >> f[i];
char p = char(i + 97); // ASCII 'a' 的值是 97
q.push(new node(p, f[i], 1));
}
hafuman();
//cout << "前序遍历(根左右): ";
map<char, string> codes;
printt(root,"",codes);
for (auto &pair : codes) {
cout << pair.first << " " << pair.second << endl;
}
return 0;
}
结果
有很多可以优化的地方,这边只是一个简单的例子