哈夫曼编码 C/C++

哈弗曼编码需要用到哈弗曼树。如果不知道可以随便看看这里------------>构建哈弗曼树

什么是哈夫曼编码?

哈夫曼编码是一种可变字长编码。根据给定信息中字符出现的频次动态生成最优编码。常用于数据压缩。

 

哈夫曼编码实现:

哈夫曼编码要用到哈弗曼树,在一棵哈弗曼树的基础上,将哈弗曼树每个节点的左分支当做0,右分支当做1。与二进制编码01相对应。

哈弗曼树中,节点对应哈夫曼编码应该为:

A :1100

B:1101

C:111

D:10

E:0

 

实现哈弗曼编码主要数据和函数:

1、哈弗曼树节点结构体:数据、编码、左子树、右子树、队列升序判断函数

//哈弗曼树节点和权重比较方法,优先队列会使用这个权重比较方法
typedef struct HuffmanNode
{
	char data;  //数据
	string code;  //编码
	int weight;  //权重
	struct HuffmanNode *lChild;  //左节点
	struct HuffmanNode *rChild;  //右节点
								 //重写()作为队列比较函数
	bool operator()(struct HuffmanNode*nodeA, struct HuffmanNode *nodeB)
	{
		return nodeA->weight > nodeB->weight;
	}
}HuffNode;

2、创建哈弗曼树 

//构建哈夫曼树
HuffNode * createHuffmanTree(vector<char>data, vector<int> weight)  //data:数据 weight:节点权重
{
	//优先队列
	priority_queue<HuffmanNode*, vector<HuffmanNode*>, HuffNode > huffQue;

	//按照权重构造节点,并将节点插入队列中
	for (size_t i = 0;i < weight.size();i++)
	{
		HuffNode *node = new HuffNode;
		node->weight = weight[i];
		node->lChild = NULL;
		node->rChild = NULL;
		node->code = "";
		node->data = data[i];
		huffNodes[i] = node;  //用作哈弗曼编码遍历
		huffQue.push(node);
	}

	//将权重最小和次小的节点弹出,将两个节点的权重相加,作为构造新节点的权重
	//将这个新节点作为根节点,权重最小的节点作为左孩子,次小的作为右孩子。
	//将新的根节点插入队列中
	while (huffQue.size() > 1)
	{
		HuffNode *lChild = huffQue.top();
		huffQue.pop();
		HuffNode *rChild = huffQue.top();
		huffQue.pop();

		HuffmanNode *parent = new HuffmanNode;
		parent->lChild = lChild;
		parent->rChild = rChild;
		parent->code = "";
		parent->data = NULL;
		parent->weight = lChild->weight + rChild->weight;
		huffQue.push(parent);
	}

	//弹出队列中最后一个节点,作为哈弗曼树的根节点
	HuffmanNode *root = huffQue.top();
	huffQue.pop();
	return root;
}

3、编码函数(递归,贼简单)

//填充二进制编码
void encodeToNode(HuffmanNode *root, string code)
{
	if (NULL == root)
	{
		return;
	}

	root->code = code;
	encodeToNode(root->lChild,root->code + "0");  //左节点编码为 0
	encodeToNode(root->rChild,root->code + "1");  //右节点编码为 1
}

验证结果,直接看全部代码:


#include<iostream>
#include<vector>
#include<queue>
#include<functional>
#include<string>
using namespace std;

//哈弗曼树节点和权重比较方法,优先队列会使用这个权重比较方法
typedef struct HuffmanNode
{
	char data;  //数据
	string code;  //编码
	int weight;  //权重
	struct HuffmanNode *lChild;  //左节点
	struct HuffmanNode *rChild;  //右节点
								 //重写()作为队列比较函数
	bool operator()(struct HuffmanNode*nodeA, struct HuffmanNode *nodeB)
	{
		return nodeA->weight > nodeB->weight;
	}
}HuffNode;

HuffNode *huffNodes[5];  //遍历哈弗曼树编码的时候用起来方便

//构建哈夫曼树
HuffNode * createHuffmanTree(vector<char>data, vector<int> weight)  //data:数据 weight:节点权重
{
	//优先队列
	priority_queue<HuffmanNode*, vector<HuffmanNode*>, HuffNode > huffQue;

	//按照权重构造节点,并将节点插入队列中
	for (size_t i = 0;i < weight.size();i++)
	{
		HuffNode *node = new HuffNode;
		node->weight = weight[i];
		node->lChild = NULL;
		node->rChild = NULL;
		node->code = "";
		node->data = data[i];
		huffNodes[i] = node;  //用作哈弗曼编码遍历
		huffQue.push(node);
	}

	//将权重最小和次小的节点弹出,将两个节点的权重相加,作为构造新节点的权重
	//将这个新节点作为根节点,权重最小的节点作为左孩子,次小的作为右孩子。
	//将新的根节点插入队列中
	while (huffQue.size() > 1)
	{
		HuffNode *lChild = huffQue.top();
		huffQue.pop();
		HuffNode *rChild = huffQue.top();
		huffQue.pop();

		HuffmanNode *parent = new HuffmanNode;
		parent->lChild = lChild;
		parent->rChild = rChild;
		parent->code = "";
		parent->data = NULL;
		parent->weight = lChild->weight + rChild->weight;
		huffQue.push(parent);
	}

	//弹出队列中最后一个节点,作为哈弗曼树的根节点
	HuffmanNode *root = huffQue.top();
	huffQue.pop();
	return root;
}

//填充二进制编码
void encodeToNode(HuffmanNode *root, string code)
{
	if (NULL == root)
	{
		return;
	}

	root->code = code;
	encodeToNode(root->lChild,root->code + "0");  //左节点编码为 0
	encodeToNode(root->rChild,root->code + "1");  //右节点编码为 1
}

//先序遍历哈弗曼树
void preOrder(HuffmanNode *root)
{
	if (NULL == root)
	{
		return;
	}
	 
	cout << root->weight << " ";	//输出哈弗曼树各节点对应权重,包括各个生成的父节点
	preOrder(root->lChild);
	preOrder(root->rChild);
}

//释放哈弗曼树
void freeHuffManTree(HuffNode* root)
{
	if (NULL == root)
	{
		return;
	}

	freeHuffManTree(root->lChild);
	freeHuffManTree(root->rChild);
	free(root);
	root = NULL;
}

//输出哈弗曼树叶子结点的编码
void printNodeCode()
{
	for (size_t i = 0; i < sizeof(huffNodes)/sizeof(huffNodes[0]); i++)
	{
		cout << huffNodes[i]->data << "---权重: " << huffNodes[i]->weight << "\t编码: " << huffNodes[i]->code << endl;
	}
}

int main()
{
	vector<char> data = {'A','B','C','D','E'};
	vector<int> weight = { 4,5,10,15,20 };

	//构造哈夫曼树
	HuffmanNode *root = createHuffmanTree(data,weight);

	//前序遍历哈弗曼树
	cout << "哈弗曼树的前序遍历结果为:" << endl;
	preOrder(root);
	cout << endl;

	cout << "哈弗曼树叶子结点对应编码为:"<< endl;
	encodeToNode(root, "");
	printNodeCode();
	cout << endl;

	freeHuffManTree(root);

	system("pause");
	return 0;
}

 

运行结果:和上面哈弗曼树推导结果一致 。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值