赫夫曼编码长度

题目描述

每行一个大小写英文字母组成的字符串,长度不大于 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值