c++哈夫曼树以及编码

1、哈夫曼树的构建原理如下

http://jingyan.baidu.com/article/380abd0a717c061d90192ca2.html


2、构建哈夫曼树以及编码的步骤

哈夫曼编码步骤:

一、对给定的n个权值{W1,W2,W3,...,Wi,...,Wn}构成n棵二叉树的初始集合F= {T1,T2,T3,...,Ti,...,Tn},其中每棵二叉树Ti中只有一个权值为Wi的根结点,它的左右子树均为空。(为方便在计算机上实现算 法,一般还要求以Ti的权值Wi的升序排列。)
二、在F中选取两棵根结点权值最小的树作为新构造的二叉树的左右子树,新二叉树的根结点的权值为其左右子树的根结点的权值之和。
三、从F中删除这两棵树,并把这棵新的二叉树同样以升序排列加入到集合F中。
四、重复二和三两步,直到集合F中只有一棵二叉树为止。

简易的理解就是,假如我有A,B,C,D,E五个字符,出现的频率(即权值)分别为5,4,3,2,1,那么我们第一步先取两个最小权值作为左右子树构造一个新树,即取1,2构成新树,其结点为1+2=3,如图:

12

虚线为新生成的结点,第二步再把新生成的权值为3的结点放到剩下的集合中,所以集合变成{5,4,3,3},再根据第二步,取最小的两个权值构成新树,如图:

13

再依次建立哈夫曼树,如下图:

14

其中各个权值替换对应的字符即为下图:

15

所以各字符对应的编码为:A->11,B->10,C->00,D->011,E->010

霍夫曼编码是一种无前缀编码。解码时不会混淆。其主要应用在数据压缩,加密解密等场合。


代码如下:


// Huffman.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
#include <queue>
#include <vector>
#include <map>
#include <string>

using namespace std;

class Node {
public:
	char c; //表示字符
	int frequency; //表示该字符出现的次数或频率
	Node *left;
	Node *right;

	Node(char _c, int f, Node *l = NULL, Node *r = NULL)
		:c(_c), frequency(f), left(l), right(r) { }

	bool operator<(const Node &node) const { //重载<运算法以至于在加入优先队列的时候决定如何处理结点位置
		return frequency > node.frequency;
	}
};

void initNode(priority_queue<Node> &q, int nodeNum) {
	char c;
	int frequency;
	for (int i = 0; i < nodeNum; i++) {
		cout << "输入字符和结点出现的次数: ";
		cin >> c >> frequency;
		Node node(c, frequency);
		q.push(node);
	}
}

void showNode(priority_queue<Node> q) {
	while (!q.empty()) {
		Node node = q.top(); q.pop();
		cout << node.c << ", " << node.frequency << endl;
	}
}

//构造哈夫曼树
void huffmanTree(priority_queue<Node> &q) {
	while (q.size() != 1) {
		Node *left = new Node(q.top()); q.pop();
		Node *right = new Node(q.top()); q.pop();

		Node node('R', left->frequency + right->frequency, left, right);
		q.push(node);
	}
}


// 打印哈夫曼编码
void huffmanCode(Node *root, string &prefix, map<char, string> &result) {
	string m_prefix = prefix;

	if (root->left == NULL)
		return;

	//处理左子树
	prefix += "0";
	//如果是叶子结点则输出,否则递归打印左子树
	if (root->left->left == NULL)
		result[root->left->c] = prefix;
	//cout << root->left->c << ": " << prefix << endl;
	else
		huffmanCode(root->left, prefix, result);

	//还原原来的路径,回溯
	prefix = m_prefix;

	//处理右子树
	prefix += "1";
	//如果是叶子结点,,则输出, 否则递归打印右子树
	if (root->right->right == NULL)
		result[root->right->c] = prefix;
	//cout << root->right->c << ": " << prefix << endl;
	else
		huffmanCode(root->right, prefix, result);

}

void testResult(map<char, string> result) {
	//迭代map容器
	map<char, string>::const_iterator it = result.begin();
	while (it != result.end()) {
		cout << it->first << ": " << it->second << endl;
		++it;
	}
}
int main() {
	priority_queue<Node> q;
	int nodeNum;

	//初始化字符信息
	cout << "请输入结点个数: ";
	cin >> nodeNum;
	initNode(q, nodeNum);
	showNode(q);

	//构造哈夫曼树
	huffmanTree(q);

	//构造哈夫曼编码
	Node root = q.top();
	string prefix = "";
	map<char, string> result;
	huffmanCode(&root, prefix, result);

	//检验结果是否正确
	testResult(result);
	system("Pause");
	return 0;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值