#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct{
int weight;
int lchild,rchild,parent;
}Htnode,*HuffmanTree; //哈弗曼树节点类型,动态分配数组存储哈弗曼树typedef char * * Huffmancode; //动态分配数组存储哈弗曼编码表
void bianma(Huffmancode ch,int n); //编码
void yima(Htnode *HT, int n); //译码
int createtree(Htnode *&HT, Huffmancode &HC,int *weight,int n); //构建哈弗曼树void select(Htnode *HT,int n,int *s1,int *s2); //求节点中两个最小数
/*----------main 函数----------*/
int main (void)
{
Htnode *HT;
int n=4,a; //叶子节点4个
int weight[5]={18,7,5,2,4}; //weight[0]为权值之和
char ch[4]={'A','B','C','D'},c;
char **HC;
createtree(HT, HC,weight, n);
while(a!=0){ //a=0时退出,so是按0键退出,或者改成a!=3
printf("***编码请按1,译码请按2,退出请按0***");
printf("请输入您的选择:\n");
scanf("%d%c",&a,&c);
switch(a){
case 1: bianma(HC,n); break;
case 2: yima(HT,2*n); break;
case 0: break;
default:printf("输入错误!");break;
}
}
return 0;
}
/*----------构建哈弗曼树---------- */
int createtree(Htnode *&HT, Huffmancode &HC,int *weight,int n)
{
int m,i ,start,s1,s2,c,f;
char *cd;
if(n<=1)
return 0;
m=2*n-1;
HT=(HuffmanTree)malloc((m+1)*sizeof(Htnode)); //0号单元未用,动态分配内存
for(i=0;i<=n;i++){ //n个节点权值初始化
HT[i].weight=weight[i];
}
for(i=0;i<=m;i++){ //m个节点双亲,左右孩子初始化
HT[i].parent=0;
HT[i].lchild=0;
HT[i].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;
}
/*从叶子到根逆向求每个字符的编码*/
HC=(Huffmancode)malloc((n+1)*sizeof(char*)); //分配n个字符编码的头指针向量
cd=(char *)malloc(n*sizeof(char)); //分配求编码的工作空间
cd[n-1]='\0';
for (i=1; i<=n; i++){ //从叶子到根计算第n个叶子结点的编码start=n-1; //编码结束符位置
for(c=i, f=HT[i].parent ; f!=0 ; c=f, f=HT[f].parent){ //到最后只有根的父节点是0 if(HT[f].lchild==c) cd[--start]='0';
else cd[--start]='1'; //存储时编码顺序还是正着的
}
HC[i]=(char *)malloc((n-start)*sizeof(char)); //为第i个字符编码分配空间
strcpy(HC[i],&cd[start]); //从cd复制编码到HC
}
free(cd);
return 1;
}
/*----------编码----------*/
void bianma(Huffmancode ch,int n)
{
char c[52];
int i;
printf("请输入一个字符串(输入的字符个数少于50):\n");
gets(c);
for( i=0; c[i]!='\0'; i++){
if(c[i]<'A'||c[i]>'D')
continue;
printf("%s",ch[c[i]-64]);
}
printf("\n");
}
/*----------译码----------*/
void yima(Htnode *HT, int n)
{
char c[102];
int i,a;
printf("请输入一个01字符串(字符个数少于100个):\n");
gets(c);
for( i=0; c[i]!='\0';){
for( a=n-1; HT[a].lchild!=0 && c[i]!='\0';i++ ){ //每次查找一个字母a都要从n-1开始,
if(c[i]!='0'&&c[i]!='1') //并且从上次01字符结束的地方开始
continue ;
else{
if(c[i] =='1') a=HT[a].rchild;
else
a=HT[a].lchild;
}
}
if(a<=n/2)
printf("%c",'A'+a-1);
else{
printf("出现错误\n");
break;
}
}
printf("\n");
}
/*----------求节点中两个最小数----------*/
void select(Htnode *HT,int n,int *s1,int *s2)
{
int i,min1=18,min2=18;
min1=HT[0].weight;
for(i=1;i<=n;i++){
if(HT[i].parent==0){
if(HT[i].weight<min1)
{
min1=HT[i].weight;
*s1=i;
continue;
}
if(HT[i].weight<min2){
min2=HT[i].weight;
*s2=i;
}
}
}
for(i=1;i<=n;i++){
if(HT[i].parent==0&&HT[i].weight<min2&&HT[i].weight>=min1&&*s1!=i){ min2=HT[i].weight;
*s2=i;
}
}
}。