编译环境:VC++ 6.0编程要求简述:
[问题描述]
利用哈夫曼编码进行信息通讯可以大大提高信道利用率,缩短信息传输时间,降低传输成本。但是,这要求在发送端通过一个编码系统对待传数据预先编码;在接收端将传来的数据进行译码(复原)。对于双工信道
(即可以双向传输信息的信道),每端都需要一个完整的编/译码系统。试为这样的信息收发站写一个哈夫曼码的编译码系统。
[基本要求]
一个完整的系统应具有以下功能:
(l)I:初始化
(Initialization)。从终端读入字符集大小n,及n个字符和m个权值,建立哈夫曼树,并将它存于文件hfmtree中。
(2)C:编码
(Coding)。利用已建好的哈夫曼树(如不在内存,则从文件hfmtree中读入),对文件tobetrans中的正文进行编码,然后将结果存入文件codefile中。
(3)D:编码
(Decoding)。利用已建好的哈夫曼树将文件codefile中的代码进行译码,结果存入文件textfile中。
(4)P:印代码文件
(Print)。将文件codefile以紧凑格式显示在终端上,每行50个代码。同时将此字符形式的编码文件写入文件codeprint中。
(5)T:印哈夫曼树 (Tree
printing)。将已在内存中的哈夫曼树以直观的方式
(树或凹入表形式)显示在终端上,同时将此字符形式的哈夫曼树写入文件treeprint中。
程序源代码:
文件一:my.h(自定义头文件)
//调用有文件以及定义常数值
#include "stdio.h"
#include "string.h"
#define MAXLEN 100
#define MAXLEN_1 1000
//自定义类型声明
typedef struct
{
int weight;
char data;
int lchild,rchild,parent;
}HFMTnode;
typedef HFMTnode HFMT[MAXLEN];
typedef
struct
{
char code[MAXLEN];
char data;
}HFMCnode;
typedef HFMCnode HFMC[MAXLEN];
typedef
struct
{
char data[MAXLEN];
int top;
}seqstack;
//文件全局变量外部声明
extern int n;
//所有子函数声明
void InitializeTree(HFMT T);
void InputTree(HFMT T);
void Selectleast(HFMT T,int *p1,int *p2);
void CreateHFMT(HFMT T);
void push(char x);
void hfmc(HFMT T,int i);
void CreateHFMC(HFMT T,HFMC C);
void Initialization(HFMT T,HFMC C);
void Codeing(HFMC C);
void Decodeing(HFMC C);
void Showcodefile();
void Showhfmt(HFMT T);
int TreeDepth(HFMT T,int i);
void print(HFMT T,int i,int a);
文件二:Initialization.c(初始化)
#include
"my.h"
seqstack
s;
//初始化树
void InitializeTree(HFMT T)
{
int i;
printf("请输入要输入的字符个数n(n应大于1):");
scanf("%d",&n);
for(i=0;i<2*n-1;i++)
{
T.weight=-1;
T.lchild=-1;
T.rchild=-1;
T.parent=-1;
T.data='\0';
}
}
//输入树
void InputTree(HFMT T)
{
int i;
for(i=0;i
{
printf("请输入第%d个字符与权重:",i+1);
getchar();
scanf("%c %d",&T.data,&T.weight);
}
}
//从树数组中选取权值最小的两个元素
void Selectleast(HFMT T,int *p1,int *p2)
{
long min1,min2;
int i;
min1=min2=999999;
for(i=0;i<2*n-1;i++)
{
if(T.parent==-1&&T.weight!=-1)
if(T.weight
{
min1=T.weight;
*p1=i;
}
}
for(i=0;i<2*n-1;i++)
{
if(T.parent==-1&&T.weight!=-1)
if(T.weight
{
min2=T.weight;
*p2=i;
}
}
}
//构建哈夫曼树
void CreateHFMT(HFMT T)
{
int i,p1,p2;
InitializeTree(T);
InputTree(T);
for(i=n;i<2*n-1;i++)
{
Selectleast(T,&p1,&p2);
T.weight=T[p1].weight+T[p2].weight;
T.lchild=p1;
T.rchild=p2;
T[p1].parent=T[p2].parent=i;
}
}
//入栈
void push(char x)
{
s.top++;
s.data[s.top]=x;
}
//构建哈夫曼树编码库递归调用函数
void hfmc(HFMT T,int i)
{
int j;
j=T.parent;
if(j!=-1)
{
if(i==T[j].lchild)
push('0');
if(i==T[j].rchild)
push('1');
hfmc(T,j);
}
}
//构建哈夫曼树编码库
void CreateHFMC(HFMT T,HFMC C)
{
int i,j;
s.top=-1;
for(i=0;i
{
hfmc(T,i);
C.data=T.data;
for(j=0;s.top!=-1;j++)
{
C.code[j]=s.data[s.top];
s.top--;
}
C.code[j]='\0';
}
}
//初始化函数
void Initialization(HFMT T,HFMC C)
{
FILE *out;
int i;
CreateHFMT(T);
CreateHFMC(T,C);
if((out=fopen("hfmt.dat","w"))!=NULL)
{
fprintf(out,"%d",n);
for(i=0;i
fprintf(out,"%c",T.data);
for(i=0;i<2*n-1;i++)
fprintf(out,"\n%d %d %d
%d",T.weight,T.parent,T.lchild,T.rchild);
}
else
{
printf("\n文件打开错误!");
return;
}
fclose(out);
printf("\n初始化完毕!");
}
文件三:Codeing.c(编码)
#include
"my.h"
//编码函数
void Codeing(HFMC C)
{
FILE
*in,*out;
char zw[MAXLEN],code[MAXLEN_1];
int i=0,j,k,c_len,error=1;
c_len=0;//编码正文初始长度置零
//打开文件toberrans.dat并读取正文存入正文数组zw
if((in=fopen("tobetrans.dat","r"))!=NULL)
{
zw=fgetc(in);
while(feof(in)==0)
{
i++;
zw=fgetc(in);
}
zw='\0';
}
else
{
printf("\n文件打开错误!");
return;
}
fclose(in);
//进行编码
for(i=0;zw!='\0';i++)
{
error=1;//错误置为真
for(j=0;j
{
if(zw==C[j].data)
{
for(k=0;C[j].code[k]!='\0';k++)
{
code[c_len]=C[j].code[k];
c_len++;
}
error=0;//若编码库存在匹配字符,则错误为假
break;
}
}
if(error==1)
break;
}
code[c_len]='\0';
if(error)
{
printf("\n编码错误,请重新检查!");
return;
}
else
{
printf("\n正文为:%s",zw);
printf("\n编码为:%s",code);
//打开文件codefile.dat,并将编码正文写入文件
if((out=fopen("codefile.dat","w"))!=NULL)
fprintf(out,"%s",code);
else
{
printf("\n打开文件错误!");
return;
}
fclose(out);
printf("\n编码成功!");
}
}
文件四:Decodeing.c(译码)
#include
"my.h"
//译码函数
void Decodeing(HFMC C)
{
FILE *in,*out;
int i,j,k,c_max,c_len,dq,dq_len,flag,error=0;//error初始状态为假
char code[MAXLEN_1],a[MAXLEN],zw[MAXLEN];
code[0]='\0';
//打开文件codefile.dat,读取编码正文写入内存,存入数组code
if((in=fopen("codefile.dat","r"))!=NULL)
{
fscanf(in,"%s",code);
}
else
{
printf("\n打开文件错误!");
return;
}
fclose(in);
//求编码正文长度c_len
for(i=0;code!='\0';i++);
c_len=i;
if(c_len==0)
error=1;//错误情况1
//求编码库最长编码长度c_max
c_max=0;
for(i=0;i
{
for(j=0;C.code[j]!='\0';j++);
if(c_max
c_max=j;
}
//进行译码
dq=0; //dq用来记录code数组的读取位置
k=0; //k用来记录zw数组读取位置
while(dq
{
flag=1;
dq_len=c_max;
for(i=dq,j=0;j
a[j]=code;
a[j]='\0';
while(flag&&!error)//若无错误且flag为1则继续循环
{
for(i=0;i
{
if(strcmp(a,C.code)==0)
{
zw[k]=C.data;
k++;
flag=0;
break;
}
}//若找到编码库里匹配的编码,则结束循环
if(flag)
{
dq_len--;
a[dq_len]='\0';
}//未找到则将当前长度减一,继续寻找
if(dq_len<1)
error=1;//译码错误情况2
}
dq=dq+dq_len;//编码正文当前读取位置改变
}
zw[k]='\0';//在zw数组的最后一个位置添加字符串结束符
if(error)
{
printf("\n译码错误,请重新检查!");
return;
}
else
{
//打印编码正文以及译码正文
printf("\n编码为:%s",code);
printf("\n译码为:%s",zw);
//打开文件textfile.dat,将译码正文即数组zw写入文件
if((out=fopen("textfile.dat","w"))!=NULL)
fprintf(out,"%s",zw);
else
{
printf("\n打开文件错误!");
return;
}
fclose(out);
printf("\n译码成功!");
}
}
文件五:Showcodefile.c(显示代码文件)
#include
"my.h"
//显示编码文件内容函数
void Showcodefile()
{
FILE *in;
char code[MAXLEN_1];
int i;
code[0]='\0';
//打开文件
if((in=fopen("codefile.dat","r"))!=NULL)
{
fscanf(in,"%s",code);
}
else
{
printf("\n打开文件错误!");
return;
}
fclose(in);
//打印内容
printf("\n代码文件内容为:");
for(i=0;code!='\0';i++)
{
if(iP==0)
printf("\n");
printf("%c",code);
}
}
文件六:Showhfmt.c(以凹入法显示哈夫曼树)
#include
"my.h"
//求哈夫曼树深度函数
int TreeDepth(HFMT T,int i)
{
int ldep,rdep;
if(T.lchild==-1)
return 1;
else
{
ldep=TreeDepth(T,T.lchild);
rdep=TreeDepth(T,T.rchild);
if(ldep>rdep)
return ldep+1;
else
return rdep+1;
}
}