数据结构课程设计报告——哈夫曼编译器.doc
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
数据结构课程设计
设计说明书
(题目)
哈夫曼编译器
起止日期: 2011 年 6 月 20 日至 2011 年 6 月 27 日
学生姓名
班级
学号
成绩
指导教师(签字)
计算机与通信学院
2011年 6月 23 日
一、课题任务与说明
1.编辑一个哈夫曼编译器系统程序
2.问题描述
设某编码系统共有n个字符,使用频率分别为{w1,w2,…,w n},设计一个不等长编码方案,使得该编码系统的空间效率最好。
3.所具有的功能:
(1) 为一字符文本编码功能:将一字符文本复制到指定的文本
中,并保存到指定路径,让程序自动为它编码。
(2) 为部分字符编码功能:输入部分字符与对应的字符频率,
让程序为之编码(需注意输入格式)。
(3) 保存输出到文本功能:将编码结果输出到文本。
(4) 输出保存文本信息功能:将功能3保存的文本信息输出到
屏幕上,用于查看结果是否正确。
4.设计要求
(1)设计数据结构;
(2)设计编码算法;
(3)分析时间复杂度和空间复杂度。
(4)字符和频度如下:
字符空格 A B C D E F G H I J K L M N O P Q R S T U V
W X Y Z
频度 186 64 13 22 32 103 21 15 47 57 1 2 32 20 57 63 15
1 48 51 80 23 8 18 1 16
5.设计内容与步骤
(1)选择合适的数据结构
(2)结点结构的设计
(3)算法设计与分析
(4)程序设计、实现、调试
(5)课程设计说明书
6.设计工作计划与进度安排
(1)设计工作4学时
(2)实现与调试16学时
(3)课程设计说明书4学时
二、算法设计
Huffman编码是一种可变长编码方式,是由美国数学家David Huffman创立的,是二叉树的一种特殊转化形式。
编码的原理是:将使用次数多的代码转换成长度较短的代码,而使用次数少的可以使用较长的编码,并且保持编码的唯一可解性。
Huffman算法的最根本的原则是:累计的(字符的统计数字*字符的编码长度)为最小,也就是权值(字符的统计数字*字符的编码长度)的和最小。
三、程序的功能设计
为实现系统功能,本程序主要分为五个模块。
它们分别为:
1.初始化功能模块
此功能模块的功能为从键盘接收字符集大小n,以及n 各字
符和n 个权值。
2.建立哈弗曼树的功能模块
此模块功能为使用1中或从一文本中得到的数据按照教材
的构造哈夫曼树的算法构造哈夫曼树。
3.建立哈夫曼编码与译码的功能模块
此模块功能为读入相关的字符信息进行哈夫曼编码,并将译码结果输出,在必要时也可保存到文件中。
其中各个函数的功能分别如下:
notesave 函数用于保存输出的结果;
hfmtree 函数用于建立结点哈夫曼树并输出最终结果; readnote 函数用于读取目标文本字符信息;
4.流程图:
四、函数编码及调试
由于本人能力有限难免不会在编码与调试过程中遇到这样或那样的问题,但通过长时间的改正,查询资料与询问,终于能将出现一些致命错误得以修正。
例如:在输入编码结果信息时由于少了一个很不明显的Getchar ()的接收Enter 的函数,后面的就全乱了使程序出现了不能达到意料之中的效果。
还有先是运行完一个函数后就跳出了整个运行程序不能再继续,后来通过查阅书籍,明白再主函数中加一个For 语句就可以避免这一问题。
第界面
结束
main()
Hfmtree() Exit()
Readnote() Notesave() Main()
三个问题就是由于调用完一个函数后显示的信息还是留在运行界面,但它们的确有没什么用且占用界面,不美观,后来通过询问同学得知,在每个要调用的函数后加一个system("cls")语句就可达到清除上屏信息的功能。
五、总结
该程序主要用于哈夫曼编码,并在必要时保存数据。
做法主要是用一个主函数MAIN,用它达到显示欢迎界面,提示选择操作与调用其它函数功能(用到Switch函数),这样使得程序简单,易读,运行效果也好。
但由于能力有限,该程序在时间与空间复杂度上有待作改正。
参考文献:
(1)刘振鹏、张小莉等编著;数据结构(第二版).中国铁道出版社。
(2)石强、罗文浩等编著;数据结果习题解答与实验指导(第二版).中国铁道出版社。
(3)刘克成主编;C语言程序设计.中国铁道出版社。
附全部代码(正常运行VC++6.0):
#include<stdio.h>
#include<conio.h>
#include<string.h>
#include<stdlib.h>
#define MAXLEAF 27
#define MAXNODE MAXLEAF*2-1
#define MAXBIT 25
#define MAXVALUE 2000
#define H "\t\t
=======================================\n"
typedef struct{
int parent;
int weight;
int lchild;
int rchild;
}hfm_n;
typedef struct{
int bit[MAXBIT];
int start;
}hfm_c;
void notesave(int n,char a[],hfm_c hfm_code[]) {
FILE *fp;
int i=0,j;
char c;
if((fp=fopen("d:\\notesave.txt","w"))==NULL) {
printf("\n Cannot open file!\n");
getchar();
exit(1);
}
for(i=0;i<n;i++)
{
fputc(a[i],fp);
fputs("-->",fp);
for(j=hfm_code[i].start+1;j<n;j++)
{
c=char(48+hfm_code[i].bit[j]);
fputc(c,fp);
}
fputs(" ",fp);
if((i+1)%3==0) fputs("\n",fp);
}
fclose(fp);
printf("\n 保存成功!\n");
}
hfm_n *hfmtree(int n,char a[],int s[])
{
hfm_n hfm_node[MAXNODE];
hfm_c hfm_code[MAXLEAF],cd;
int i,j,m1,m2,x1,x2,c,p;
char ch1;
for(i=0;i<2*n-1;i++)
{
hfm_node[i].weight=0;
hfm_node[i].parent=-1;
hfm_node[i].lchild=-1;
hfm_node[i].rchild=-1;
}
for(i=0;i<n;i++)
hfm_node[i].weight=s[i];
for(i=0;i<n-1;i++)
{
m1=m2=MAXVALUE;
x1=x2=0;
for(j=0;j<n+i;j++)
{
if(hfm_node[j].parent==-1&&hfm_node[j].weight<m1)
{
m2=m1;
x2=x1;
m1=hfm_node[j].weight;
x1=j;
}
else
if(hfm_node[j].parent==-1&&hfm_node[j].weight<m2)
{
m2=hfm_node[j].weight;
x2=j;
}
}
hfm_node[x1].parent=hfm_node[x2].parent=n+i;
hfm_node[n+i].weight=hfm_node[x1].weight+hfm_node[x2].weight;
hfm_node[n+i].lchild=x1;
hfm_node[n+i].rchild=x2;
}
for(i=0;i<n;i++)
{
cd.start=n-1;
c=i;
p=hfm_node[c].parent;
while(p!=-1)
{
if(hfm_node[p].lchild==c)
cd.bit[cd.start]=0;
else
cd.bit[cd.start]=1;
cd.start--;
c=p;
p=hfm_node[c].parent;
}
for(j=cd.start+1;j<n;j++)
hfm_code[i].bit[j]=cd.bit[j];
hfm_code[i].start=cd.start;
}
printf("\n\n 所有编码:\n ");
for(i=0;i<n;i++)
printf("%c",a[i]);
printf("<===>");
for(i=0,c=0;i<n;i++)
for(j=hfm_code[i].start+1;j<n;j++)
{
printf("%d",hfm_code[i].bit[j]);
c++;
if(c==48||(c-48)%78==0) printf("\n ");
}
printf("\n\n 各字符对应的编码:\n");
for(i=0;i<n;i++)
{
printf(" ");
printf("%c-->",a[i]);
for(j=hfm_code[i].start+1;j<n;j++)
printf("%d",hfm_code[i].bit[j]);
printf(" ");
if((i+1)%5==0) printf("\n");
}
printf("\n\n 是否将结果保存到--->路径D:\\ notesave (y/n)?");
ch1=getchar();getchar();
if(ch1=='y'||ch1=='Y')
notesave(n,a,hfm_code);
return NULL;
}
int readnote()
{
FILE *fp;
int i,j,b[26],s[26],k;
char a[26],ch,ch1='n';
memset(b,0,sizeof(b));
if((fp=fopen("d:\\note.txt","r"))==NULL)
{
printf("\n Cannot open the file of note!");
printf("\n Please creat a new text!\n");
ch1='y';
}
if(ch1=='y')
{
printf("\n 此功能你要做的只是将要编码的字符文本复制到下面文本并将它命名为note并\
\n 保存到--->D:\\...\
\n 需注意的是一定要是字符文本且文本保存路径是D盘下.\n ");
system("notepad");printf("\n 保存好文本后,请按任意键继续....");
getchar();
if((fp=fopen("d:\\note.txt","r"))==NULL)
{
printf("\n Open files fail!");
getchar();
exit(1);
}
}
while((ch=fgetc(fp))!=EOF)
{
if(sizeof(ch)!=1) break;
k=int(ch);
if(k>=65&&k<=90)
b[k-65]++;
if(k>=97&&k<=122)
b[k-97]++;
}
fclose(fp);
printf("\n 文本中各字符的频率为:\n");
for(i=0,j=0;i<26;i++)
if(b[i]!=0)
{
ch=char(i+65); a[j]=ch;s[j]=b[i];
printf(" %c--->%d ",a[j],s[j]); j++;
if(j%6==0) printf("\n");
}
hfmtree(j,a,s);
return 1;
}
void main()
{
int i,h,n=0,b[26];
char a[26],c[30],ch,ch1;
for(;;)
{
printf("\n\n\n\t\t <<-\1 \1 \1 \1 \1 \1 \1 \1 \1 \1 \1 \1 \1 \1 \1 \1 \1 \1 \1 \1->>\n");
printf("\t\t =======* * * * * * * * * * * * * *=======\n");
printf("\t\t =====>>*欢迎使用本哈夫曼编码系统!*<<=====\n");
printf("\t\t = *__*__*__*__*__*__*__*__* =\n");
printf("\t\t = |_ _ _ _ 功能选项!_ _ _ _| =\n");
printf("\t\t = ------------/ \\----------- =\n");
printf("\t\t = | | =\n");
printf("\t\t = | 1.为一字符文本编码. | =\n");
printf("\t\t = | | =\n");
printf("\t\t = | 2.输入部分字符与相应频率为之编码.| =\n");
printf("\t\t = | | =\n");
printf("\t\t = | 3.退出程序. | =\n");
printf("\t\t = | | =\n");
printf("\t\t = | 4.打开保存的文本. | =\n");
printf("\t\t = | | =\n");
printf("\t\t = ------------------------------------- =\n");
printf(H);
printf("\n\t\t 请选择某功能选项(1~4):");
scanf("%d",&h);getchar();
switch(h)
{
case 1: system("cls");printf("\n 功能1:为一字符文本编
码!\n");readnote();break;
case 2: system("cls");printf("\n 功能2:输入部分字符与相应频率为之编码!\n");
printf("\n ===>输入格式应为:字符+空格\n ===>例如:a b c.....\
\n ===>对应的字符频率格式也应如此.\n");
do
{
printf("\n 请输入叶子结点个数:");
if(scanf("%d",&n)!=1||sizeof(n)!=4)
{
ch='s';
printf("\n Input worry!\n Please input again.\n");
}
else ch='n';
getchar();
}while(ch=='s');
do
{
printf("\n =======>请输入相应个字符:");
for(i=0;i<n;i++)
{
a[i]=getchar();
ch1=getchar();
}
if(ch1!='\n') gets(c);
printf("\n 请输入相应字符对应的频率:");
for(i=0;i<n;i++)
scanf("%d",&b[i]);
ch1=getchar();
if(ch1!='\n') gets(c);
printf("\n 确认所有数据无误后请按'Enter'(否则按'y')");
ch=getchar();
}while(ch=='y'||ch=='Y');
hfmtree(n,a,b);break;
case 3: printf("\n\n\n");printf(H);printf("\t\t\t\t \1欢迎下次使用\1\n");printf(H);
printf("\t\t");return;
case 4: printf("\nNotesave 中的信息:\n");system("type
d:\\notesave.txt");break;
default: printf("\t\t \a输入有误!\t");getchar();break;
}
printf("\n ");
system("pause");
system("cls");
}
}。