一、基础知识
二、代码要求
任意给定一个由26个大写英文字母组成的字符串,能对字符串中所有可能出现的字母进行哈夫曼编码(2学时)
三、代码实现
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define MAXBIT 10 //每个字符编码的最大长度
#define MAXVALUE 1000 //哈夫曼树中叶子结点的最大权值
#define MAXSIZE 26 //电文中出现字符种类的最大值(26个英文字母)
typedef struct HNode //哈夫曼树的结点结构
{
int weight;//权值
int parent,lchild,rchild;
}HNode,*HTree;
typedef char** HCode;//用来指向哈夫曼编码
/*统计电文中的字符种类以及每种字符出现的次数*/
int Count(char *s,int cnt[],char str[])//*s指向电文字符串,cnt存储电文中字符出现的次数,str存储电文中出现的字符
{
char *p;
int i,j,k;
int temp[26];
for(i=0;i<26;i++)
{
temp[i]=0;//临时数组,用于统计每个字符出现的次数
}
for(p=s; *p!='\0'; p++)
if(*p>='A' && *p<='Z')
{
k=(*p)-65;
temp[k]++;
}
for(i=0,j=0;i<26;i++)//统计电文中出现的字符
if(temp[i]!=0)
{
str[j]=i+65;//将其存入字符数组
cnt[j]=temp[i];
j++;
}
str[j]='\0';
return j;
}
/*构造哈弗曼树并生成叶子节点的前缀编码*/
/*思路:1、先根据给定n的权值,构造n课二叉树的集合F,没有孩子
2、在这中间选择两个权值最小的作为左右子树构造一颗新的二叉树,新权值为和
3、并删掉刚才那两棵树,并把新的加入到数组F中
4、重复2,3,最后所得即为哈夫曼树*/
void HuffmanCoding(HTree *HT,HCode *HC,int *w,int n)
{//w存储n个字符的权值,构造哈夫曼树HT,并求出n个字符的哈夫曼编码HC
int m;//结点个数
int m1,m2,x1,x2;//m1,m2存储最小权值,x1,x2存储对应的下标
int i,j,start;
char *cd;
int c,f;
HNode *p;
if(n<=1)
return;
m=2*n-1;/*下边为构造哈夫曼树*/
*HT=(HNode *)malloc(m*sizeof(HNode));
for(p=*HT,i=0;i<n;++i,++p,++w)//初始化叶子结点信息
{//
p->weight=*w;
p->lchild=-1;
p->rchild=-1;
p->parent=-1;
}
for(;i<m;++i,++p)//初始化分支结点信息
{
p->weight=0;
p->lchild=-1;
p->rchild=-1;
p->parent=-1;
}
for(i=n;i<m;++i)//构造哈夫曼树
{
m1=m2=MAXVALUE;//先都设为最大值,然后进行不断更新迭代为最小值
x1=x2=0;
for(j=0;j<i;++j)
{
if((*HT)[j].parent==-1&&(*HT)[j].weight<m1)
{
m2=m1;
x2=x1;
m1=(*HT)[j].weight;
x1=j;
}
else if((*HT)[j].parent==-1&&(*HT)[j].weight<m2)
{
m2=(*HT)[j].weight;
x2=j;
}
}
/*合并成一棵新的子树*/
(*HT)[x1].parent=i;
(*HT)[x2].parent=i;
(*HT)[i].lchild=x1;
(*HT)[i].rchild=x2;
(*HT)[i].weight=m1+m2;
}
/*生成字符的前缀编码*/
/*
分解电文中的字符串,从哈夫曼树的根节点出发, 根据要找的字符寻找左右孩子,
并为路径置标志,然后通过置的0,1标志来写出编码
*/
*HC=(HCode)malloc(n*sizeof(char *));
cd=(char *)malloc(n*sizeof(char));
cd[n-1]='\0';
for(i=0;i<n;++i)
{
start=n-1;
for(c=i,f=(*HT)[i].parent; f!=-1; 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]);
}
free(cd);
}
/*
void Coding(HCode HC,char *s,char str[])/*s指向电文字符串,str存储电文中出现的字符,HC字符的哈夫曼编码表*/
/*{
int i,j;
char *cp;
FILE *fp;
fp=fopen("\\codefile.txt","w");
while(*s)
{
for(i=0; i<MAXSIZE; i++)
{
if(str[i]==*s)
{
for(j=0,cp=HC[i]; j<strlen(HC[i]); j++,cp++)
fputc(*cp,fp);
break;
}
s++;
}
}
fclose(fp);
}*/
/*输出电文中每个字符出现的次数及其前缀编码*/
void Print(HCode HC,char str[],int cn[],int n)
{
int i;
for(i=0; i<n; i++)
{
printf("%c出现%d次,编码是:",str[i],cn[i]);
puts(HC[i]);
putchar('\n');
}
return;
}
/*对编码进行译码,恢复电文安全*/ //有问题!!!尚未修改!!!
/*char *Decode(HCode HC,char str[],int num)
{
FILE *fp;
char s[254];
char *p;
static char cd[MAXBIT+1];
int i, j, k=0, cjs;
fp=fopen("\\codefile.txt","r");
while(!feof(fp))
{
cjs=0;
for(i=0; i<MAXSIZE && cjs==0 && !feof(fp); i++)
{
cd[i]=' ';
cd[i+1]='\0';
cd[i]=fgetc(fp);
for(j=0; j<num; j++)
{
if(strcmp(HC[j],cd)==0)
{
s[k]=str[j];
k++;
cjs=1;
break;
}
}
}
}
s[k]='\0';
p=s;
return p;
}
*/
/*主函数*/
int main()
{
char st[254],*s,str[26];
int cn[26];
int num;
HNode *HT;
HCode HC;
printf("输入需要编码的字符串(假设均为大写字母):\n");
gets(st);
num=Count(st,cn,str);
HuffmanCoding(&HT,&HC,cn,num);
Print(HC,str,cn,num);
// Coding(HC,st,str);
printf("\n");
// s=Decode(HC,str,num);
// printf("%s\n",s);
return 0;
}