给定一个字符串,用最少的01比特对该字符串进行编码,即哈夫曼编码。
根据输入字符串获得每个字母按字典顺序的权值序列(每个字母的权值即该字母在字符串中出现的次数),构造哈夫曼树时每次从权值序列选取(从左到右选取)两个最小的权值,若选取的值不相等,那么较小值的结点作为以他们值加和的新结点的左孩子,另一个则为右孩子,若选取的值相等,先选取的做左孩子,后选取的做右孩子,删除已选取的值的结点,并在权值序列最后添加两个选取值加和的新结点。
输入
第一行输入一个正整数n<=26,表示要编码字母的数量;第二行输入一行字符串(无分隔),包含n个字母,字母为A, B, C…共有n个,每个字母的权值即该字母在字符串中出现的次数。
输出
根据题目描述的哈夫曼编码规则,输出以上字符串对应的哈夫曼编码(无分隔)。
样例
输入
5 EDDCCCBBBBAAAAA
输出
010011011000000101010101111111111
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
struct HFMNode { //哈夫曼树结点类
int w; //权值
char ch; //字符
string code; //字符对应编码
int lchild, rchild, parent;
};
class HFMCode {
public:
void select(int& min1, int& min2, int parent, int x, int y) { //构造哈夫曼树时每次从权值序列选取(从左到右选取)两个最小的权值,详见题目说明 x,y为两个最小树的下标
HFMTree[x].parent = parent;
HFMTree[y].parent = parent;
HFMTree[parent].lchild = x;
HFMTree[parent].rchild = y;
HFMTree[parent].w = min1 + min2; //定义父的权重是两个子节点的权重相加
HFMTree[parent].code = "";
HFMTree[parent].parent = -1;
}
HFMCode(string str, int n) { //哈夫曼树构造函数
leafSize = n * 2 - 1;
HFMTree = new HFMNode[leafSize];
int N = str.length();
for (int i=0,current = 0; current < N && i<=n; current++, i++)
{
int logic = 0;
for (int j = 0; j < i; j++)
{
if (str[current] == HFMTree[j].ch)
{
logic = 1;
HFMTree[j].w = HFMTree[j].w + 1;
i--;
break;
}
}
if (logic == 0)
{
HFMTree[i].ch = str[current];
HFMTree[i].w = 1;
HFMTree[i].lchild = 0;
HFMTree[i].rchild = 0;
HFMTree[i].parent = -1;
HFMTree[i].code = "";
}
}
for (int i = 0; i < n-1; i++)
for (int j = 0; j < n-i-1; j++)
{
HFMNode temp;
if (HFMTree[j].ch > HFMTree[j+1].ch)
{
temp = HFMTree[j];
HFMTree[j] = HFMTree[j + 1];
HFMTree[j + 1] = temp;
}
}
for (int i=n; i < leafSize; i++)
{
int min1 = 10000, min2 = 10000;
int x = 0, y = 0;
for (int j = 0; j < i; j++)
{
if (HFMTree[j].parent == -1)
{
if (HFMTree[j].w < min1)
{
min2 = min1;
min1 = HFMTree[j].w;
y = x;
x = j;
}
else if (HFMTree[j].w < min2)
{
min2 = HFMTree[j].w;
y = j;
}
}
}
select(min1, min2, i, x, y);
}
}
void getcode(string str, int n) { //得到并输出哈夫曼编码
for (int j = leafSize - 1; j >= n; j--)
{
HFMTree[HFMTree[j].lchild].code = HFMTree[j].code + '0';
HFMTree[HFMTree[j].rchild].code = HFMTree[j].code + '1';
}
int N = (leafSize + 1) / 2;
for (int i = 0; i < str.length(); i++)
{
for (int j = 0; j < n; j++)
{
if (str[i] == HFMTree[j].ch)
cout << HFMTree[j].code;
}
}
}
private:
HFMNode* HFMTree; //构造哈夫曼树所用到的结点序列
int leafSize; //结点序列规模
};
int main() {
int N;
cin >> N;
string str;
cin >> str;
HFMCode hfmtree(str, N);
hfmtree.getcode(str, N);
return 0;
}