【问题描述】给定一个文件,文件由n个字符组成,但他们出现的频度不相同。要求对该文件中的字符集构造哈夫曼树,并计算编码后的文件长度。
【输入形式】
输入的第1行有1个数字n,表示文件中总的字符个数。接下来1行中有n个数字,分别表示n个字符出现的频度。
【输出形式】
输出1行包含1个数字,表示使用哈夫曼编码后该文件的长度。
【样例输入】
5
20 7 10 4 18
【样例输出】
129
【样例说明】
使用哈夫曼编码后,各字符的编码长度分别为2 3 2 3 2,文件长度为2*20+3*7+2*10+3*4+2*18=129
题解:
#include <iostream>
#include <queue>
using namespace std;
int n, num[101];
struct hfmNode {
int num, fa, lf, rt, h;
hfmNode() :fa(0), lf(0), rt(0) {}
}hfm[101];
struct Pair {
int pos, w;
Pair(int p, int wt) :pos(p), w(wt) {}
bool operator<(const Pair& a)const {
return w > a.w;
}
};
//求字符编码长度,基于字符都位于叶子结点的特性
void getHeight(int k, int h) {
if (k > 0) {
if (hfm[k].lf != 0) {
getHeight(hfm[k].lf, h + 1);
}
if (hfm[k].rt != 0) {
getHeight(hfm[k].rt, h + 1);
}
if (hfm[k].lf == 0 && hfm[k].rt == 0) {
hfm[k].h = h;
}
}
}
void huffman() {
int cnt = n; priority_queue<Pair> q;
for (int i = 1; i <= n; i++) {
q.push({ i,hfm[i].num });
}
//最后留在队列里的一定是根节点
while (q.size() != 1) {
Pair t1 = q.top(); q.pop();
Pair t2 = q.top(); q.pop();
++cnt;
hfm[cnt].num = hfm[t1.pos].num + hfm[t2.pos].num;
hfm[cnt].lf = t1.pos, hfm[cnt].rt = t2.pos;
q.push({ cnt,hfm[cnt].num });
}
//根据Huffman树的构建过程,最后一个结点一定是根节点
getHeight(cnt, 0);
}
int main()
{
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> hfm[i].num;
}
huffman();
int sum = 0;
for (int i = 1; i <= n; i++) {
sum += hfm[i].num * hfm[i].h;
}
cout << sum;
return 0;
}