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

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

实验内容

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

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

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

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

已标记关键词 清除标记
#include<string.h> #include<ctype.h> #include<malloc.h> #include<limits.h> #include<stdio.h> #include<stdlib.h> #include<io.h> #include<math.h> #include<process.h> #define TURE 1 #define FALSE 0 #define OK 1 #define ERROR 0 #define INFEASIBLE -1 typedef int Status; typedef int Boolean; typedef struct { unsigned int weight; unsigned int parent,lchild,rchild; }HTNode,*HuffmanTree; //动态分配数组存储哈夫曼树 typedef char **HuffmanCode; //动态分配数组存储哈夫曼编码 void HuffmanCoding(HuffmanTree *HT,HuffmanCode *HC,int *w,int n) { int m,i,s1,s2,start; unsigned c,f; HuffmanTree p; char *cd; if(n<=1) return; m=n*2-1; *HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));//0號未用 for(p=*HT+1,i=1;i<n;++i,++p,++w) { (*p).weight = *w; //對每個weight初始化 (*p).parent = 0; //對每個parent初始化 (*p).lchild = 0; //對每個lchild初始化 (*p).rchild = 0; //對每個rchild初始化 } for(;i<m;++i,++p) (*p).parent = 0; for(i = n+1;i <= m; ++i) //建哈夫曼樹 { select(*HT,i-1,&s1,&s2); /*在HT[1~i-1]中選擇parent為0 并且 weight 最小的兩個結點,其序號分別是 s1和s2*/ (*HT)[s1].parent = (*HT)[s2].parent =i; (*HT)[i].lchild = s1; (*HT)[i].rchild = s2; (*HT)[i].weight = (*HT)[s1].weight + (*HT)[s2].weight; } //求哈夫曼編碼 *HC = (HuffmanCode)malloc((n+1)*sizeof(char*));//分配n個字符編碼 //的頭指針向量【第0個不用】 cd = (char*)malloc(n*sizeof(char));//分配求編碼的工作空間 cd[n-1] = '\0'; //編碼結束符 for(i=1;i<=n;i++) //循環逐個字符求編碼 { start = n-1; //編碼結束符位置 for(c = i,f = (*HT)[i].parent;f!=0;c=f,f=(*HT)[f].parent) { if((*HT)[f].lchild == c) cd[--start] = '0'; else cd[--start] = '1'; } (*HC)[i] = (char*)malloc((n-start)*sizeof(char)); strcpy((*HC)[i],&cd[start]); //複製:從cd輔助編碼(串)到HC } free(cd); //釋放工作空間 } int min(HuffmanTree t,int i) { int j,flag; unsigned int k = UINT_MAX; for(j=1;j<=i;j++) { if(t[j].weight<k && t[j].parent ==0) //循環查找最小的值 k = t[j].weight,flag = j; } t[flag].parent = 1; //對已經查找出來的最小值進行標記 .parent為1 return flag; } void select(HuffmanTree t,int i,int *s1,int *s2) { int j; *s1 = min(t,i); *s2 = min(t,i); if(*s1>*s2) { j = *s1; *s1 = *s2; *s2 = j; //s1為最小的兩個值中序號小的那個 } } void main() { HuffmanTree HT; HuffmanCode HC; printf("請輸入權值的個數(>1):"); int n,i,*w; scanf("%d",&n); w = (int*)malloc(n*sizeof(int)); printf("請依次輸入%d個權值(整數):\n",n); for(i=0;i<=n-1;i++) scanf("%d",w+i); HuffmanCoding(&HT,&HC,w,n); for(i = 1;i<=n; i++) puts(HC[i]); }
©️2020 CSDN 皮肤主题: 1024 设计师:上身试试 返回首页