这一题,题目很长,但是大多都是废话。主要的意思就是:给出一个字符串,将各个字符变成Huffman编码,并计算其长度。但是,需要注意的是,这里的字符,只需要统计大写字母和下划线的,其他的不需要统计。也就是其他Huffman编码的长度不用计算进去。
这一题我是先构造Huffman树,再来计算各个Huffman编码的长度的。
需要我们输出的是原来字符串的长度 * 8,编码之后的长度,以及压缩率。
下面是AC的代码:
# include <iostream>
# include <string>
using namespace std;
class Treenode //Huffman树的结点
{
public:
char a, t; //a为该字符,t为0或1字符
int weight, flag, len; //len为该字符编码长度,flag为是否被用过的标记
Treenode *lchild, *rchild; //左右孩子
};
char table[20], str[10001];
int len, length, tag;
Treenode *p = new Treenode[70]; //前27个为叶子结点,后面的为备用结点,构造Huffman树需要用到的
int main()
{
Treenode *bulid_Huffman(); //构造Huffman树的函数
void make_table(Treenode *root, int x); //求解Huffman编码的递归函数
while(cin >> str)
{
if(!strcmp(str, "END")) //判断是否结束
break;
int i, len = 0; tag = 0;
for(i = 0; i < 70; i++) //初始化结构体数组
{
p[i].weight = p[i].flag = p[i].len = 0;
p[i].lchild = p[i].rchild = NULL;
if(i <= 25)
p[i].a = 'A' + i;
else if(i == 26)
p[i].a = '_';
else
p[i].a = ' ';
}
length = strlen(str); //字符串长度
Treenode *root;
for(i = 0; i < length; i++) //统计各个字符权值
{
if(str[i] >= 'A' && str[i] <= 'Z')
{
p[str[i] - 'A'].weight++;
}
else if(str[i] == '_')
{
p[26].weight++;
}
}
root = bulid_Huffman(); //构造Huffman树
make_table(root, 0);
for(i = 0; i < 70; i++) //计算各个编码长度
len += p[i].weight * p[i].len; //len为编码之后的长度
cout << length * 8 << ' ' << len << ' ';
printf("%.1lf\n", (1.0 * length * 8) / len);
}
return 0;
}
int is_empty1() //判断结构体数组是否剩下一个结点
{
int count = 0;
for(int i = 0; i < 70; i++)
{
if(p[i].weight > 0 && p[i].flag == 0)
count++;
}
if(count > 1)
return 1;
else
return 0;
}
int get_min() //返回结构体中没用过的权值最小的结点
{
int i = 0;
while(p[i].weight == 0 || p[i].flag == -1)
i++;
int min = i;
for( ; i < 70; i++)
{
if(p[min].weight > p[i].weight && !p[i].flag && p[i].weight > 0)
min = i;
}
return min;
}
Treenode *bulid_Huffman() //构造Huffman树
{
int k = 27, flag = 0; //备用结点的开始的位置为27,flag为一开始只有一个结点的标记
while(is_empty1())
{
flag = 1;
int i = get_min();
p[i].flag = -1;
int j = get_min(); //获得两个权值最小的,并标记已用过
p[j].flag = -1;
p[k].lchild = (p + i); //连接到备用结点的左右孩子
p[i].t = '1';
p[k].rchild =(p + j);
p[j].t = '0';
p[k++].weight = p[i].weight + p[j].weight; //权值相加
}
if(flag == 0) //一开始只有一个结点,不用构造Huffman树
{
tag = 1; //tag标记为1
int i = get_min();
(p + i)->t = '0';
return (p + i);
}
p[k - 1].t = ' ';
return (p + k - 1);
}
void make_table(Treenode *root, int x) //递归求解编码长度
{
Treenode *p;
p = root;
table[x] = p->t;
if(p->lchild == NULL && p->rchild == NULL)
{
table[++x] = '\0';
char *q = table;
if(!tag) //tag为0,说明开始结点不止一个,所以根节点的t为空格,需要跳过
q++;
p->len = strlen(q);
}
if(p->lchild != NULL)
make_table(p->lchild, x + 1);
if(p->rchild != NULL)
make_table(p->rchild, x + 1);
}
有什么不懂的,欢迎来询问!~~~
也可以去参考我的另外一篇博客,实现Huffman编码解码的!~~
这是地址: http://blog.csdn.net/qq_25425023/article/details/44597327