7-1 哈夫曼编码
题目描述
本题目要求针对给定的字符串,按照哈夫曼编码原理对其进行编码(即:转换为01串),并输出其对应的哈夫曼编码。注:字符串中的字符按照ASCII码给定序号,如vggba这个字符串中的字符序号分别为43321;构建哈夫曼树时则按照序号顺序排列字符,如权值最小的两个字符为a和b,而不是b和a。
输入格式:
输入一个整数n,然后依次输入n个字符串。
输出格式:
针对每个输入的字符串,输出其哈夫曼编码。
输入样例:
2
avvvdddeeeffffgggggjk
eeeffrnvjshvhssnn
输出样例:
11110110110110100100100101101101000000000101010101111111110
11011011001001010111111001010000111000110000111111
题解思路
前言
对于基本哈夫曼树的思想我就不做解释了,其实用来构造哈夫曼树的方法很多,例如小根堆(见往期博客),数组,结构等等,我之前尝试用小根堆解决本题,但是编码结果一直和本题结果不相同,一种原因是,在removefirst之后的小根堆重建时,可能会导致相同权重的叶节点无法按照题目要求的ASCII码排序,但本次用的
struct
类型的数组则不会出现这种问题。
基本思路
我们利用一个两倍长度数组来存储节点,前n个就是原本的叶子节点,后面n个就是我们不断合并的新节点,因为最开始我们是用 map 来存给定字符串的 value 和 weight,其中的顺序就是按照 value的ASCII 码的升序,同时我们是从前往后遍历,所以在构建 huffman 树的过程并不会破坏这种排序,结合代码和注释理解理解叭--------
#include <bits/stdc++.h>
using namespace std;
const int MAX = 50;
map<char,string> codeMap; //存编码
struct huffNode {
char val;
int weight;
int left;
int right;
int parent;
string code;
};
//初始化每个节点
void init(huffNode * huffTree, int *wgt, char *value, int n) {
for (int i = 0; i < 2*n-1; i++) {
huffTree[i].val = value[i];
huffTree[i].weight = wgt[i];
huffTree[i].left = -1;
huffTree[i].right = -1;
huffTree[i].parent = -1;
}
}
//建立一颗huffTree
//我们把空间定义为叶子节点的2倍,然后合并的节点就往后加
//找到权重最小的两个节点合并,然后放到后面
//因为我们是从前往后找,所以能保证是按照ASCII升序
void setHuffTree(huffNode * huffTree, int n) {
int min1,min2,pos1,pos2;
for (int i = n; i < 2*n-1; i++) { //新节点的位置
min1 = min2 = INT_MAX;
pos1 = pos2 = 0;
for (int j = 0; j < i; j++) { //找到当前范围内的权重唯二最小
if (huffTree[j].parent == -1 && huffTree[j].weight < min1) {
min2 = min1;
pos2 = pos1;
min1 = huffTree[j].weight;
pos1 = j;
} else if (huffTree[j].parent == -1 && huffTree[j].weight < min2) {
min2 = huffTree[j].weight;
pos2 = j;
}
}
//建立联系
huffTree[pos1].parent = i;
huffTree[pos2].parent = i;
huffTree[i].left = pos1;
huffTree[i].right = pos2;
huffTree[i].weight = min1+min2;
}
}
void huffCode(huffNode *huffTree, int n) {
for (int i = 0; i < n; i++) {
string nodeCode = "";
int parent = huffTree[i].parent;
int curr = i;
while (parent != -1) { //一直找到根节点
if (huffTree[parent].left == curr) //左孩子
nodeCode += "0";
else nodeCode += "1";
curr = parent;
parent = huffTree[parent].parent;
}
reverse(nodeCode.begin(),nodeCode.end());
huffTree[i].code = nodeCode;
//存到map里,方便后面输出
codeMap[huffTree[i].val] = nodeCode;
}
}
int main() {
int N;
cin >> N;
while (N--) {
map<char,int> valMap;
string str = "";
cin >> str;
for(auto x : str) valMap[x]++;
int n = valMap.size();
char *val = new char(MAX);
int *wgt = new int(MAX);
huffNode huffTree[MAX];
int i = 0;
for(auto it=valMap.begin(); it!=valMap.end();it++,i++) {
val[i] = it->first;
wgt[i] = it->second;
}
init(huffTree,wgt,val,n);
setHuffTree(huffTree,n);
huffCode(huffTree,n);
string ans = "";
for (auto x : str) {
ans += codeMap[x];
}
cout << ans<<endl;
}
}
学习愉快!!!