哈夫曼编译码其实我觉得是很麻烦的,我做的时候老是出一些小错误,是我找错找的很久的一个程序,而且我做的时候对文件操作完全没概念,所有的函数都是慢慢从各种途径找出来的,当时做的不知道多纠结了。不多说,看源码
#include<stdio.h>
#include<iostream>
#include<stdlib.h>
typedef struct{
char character; //字符
int weight; //权值
int parent,lchild,rchild; //双亲以及左孩子右孩子的信息
}HTNode,*HuffermanTree;
typedef char **HuffermanCode;
/*全局变量*/
char *a; //动态生成数组,用来存放输入的字符
int *w; //动态生成数组,用来存放输入的字符的权值
void Input(int &n);
void saveNumber(int n);
void CreatHuffermanTree(HuffermanTree &HT,int *w,char *a,int n);
void readFile(HuffermanTree &HT,int n); //从hfmTree.txt文件中读入HuffermanTree
void huffermanCoding(HuffermanTree HT,HuffermanCode &HC,int n);
void showEveryCode(HuffermanTree HT,HuffermanCode HC,int n);
void Article(HuffermanTree HT,HuffermanCode HC,int &wordNumber,int n);
void translation(HuffermanTree HT,int wordNumber,int n);
void CodePrint();
void TreePrinting(HuffermanTree HT,int n);
void getNumber(int &n);
void main()
{
char x='N'; //用于判断是否结束
int n; //n是字符个数
int wordNumber; //文章字符数
HuffermanTree HT=NULL; //定义haffermantree
HuffermanCode HC;
while(x!='Q')
{
system("cls");
printf("/t/t哈夫曼编译码器/n");
printf("/t指令说明:/n");
printf("/tI:初始化(Initialization)/n");
printf("/tE:编码(Encoding)/n");
printf("/tD:译码(Decoding)/n");
printf("/tP:印代码文件(Print)/n");
printf("/tT:印哈夫曼树(Tree printing)/n");
printf("/tQ:退出(Quit)/n");
printf("*******************************************/n/n");
printf("请输入指令(按回车确认): ");
scanf("%c",&x);
switch(x)
{
case 'I':
{
Input(n);
saveNumber(n);
CreatHuffermanTree(HT,w,a,n);
}
break;
case 'E':
{
if(HT==NULL)
{
getNumber(n);
readFile(HT,n);
}
huffermanCoding(HT,HC,n);
showEveryCode(HT,HC,n);
Article(HT,HC,wordNumber,n);
}
break;
case 'D':
{
translation(HT,wordNumber,n);
}
break;
case 'P':
CodePrint();
break;
case 'T':
TreePrinting(HT,n);
break;
case 'Q':
break;
default:
{
printf("您输入的指令有错误,请看指令说明重新输入!");
getchar();
getchar();
break;
}
}
}
}
void Input(int &n)
{
printf("请输入字符个数:");
scanf("%d",&n);
a=(char*)malloc(n*sizeof(char)); //动态分配空间存放n个字符
w=(int*)malloc(n*sizeof(int)); //动态分配空间存放n个字符的权值
for(int i=0;i<n;i++)
{
getchar();
printf("请输入第%d个字符:",i+1);
scanf("%c",&a[i]);
printf("请输入该字符的权值:");
scanf("%d",&w[i]);
}
}
void saveNumber(int n)
{
FILE *fp;
fp=fopen("number.txt","w");
if(!fp)
{
printf("文件打开失败!");
exit(0);
}
fwrite(&n,sizeof(int),1,fp);
fclose(fp);
}
void Select(HuffermanTree &HT,int n,int &s1,int &s2) //s1是最小的一个数,s2倒数第二小
{
int min,secondmin;
for(int i=1;i<=n;i++)
{
if(HT[i].parent==0)
{
min=i;
break;
}
}
for(i=1;i<=n;i++)
{
if((HT[i].parent==0)&&(HT[i].weight<HT[min].weight))
{
min=i;
}
}
s1=min;
for(i=1;i<=n;i++)
{
if((HT[i].parent==0)&&(i!=min))
{
secondmin=i;
break;
}
}
for(i=1;i<=n;i++)
{
if((HT[i].parent==0)&&(HT[i].weight<HT[secondmin].weight)&&(i!=min))
{
secondmin=i;
}
}
s2=secondmin;
}
void CreatHuffermanTree(HuffermanTree &HT,int *w,char *a,int n)
{
int m;
int s1,s2;
HuffermanTree p;
FILE *fp;
if(n<=1) return;
m=2*n-1;
HT=(HuffermanTree)malloc((m+1)*sizeof(HTNode)); //0号单元未用
p=HT;
for(int i=1;i<=n;i++)
{
p[i].character=a[i-1];
p[i].weight=w[i-1];
p[i].parent=0;
p[i].lchild=0;
p[i].rchild=0;
}
for(i=n+1;i<=m;i++)
{
p[i].character='*';
p[i].weight=0;
p[i].parent=0;
p[i].lchild=0;
p[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=s2;
HT[i].rchild=s1;
HT[i].weight=HT[s2].weight+HT[s1].weight;
}
fp=fopen("hfmTree.txt","w"); //保存哈夫曼树
if(!fp)
{
printf("文件打开错误!");
exit(0);
}
for(i=1;i<=m;i++)
{
fwrite(&HT[i],sizeof(HTNode),1,fp);
}
fclose(fp);
printf("哈夫曼树已经成功构建,并保存在hfmTree.txt文件中。按任意键继续...");
getchar();
getchar();
}
void getNumber(int &n)
{
FILE *fp;
fp=fopen("number.txt","r");
fread(&n,sizeof(int),1,fp);
fclose(fp);
}
void readFile(HuffermanTree &HT,int n)
{
FILE *fp;
int m=2*n-1;
fp=fopen("hfmTree.txt","r");
if(!fp)
{
printf("文件打开错误!");
exit(0);
}
HT=(HuffermanTree)malloc((m+1)*sizeof(HTNode));
for(int i=1;i<=m;i++)
{
fread(&HT[i],sizeof(HTNode),1,fp);
}
}
void huffermanCoding(HuffermanTree HT,HuffermanCode &HC,int n)
{
int start;
int c,f;
HC=(HuffermanCode)malloc((n+1)*sizeof(char*)); //分配n个字符编码的头指针向量,0号单元不用
char *code=(char*)malloc(n*sizeof(char)); //分配求编码的工作空间
code[n-1]='/0'; //编码结束符,n个叶子结点最长编码为n-1位
for(int 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)
{
code[--start]='1';
}
else
{
code[--start]='0';
}
}
HC[i]=(char*)malloc((n-start)*sizeof(char));
strcpy(HC[i],&code[start]);
}
free(code);
}
void showEveryCode(HuffermanTree HT,HuffermanCode HC,int n)
{
for(int i=1;i<=n;i++)
{
printf("%c的哈夫曼编码是:",HT[i].character);
printf("%s",HC[i]);
printf("/n");
}
}
void Article(HuffermanTree HT,HuffermanCode HC,int &wordNumber,int n)
{
FILE *fp;
wordNumber=0;
char article[200];
printf("请输入英文文章#号结束:/n");
article[0]=getchar();
while(article[wordNumber]!='#')
{
wordNumber++;
article[wordNumber]=getchar();
}
fp=fopen("CodeFile.txt","w");
if(!fp)
{
printf("打开文件失败!");
exit(0);
}
for(int i=0;i<wordNumber;i++)
{
for(int j=1;j<=n;j++)
{
if(article[i]==HT[j].character)
{
fputs(HC[j],fp);
}
}
}
fclose(fp);
printf("文章已经编码完成,保存在CodeFile.txt文件中。按任意键继续...");
getchar();
getchar();
}
void translation(HuffermanTree HT,int wordNumber,int n)
{
FILE *fp1,*fp2;
char article[200];
char a;
int p; //临时变量
int c; //标记根结点
fp1=fopen("CodeFile.txt","r");
if(!fp1)
{
printf("文件无法打开!");
exit(0);
}
fp2=fopen("TextFile.txt","w");
if(!fp2)
{
printf("文件无法打开!");
exit(0);
}
for(int i=1;i<=2*n-1;i++)
{
if(HT[i].parent==0)
c=i;
}
for(i=0;i<wordNumber-1;i++)
{
p=c;
while(HT[p].lchild!=0||HT[p].rchild!=0)
{
a=fgetc(fp1); //从流中读取一个字符
if(a=='0')
p=HT[p].rchild;
else
p=HT[p].lchild;
}
article[i]=HT[p].character;
fputc(article[i],fp2);
}
fclose(fp1);
fclose(fp2);
printf("翻译后:");
for(i=0;i<wordNumber-1;i++)
{
printf("%c",article[i]);
}
printf("/n");
printf("译码已经完成,结果存入TextFile.txt文件中。按任意键继续...");
getchar();
getchar();
}
void CodePrint()
{
FILE *fp1,*fp2;
char a;
fp1=fopen("CodeFile.txt","r");
if(!fp1)
{
printf("文件打开失败1");
exit(0);
}
fp2=fopen("CodePrin.txt","w");
a=fgetc(fp1);
while(a!=EOF)
{
for(int i=0;i<50;i++)
{
fputc(a,fp2);
printf("%c",a);
a=fgetc(fp1);
if(a==EOF)
break;
}
if(a!=EOF)
{
fputc('/n',fp2);
printf("/n");
}
}
fclose(fp1);
fclose(fp2);
printf("/n此字符形式的编码已经存入CodePrin.txt文件中。按任意键继续...");
getchar();
getchar();
}
void Bianli(HuffermanTree HT,FILE *fp,int c)
{
int p,q;
int k=0;
p=c;
q=c;
while(HT[p].parent!=0)
{
p=HT[p].parent;
k++;
}
if(k==0)
{
printf("%c",HT[c].character);
fputc(HT[c].character,fp);
printf("/n");
fputc('/n',fp);
}
else if(k==1)
{
printf("┠");
printf("%c",HT[c].character);
fputc('-',fp);
fputc(HT[c].character,fp);
printf("/n");
fputc('/n',fp);
}
else
{
for(int i=0;i<k-1;i++)
{
printf("┃");
fputc('|',fp);
}
printf("┠");
printf("%c",HT[c].character);
fputc('-',fp);
fputc(HT[c].character,fp);
printf("/n");
fputc('/n',fp);
}
if(HT[c].lchild!=0)
{
q=HT[c].lchild;
Bianli(HT,fp,q);
}
if(HT[c].rchild!=0)
{
q=HT[c].rchild;
Bianli(HT,fp,q);
}
}
void TreePrinting(HuffermanTree HT,int n)
{
FILE *fp;
int c; //指示根结点
fp=fopen("TreePrint.txt","w");
for(int i=1;i<=2*n-1;i++)
{
if(HT[i].parent==0)
{
c=i;
break;
}
}
Bianli(HT,fp,c);
fclose(fp);
printf("哈夫曼树的直观形式凹形表已经存入文件TreePrint.txt中。按任意键继续...");
getchar();
getchar();
}