题目描述
每行一个大小写英文字母组成的字符串,长度不大于 1000,通过前缀编码后最短的编码长度。
输入:每组数据一行,大小写英文字母
输出:每组数据输出赫夫曼编码长度
输入
3 AABBCCDEEEE AAABCCC BBACB
输出
25
11
7
代码分析
#include<iostream>
#include<string>
using namespace std;
const int MaxW = 9999999; // 假设结点权值不超过9999999
// 定义huffman树结点结构体
struct HuffNode
{
char data;
int weight = 0; // 权值
int parent = 0; // 父结点下标
int leftchild = 0; // 左孩子下标
int rightchild = 0; // 右孩子下标
};
// 定义赫夫曼树类
class HuffMan
{
private:
string LeafNode;//叶子节点存储
HuffNode* huffTree; // 赫夫曼树,用数组表示
int len; // 结点数量
int lnum;//叶子数量
public:
HuffMan();
void MakeTree(); // 建树
void SelectMin(int pos, int* s1, int* s2);//从 1 到 pos 的位置找出权值最小的两个结点,把结点下标存在 s1 和 s2中
void show_HuffmanLength();
};
HuffMan::HuffMan()
{
string str;
cin >> str;
LeafNode.push_back(str[0]);
for (int i = 1; i < str.length(); i++)
{
int flag = 1;
for (int j = 0; j < LeafNode.length(); j++)
{
if (str[i] == LeafNode[j])//说明重复了,直接退出
{
flag = 0;
break;
}
}
if (flag == 1) LeafNode.push_back(str[i]);
}
len = 2 * LeafNode.length() - 1;
huffTree = new HuffNode[len + 1];
// 赫夫曼树huffTree初始化
for (int i = 1; i <= LeafNode.length(); i++)
{
huffTree[i].data = LeafNode[i - 1];
for (int j = 0; j < str.length(); j++)
{
if (LeafNode[i - 1] == str[j])
huffTree[i].weight++;
}
}
lnum = LeafNode.length();
MakeTree();
}
void HuffMan::MakeTree()
{
int i, s1, s2;
for (i = lnum + 1; i <= len; i++)
{
SelectMin(i - 1, &s1, &s2); // 找出两个最小权值的下标放入 s1 和 s2 中
// 将找出的两棵权值最小的子树合并为一棵子树
huffTree[s1].parent = i;// 结点 s1 和结点 s2 的父亲设为 i
huffTree[s2].parent = i;
huffTree[i].leftchild = s1;// 结点 i 的左右孩子分别设为 s1 和 s2
huffTree[i].rightchild = s2;
huffTree[i].weight = huffTree[s1].weight + huffTree[s2].weight;// 结点 i 的权值等于 s1 和 s2 的权值和
}
}
void HuffMan::SelectMin(int pos, int* s1, int* s2)
{
// 找出最小的两个权值的下标
// 函数采用地址传递的方法,找出两个下标保存在 s1 和 s2 中
int w1, w2, i;
w1 = w2 = MaxW; // 初始化w1和w2为最大值,在比较中会被实际的权值替换
*s1 = *s2 = 0;
for (i = 1; i <= pos; i++)
{
// 比较过程如下:
if (huffTree[i].weight < w1 && huffTree[i].parent == 0)// 如果第 i 个结点的权值小于 w1,且第 i 个结点是未选择的结点,提示:如果第 i 结点未选择,它父亲为 0
{
w2 = w1;// 把第 w1 和 s1 保存到 w2 和 s2,即原来的第一最小值变成第二最小值
*s2 = *s1;// 把第 i 结点的权值和下标保存到 w1 和 s1,作为第一最小值
w1 = huffTree[i].weight;
*s1 = i;
}
else if (huffTree[i].weight < w2 && huffTree[i].parent == 0)
{// 否则,如果第 i 结点的权值小于 w2,且第 i 结点是未选择的结点
w2 = huffTree[i].weight;// 把第 i 结点的权值和下标保存到 w2 和 s2,作为第二最小值
*s2 = i;
}
}
}
void HuffMan::show_HuffmanLength()
{
int leng = 0;
for (int i = lnum + 1; i <= len; i++)
{
leng = leng + huffTree[i].weight;
}
cout << leng << endl;
}
int main(void)
{
int n;
cin >> n;
for (int i = 0; i < n; i++)
{
HuffMan myhuffMan;
myhuffMan.show_HuffmanLength();
}
return 0;
}