哈夫曼编码和译码

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <stdlib.h>
typedef char** HuffmanCode;
typedef struct //构建哈夫曼树
{
int weight;
int parent,lchild,rchild;
}HTNode,*HuffmanTree;
typedef struct Words //此结构体用于词频统计
{
char **word;
int *time;
}Words;
void Select(HuffmanTree HT,int i,int &s1,int &s2) //选择权值最小的两个点,s1,s2记录位置{
int j,min=99999;
for(j=1;j<=i;j++)
{
if(HT[j].weight<min&&HT[j].parent==0)
{
min=HT[j].weight;
s1=j;
}
}
min=99999;
for(j=1;j<=i;j++)
{
if(HT[j].weight<min&&HT[j].parent==0&&j!=s1)
{
min=HT[j].weight;
s2=j;
}
}
}
void CreateHuffmanTree(HuffmanTree &HT,int *w,int n) //创建哈夫曼树
{
if(n<=1) return;
int m=2*n-1,i=0,s1=0,s2=0; //有n个叶子,则结点数m=2*n-1
HuffmanTree p;
HT=(HuffmanTree)malloc(sizeof(HTNode)*(m+1));
for(p=HT+1,i=1;i<=n;i++,p++,w++) //先将统计出的权值存储进去
{
(*p).weight=*w;
(*p).parent=0;
(*p).lchild=0;
(*p).rchild=0;
}
for(;i<=m;i++,p++) //在剩余的地方全部存入0
{
(*p).weight=0;
(*p).parent=0;
(*p).lchild=0;
(*p).rchild=0;
}
for(i=n+1;i<=m;i++) //选择出权值最小的结点,权值相加构成一个新的结点{
Select(HT,i-1,s1,s2);
HT[s1].parent=i;HT[s2].parent=i;
HT[i].lchild=s1;HT[i].rchild=s2;
HT[i].weight=HT[s1].weight+HT[s2].weight;
}
}
void HuffmanCoding(HuffmanTree HT,HuffmanCode &HC,int n) //编码
{
int i,c,f,start;
HC=(HuffmanCode)malloc(sizeof(char*)*(n+1));
char *cd=(char*)malloc(sizeof(char)*n);
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'; //左分支为0
else cd[--start]='1'; //右分支为1
HC[i]=(char*)malloc(sizeof(char)*(n-start));
strcpy(HC[i],cd+start); //HC用来存放编码
}
}
void WordFrequency(char *t); //函数声名
void CharCode(HuffmanCode HC,HuffmanCode &s,int *w,int n);
void Print(char *t,HuffmanCode s,int n);
void BeginDecoding(HuffmanCode s,int n);
void BeginCoding(int &n) //由主函数调用,其功能是调用各个函数
{
//w测算每个字符出现次数,w[0-25]表示26个小写字母,w[26]表示空格,p是把w中出现次数不为0的字符摘出来
int i,w[27]={0},*p,k=0;
char t[50];
HuffmanTree HT;
HuffmanCode HC,s;
gets(t);
for(i=0;i<strlen(t);i++) //统计字符次数
{
if(t[i]>='a'&&t[i]<='z')
w[t[i]-'a']++;
if(t[i]==' ')
w[26]++;
}
for(i=0;i<27;i++) //统计一共出现了多少种字符
{
if(w[i]==0)
continue;
else n++;
}
p=(int*)malloc(sizeof(int)*n);
for(i=0;i<27;i++) //将w中不为0的次数摘出来,依次放入p
{
if(w[i]==0)
continue;
else
{
p[k]=w[i];
k++;
}
}
WordFrequency(t); //统计词频
CreateHuffmanTree(HT,p,n); //创建哈夫曼树
HuffmanCoding(HT,HC,n); //编码
CharCode(HC,s,w,n); //输出每个字符的编码
Print(t,s,n); //输出密文,并存入文件中
BeginDecoding(s,n); //从文件中读取密文译码
}
void CharCode(HuffmanCode HC,HuffmanCode &s,int *w,int n)
{
int i,k=1;
s=(HuffmanCode)malloc(sizeof(char*)*n);
printf("\n各字符编码:\n");
for(i=0;i<27;i++)
{
if(w[i]!=0)
{
s[k]=(char*)malloc(sizeof(char)*(strlen(HC[k])+1));
if(i==26)
s[k][0]=' ';
else s[k][0]='a'+i; //s[k][0]的位置存放的是对应字符
strcpy(&s[k][1],HC[k]); //s[k][1]开始存放的是该字符的编码
printf("%c:%s\n",s[k][0],&s[k][1]);
k++;
}
}
}
void Print(char *t,HuffmanCode s,int n)
{
int i,k=1;
FILE *fp; //文件指针
fp=fopen("data.txt","w");
printf("\n密文:\n");
for(i=0;i<strlen(t);i++)
for(k=1;k<=n;k++)
if(t[i]==s[k][0]) //根据所输入的字符输出对应的密文
{
printf("%s",&s[k][1]);
fputs(&s[k][1],fp); //将密文存入文件中
}
putchar('\n');
fclose(fp);
}
void BeginDecoding(HuffmanCode s,int n)
{
char temp,*t;
FILE *fp;
int flength=0;
fp=fopen("data.txt","r");
while(temp=getc(fp)!=EOF) //计算文件中密文的长度
flength++;
t=(char*)malloc(sizeof(char)*(flength+1)); //根据密文长度开辟空间
printf("\n明文:\n");
fp=fopen("data.txt","r"); //重新定位fp
fgets(t,flength+1,fp); //将文件里的密文存入t中
int front=0,rear=1,i,exist=0; //front,rear分别表示头尾
while(rear<=strlen(t)+1)
{
temp=t[rear]; //记录当前rear位置的字符
t[rear]='\0'; //先将rear位置替换为'\0'
for(i=1;i<=n;i++) //进行比较,看看&t[front]是否是某个字符的密文
{
if(strcmp(&t[front],&s[i][1])==0) //如果是,则译码,输出对应字符
{
printf("%c",s[i][0]);
t[rear]=temp;
front=rear;
rear++;
exist=1;
break;
}
}
if(!exist) //如果不是,则换回rear位置字符,然后rear加1
{
t[rear]=temp;
rear++;
}
else exist=0;
}
putchar('\n');
fclose(fp);
}
void WordFrequency(char *t) //统计词频
{
int i,k,l=0,j=0,front=0,exist=0;
char save[50];
Words wd;
strcpy(save,t); //先存储一下t
t[strlen(t)]=' '; //将t的最后一个位置变为一个空格
for(i=0;i<strlen(t);i++) //统计t里有多少个空格,则表示有多少个单词
{
if(t[i]==' ')
j++;
}
wd.word=(char**)malloc(sizeof(char*)*j); //二维数组,根据单词数量开辟列空间wd.time=(int*)malloc(sizeof(int)*j); //根据单词数量开辟空间
for(i=0;i<j;i++) //把每个行空间开辟1个位置,存储一个\0
{
wd.time[i]=0;
wd.word[i]=(char*)malloc(sizeof(char)*1);
wd.word[i][0]='\0';
}
for(i=0;i<strlen(t);i++)
{
if(t[i]==' ') //如果是空格,替换为\0,并继续循环
t[i]='\0';
else continue; //不是则打断本次循环,进入下一次循环
for(k=0;k<j;k++) //检测t中当前单词是否已经存储
if(strcmp(wd.word[k],&t[front])==0) //已经存储则对应次数加1
{
wd.time[k]++;
front=i+1;
t[i]=' ';
exist=1;
break;
}
if(!exist) //未存储则存入,并对应次数变为1
{
free(wd.word[l]);
wd.word[l]=(char*)malloc(sizeof(char)*(strlen(&t[front])+1));
strcpy(wd.word[l],&t[front]);
wd.time[l]++;
l++;
t[i]=' ';
front=i+1;
}
else exist=0;
}
strcpy(t,save); //统计后将t复原
printf("\n单词频率:\n");
for(i=0;i<j;i++)
{
if(wd.word[i][0]!='\0') //输出每个单词以及出现次数
{
printf("%s:",wd.word[i]);
printf("%d\n",wd.time[i]);
}
}
}
void main() //主函数
{
int n=0;
printf("请输入一段英文(支持小写字母和空格)\n");
BeginCoding(n);
}
程序运行结果:。

相关文档
最新文档