1、建立哈夫曼树:读入文件(*.souce),统计文件中字符出现的频度,并以这些字符的频度作为权值,建立哈夫曼树。
2、编码:利用已建立好的哈夫曼树,获得各个字符的哈夫曼编码,并对正文进行编码,然后输出编码结果,并存入文件(*.code)中。
3、译码:利用已建立好的哈夫曼树将文件(*.code)中的代码进行译码,并输出译码结果,并存入文件(*.decode)中。
4、利用位操作,实现文件的压缩与解压。(选作)
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define N 100
#define M 2*N-1
#define MAXINT 32767
#define ch 30
#define NUM 100
typedef char numcode;
typedef char charcode;
typedef char* HuffmanCode[N] ;
typedef struct{
char data;//字符
int weight;//权值
int parent;
int lchild;
int rchild; //父结点及左右孩子结点
}HTNode,HuffmanTree[M];
void CrtHuffmanTree(HuffmanTree ht,int w[],int n);
void select(HuffmanTree ht,int pos,int *s1,int *s2);
void CrtHuffmanTree(HuffmanTree ht,int w[],int n)//创建哈夫曼树
{
int i,s1,s2,m;
m=2*n-1;
for(i=0;i<n;i++){
ht[i].weight=w[i];ht[i].parent=-1;
ht[i].lchild=-1;ht[i].rchild=-1;
}
for(i=n;i<m;i++){
ht[i].weight=0;ht[i].parent=-1;
ht[i].lchild=-1;ht[i].rchild=-1;
}
for(i=n;i<m;i++) {
select(ht,i-1,&s1,&s2);
ht[i].weight=ht[s1].weight+ht[s2].weight;
ht[s1].parent=i;
ht[s2].parent=i;
ht[i].lchild=s1;
ht[i].rchild=s2;
}
}
void select(HuffmanTree ht,int pos,int *s1,int *s2)
{
int i,j,m1,m2;
m1=m2=MAXINT;
for(j=0;j<=pos;j++) {
if(ht[j].weight<m1&&ht[j].parent==-1){
m2=m1;*s2=*s1;
*s1=j;m1=ht[j].weight;
}
else if(ht[j].weight<m2&&ht[j].parent==-1){
m2=ht[j].weight;
*s2=j;
}
}
}
void CrtHuffmanCode(HuffmanTree ht,HuffmanCode hc,int n){
char *cd;int start,c,p,i;
cd=(char*)malloc(n*sizeof(char));
cd[n-1]='\0';
for(i=0;i<n;i++){
start=n-1;c=i;
p=ht[i].parent;
while(p!=-1){
--start;
if(ht[p].lchild==c) cd[start]='0';
else cd[start]='1';
c=p;p=ht[p].parent;
}
hc[i]=(char*)malloc((n-start)*sizeof(char));
strcpy(hc[i],&cd[start]);
}
free(cd);
}
void printcode(char s[],HuffmanCode hc,int length)//打印输出各字符
{
int i;
for( i=0;i<length;i++){
printf("\t\t\t\t%c:",s[i]);
printf("%s\n",hc[i]);
}
}
void chartocode(charcode c[],char s[],HuffmanCode hc,int length){
printf("\n");
int i=0;
int j;
FILE *fp;
if((fp=fopen("编码后文件.txt","wt"))==NULL)
{
printf("写文件出错!!按任意键退出。");
getch();
exit(0);
}
while(c[i]!='\0'){
for(j=0;j<length;j++){
if(c[i]==s[j])
{
printf("%s",hc[j]);
fprintf(fp,"%s",hc[j]) ;//向所建文件写一字符串
// printf("%s",hc[j]);
// printf("保存成功!!请按任意键继续。\n");
}
}
i++;
}
printf("\n");
fclose(fp);
//printf("按任意键返回主菜单!!!");
//getch();
}
void numtochar(numcode ns[],HuffmanTree ht,char s[],int length)
{
printf("\n");
FILE *fp;
if((fp=fopen("译码后文件.txt","wt"))==NULL)
{
printf("写文件出错!!按任意键退出。");
getch();
exit(0);
}
int m;
int i=0;
int key;
HTNode g;
m=2*length-1;
while(ns[i]!='\0'){
g=ht[m-1];
while(g.lchild!=-1){
switch(ns[i]){
case '0':key=g.lchild;g=ht[g.lchild];break;
case '1':key=g.rchild;g=ht[g.rchild];break;
}
i++;
}
printf("%c",s[key]);
fprintf(fp,"%c",s[key]) ;//向所建文件写一字符串
}
fclose(fp);
}
void print1()
{
int i;
system("cls");
printf("\n\n");
printf("\t\t|******************************|\n");
printf("\t\t||****************************||\n");
printf("\t\t||| |||\n");
printf("\t\t||| 欢迎进入ZERO编码系统 |||\n");
printf("\t\t||| |||\n");
printf("\t\t||****************************||\n");
printf("\t\t|******************************|\n");
printf("\n\t\t\t系统开始启动.........\n");
printf("============================================================================\r");
for(i=1;i<77;i++)
{
Sleep(40);
printf(">");
}
}
void print2()
{
system("cls");
printf("\n\n\n\n");
printf("\t\t\t|******************************|\n");
printf("\t\t\t||****************************||\n");
printf("\t\t\t||| |||\n");
printf("\t\t\t||| 谢谢使用 |||\n");
printf("\t\t\t||| |||\n");
printf("\t\t\t||****************************||\n");
printf("\t\t\t|******************************|\n");
Sleep(2000);
}
void print3()
{
system("cls");
printf("\t\t\t|*******************************|\n");
printf("\t\t\t| 欢迎来到ZERO编码世界 |\n");
printf("\t\t\t|*******************************|\n");
printf("\t\t\t| 1.初始化源文件 |\n");
printf("\t\t\t| 2.查询字符的编码 |\n");
printf("\t\t\t| 3.查询编码后的文件 |\n");
printf("\t\t\t| 4.查询译码后的文件 |\n");
printf("\t\t\t|-------------------------------|\n");
printf("\t\t\t|-------------------------------|\n");
printf("\t\t\t| 0.退出程序 |\n");
printf("\t\t\t|===============================|\n");
}
void save_in_f1()//创建文件
{
char ch1[100];
FILE *fp;
if((fp=fopen("源文件.txt","wt"))==NULL)
{
printf("写文件出错!!按任意键退出。");
getch();
exit(0);
}
printf("请输入原始文档:\n");
scanf("%s",ch1);
fprintf(fp,"%s",ch1) ;//向所建文件写一字符串
printf("%s",ch1);
printf("保存成功!!请按任意键继续。\n");
fclose(fp);
printf("按任意键返回主菜单!!!");
getch();
}
int main(){
print1();
HuffmanTree ht;
HuffmanCode hc;
charcode c[1000];
numcode ns[1000];
int i;
int n;
int j,k;
int loop;
int count[95]={0}; //计数数组初始化
int w[N]={0};
int num=0;
int length;
int choice;
int back;
char s[1000]={0};
char b[1000]={0}; //*a[10]定义了一个指针数组
FILE *fp;
loop1:
if((fp=fopen("e:\\数据结构实验报告\\源文件.txt", "rw"))==NULL)
printf("读取失败!");
else
{
i=0;
while(!feof(fp))
{
b[i]=fgetc(fp);
i++;
// printf("%d\t",i);
}
// printf("\nb:%s",b);
// system("pause");
}
length=i;
// printf("length:%d\n",length);
for( j=0;j<length;j++)
{
++count[b[j]-32]; //统计每种字符的个数
// printf("%c的权值:%d",b[j],count[b[j]-33]);
}
for(k=0,j=0;k<95;k++)
if(count[k])
{
w[j]=count[k];
s[j]=k+32;
// printf("%c:%d\n",s[j],w[j]);
j++;
}
length=j;
// printf("length:%d",length);
// system("pause");
CrtHuffmanTree(ht,w,length);
CrtHuffmanCode(ht,hc,length);
loop:
{
print3();
scanf("%d",&choice);
switch(choice)
{
case 1:{
system("cls");
save_in_f1();
CrtHuffmanTree(ht,w,length);
CrtHuffmanCode(ht,hc,length);
printf("返回上一层(1/0)");
scanf("%d",&back);
if(back==1)
goto loop1;
print2();
break;
}
case 2:system("cls");
printcode(s,hc,length);
printf("返回上一层(1/0)");
scanf("%d",&back);
if(back==1)
goto loop;
print2();
break;//对的
case 3:{
system("cls");
FILE *fp;
if((fp=fopen("e:\\数据结构实验报告\\待编码文件.txt", "rw"))==NULL)
printf("读取失败!");
else{
i=0;
while(!feof(fp))
{
c[i]=fgetc(fp);
printf("%c",c[i]);
i++;
}
}
chartocode(c,s,hc,i);
printf("返回上一层(1/0)");
scanf("%d",&back);
if(back==1)
goto loop;
print2();
break;
}
case 4: { system("cls");
FILE *fp;
if((fp=fopen("e:\\数据结构实验报告\\待译码文件.txt", "rw"))==NULL)
printf("读取失败!");
else fscanf(fp,"%s",ns);
fclose(fp);
// printf("\n");
printf("ns:%s",ns);
numtochar(ns,ht,s,length);
printf("\n");
printf("返回上一层(1/0)");
scanf("%d",&back);
if(back==1)
goto loop;
print2();
break;
}
case 0:print2();break;
}
}
}
设计流程图: