数据结构 哈夫曼编码的实现

数据结构实验 哈夫曼编码的实现

实验内容

本人完成了哈夫曼编码的实现,包含哈夫曼树和哈夫曼编码表的建立,实现了编码操作和译码操作。用户输入字符串后可以得到每个字符对应的哈夫曼编码;同样输入包含表中存在的字符编码也可以得到对应的原字符串。

程序中主要用到的数据结构和函数如下:

typedef struct
{
int weight;
int parent;
int lchild;
int rchild;
}HTNode,HuffmanTree;//动态分配数组存储哈夫曼树
typedef char
* HuffmanCode;//动态分配数组存储哈夫曼编码表

void Select(HuffmanTree &HT,int num,int &child1,int &child2)
//在HT[1]-HT[num]中选择parent为0且weight最小的两个结点,其序号分别为s1和s2

void HuffmanCoding(HuffmanTree &HT,HuffmanCode &HC,int *w,int n)
//建哈夫曼树,从叶子到根逆向求出每个字符的哈夫曼编码

map<char,int> mp;//用于统计字符串中的字符及其出现次数
map<char,char *> MP;//用于存取各字符对应的哈夫曼编码

运行结果截图:
在这里插入图片描述
耗子尾汁~~~

实验代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <cstring>
#include <map>
using namespace std;

typedef struct
{
	int weight;
	int parent;
	int lchild;
	int rchild;
}HTNode,*HuffmanTree;//动态分配数组存储哈夫曼树 
typedef char** HuffmanCode;//动态分配数组存储哈夫曼编码表 

void Select(HuffmanTree &HT,int num,int &child1,int &child2)
{
	child1=0;child2=0;
	int w1,w2;
	for(int i=1;i<=num;i++)
	{
		if(HT[i].parent==0)
		{
			if(child1==0||w1>w2&&w1>HT[i].weight)
			{
				child1=i;
				w1=HT[i].weight;
				continue;
			}
			if(child2==0||w2>w1&&w2>HT[i].weight)
			{
				child2=i;
				w2=HT[i].weight;
				continue;
			}
		}
	}
}//在HT[1]-HT[num]中选择parent为0且weight最小的两个结点,其序号分别为s1和s2 

void HuffmanCoding(HuffmanTree &HT,HuffmanCode &HC,int *w,int n)
{
	int child1,child2;
	if(n<=1) return;
	int m=n*2-1;
	HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));
	for(int i=1;i<=n;i++,w++)
		HT[i]={*w,0,0,0};
	for(int i=n+1;i<=m;i++)
		HT[i]={0,0,0,0};
	for(int i=n+1;i<=m;i++)
	{
		Select(HT,i-1,child1,child2);
		HT[child1].parent=i;
		HT[child2].parent=i;
		HT[i].lchild=child1;
		HT[i].rchild=child2;
		HT[i].weight=HT[child1].weight+HT[child2].weight;
	}//建哈夫曼树 
	HC=(HuffmanCode)malloc((n+1)*sizeof(char *));
	char* cd=(char *)malloc(n*sizeof(char));
	cd[n-1]='\0';
	for(int i=1;i<=n;i++)
	{
		int pos=n-1;
		for(int c=i,f=HT[i].parent;f!=0;c=f,f=HT[f].parent)
		{
			if(HT[f].lchild==c)
				cd[--pos]='0';
			else
				cd[--pos]='1';
		}
		HC[i]=(char *)malloc((n-pos)*sizeof(char));
		strcpy(HC[i],&cd[pos]);
	}//从叶子到根逆向求出每个字符的哈夫曼编码 
}


int main()
{
	string s;
	int len;
	cout<<"请输入字符串:"<<endl;
	getline(cin,s);
	len=s.length();
	map<char,int> mp;//用于统计字符串中的字符及其出现次数 
	map<char,char *> MP;//用于存取各字符对应的哈夫曼编码 
	for(int i=0;i<len;i++)
		mp[s[i]]++;
	int size=mp.size();
	char *ch=(char *)malloc((size)*sizeof(char));
	int *cnt=(int *)malloc((size)*sizeof(int));
	int i;
	map<char,int>::iterator it;//map迭代器 
	for(it=mp.begin(),i=0;it!=mp.end();it++,i++)
		cnt[i]=it->second;
	HuffmanTree HT;//哈夫曼树 
	HuffmanCode HC;//哈夫曼编码表 
	HuffmanCoding(HT,HC,cnt,size);//进行哈夫曼编码操作 
	for(it=mp.begin(),i=0;it!=mp.end();it++,i++)
	{ 
		ch[i]=it->first;
		MP[ch[i]]=HC[i+1];
	}
	cout<<"各字符对应的哈夫曼编码为:"<<endl;
	for(i=1;i<=size;i++)
		cout<<ch[i-1]<<" "<<HC[i]<<endl;
	cout<<"原字符串对应的哈夫曼编码为:"<<endl;
	for(i=0;i<len;i++)
		cout<<MP[s[i]];
	cout<<endl<<endl;
	
	//下面部分实现译码过程(仅限输入当前表中已存在字符的编码) 
	cout<<"请输入哈夫曼编码:"<<endl;
	cin>>s;
	len=s.length();
	string t;
	int temp=2*size-1;
	for(i=0;i<len;i++)
	{
		if(s[i]=='0')
		{
			if(HT[temp].lchild!=0)
				temp=HT[temp].lchild;
			if(HT[temp].lchild==0&&HT[temp].rchild==0)
			{
				t+=ch[temp-1];
				temp=2*size-1;
			}
		}
		if(s[i]=='1')
		{
			if(HT[temp].rchild!=0)
				temp=HT[temp].rchild;
			if(HT[temp].lchild==0&&HT[temp].rchild==0)
			{
				t+=ch[temp-1];
				temp=2*size-1;
			}
		}
	}
	cout<<"哈夫曼编码对应的原字符串为:"<<endl;
	cout<<t<<endl;
	
	return 0;
}

问题解决和心得记录

这是我的第七次数据结构课程实验,完成了哈夫曼编码的实现。在完成了课本上要求的编码操作以后,我还自行完成了译码操作。实验过程让我对二叉树的应用有了更深入的认识和理解。

实验过程中也曾遇到一些问题,一些细节完成的时候需要非常细心。比如哈夫曼树和哈夫曼编码的存储用到了动态分配数组,HuffmanCoding函数中下标的计算也需要注意,由于是从叶子到根逆向求出每个字符的哈夫曼编码,因此字符的存储顺序是倒过来的,以及需要记录当前下标的位置,最后再复制到编码表中。Select函数的实现也需要进行一定的思考。

主函数中用到了两个map容器来存取输入字符串中的字符,统计它们的数量,以及存存储们对应的哈夫曼编码,在后续的操作中使用到了迭代器。完成了编码操作之后,我自行思考并完成了译码操作。测试的过程中也遇到过一些问题,经过我的耐心修改和调试以后,最终都能够运行得到正确的结果。

编程能力的提升是一个日积月累的过程。有时候可能为了搞懂一些内容,而不仅仅是蒙混过关,确实自己在课外要花非常多的时间。我一直相信,这些付出最终都会有回报。数据结构是非常重要的专业核心课程,要感谢老师用心的指导。我将在后续的学习中再接再厉,争取在期末考试中取得理想的成绩,也为将来的课程学习打下扎实的基础。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

球王武磊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值