哈夫曼树的编码与解码

本文介绍了哈夫曼树的概念,基于权值构建哈夫曼树的规则,以及如何通过哈夫曼树进行编码和解码。通过示例展示了编码和解码的过程,并提供了完整的代码实现。
摘要由CSDN通过智能技术生成

DS二叉树——Huffman编码与解码

哈夫曼树简介

给定N个权值作为N个叶子结点,构造一棵二叉树,若该树的带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树。哈夫曼树是带权路径长度最短的树,权值较大的结点离根较近。
在这里插入图片描述
在这里插入图片描述

  • 根据数据出现的频率,使用不同长度的编码

一段文字由x个字符组成,每个字符的出现频率不同,比如a出现114514次,而c只出现了810次,如果对a使用短长度的编码(比如01),对b使用较长的编码(比如01011),相比于使用同样长度的编码(00001 与 01011),可使编码效率变高

题目

  • 给定n个字符及其对应的权值,构造Huffman树,并进行huffman编码和译(解)码。
  • 构造Huffman树时,要求左子树根的权值小于、等于右子树根的权值。
  • 进行Huffman编码时,假定Huffman树的左分支上编码为‘0’,右分支上编码为‘1’。

输入
第一行测试次数
第2行:第一组测试数据的字符个数n,后跟n个字符
第3行:第一组测试数据的字符权重 待编码的字符串s1 编码串s2

输出
第一行~第n行,第一组测试数据各字符编码值
第n+1行,串s1的编码值
第n+2行,串s2的解码值,若解码不成功,输出error!

样例输入
2 5 A B C D E
15 4 4 3 2
ABDEC
00000101100
4 A B C D
7 5 2 4
ABAD
1110110

样例输出
A :1
B :010
C :011
D :001
E :000
1010001000011
error!
A :0
B :10
C :110
D :111
0100111
DAC

哈夫曼树的构造规则

共有 n 个不同的字符需要编码,编码规则如下:

  • 每次合并,选择没有被选择的,两个权值最小的根节点:x1, x2,将他们的合并
  • 合并之后的根节点的权值是 x1的权值 + x2的权值
  • 合并之后的根节点仍然可以作为新的根节点被选择
  • 需要合并 n-1 次,最后剩下一个根,就是哈夫曼树的根

使用顺序结构(数组)构造哈夫曼树

初始状态:
在这里插入图片描述

第一次合并,选择 2,3 合并 在这里插入图片描述 在这里插入图片描述

第二次合并,选择 4, 4 在这里插入图片描述 在这里插入图片描述

第三次合并,选择 5, 8
在这里插入图片描述
在这里插入图片描述

第四次合并,选择 15, 13
在这里插入图片描述
在这里插入图片描述

哈夫曼树结构实现与创建:

#define maxlen 100

// 哈夫曼树节点类
class hft_node
{
   
public:
	hft_node();
	int weight;
	int parent;
	int lchild;
	int rchild;
	char ch;		// 该节点代表的字符
	string code;	// 该节点字符对应的编码
};

hft_node::hft_node()
{
   
	this->lchild = -1;
	this->rchild = -1;
	this->parent = -1;
}

// 哈夫曼树类
class hft
{
   
public:
	hft();
	int n;					// 需要编码的字符个数
	hft_node nodes[maxlen];	// 节点
	int visited[maxlen];	// 选择标识数组
	
	// 找两个未被选择的最小权值节点
	void min2(int &index1, int &m1, int &index2, int &m2, int range);
	void encode(string s);	// 获得字符的01编码
	void decode(string s);	// 对01编码解码获得字符串
};

创建哈夫曼树

  • 找两个最小权值且未被选择的节点:函数实现
void hft::min2(int &index1, int &m1, int &index2, int &m2, int range)
{
   
	int i;
	int min = 114514;
	int min_index = 0;
	
	// min
	for(i=0; i<range; i++)
	{
   
		if(visited[i]==0 && min>nodes[i].weight)
		{
   
			min = nodes[i].weight;
			min_index = i;
		}
	}
	visited[min_index] = 1;
	m1 = min;
	index1 = min_index;
	
	// sub min
	min = 114514;
	min_index = 0;
	for(i=0; i<rang
  • 11
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值