数据结构实验三:Huffman树及Huffman编码的算法实现

该博客介绍了如何使用C++标准模板库(STL)中的优先队列和映射来实现哈夫曼编码和解码的过程。实验内容包括读取英文短文,统计字母频率,构建哈夫曼树,编码和解码文本,并将结果保存到文件中。通过特例和典型测试数据的分析,验证了算法的正确性,强调了STL在实现哈夫曼编码算法中的便利性。
摘要由CSDN通过智能技术生成

Exp03 Huffman树及Huffman编码的算法实现

Author: Maskros

实验目的

  • 了解该树的应用实例,熟悉掌握Huffman树的构造方法及Huffman编码的应用,

  • 了解Huffman树在通信、编码领域的应用过程。Huffman树及Huffman编码的算法实现

实验内容与要求

  1. 输入一段100—200字的英文短文,存入一文件a中。

  2. 写函数统计短文出现的字母个数n及每个字母的出现次数

  3. 写函数以字母出现次数作权值,建Haffman树(n个叶子),给出每个字母的Haffman编码。

  4. 用每个字母编码对原短文进行编码,码文存入文件b中。

  5. 用Haffman树对b中码文进行译码,结果存入文件c中,比较a,c是否一致,以检验编码、译码的正确性。

实验内容和实验步骤

通过优先队列 priority_queue和 map简化建树和编码过程

  • 大体思路:
    • 需要进行文件读写操作,通过fopen(), fputc(), fputs(), fclose()等函数实现
    • 定义结点 struct Node, 其中存储char alpha 作为字母,int value对应字母的权值,Node *lchild,*rchild对应左右孩子结点,string code存储编码后的Huffman编码,构造函数不再赘述。
    • write_file(char *name)函数,为了读入回车字符,使用* 作为读入结束标志,同时存入数组和文件中
    • cal_alpha(vector<char> v,int l) 函数运用map<char,int>进行映射,键为字母,值为出现的次数,使用print_times()函数进行打印
    • create_HT()函数用于建立Huffman树,首先将map<char,int> 压入优先队列priority_queue<Node*,vector<Node*>,cmp> 中,其中bool cmp(Node *a,Node *b) 定义按照字母的权重从小到大排序,这样每次取出队首两个结点构成新节点压入队列,循环往复直到队空,将最后两个结点结合作为Huffman树的根节点
    • encode_HT(Node *p, string ss) 函数用于编码Huffman树,从根节点前序遍历整棵树,左子树在字符串后加0, 右子树加1 , 递归遍历即可, print_hfcode()用于打印哈夫曼编码
    • decode_Text(char *name)函数用于对文件中的密文解码,从根结点遍历整棵树,检测到0 就往左孩子找,1 就去右孩子找,如果对应结点的alpha值为字母即将其添加到译文中,然后在返回根节点遍历,以此往复,最后将结果译文写入文件中
    • tips:程序对只有一个结点的Huffman树进行了特判
  • 输入形式:一段英文短文可包含逗号等标点以及回车,空格等白字符。输入以 * 符号结束
  • 输出形式:包含字母数量、各字母的出现次数、每个字母对应的哈夫曼编码。原文、编码后的密文、以及解码后的密文分别保存在源目录的a.txt, b.txt, c.txt
//presented by Maskros - 2021/05/20
#include<bits/stdc++.h>
using namespace std;
vector<char> s;	//Save the original text
string s2=""; //Save the original text after encoding
map<char,int> mp;	//Count the number of occurrences of letters
map<char,string> hfcode; //Save Huffman Code
int len,len2;	//Text length
map<char,int>::iterator it;
map<char,string>::iterator it2;
struct Node{
	int value;
	char alpha;
	Node *lchild,*rchild;
	string code;
	Node(){}
	Node(int v,char a,Node *l,Node *r):value(v),alpha(a),lchild(l),rchild(r){code="";}
};
Node *HTroot;
void write_file(char *name){	//Write file
	cout<<"Print \'*\' to stop typing...."<<endl<<endl;
	char ch;
	if(FILE *fp=fopen(name,"w")){
		while(1){
			ch=getchar();
			if(ch=='*') break; //while read '*' then end input
			fputc(ch,fp);
			s.push_back(ch);
		}
		fclose(fp);
	}
}
void cal_alpha(vector<char> v,int l){	//Count the number of words appearing in a letter
	for(int i=0;i<l;i++){
		if((v[i]<='Z'&&v[i]>='A')||(v[i]<='z'&&v[i]>='a'))
			mp[v[i]]++;
	}
}
void print_times(){	//Print the number of occurrences and the number of each letter
	it=mp.begin();
	putchar('\n');
	cout<<"n="<<mp.size()<<endl;
	while(it!=mp.end()){
		cout<<it->first<<": "<<it->second<<endl;	
		it++;
	}
	putchar('\n');
}
struct cmp{	//Used for priority queue sorting
	bool operator()(Node *a,Node *b){
		return a->value>b->value;
	}
};
void create_HT(){	//Build Huffman Tree
	priority_queue<Node*,vector<Node*>,cmp> q;
	for(it=mp.begin();it!=mp.end();it++){
		q.push(new Node(it->second,it->first,NULL,NULL));
	}
	if(mp.size()==1){HTroot=q.top(); return;}	//Huffman tree has only one root node
	Node *left,*right;
	while(1){
		left=q.top(); q.pop();
		right=q.top(); q.pop();
		if(q.empty()){
			HTroot=new Node(left->value+right->value,'0',left,right);
			break;
		}	
		q.push(new Node(left->value+right->value,'0',left,right));
	}
}
void encode_HT(Node *p,string ss){ //Coding the Huffman tree
	if(!p) return;
	p->code=ss;
	if(p->alpha!='0'){
		if(p->code.length()==0){ hfcode[p->alpha]="1"; return;}	//If the Huffman tree has only one root node, the default is 1
		hfcode[p->alpha]=p->code;		
	}
	encode_HT(p->lchild,ss+"0");
	encode_HT(p->rchild,ss+"1");
}
void print_hfcode(){	//Print Huffman code
	for(it2=hfcode.begin();it2!=hfcode.end();it2++){
		cout<<it2->first<<" => "<<it2->second<<endl;
	}
}
void encode_Text(char *name){ //Write the encoded original text to the file
	char tmp[100];
	string st;
	if(FILE *fp=fopen(name,"w")){
		for(int i=0;i<len;i++){	
			st=hfcode[s[i]];
			s2+=st;
			strcpy(tmp,st.c_str());	//String to char array
			fputs(tmp,fp);
		}
		fclose(fp);
	}
}
void decode_Text(char *name){	//Decode b.txt and save in c.txt
	Node *tmp=HTroot;
	char decode[10000];
	int j=0;
	if(mp.size()==1){	//If the Huffman tree has only one root node
		for(int i=0;i<s2.length();i++){
			if(tmp->alpha!='0') decode[j++]=tmp->alpha;		
		}
	}
	else{
		for(int i=0;i<=s2.length();i++){
			if(tmp->alpha!='0'){
				decode[j++]=tmp->alpha;
				tmp=HTroot;
			}
			if(s2[i]=='0') tmp=tmp->lchild;
			else tmp=tmp->rchild;
		}
	}
	if(FILE *fp=fopen(name,"w")){	
		for(int i=0;i<j;i++) fputc(decode[i],fp);
		fclose(fp);
	}
}
int main(){
	char a[]="a.txt";
	char b[]="b.txt";
	char c[]="c.txt";
	write_file(a);
	len=s.size();
	cal_alpha(s,len);
	print_times();
	create_HT();
	encode_HT(HTroot,"");
	print_hfcode();
	encode_Text(b);
	decode_Text(c);
	return 0;
}

实验用测试数据和相关结果分析

Test 1
The quick brown fox
jumps
over the lazy dog.

Test 2
aaaaa

Test 3
bbcbaaaad
  • 结果分析:特例普例都能通过,起飞,更长文本的不好截图,在这里不放了

实验总结

  • stl 雀实太好使了xdm,当时一看Huffman的建树方式一下就想到了priority_queue了,用起来太爽了,map也为编码提供了方便
  • 在程序的编写过程中,Huffman编码方式确实让我感觉非常神奇
  • 文件的读写操作都忘了,现查的资料,正好复习一下TuT
  • 6
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值