(二)在某一界面结束后,会有“请按回车继续下面操作"提示,请按提示进行操作,如输入其他数字则无效,知道输入回车符界面才会跳转。
(三)对界面的操作可以自行选择,在询问是否译码的时候,请按要求进行选择,在一次译码结束后会询问是否继续译码,如需要则输入y或者Y,输入其他字符则退出程序。
六、测试结果
亠)、初始/
化蹙气大于时勺数字.哥K播T卫宇则援第一八毀字运17》猛入字斑的枚啓睛軸入一牛數工“
h
嘯入字坷的枕直*:
砖笹人一忖文字》
鼠\车対前仁借£'芒轲h…卜常』
J、建立哈夫曼树
]"送呈'CsVBo^uscELtiS皿』■…HE
X
序号钳值
或亲
右疾子
A
工a
1
£
0
0
2b
2
5
R
n
2d
3
4
£
7
B
0
en
图6-2
£*
3
(
1
2
E*
召
7
3
b
7«
IB
e
4
G
三)、哈夫曼编码
逢崑-Ci
MJOcuKDntsUidSettJtratdrkj$di\hutt>anXDe3
WIMHEJuh|
垢出福码匚的抢杲二
■
11H
b
ill
1H
图6-3
a
e
请苇入编禺
四)、哈夫曼译码
聃2臥
:
nn
图6-4
悬皆塑共輸扎丫是[新扎站奋伞其-也〉
(五)、错误判定
I对/
5-
不电
WL11码苦
lwm輛罡
附录:
源代码:
#include
#include
#include#include
structcode//结构体的定义
chara;
intw;
intparent;
intlchild;
intrchild;
};
voidcreation(code*p,intn,intm);//建立哈夫曼树
voidcoding(code*p,intn);〃编码
voidtranslate(char**hc,code*p,intn);//译码voiddisplay(code*p,intn,intm);〃输出函数
〃主函数
voidmain()
{
inti,n,m;
code*ht;
printf(”字符的数量:
\n(请输入一个大于0的数字,
入多个数字则按第一个数字运行)\n");
while(scanf("%d",&n)!
=1||n<0||n>9999)
{
printf("重新输入:
\n");
fflush(stdin);
}
m=2*n-1;II哈夫曼树中没有度为
结点,故含有m=2n-1个结点
ht=(code*)malloc((m+1)*sizeof(code));II动态申存
'))
{
printf("输入编码中的字符(请输入一个
):
\n");
fflush(stdin);
scanf("%c",&ht[i].a);
while(!
(ht[i].a>'a'||ht[i].av'z'||ht[i].a>'A'||ht[i].av'Zprintf("重新输入:
\n");
fflush(stdin);
seanf("%c",&ht[i].a);//清空输入缓冲区,往
往是确保不影响后面数据的读取
}
printf(”输入字符的权值(请输入一个数字):
\n");
while(scanf("%d",&ht[i].w)!
=1||ht[i].w<0||ht[i].w>9999)
{
printf("重新输入:
\n");
fflush(stdin);//清空输入缓冲区,往
往是确保不影响后面数据的读取
}
ht[i].lchild=0;
ht[i].rchild=0;
ht[i].parent=O;
}
for(i=n+1;i<=m;i++)〃对n+1~2n-1的数
进行初始化
ht[i].a='*';
ht[i].w=O;
ht[i].lchild=O;
ht[i].rchild=O;
ht[i].parent=O;
}
creation(ht,n,m);
printf("请按回车进入哈夫曼树对应界面\n");
getchar();
getchar();
system("cls");
display(ht,n,m);
printf("请按回车进入编码对应界面\n");
getchar();
system("cls");
coding(ht,n);
getchar();
}
voidcreation(code*ht,intn,intm)
{
inti,j,m1,m2,t1,t2;
for(i=n+1;i<=m;i++)
{
j=1;〃找到第一个最小值(双亲不为
while(ht[j].parent!
=O)//找到表中第一个没有双亲的结点
{
j++;
}
t1=ht[j].w;
m1=j;
for(j=m1+1;jv=m;j++)
{
if(ht[j].parent==O&&ht[j].w!
=0)//条
(ht[j].w!
=0)是因为n〜2n-1的权值初始值为0
{
if(ht[j].w{
t1=ht[j].w;
m1=j;
}
}
ht[m1].parent=i;//第一个值的双亲为ht[i]
ht[i].lchild=m1;〃h[i]的的左孩子是最小值的
序号
不为0)
while(ht[j].parent!
=0)
{
j++;
}
t2=ht[j].w;
m2=j;
for(j=m2+1;jv=m;j++)
{
if(ht[j].parent==0&&ht[j].w!
=0)
{
if(ht[j].w{
t2=ht[j].w;
m2=j;
}
}
ht[m2].parent=i;//第二个值的双亲为ht[i]
ht[i].rchild=m2;〃h[i]的的左孩子是最小值的
号
}
voidcoding(code*p,intn)
{
inti,c,f;
//指针的指针
char**hc;
char*cd;
charch;
intstart;
hc=(char**)malloc((n+1)*sizeof(char*));//分配
字符编码的头指针向量
〃分配求编
cd=(char*)malloc(n*sizeof(char));
的工作空间
//编码结束符
cd[n-1]='\0:
for(i=1;i<=n;i++){
start=n-1;
for(c=i,f=p[i].parent;f!
=0;c=f,f=p[f].parent)//从
叶子到根逆向求编码
'O'
{
cd[--start]='O:
}
〃右孩子编码为'1'
else{
cd[--start]='1';
}
}
hc[i]=(char*)malloc((n-start)*sizeof(char));〃
i个字符编码分配空间
strcpy(hc[i],&cd[start]);//从cd复制编
(串)至Uhc,&是取地址符,即取首地址,从start
置到'\0'的编码为止。
}
free(cd);//释放工作空间
printf("\n输出编码后的结果:
\n");
printf("符号数码\n");
for(i=1;i<=n;i++)
printf("\n%c%s\n",p[i].a,hc[i]);
}
printf("是否进行译码操作,是则译码,否则退出序!
\n是(输入y/Y)否(输入其他字符)\n");
scanf("%d",&ch);
if(ch=='y'||ch=='Y')
{
translate(hc,p,n);
}
else
exit(0);
translate(char**hc,code*p,intn)
chara[10],ch;inti,j,c;
do
'\0'
for(i=1;i<=n;i++)
{
if(strcmp(a,hc[i])==O)//比较两个字符串是否
相等,相等则输出0
{
for(c=2*n-1,j=0;a[j]!
='\0';j++)//从根
发,按字符'0'或'1'确定找左孩子或右孩子
{
if(a[j]=='0')//左孩子
{
c=p[c].lchild;
}
else
{
c=p[c].rchild;〃右孩子
}
}
printf("字符是:
\n");
printf("%c\n",p[c].a);
break;
}
if(i>n)
{
printf("编码不存在对应的字符!
\n");
}
printf("是否继续输入?
是(输入y或者丫)否(其他)\n");
fflush(stdin);
scanf("%c",&ch);
}while(ch=='y'||ch=='Y');
}
voiddisplay(code*p,intn,intm)
{
inti;
\n
printf("\n序号码值权值双亲左孩子右孩');
for(i=1;i<=m;i++)
{
printf("%d%c%d%d%d
%d\n",i,p[i].a,p[i].w,p[i].parent,p[i].lchild,p[i].rchild);
}
}
设计体会
通过这个课程设计,让我对数据结构这门课程有了更深一步的了解,对以后的深造奠定了基础。
本次课程设计的课题是:
哈夫曼编码以及译码的实现。
本程序的特色是:
结构清晰,内容全面,输入的错误提醒。
在输入的错误的提醒方面,做了很大的改进。
不过在这方面仍存在些许的不足,就是在输入一个字母的时候,如果输入的数据是"ab",不会提示错误,只会按第一个'a'有效。
在初始化的时候,输入'a3'这种数据,则不会提示错误,而是执行了下一条seanf
语句输入的数字。
学习是一个无止境的过境,我们要善于使用资源,书籍,网络等等,努力地提升自己,为今后的发展做更大的努力。