数据结构课程设计哈夫曼编码问题的设计和实现.docx
- 文档编号:24848464
- 上传时间:2023-06-02
- 格式:DOCX
- 页数:24
- 大小:156.58KB
数据结构课程设计哈夫曼编码问题的设计和实现.docx
《数据结构课程设计哈夫曼编码问题的设计和实现.docx》由会员分享,可在线阅读,更多相关《数据结构课程设计哈夫曼编码问题的设计和实现.docx(24页珍藏版)》请在冰豆网上搜索。
数据结构课程设计哈夫曼编码问题的设计和实现
数据结构课程设计--哈夫曼编码问题的设计和实现
成绩
课程设计说明书(论文)
题目哈夫曼编码问题的设计和实现
课程名称数据结构课程设计
院(系、部、中心)
专业
班级
学生姓名
学号
设计地点
指导教师
设计起止时间:
2008年6月2日至2008年6月6日
1问题描述
1.1题目内容
哈夫曼编码问题的设计和实现
输入一个英文字符串,对该字符串中各字符个数进行统计取得各字符的出现次数;以其出现次数作为关键字建立哈夫曼树并进行编码,最后输出各个字符对应的码值。
1.2基本要求
要求:
设计存储结构、基本算法(主要采用程序流程图体现);完成基本算法的实现代码;设计测试输入数据对程序进行测试,分析输出结果数据、算法的时间复杂度分析,如有改进算法则提出算法的改进方法。
1.3测试数据
测试数据三组:
AAAABBBCCD(判断连续的字符串是否可行)
AABBAABCDC(判断间段的字符串是否可行)
AAAABBBCCD(判断含空格的字符串是否可行)
2需求分析
2.1程序的基本功能
该程序大体上有两个功能:
1.输入任何一个字符串后,该程序能统计不同字符串的个数,并以不同字符串的个数作为权值。
2.已知不同字母的权值,以该权值作为叶结点,构造一棵带权路径最小的树,对该树从叶结点到根结点路径分支遍历,经过一个分支就得到一位夫曼编码值。
(规定哈夫曼树中的左分支为0,右分支为1,则从根结点到每个叶结点所经过的分支对应的0和1组成的序列便为该结点对应字符的编码)
2.2输入值、输出值以及输入输出形式
输入值:
AAAABBBCCD
输出值:
W=4C=0
W=3C=10
W=2C=111
W=1C=110
输入值:
AABBAABCDC
输出值:
W=4C=0
W=3C=10
W=2C=111
W=1C=110
输入值:
AAAABBBCCD
输出值:
W=4C=11
W=1C=010
W=3C=10
W=2C=00
W=1C=011
2.3各个模块的功能要求
1.统计模块
任意输入一个字符串,不论字母是否相联,字符串中是否含空格都能统计出不同字母的个数。
2.建立哈夫曼树模块
以统计的字符串个数作为权值,利用仿真存储结构,建立带权路径最小的树。
其中对结点的存储需要六个域,分别是weight域,flag域,parent域,leftChild域,rightChild域。
weight域是对权值的存放,flag域是一个标志域,flag=0时表示该结点尚未加入到哈夫曼树中,flag=1时表示该结点已加入到哈夫曼树中。
3.哈夫曼编码模块
从哈夫曼树的叶结点到根结点路径分支逐步遍历,每经过一个分支就得到一位哈夫曼编码。
哈夫曼编码也利用仿真存储结构。
4.主函数模块
从屏幕上输入字符串,调用函数,输出每个字母的权值与编码。
3概要设计
3.1所需的ADT,每个程序中使用的存储结构设计说明(如果指定存储结构请写出该存储结构的定义)
抽象数据类型集合:
在该程序中未用到抽象数据类型,主要用到的数据类型为:
int,char。
在哈夫曼树的建立与哈夫曼树的编码中用到仿真存储
3.2主程序流程以及模块调用关系
输入字符串——〉调用count函数——〉申请内存空间——〉调用Haffman
——〉调用HaffmanCode——〉输出权值与编码。
3.3各个模块的算法设计说明
1.主函数模块
n
y
y
n
n
y
主函数中利用gets输入一个字符串,调用count函数统计不同字母的个数,在调用
Haffman函数建立哈夫曼树,然后调用HaffmanCode函数进行编码,如果成功,输出权
值与编码,否则退出。
2.
统计函数
y
N
y
y
N
Y
统计函数在统计不同字符个数时先利用一个for循环遍历所有的字母,每遍历一个不同字母前令temp=1,然后用一个for循环将其后的字母与之比较,若相等则temp++,且将该字母从字符串中删除,否则从下一个字母遍历。
如此循环直到字符串结束。
3.Haffman函数
n
yn
n
y
n
y
n
y
y
Haffman函数主要以仿真结构存储信息,开始对每个域开始赋值,再根据不同的情况对每个域的值进行修改,如此循环下去,直到每个域的值修改完全。
4.HffmanCode函数
n
y
n
nny
y
HaffmanCode函数主要以仿真结构存储信息,由叶结点向根结点遍历,从数据域start域开始编码,bit数组存放编码,其编码为0,1序列.。
4详细设计
4.1数据类型
typedefstruct
{
intweight;/*权值*/
intflag;/*标记*/
intparent;/*双亲结点下标*/
intleftChild;/*左孩子下标*/
intrightChild;/*右孩子下标*/
}HaffNode;/*哈夫曼树的结点结构*/
typedefstruct
{
intbit[MaxN];/*数组*/
intstart;/*编码的起始下标*/
intweight;/*字符的权值*/
}Code;/*哈夫曼编码结构*/
intweight[16];/*用于存放权值*/
chars[30];/*存放字符串*/
函数调用
5各个算法实现的源程序
1.字符串统计源程序:
intcount(char*s,int*weight,intn)
{
inti,j,temp,k=0,p;
for(i=0;i ='\0';i++) { temp=1; for(j=0;j { if(s[j]==s[i]&&i! =j) { temp++; for(p=j;p s[p]=s[p+1]; n--; j--; } } weight[k++]=temp;/*temp作为权值赋给weight数组*/ } returni;/*返回权值个数*/ } 2.哈夫曼树建立源程序 voidHaffman(intweight[],intn,HaffNodehaffTree[]) /*建立叶结点个数为n,权值数组为weight的哈夫曼树haffTree*/ { inti,j,m1,m2,x1,x2; for(i=0;i<2*n-1;i++) { if(i haffTree[i].weight=weight[i]; else haffTree[i].weight=0; haffTree[i].parent=0; haffTree[i].flag=0; haffTree[i].leftChild=-1; haffTree[i].rightChild=-1; } /*构造哈夫曼树haffTree的n-1个非叶结点*/ for(i=0;i { m1=m2=MaxValue; x1=x2=0; for(j=0;j { if(haffTree[j].weight { m2=m1; x2=x1; m1=haffTree[j].weight; x1=j; } else if(haffTree[j].weight { m2=haffTree[j].weight; x2=j; } } /*将找出的两颗权值最小的子树合并为一棵子树*/ haffTree[x1].parent=n+i; haffTree[x2].parent=n+i; haffTree[x1].flag=1; haffTree[x2].flag=1; haffTree[n+i].weight=haffTree[x1].weight+haffTree[x2].weight; haffTree[n+i].leftChild=x1; haffTree[n+i].rightChild=x2; } } 3.哈夫曼树编码函数 voidHaffmanCode(HaffNodehaffTree[],intn,CodehaffCode[]) /*由n个结点的哈夫曼树haffTree构造哈夫曼编码haffCode*/ { Code*cd=(Code*)malloc(sizeof(Code)); inti,j,child,parent; /*求n个结点的哈夫曼编码*/ for(i=0;i { cd->start=n-1; cd->weight=haffTree[i].weight; child=i; parent=haffTree[child].parent; /*由叶结点向上直到根结点*/ while(parent! =0) { if(haffTree[parent].leftChild==child) cd->bit[cd->start]=0;/*左孩子分支编码0*/ else cd->bit[cd->start]=1;/*左孩子分支编码1*/ cd->start--; child=parent; parent=haffTree[child].parent; } for(j=cd->start+1;j haffCode[i].bit[j]=cd->bit[j];/*保存每个叶结点的编码*/ haffCode[i].start=cd->start;/*保存不等长编码的起始位置*/ haffCode[i].weight=cd->weight;/*保存相应字符的权值*/ } } 6调试分析 测试数据与输出结果与2.2结果相同。 对过函数的分析: 1.count函数: 最坏情况下时间复杂度为O(n*n*n),调试时必须给定字符串的长度,否则会输出乱码,这很不方便。 只要在条件语句中加上”s[i]! ='\0'”,就能解决。 同时对入含空格的字符串不能正确统计,因为输入字符串是以scanf的形式输入,scanf遇到空格自动结束,将scanf改为gets即可,出现gets(s); 2.Haffman函数在最坏情况下计算的次数为2*n-1+(3*n-3)*n/2时间复杂度最坏情况下为O(n*n);Haffman函数在书写时要注意定义变量的位置。 3.HaffmanCode函数在最坏情况下计算的次数为n*(3*n-1),时间复杂度为O(n*n);HaffmanCode函数在书写时要注意定义变量的位置。 4.主函数的时间复杂度又输入的字符串决定。 曾在主函数中将printf("输入: \n");get(s),n=count(s,weight,30)放在Haffman(weight,n,myHaffTree);HaffmanCode(myHaffTree,n,myHaffCode)前面,出现很多问题,像“HaffNodeundefine”,”seeundeclearHaffNode”等,调整后没有问题。 主函数的时间复杂度由输入的字符串决定。 算法改进设想: 由于统计函数时间复杂度较高,是否降低其时间复杂度? 统计函数中用到三个循环,一个用于遍历所有字符,一个用于寻找相同字符,一个用于删除相同字符。 而且三个循环嵌套,如果能减少循环的次数或者是由较少的循环嵌套,就能降低时间复杂度了。 7使用说明 在写源程序前先将所要用到的函数都写好,以“haffman.h”保存起来。 再书写主函数,保存到相同的位置。 在vc环境下,用“Build”里面的“complie”,进行编译,运行。 利用Debug中的F5,F10,F9,F11设置断点等进行调试。 8测试结果 9源程序 包含哈夫曼树和图,以哈夫曼树为主要。 图在压缩文件中 哈夫曼树 #include #include #defineMaxValue10000 #defineMaxBit4 #defineMaxN10 typedefstruct { intweight;/*权值*/ intflag;/*标记*/ intparent;/*双亲结点下标*/ intleftChild;/*左孩子下标*/ intrightChild;/*右孩子下标*/ }HaffNode;/*哈夫曼树的结点结构*/ typedefstruct { intbit[MaxN];/*数组*/ intstart;/*编码的起始下标*/ intweight;/*字符的权值*/ }Code;/*哈夫曼编码结构*/ voidHaffman(intweight[],intn,HaffNodehaffTree[]) /*建立叶结点个数为n,权值数组为weight的哈夫曼树haffTree*/ { inti,j,m1,m2,x1,x2; for(i=0;i<2*n-1;i++) { if(i haffTree[i].weight=weight[i]; else haffTree[i].weight=0; haffTree[i].parent=0; haffTree[i].flag=0; haffTree[i].leftChild=-1; haffTree[i].rightChild=-1; } /*构造哈夫曼树haffTree的n-1个非叶结点*/ for(i=0;i { m1=m2=MaxValue; x1=x2=0; for(j=0;j { if(haffTree[j].weight { m2=m1; x2=x1; m1=haffTree[j].weight; x1=j; } else if(haffTree[j].weight { m2=haffTree[j].weight; x2=j; } } /*将找出的两颗权值最小的子树合并为一棵子树*/ haffTree[x1].parent=n+i; haffTree[x2].parent=n+i; haffTree[x1].flag=1; haffTree[x2].flag=1; haffTree[n+i].weight=haffTree[x1].weight+haffTree[x2].weight; haffTree[n+i].leftChild=x1; haffTree[n+i].rightChild=x2; } } voidHaffmanCode(HaffNodehaffTree[],intn,CodehaffCode[]) /*由n个结点的哈夫曼树haffTree构造哈夫曼编码haffCode*/ { Code*cd=(Code*)malloc(sizeof(Code)); inti,j,child,parent; /*求n个结点的哈夫曼编码*/ for(i=0;i { cd->start=n-1; cd->weight=haffTree[i].weight; child=i; parent=haffTree[child].parent; /*由叶结点向上直到根结点*/ while(parent! =0) { if(haffTree[parent].leftChild==child) cd->bit[cd->start]=0;/*左孩子分支编码0*/ else cd->bit[cd->start]=1;/*左孩子分支编码1*/ cd->start--; child=parent; parent=haffTree[child].parent; } for(j=cd->start+1;j haffCode[i].bit[j]=cd->bit[j];/*保存每个叶结点的编码*/ haffCode[i].start=cd->start;/*保存不等长编码的起始位置*/ haffCode[i].weight=cd->weight;/*保存相应字符的权值*/ } } intcount(char*s,int*weight,intn) { inti,j,temp,k=0,p; for(i=0;i ='\0';i++) { temp=1; for(j=0;j { if(s[j]==s[i]&&i! =j) { temp++; for(p=j;p s[p]=s[p+1]; n--; j--; } } weight[k++]=temp; } returni; } voidmain() { inti,j,n; intweight[16]; chars[30]; HaffNode*myHaffTree; Code*myHaffCode; printf("************输入字符串************\n"); gets(s); n=count(s,weight,30); myHaffTree=(HaffNode*)malloc(sizeof(HaffNode)*(2*n+1)); myHaffCode=(Code*)malloc(sizeof(Code)*n); if(n>MaxN) { printf("给出的n越界,修改MaxN! \n"); exit (1); } Haffman(weight,n,myHaffTree); HaffmanCode(myHaffTree,n,myHaffCode); /*输出每个叶结点的哈夫曼编码*/ for(i=0;i { printf("W=%dC=",myHaffCode[i].weight); for(j=myHaffCode[i].start+1;j printf("%d",myHaffCode[i].bit[j]); printf("\n"); } }
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 数据结构 课程设计 哈夫曼 编码 问题 设计 实现