哈夫曼编码 POJ 1521


第一篇文章,格式无要求。

哈夫曼编码原理

哈夫曼编码是一种根据词频变化的变长二进制编码方式,多用于压缩算法(实践中用的也不多,虽然最优但比较古老了)。作为一个比较基础的数学原理,其思想多用于计算机的算法编程实践中。
详见:哈弗曼编码的实现

题目理解

输入: 大写字符串+下划线的集合,下划线代表空格。
输出: ascii编码所需2进制长度 哈夫曼编码后长度 压缩率(前者除以后者),遇到END终结。
解题思路: 重点在哈夫曼树的实现。

实现

讲真,这哈夫曼用的比较简单,本来想用正常的哈夫曼,后来还是简化了。
PS:一些代码没优化,可以进一步改动

#include <iostream>
#include <string>
#include <queue>
#include <malloc.h>
#include <map>
#include <vector> 
#include <cstdio>
using namespace std;

int N;
string s;
typedef struct Tree{
	int freq;
	int num;
	int depth;
	struct Tree* left;
	struct Tree* right;
	
}Node;

struct cmp{
	bool operator() (Node* a, Node* b){
		if (a->freq > b->freq)
			return true;
		else 
			return false;
	} 
};


//Node node[30];
int allSize; 

int main(){
	while (cin >> s && s != "END"){
		map<char, int> tmpMap;
		for (int i=0; i<s.size(); i++){
			map<char, int>::iterator iter = tmpMap.find(s[i]);
			if (iter == tmpMap.end()){
				tmpMap.insert(pair<char, int>(s[i], 1));
			}else{
				iter->second += 1;
			}
		}
		
		map<char, int>::iterator iter = tmpMap.begin();
		allSize = 0;
		Node** node = (Node**)malloc(30*sizeof(Node*)) ;
		priority_queue<Node*, vector<Node*>, cmp> queue; 
		
		// 创建node,从0到allSize-1; 
		for (; iter != tmpMap.end(); iter++){
			node[allSize] = (Node*)malloc(sizeof(Node));
			node[allSize]->freq = iter->second;
			node[allSize]->depth = 0;
			node[allSize]->num = allSize;
			node[allSize]->left = NULL;
			node[allSize]->right = NULL; 
			queue.push(node[allSize]);
			allSize++;
			//
		}
		
		// 合并,形成哈夫曼树
		// 使用优先队列
		int last, result = 0;
		while (queue.size() > 1){
			Node* tmp1 = queue.top();
			queue.pop();
			Node* tmp2 = queue.top();
			queue.pop();
			int tmpNum = (tmp1->freq + tmp2->freq);
			result += tmpNum; 
			//cout << "test " << tmpNum << endl;
			int num = tmp1->num;
			node[num]->freq = tmpNum;
			queue.push(node[num]);
			free(node[tmp2->num]);
			last = num;
		}
		if (result == 0){
			result = s.size();
		}
		cout << s.size()*8 << " " << result << " " ;
		printf("%.1lf\n", s.size()*8.0/result);
		free(node[last]);
		free(node);
	}
	
	return 0;
} 

可以学到的知识

  1. 哈夫曼编码的原理,是最优前缀编码

  2. STL使用: <map>
    map初始化:map<char, int> tmpMap;
    map查找:map<char, int>::iterator iter = tmpMap.find(“A”);
          如果返回tmpMap.end()表示无,否则返回对应的元素,使用iter->first,iter->second来获得前后元素。
    map迭代:for(; iter != tmpMap.end(); iter++);

  3. STL使用 <queue>
    priority_queue初始化:priority_queue<int, vector<int>, cmp>
          其中int表示数据类型,vector<int>表示队列的容器,cmp表示比较方法,可以使用默认提供的less<数据类型>(降序)或greater<数据类型>(升序);或者自定义。
          自定义有两种方式,一种是重载运算符<:

bool operator< (Node a, Node b)
if (a.x == b.x) return a.y > b.y;
return a.x > b.x
// return true 表示a的优先级比b小,放在b之后,本例中表示升序排列。

               另一种是重写仿函数:

struct cmp{
bool operator() (Node a, Node b){
if (a.x == b.x) return a.y > b.y;
return a.x > b.x;
}
}
// return true表示a的优先级小于b的优先级,a放在b后

priority_queue插入:queue.push();
priority_queue头部元素:queue.top();
priority_queue弹出队头元素:queue.pop();

注:queue使用堆来实现。

  1. 精度控制
    使用<cstdio>的printf("%.2lf\n", result)来控制小数点后精度为2。
    使用<iostream>的cout << setiosflags(ios::fixed) << setprecision(2) << result; 保留2位小数。
    使用cout << setprecision(3) << result; 保留3位有效数字。

可扩展部分

  1. 哈弗曼编码与信息论中的自信息量,证明最优
  2. 哈夫曼编码的图论理解:树的最短带权路径长度(WPL)
  3. 实际使用
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值