杭电1053~~Entropy

这一题,题目很长,但是大多都是废话。主要的意思就是:给出一个字符串,将各个字符变成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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值