树-哈夫曼编码树 c++

哈夫曼树是一种最优二叉树,适用于数据压缩。通过选取权值最小的两棵树合并来构建,最小带权路径长度保证了效率。算法过程包括构造n个单节点树集合,不断合并最小权值树,直至只剩一棵树。哈夫曼编码通过左0右1的方式为每个字符生成唯一编码,避免前缀冲突。

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

哈夫曼树也称为最优二叉树,其叶子结点带有权值,所有根结点到叶子结点的路径长度与该叶子结点的权值乘积之和被称为带权路径长度。对于一组确定权值的叶子结点,哈夫曼树是具有最小带权路径长度的二叉树。

哈夫曼算法:对于给定的n个权值构造n个只有根结点的二叉树,其集合为F;

选取F中根结点权值最小的两个两颗树分别作为左右子树合并为一颗新二叉树,其根结点权值为左右子树根结点之和;

将新树加入F,而合并前的两棵树从F中删除;

重复直到F中只有一棵树;

利用哈夫曼算法即可构造出哈夫曼编码树。哈夫曼编码树常用于压缩与解码,例如对于一组字符,其各个字母的使用频率作为权值,构造哈夫曼编码树,左树为0,右树为1,从根结点到叶子结点所构成的编码具有唯一性,其任意编码都不是其他编码的前缀。

struct element
{
	float weight;
	int lchild, rchild, parent;
	bool can_be_select;
	size_t pos_in_list;
};

struct char_list
{
	float weight;
	char c;
	size_t pos_in_huffman;
	string code;
};

void select(vector<element>& huffman, size_t& i1, size_t& i2)//从F中选择二叉树
{
	size_t k1=-1, k2=-1;
	for (vector<element>::size_type i = 0; i < huffman.size(); ++i)
	{
		if (!huffman[i].can_be_select)continue;
		if (k1 == -1)
		{
			k1 = i;
			continue;
		}
		if (k2 == -1)
		{
			k2 = i;
			continue;
		}
		if (huffman[i].weight < huffman[k1].weight)
			k1 = i;
		else if (huffman[i].weight < huffman[k2].weight)
			k2 = i;
	}
	huffman[k1].can_be_select = false;
	huffman[k2].can_be_select = false;
	i1 = k1;
	i2 = k2;

}

void HuffmanTree(vector<element>& huffman, size_t n)//构造哈夫曼树
{
	for (size_t i = 0; i < n - 1; i++)
	{
		size_t i1, i2;
		select(huffman, i1, i2);
		element t;
		t.weight = huffman[i1].weight + huffman[i2].weight;
		t.lchild = i1;
		t.rchild = i2;
		t.can_be_select = true;
		t.pos_in_list = -1;
		huffman.push_back(t);
		huffman[i1].parent = i + n;
		huffman[i2].parent = i + n;
	}

}

void get_code(vector<element>& huffman, char_list l[], size_t n)//获得编码
{
	string temp;
	list<element> t;
	list<element>::iterator it;
	t.push_front(huffman.back());
	it = t.begin();
	while (it!=t.end())
	{
		while (it->lchild != -1)
		{
			temp.push_back('0');
			t.push_front(huffman[it->lchild]);
			it->lchild = -1;
			it = t.begin();
		}
		if (it->rchild != -1)
		{
			temp.push_back('1');
			t.push_front(huffman[it->rchild]);
			it->rchild = -1;
			it = t.begin();
		}
		else
		{
			if (it->pos_in_list!=-1)
				l[it->pos_in_list].code = temp;
			if (temp.size()!=0)
				temp.pop_back();
			t.pop_front();
			it = t.begin();

		}
	}
}





### C++哈夫曼编码进行电报加密解密 #### 哈夫曼编码简介 哈夫曼编码是一种变长编码方式,通过构建最优二叉(即哈夫曼),使得频率较高的字符拥有较短的编码长度,从而达到压缩数据的目的。此方法不仅可用于文件压缩,也可应用于电文传输等领域[^2]。 #### 构建哈夫曼 为了创建哈夫曼,程序会统计待编码字符串中各字符出次数,并以此为基础建立最小堆构。接着不断取出两个重最小节点组合成新节点直到只剩下一个根节点为止。 ```cpp struct Node { char ch; int freq; Node *left, *right; Node(char c, int f) : ch(c), freq(f), left(nullptr), right(nullptr){} }; // 定义比较函数用于优先队列排序 struct compare { bool operator()(Node* l, Node* r){ return (l->freq > r->freq); } }; ``` #### 编码过程 当完成上述步骤后,则可以从叶子到根逆向遍历路径生成对应字符的编码表: ```cpp void encode(Node* root, string str, unordered_map<char, string> &huffmanCode) { if (!root) return; // 叶子结点保存编码关系 if (!root->left && !root->right) huffmanCode[root->ch] = str; encode(root->left, str + "0", huffmanCode); encode(root->right, str + "1", huffmanCode); } ``` #### 解码过程 对于已知的哈夫曼编码串,可以通过依次读取'0'/'1'沿着哈夫曼向下查找直至遇到叶节点获得原字符,重复该操作即可恢复整个消息原文本。 ```cpp string decode_file(struct MinHeapNode* root, string s) { string ans = ""; struct MinHeapNode* curr = root; for (int i=0;i<s.size();i++) { if (s[i] == '0') curr = curr->left; else curr = curr->right; // 到达叶节点则记录下对应的字符并返回起点继续处理剩余位数 if (curr->left==NULL and curr->right==NULL) { ans += curr->data; curr = root; } } // 返回最终译码后的字符串 return ans+"\n"; } ``` 以上展示了基于C++语言环境下的简单版哈夫曼编/解码器的设计思路与部分核心代码片段。实际项目开发时还需考虑更多边界情况以及性能优化等问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值