哈夫曼编码与译码课程设计
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
哈夫曼编码与译码课程设计
本科⽣课程设计论⽂
题⽬:哈夫曼编码与译码
学⽣姓名:
学号:
专业:
班级:
指导教师:
2015年1⽉8⽇
内蒙古科技⼤学课程设计任务书课程名称数据结构与算法课程设计
设计题⽬Huffman编码和译码
指导教师时间2015.1.5——2015.1.9
⼀、教学要求
1. 掌握数据结构与算法的设计⽅法,具备初步的独⽴分析和设计能⼒
2. 初步掌握软件开发过程的问题分析、系统设计、程序编码、测试等基本⽅法和技能
3. 提⾼综合运⽤所学的理论知识和⽅法独⽴分析和解决问题的能⼒
4. 训练⽤系统的观点和软件开发⼀般规范进⾏软件开发,培养软件⼯作者所应具备的科学的⼯作⽅法和作风
⼆、设计资料及参数
每个学⽣在教师提供的课程设计题⽬中任意选择⼀题,独⽴完成,题⽬选定后不可更换。
Huffman编码和译码
根据给定的字符集和各字符的频率值,求出其中给定字符Huffman编码,并针对⼀段⽂本(定义在该字符集上)进⾏编码和译码,实现⼀个Huffman编码/译码系统。
要求设计类(或类模板)来描述Huffman树及其操作,包含必要的构造函数和析构函数,以及其他能够完成如下功能的成员函数:
求Huffman编码
输⼊字符串,求出编码
输⼊⼀段编码,实现译码
并设计主函数测试该类。
三、设计要求及成果
1. 分析课程设计题⽬的要求
2. 写出详细设计说明
3. 编写程序代码,调试程序使其能正确运⾏
4. 设计完成的软件要便于操作和使⽤
5. 设计完成后提交课程设计报告
四、进度安排
资料查阅与讨论(1天)
系统分析(2天)
系统的开发与测试(5天)
编写课程设计说明书和验收(2天)
五、评分标准
1. 根据平时上机考勤、表现和进度,教师将每天点名和检查
2. 根据课程设计完成情况,必须有可运⾏的软件。
3. 根据课程设计报告的质量,如有雷同,则所有雷同的所有⼈均判为不及格。
4. 根据答辩的情况,应能够以清晰的思路和准确、简练的语⾔叙述⾃⼰的设计和回答教师的提问
六、建议参考资料
1.《数据结构(C语⾔版)》严蔚敏、吴伟民主编清华⼤学出版社2004.11
2.《数据结构课程设计案例精编(⽤C/C++描述)》,李建学等编著,清华⼤学出版社 2007.2
3.《数据结构:⽤⾯向对象⽅法与C++语⾔描述》,殷⼈昆主编,清华⼤学出版社 2007
⽬录
第1章需求分析 (3)
第2章总体设计 (3)
第3章抽象数据类型定义 (4)
3.1 哈夫曼编码与译码抽象数据类型的设计 (4)
第4章详细设计 (4)
4.1 ⼯程视图 (4)
4.2 类图视图 (5)
4.3 函数的调⽤关系 (5)
4.4 主程序流程图 (6)
4.5 主要算法的流程图 (7)
第5章测试 (9)
第6章总结 (10)
附录:程序代码 (11)
第1章需求分析
Huffman编码和译码
根据给定的字符集和各字符的频率值,求出其中给定字符Huffman编码,并针对⼀段⽂本(定义在该字符集上)进⾏编码和译码,实现⼀个Huffman编码/译码系统。
要求设计类(或类模板)来描述Huffman树及其操作,包含必要的构造函数和析构函数,以及其他能够完成如下功能的成员函数:
求Huffman编码
输⼊字符串,求出编码
输⼊⼀段编码,实现译码
并设计主函数测试该类。
第2章总体设计
图2.1
主函数:对输⼊的字符段进⾏存储,并对字符数和对应的权值(字符个数)进⾏统计存储。
哈夫曼树初始化函数:对给定的字符数和权值,创建⼀棵哈夫曼树。
权值⼤⼩⽐较函数:找到每次所给集合的最⼩值和次⼩值,并返回给哈夫曼树初始化函数。
哈夫曼树编码函数:对创建的哈夫曼树,为左孩⼦的赋值为0,右孩⼦赋值为1,然后对叶⼦结点依次编码。
哈夫曼树译码函数:对输⼊的01⼆进制数⼀⼀与叶⼦结点的编码依次⽐较匹配。
第3章抽象数据类型定义
3.1哈夫曼编码与译码抽象数据类型的设计
enum Child{none,lchild,rchild}; //采⽤枚举,标记是左孩⼦还是右孩⼦class element //元素类
{
public://类的公有成员
elememt(); //构造函数
void change(char l,char *c,int p,Child h,int w) //对对象进⾏修改操作
void getparent(int p) //对⽗结点的值进⾏修改操作
void geta(Child h) //对孩⼦结点进⾏修改操作
void getweight(int w) //对权值进⾏修改操作
int returnweight() //返回权值操作
friend void Select(element h[],int k,int *a,int *b);//友元函数的声明
friend void HuffmanTreeCode(element HT[]);
friend void HuffmanTreeYima(element huff[],char cod[],int b);
private://类的私有成员
char letter,*code; //letter为字符,*code指向编码字符串
int weight; //权值
int parent; //⽗结点
Child a; //为⽗结点的左孩⼦还是右孩⼦};
第4章详细设计
4.1⼯程视图
图4.1⼯程视图
4.2类图视图
图4.2类图视图
4.3函数的调⽤关系
如下图:
图4.3函数调⽤关系图
4.4主程序流程图
4.5主要算法的流程图
图4.5.1哈夫曼编码函数
图4.5.2哈夫曼译码函数
图5.1哈夫曼编码与译码
这次课程设计写得⽐较仓促,程序许多处仍需要完善和修改。
写课程设计的过程中也暴露出⾃⾝的许多不⾜,⽐如对c++语⾔有许多遗忘,⽐如把算法思想付诸实际代码的能⼒仍然不⾜。
课程设计的过程也是对⾃⼰所学的知识回顾和检验的过程,在这期间不断遇到问题和解决问题也使我对所学过的知识有着更深层次的认识,编程能⼒也有很⼤的进步。
对于程序,不⾜之处是友元函数的定义使得类的封装性⼤⼤降低,程序的主函数不够简明,没有进⼀步细分函数的功能等。
附录:程序代码
#include
#include
#include
#include
#include
const int Lengh=1000; //最⼤长度为1000
char coding[100]; //存储⼆进制字符串
int n; //定义全局变量
ofstream file1("编码.txt");; //创建编码保存⽂件
ofstream file2("译码.txt");; //创建译码保存⽂件
enum Child{none,lchild,rchild}; //采⽤枚举标记事左孩⼦还是右孩⼦class element
{
public:
elememt();
void change(char l,char *c,int p,Child h,int w)
{
code=c;
letter=l;
a=h;
weight=w;
parent=p;
}
void getparent(int p)
void geta(Child h)
{
a=h;
}
void getweight(int w)
{
weight=w;
}
int returnweight()
{
return weight;
}
friend void Select(element h[],int k,int *a,int *b);
friend void HuffmanTreeCode(element HT[]);
friend void HuffmanTreeYima(element huff[],char cod[],int b);
private:
char letter,*code; //letter为字符,*code指向编码字符串
int weight; //权值域
int parent; //⽗结点序号
Child a; //为⽗结点的左孩⼦还是右孩⼦
};
void Select(element h[],int k,int *a,int *b);//寻找最⼩和次⼩节点的序号void InitHuffmanTree(element huffTree[],char t[],int w[]) //哈夫曼树的初始化{
int i,m=2*n-1,s1,s2; //no+n2=n 所以⼀要申请m个空间
for(i=0;i
{
huffTree[i].change(t[i],'\0',-1,none,w[i]);
}
for(;i<=m;i++) //后m-n个结点置空
{
huffTree[i].change(' ','\0',-1,none,0);
Select(huffTree,i-1,&s1,&s2); //在huffTree中找权值最⼩的两个结点s1,s2
huffTree[s1].getparent(i); //将s1,s2合并,则s1,s2的双亲是i
huffTree[s2].getparent(i);
huffTree[s1].geta(lchild); //s1是左孩⼦
huffTree[s2].geta(rchild); //s2是右孩⼦
huffTree[i].getweight(huffTree[s1].returnweight()+huffTree[s2].returnweight ());//s1,s2的双亲的权值为s1,s2权值之和}
}
void Select(element h[],int k,int *a,int *b) //寻找最⼩和次⼩节点的序号
{
int i;
int min1=1000; //初始化最⼩结点和次⼩结点
int min2=1000;
for (i=0;i<=k;i++)//找最⼩的结点序号
{
if (h[i].parent==-1&&h[i].weight
{
*a=i; //将i放⼊a中
min1=h[i].weight; //找到第⼀个最⼩结点
}
}
for(i=0;i<=k;i++) //找次⼩结点的序号
{
if(h[i].parent==-1&&(*a!=i)&&h[i].weight
{
*b=i;
min2=h[i].weight; //找到次最⼩结点
}
}
}
void HuffmanTreeCode(element HT[]) //字符编码
{
char *temp;
temp=(char *)malloc(n*sizeof(char)); //分配n个字符空间
temp[n-1]='\0'; //最后⼀个字符以后结束字符串
int p;
int s;
for(i=0;i
{
p=i;
s=n-1; //s为最后⼀个结点
while(HT[p].parent!=-1) //从字符结点回溯,直⾄根结点
{
if(HT[p].a==lchild) //p指向的如果是左孩⼦
temp[--s]='0'; //s位置字符为0
else if(HT[p].a==rchild) //p指向的如果是右孩⼦
temp[--s]='1'; //s位置字符为1
p=HT[p].parent; //回溯⽗结点
}
HT[i].code=(char *)malloc((n-s)*sizeof(char));//分配结点编码长度的内存空间strcpy(HT[i].code,temp+s); //将temp中从第s个位置开始,将编码拷贝到 HT[i].code printf("%c",HT[i].letter);
printf(": ");
printf("%s\n",HT[i].code); //打印出字符即对应的⼆进制字符串file1<
}
void HuffmanTreeYima(element huff[],char cod[],int b) //译码
{
char sen[100];
char temp[50];
char voidstr[]=" "; //空⽩字符串
int t=0; int s=0;
int xx=0;
for(int i=0 ; i
{
temp[t++]=cod[i]; //读取字符
temp[t] = '\0'; //有效字符串
for(int j=0;j
{
if (!strcmp(huff[j].code,temp)) //匹配成功
{
sen[s]=huff[j].letter; //将字符保存到sen中
s++;
xx+=t;
strcpy(temp,voidstr); //将TEMP置空
t=0; //t置空
break;
}
}
}
if(t==0) //t如果被置空了,表⽰都匹配出来了,打印译码
{
sen[s]='\0';
cout<<"译码为:"<
file2<
cout<
}
else //t如果没有被置空,源码⽆法被完全匹配{ cout<<"⼆进制源码有错!从第"< file2<<"⼆进制源码有错!从第"<
}
}
void main()
{
char a[Lengh],p;
int i,b[Lengh];
int symbol=1;
int x;
int k;
if(!file1)。