pat 05-树9 Huffman Codes

本文介绍了一种使用优先队列构建哈夫曼树的方法,并实现了一个验证给定编码是否为最优编码的程序。文章详细解释了哈夫曼树的构建过程、节点权重计算、树的深度设置以及如何计算最小成本。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
#include <functional>
#include <cstring>
#include <map>
#include <climits>
using namespace std;
typedef struct BiTNode {
	char key;
	int weight;
	BiTNode *lchild, *rchild;
	BiTNode(char k = '\0', int w = 0, BiTNode* l = NULL, BiTNode* r = NULL) : key(k), weight(w), lchild(l), rchild(r) {}
} *BiTree;
struct cmp {
	bool operator() (const BiTree& a, const BiTree& b)
	{
		return a->weight > b->weight;
	}
};
priority_queue<BiTree, vector<BiTree>, cmp> q;
int N;
char key[64];
int frequence[CHAR_MAX + 5];
int depth[CHAR_MAX + 5];
bool flag = true;
BiTree BuildHaffmanTree() 
{
	BiTree T;
	while (q.size() > 1)
	{
		T = new BiTNode();
		T->lchild = q.top();
		q.pop();
		T->rchild = q.top();
		q.pop();
		T->weight = T->lchild->weight + T->rchild->weight;
		q.push(T);
	}
	return T;
}

void setdepth(BiTree T, int d)
{
	if (!T)
		return;
	depth[T->key] = d;
	setdepth(T->lchild, d + 1);
	setdepth(T->rchild, d + 1);
}
void destroyTree(BiTree T)
{
	if (!T)
		return;
	destroyTree(T->lchild);
	destroyTree(T->rchild);
	delete T;
}
BiTree insert(BiTree& T, const char *path)
{
	if (*path == '\0')
		return NULL;
	if (*path == '0')
	{
		
	}
}
int get_minicost(BiTree T)
{
	int minicost = 0;
	setdepth(T, 0);
	for (int i = 0; i < N; ++i)
	{
		minicost += depth[key[i]] * frequence[key[i]];
	}
	return minicost;
}
int main(void)
{
	freopen("in.txt", "r", stdin);
	freopen("out.txt", "w", stdout);
	BiTree Tree;
	char code[64][64];
	int n, w;
	char k;
	cin >> N;
	for (int i = 0; i < N; ++i)
	{
		cin >> key[i] >> w; 
		frequence[key[i]] = w;
		Tree = new BiTNode(key[i], w);
		q.push(Tree);
	}
	Tree = BuildHaffmanTree();
	int minicost = get_minicost(Tree);
	destroyTree(Tree);

	cin >> n;
	while (n--)
	{
		flag = true;
		BiTree root = new BiTNode();
		int cur_cost = 0;

		for (int i = 0; i < N; ++i)
		{
			cin >> key[i] >> code[i];
			cur_cost += frequence[key[i]] * strlen(code[i]);
		}
		

		if (cur_cost != minicost)
			flag = false;
		else
		{
			for (int i = 0; i < N && flag; ++i)
			{
				BiTree *cur = &root;	//这样才能改变root
				int len = strlen(code[i]);
				for (int j = 0; j < len; ++j)
				{
					if (code[i][j] == '0')
						cur = &(*cur)->lchild;
					else
						cur = &(*cur)->rchild;
					if (!*(cur))
						*cur = new BiTNode();
					else if (j + 1 < len)
						continue;
					else
					{
						flag = false;
						break;
					}
				}
			}
		}
		cout << (flag ? "Yes" : "No") << endl;
		destroyTree(root);
	}

	return 0;
}

### 回答1: Huffman编码是一种用于数据压缩的算法,它通过将出现频率较高的字符用较短的编码表示,从而减少数据的存储空间。该算法的基本思想是构建一棵哈夫曼,将字符的出现频率作为权值,然后从叶子节点开始向上遍历,将左子标记为,右子标记为1,最终得到每个字符的编码。哈夫曼编码具有唯一性,即每个字符都有唯一的编码,且任何一个编码都不是另一个编码的前缀。 ### 回答2: Huffman编码是一种压缩数据的方式。它使用的基本原理是将数据中频繁出现的字符使用较短的编码,而不常用的字符使用较长的编码,以达到压缩数据的目的。在Huffman编码中,我们使用二叉来表示每个字符的编码。左孩子被标记为0,右孩子被标记为1。当我们从根节点到叶子节点的路径上移动时,我们收集的所有0和1的序列将编码作为该字符的压缩表示。 具体来说,生成Huffman编码的过程包括以下步骤: 1. 统计给定数据集中每个字符出现的次数。 2. 将字符作为叶子节点构建二叉,每个叶子节点包含一个字符和该字符的频率。 3. 选择频率最小的两个节点,将它们作为左右子合并成一个新节点,其频率等于两个节点频率之和。 4. 将新节点插入二叉,并在每个节点添加一个标记为0或1的位。 5. 重复步骤3和步骤4,直到只剩下一个节点。 6. 通过遍历收集每个字符的Huffman编码。递归,并在每个节点处添加0或1,直到我们到达一个叶子节点。 Huffman编码的优点在于它可以使数据更紧凑,占用更少的存储空间。它也是在许多压缩和编码算法中广泛应用的基础。Huffman编码的缺点是在压缩小数据时,压缩效果可能不明显。这是因为压缩率受到输入数据的分布和大小的影响。在Huffman编码中,来自数据集的所有字符的比特序列可能具有不同的长度。因此,我们需要在压缩和解压缩时花费一些额外的时间来恢复原始数据。 总之,Huffman编码是一种有效的数据压缩算法,可以通过使用二叉来表示每个字符的编码来实现。它的主要优点是可以更紧凑地存储数据,但它仍然受到输入数据大小和分布的影响,并且在进行压缩和解压缩时需要花费额外的时间。 ### 回答3: 题目描述 Huffman code是一种贪心算法,用于编码数据,每个字符都对应一种可辨识的前缀二进制码,使得所有字符的编码总长度最短。给定n个权值作为n个叶子结点,构造一棵二叉,若该的带权路径长度达到最小,则称这样的二叉为最优二叉,也称为赫夫曼。 在赫夫曼中,每个叶子节点的权值就是原始数据中的权值,而非叶子节点不存储权值,比较特别的一种二叉。 输入格式 第1行: 一个正整数n(<=1000) 接下来n行: 每行一个正整数weight[i](weight[i]<=100000) 输出格式 共n-1行,为赫夫曼编码表,每个字符的赫夫曼编码占据一行。 样例输入1 5 1 3 2 10 5 样例输出1 0 110 111 10 11 样例输入2 5 23 3 6 16 8 样例输出2 100 0 101 1101 1100 解题思路 首先,将所有节点的权值从小到大排序。 接着构造一棵二叉: 每次从节点集合中选出最小的两个节点(即最小的两个权值) 将这两个点组成一棵新的二叉,其权值为这两个节点权值之和,这棵新的左右子即为这两个节点。 把这棵新加入到权值序列中,其位置按照新的权值插入,继续循环,直到权值序列只含有一个节点为止,这个节点就是赫夫曼的根。 最后,根据赫夫曼将每个叶子节点的编码求出来,一般情况下,将左子编码置“0”,右子编码置“1”,然后做前缀无歧义编码,按照这种编码方式,我们得到了每个节点的Huffman编码。 代码实现
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值