# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <limits.h>
# include <fstream>
# include <iostream>
using namespace std;
# define maxsize 100
//将信息转化为哈夫曼码
//康玉健
//17041114
typedef struct
{
int order;//序号
char letter;//字母
int count;//出现的次数
}LET;//字母
typedef struct
{
int weight;
int parent;
int left_child;
int right_child;
char elem;
}HTNode,*HuffmanTree;//定义哈弗曼树
typedef struct
{
char letter;
char *code;
}CODE;//哈夫曼表
typedef char**HuffmanCode;
void creat_HuffmanTree(HuffmanTree &HT,int n,LET *letter);//创建哈弗曼树
void HuffmanTree_select(HuffmanTree &HT,int num_node,int &s1,int &s2);//进行选择
LET* statis_letter(char *data);//统计字母个数
int statis_letternum(LET* letter);//统计含有字符多少个
//LET *outcome(LET*letters);//返回最终的数组
void Huffman_code(HuffmanTree &HT,HuffmanCode &HC,int n);//创建哈夫曼编码表
void print_HuffmanCode(HuffmanCode &HC,LET *letter,int n);//打印哈夫曼表
char* output_HuffmanCode(HuffmanCode &HC,char *data,int n,LET*letter);//输出哈夫曼编码
//void resolve_HuffmanCode(HuffmanTree &HT,HuffmanCode HC,char *code)//解哈夫曼编码
int Root_Tree(HuffmanTree &HT,int n); //得到哈夫曼树的根
void resolve_HuffmanCode(HuffmanTree &HT,LET*letter2,char *code,int n);
LET* enter_weight(int len,LET* letter);//输入权值
void output_huffman_to_file(HuffmanTree &HT,int len);//将哈夫曼树输入到文件中
void Init(int len,LET* letter);//初始化功能
HuffmanTree En_code(int len,LET* letter);//编码到一个文件中
void De_code(HuffmanTree &HT,LET*letter2,char *code,int n);//译码部分
void print_code(void);
void print_Tree(HuffmanTree &HT,int len);
int main(void)
{
int flag=0;
int returnmenu;
int choice;
printf("****************************************\n");
printf("* 哈夫曼编码器 *\n");
printf("* 版本1.0 *\n");
printf("* *\n");
printf("* *\n");
printf("* *\n");
printf("* *\n");
system("pause");
system("cls");
HuffmanTree HT=NULL;
char data[maxsize];
char code[maxsize];
printf("请输入一个您要进行编码的字符串:(长度小于100)\n");
gets(data);
LET*letter=statis_letter(data);//统计字符串中各个字母出现的频率
int len=statis_letternum(letter);
LET*letter2= enter_weight(len,letter);
do{
system("cls");
printf("* 【1】初始化 *\n");
printf("* 【2】编码 *\n");
printf("* 【3】译码 *\n");
printf("* 【4】印代码文件 *\n");
printf("* 【5】打印哈夫曼树 *\n");
printf("请输入您的选择:\n");
scanf("%d",&choice);
if(choice==1)
{
Init(len,letter2);
}
else if(choice==2)
{
HT=En_code(len,letter2);
}
else if(choice==3)
{
FILE* fp=fopen("编完码的结果.txt","r");
if(fp==NULL)
{
printf("文件打不开!\n");
}
else
{
fscanf(fp,"%s",&code);
fclose(fp);
De_code(HT,letter2,code,len);
}
}
else if(choice==4)
{
print_code();
}
else if(choice==5)
{
print_Tree(HT,len);
}
else
{
printf("输入错误!\n");
}
printf("是否返回主菜单:\n");
printf("【1】是,【2】否\n");
scanf("%d",&returnmenu);
}
while(returnmenu==1);
}
void creat_HuffmanTree(HuffmanTree &HT,int n,LET*letters)//创建哈夫曼树
{
int m;
int i;
int j;
int s1,s2;
if(n<=1)
return ;
m=2*n-1;
HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));
HT[0].elem='#';
HT[0].left_child=0;
HT[0].right_child=0;
HT[0].parent=0;
HT[0].weight=0;
for(i=1;i<=m;i++)
{
HT[i].elem='#';
HT[i].parent=0;
HT[i].left_child=0;
HT[i].right_child=0;
}
//依次输入%d个节点的位权值
for(i=1;i<=n;i++)
{
HT[i].weight=letters[i-1].count;
HT[i].elem=letters[i-1].letter;
}
//从1-i-1选择最小的两个节点并将权值返回给s1。s2
for(i=n+1;i<=m;i++)
{
HuffmanTree_select(HT,i-1,s1,s2);
HT[s1].parent=i;
HT[s2].parent=i;
HT[i].left_child=s1;
HT[i].right_child=s2;
HT[i].weight=HT[s1].weight+HT[s2].weight;
}
}
void HuffmanTree_select(HuffmanTree &HT,int num_node,int &s1,int &s2)//选择最小权值的下标
{
int i;
s1 = s2 = 0;
int min1 = INT_MAX;//最小值,INT_MAX在<limits.h>中定义的
int min2 = INT_MAX;//次小值
for ( i = 1; i <=num_node; ++i )
{
if ( HT[i].parent == 0 )
{//筛选没有父节点的最小和次小权值下标
if ( HT[i].weight < min1 )
{//如果比最小值小
min2 = min1;
s2 = s1;
min1 = HT[i].weight;
s1 = i;
}
else if ( (HT[i].weight >= min1) && (HT[i].weight < min2) )
{//如果大于等于最小值,且小于次小值
min2 = HT[i].weight;
s2 = i;
}
else
{//如果大于次小值,则什么都不做
;
}
}
}
}
LET* statis_letter(char *data)// 统计多少字符串之中各个字母数目
{
int i,j;
int len;
int count=0;
LET* letter=(LET*)malloc(26*sizeof(LET));
for(i=0;i<26;i++)//依次把26个字母放到字母结构体数组之中
{
letter[i].order=i;
letter[i].letter='A'+i;
letter[i].count=0;
}
for(i=0;i<strlen(data);i++)
{
for(j=0;j<26;j++)
{
if(letter[j].letter==data[i])
{
letter[j].count++;
}
}
}
return letter;
}
int statis_letternum(LET* letter)//统计字母的个数
{
int i;
int count=0;
for(i=0;i<26;i++)
{
if(letter[i].count!=0)
{
count++;
}
}
return count;
}
/*LET *outcome(LET*letters)//把所有返回一个有全部字母的数组
{
int i;
int counts=0;
int len=statis_letternum(letters);
LET *outcome=(LET*)malloc(len*sizeof(LET));
for(i=0;i<26;i++)
{
if (letters[i].count!=0)
{
outcome[counts].letter=letters[i].letter;
outcome[counts].order=letters[i].count;
outcome[counts].order=letters[i].order;
counts++;
}
}
printf("count=%d",counts);
return outcome;
}*/
void Huffman_code(HuffmanTree &HT,HuffmanCode &HC, int n)//哈夫曼编码树
{
int i;
int c;
int start;
int f;
HC=(HuffmanCode)malloc((n+1)*sizeof(char *));
char *cd=(char*)malloc(n*sizeof(char));
cd[n-1]='\0';
for(i=1;i<=n;++i)
{
start=n-1;
c=i;
f=HT[i].parent;
while(f!=0)
{
--start;
if(HT[f].left_child==c)
{
cd[start]='0';
}
else
{
cd[start]='1';
}
c=f;
f=HT[f].parent;
HC[i]=(char*)malloc((n-start)*sizeof(char));
strcpy(HC[i],&cd[start]);
}
}
free(cd);
}
void print_HuffmanCode(HuffmanCode &HC,LET *letter,int n)
{
FILE* fp=fopen("编码表.txt","w");
if(fp==NULL)
{
printf("文件打不开呀!兄弟!\n");
}
else
{
int i;
for(i=0;i<n;i++)
{
if(letter[i].count!=0)
{
fprintf(fp,"字母:");
fprintf(fp,"%c ",letter[i].letter);
fprintf(fp,"权值:");
fprintf(fp,"%d ",letter[i].count);
fprintf(fp,"哈夫曼编码为:\n");
fprintf(fp,"%s",HC[i+1]);
fprintf(fp,"\n");
}
}
fclose(fp);
}
}
char * output_HuffmanCode(HuffmanCode &HC,char *data,int n,LET* letter)
{
int i,j;
CODE *HCode=(CODE*)malloc(n*sizeof(CODE));
char *output_string=(char*)malloc(maxsize*sizeof(char));
output_string[0]='\0';
for(i=0;i<n;i++)
{
HCode[i].letter=letter[i].letter;
}
for(i=0;i<n;i++)
{
HCode[i].code=(char*)malloc(strlen(HC[i+1])*sizeof(char));
strcpy(HCode[i].code,HC[i+1]);
}
printf("转化为哈夫曼码为:\n");
for(i=0;i<strlen(data);i++)
{
for(j=0;j<n;j++)
{
if(data[i]==HCode[j].letter)
{
strcat(output_string,HCode[j].code);
printf("%s",HCode[j].code);
}
}
}
printf("\n");
printf("传输的哈夫曼编码为:\n");
puts(output_string);
FILE* fp=fopen("编完码的结果.txt","w");
if(fp==NULL)
{
printf("读取文件失败!\n");
}
else
{
for(i=0;i<strlen(output_string);i++)
{
if(i+1%50==0)
{
fprintf(fp,"\n");
}
fprintf(fp,"%c",output_string[i]);
}
}
fclose(fp);
return output_string;
}
int Root_Tree(HuffmanTree &HT,int n) //返回哈弗曼树根节点的下标
{
int i;
int m=2*n-1;
for(i=1;i<=m;i++)
{
if(HT[i].parent==0)
{
break;
}
}
return i;
}
void resolve_HuffmanCode(HuffmanTree &HT,LET*letter2,char *code,int n)
{
FILE* fp=fopen("译码的结果.txt","w");
if(fp==NULL)
{
printf("文件打不开,我的朋友!\n");
}
else
{
int root=Root_Tree(HT,n);
int i=root;
int weight;
do
{
if(*code=='0')//如果
{
i=HT[i].left_child;
}
else if(*code=='1')
{
i=HT[i].right_child;
}
if(HT[i].left_child==0&&HT[i].right_child==0)//如果到达了叶子节点回到根节点
{
weight=HT[i].weight;
fprintf(fp,"%c",HT[i].elem);
i=root;
}
code++;
}
while(*code!='\0');
fclose(fp);
}
}
LET* enter_weight(int len,LET* letter)
{
int i;
int count=0;
int weight;
LET*letter2=(LET*)malloc(len*sizeof(LET));
for(i=0;i<26;i++)
{
if(letter[i].count!=0)
{
printf("请输入%c的权值:\n",letter[i].letter);
scanf("%d",&weight);
letter2[count].count=weight;
letter2[count].order=letter[i].order;
letter2[count].letter=letter[i].letter;
count++;
}
}
return letter2;
}
void Init(int len,LET* letter)
{
int i;
int count=0;
char data[maxsize];
HuffmanCode HC=NULL;
HuffmanTree HT=NULL;
char code[100];
creat_HuffmanTree(HT,len,letter);
output_huffman_to_file(HT,len);
}
void output_huffman_to_file(HuffmanTree &HT,int len)//打印哈夫曼树
{
char code[100];
ofstream file;
file.open("哈夫曼树.txt");
for(int i=0;i<2*len;i++)
{
//file<<i<<" ";
file<<HT[i].elem<<" ";
file<<HT[i].weight<<" ";
file<<HT[i].parent<<" ";
file<<HT[i].left_child<<" ";
file<<HT[i].right_child<<" ";
file<<endl;
}
file.close();
}
HuffmanTree En_code(int len,LET* letter)//读取哈夫曼树并对其进行编码
{
//创建哈夫曼树
HuffmanTree HT_new=(HuffmanTree)malloc(2*len*sizeof(HTNode));
//创建一个新的哈夫曼树
//从文件中读取哈夫曼树
char ch1,ch2;
char elem;
int weight;
int parent;
int left_child;
int right_child;
char code[100];
HuffmanCode HC;
FILE *fp=fopen("哈夫曼树.txt","r");
for(int i=0;i<2*len;i++)
{
fscanf(fp,"%c",&elem);
fscanf(fp,"%d",&weight);
fscanf(fp,"%d",&parent);
fscanf(fp,"%d",&left_child);
fscanf(fp,"%d",&right_child);
fscanf(fp,"%c%c",&ch1,&ch2);
HT_new[i].elem=elem;
HT_new[i].weight=weight;
HT_new[i].parent=parent;
HT_new[i].left_child=left_child;
HT_new[i].right_child=right_child;
}
//file.close();
fclose(fp);
for(int i=0;i<2*len;i++)
{
cout<<HT_new[i].elem<<" ";
cout<<HT_new[i].weight<<" ";
cout<<HT_new[i].parent<<" ";
cout<<HT_new[i].left_child<<" ";
cout<<HT_new[i].right_child<<endl;
}
//打开要被编码的文件
FILE *fp1=fopen("要被编码的数据.txt","r");
fscanf(fp1,"%s",&code);
fclose(fp1);
Huffman_code(HT_new,HC,len);
output_HuffmanCode(HC,code,len,letter);
//打印哈夫曼树编码表
print_HuffmanCode(HC,letter,len);
return HT_new;
}
void De_code(HuffmanTree &HT,LET*letter2,char *code,int n)
{
resolve_HuffmanCode(HT,letter2,code,n);
}
void print_code(void)
{
char code[maxsize];
FILE* fp=fopen("译码的结果.txt","r");
if(fp==NULL)
{
printf("打不开文件啊,兄弟!\n");
exit(-1);
}
else
{
fscanf(fp,"%s",&code);
fclose(fp);
}
printf("译码的结果为:\n");
puts(code);
}
void print_Tree(HuffmanTree &HT,int len)
{
FILE* fp=fopen("打印哈夫曼树.txt","w");
if(fp==NULL)
{
printf("文件打不开!\n");
exit(-1);
}
else
{
for(int i=0;i<2*len;i++)
{
fprintf(fp,"序号: ");
fprintf(fp,"元素: ");
fprintf(fp,"权值: ");
fprintf(fp,"父母: ");
fprintf(fp,"左孩子: ");
fprintf(fp,"右孩子: ");
fprintf(fp,"\n");
fprintf(fp,"%d ",i);
fprintf(fp,"%c ",HT[i].elem);
fprintf(fp,"%d ",HT[i].weight);
fprintf(fp,"%d ",HT[i].parent);
fprintf(fp,"%d ",HT[i].left_child);
fprintf(fp,"%d ",HT[i].right_child);
fprintf(fp,"\n");
}
fclose(fp);
}
}