STL 用vector和priority_queue实现哈夫曼编码。

学了不少算法,哈夫曼还是第一次接触。还是太菜了。
两个有关的链接(讲得很好)——
什么是哈弗曼树?
哈弗曼编码
自己试着用STL实现了一下,搞了半天,尤其是优先队列的使用。。。。
大概是将文件转成哈夫曼编码,再转回成译文,再加上编码表,最后保存在两个文件里。
终究还是太菜了——
代码如下,依旧写了一堆 废话 备注。

#include <stdio.h>//考虑到,处理的文件可能超过一般内存限制 
#include <stdlib.h>//这里总计两次读取“输入数据.txt”,不储存原始数据。 
#include <string.h>//使用了STL中的vector和priority_queue优化程序
#include<vector>//空间复杂度最大不超过常数 
#include<queue>//时间复杂度为O(m+nlogn) m为数据量,n为字符种类数量 
#include<algorithm>
#include<iostream>
using namespace std;
/*数据类型重定义,结构体声明*/
typedef long long int ll;
struct node{
	ll value;//权值 
	int left,right;//左右节点 
	int ch;//字符 
	node():value(0),ch(0) {left=right=-1;}//两个构造函数 
	node(ll _v,int _l,int _r,int _ch):value(_v),left(_l),right(_r),ch(_ch){}
};
/*全局变量声明*/ 
vector<node> tree;//哈夫曼树
struct cmp{//用于优先队列的比较结构体 
	bool operator()(int a,int b){ return tree[a].value>tree[b].value;}//小顶堆 
};
priority_queue<int,vector<int>,cmp> q; //优先队列 
ll char_number[550],sum;//记录每种字符出现的次数 
vector<int> coding_schedle[550],book;
/*函数声明*/ 
void init();//初始化函数 
void get_in_1();//第一次读入 统计每种字符出现的次数
int build();//建立哈夫曼树
void dfs_setup(int);//建立编码表 
void get_in_2();//第二次读入同时转为哈夫曼编码输出
void put_out(int);//读入编码并输出译码 
bool dfs_print(int);//深搜输出 
void special(); //处理只有一种字符的特殊情况
/*主函数和其他函数*/ 
int main()
{
	init();
	get_in_1();
	int root=build();
	if(sum==1)//只有一种字符的特殊情况
	{
		special();
		return 0; 
	} 
	dfs_setup(root);
	get_in_2();
	put_out(root);
	return 0;
}
void special()//处理只有一种字符的特殊情况
{
	int c=0;
	for(int i=0;i<=500;i++)
	{
		if(char_number[i])
		{
			c=i;
			break;
		}
	}
	FILE *fp1=freopen("输入数据.dat","w",stdout);
	printf("字符-权重-编码\n");
	printf("%c-%lld-0\n",c,char_number[c]);
	for(ll i=1;i<=char_number[c];i++)
		printf("0");
	fclose(fp1);
	fp1=freopen("译文-输入数据.txt","w",stdout);
	for(ll i=1;i<=char_number[c];i++)
		printf("%c",c);
	fclose(fp1);
}
void init()//初始化函数 
{
	tree.clear();
	while(!q.empty()) q.pop();
	memset(char_number,sizeof(char_number),0);
	sum=0;
	book.clear();
	for(int i=0;i<=549;i++) coding_schedle[i].clear();
	return ;
}
void get_in_1()//第一次读入 统计每种字符出现的次数
{
	FILE *fp=freopen("输入数据.txt","r",stdin);
	char txt_char;
	while(scanf(" %c",&txt_char)!=EOF)//读取到文件末尾
		char_number[txt_char]++;//计数 
	fclose(fp);
	return ;
}
int build()
{
	for(int i=1;i<=500;i++)
	{
		if(char_number[i])//某个字符在原文中出现 
		{
			sum++;
			tree.push_back(node(char_number[i],-1,-1,i));//加入叶节点 
			q.push(tree.size()-1);//下标入队 
		}	
	}
	int a,b;
	while(q.size()>1)//还可以合并 
	{
		a=q.top(); q.pop();
		b=q.top(); q.pop();//最小的两个出队 
		tree.push_back(node(tree[a].value+tree[b].value,a,b,0));//生成父节点 
		q.push(tree.size()-1);
	}
	return  q.top();//根节点下标 
}
void dfs_setup(int u)
{
	int t=tree[u].ch;
	if(t)//如果为叶节点 
	{
		 coding_schedle[t]=book;//储存编码 
		 return ;
	}
	//向左递归 
	book.push_back(0);
	dfs_setup(tree[u].left);
	book.pop_back();
	//向右递归 
	book.push_back(1);
	dfs_setup(tree[u].right);
	book.pop_back();
	return ;
}
void get_in_2()//第二次读入同时转为哈夫曼编码输出
{
	FILE *fp0=freopen("输入数据.txt","r",stdin);
	FILE *fp1=freopen("输入数据.dat","w",stdout);
	printf("字符-权重-编码\n");
	for(int i=0;i<500;i++) 
	{
		if(char_number[i])
		{
			printf("%c-%lld-",i,char_number[i]);
			for(int j=0;j<=coding_schedle[i].size()-1;j++)//输出编码 
				printf("%d",coding_schedle[i][j]);
			printf("\n");
		}
	}
	char txt_char;
	while(scanf(" %c",&txt_char)!=EOF)//输出编码后的数据 
	{
		for(int i=0;i<=coding_schedle[txt_char].size()-1;i++)
			printf("%d",coding_schedle[txt_char][i]);
	}
	fclose(fp0);
	fclose(fp1);
	return ;
}
void put_out(int u)//读入编码并输出译码 
{
	FILE *fp0=freopen("输入数据.dat","r",stdin);
	FILE *fp1=freopen("译文-输入数据.txt","w",stdout);
	char helpless[150];
	for(int i=1;i<=sum+1;i++) scanf("%s",helpless);
	while(dfs_print(u));
	fclose(fp0);
	fclose(fp1);
	return ;
}
bool dfs_print(int u)//递归输出 
{
	char data_char;
	if(tree[u].ch)
	{
		printf("%c",tree[u].ch);
		return true;
	}
	if(scanf(" %c",&data_char)==EOF)
		return false;
	if(data_char-'0')
		return dfs_print(tree[u].right);
	else
		return dfs_print(tree[u].left);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值